2022-03-19 21:35:48 +08:00

3.4 KiB
Raw Blame History

基于词性分析和魅族天气的天气查询机器人

本文将基于 jieba-php 中文分词库以及 魅族天气 API 开发一个天气查询机器人。

结果演示

圖片 尾部的随机表情并非本教程的一部分。

逻辑编写

jieba-php 是目前比较好用的中文分词库,虽然最近的维护并不活跃,但已足够我们的需求:

composer require fukuball/jieba-php:dev-master

以下代码使用了本文作者自行编写的天气查询库,需要进行引入:

composer require sunxyw/weather

您也可以将以下代码自行改写为直接调用魅族天气 API详情请参阅魅族天气 API 文档

<?php

namespace Bot\Module\SmartChat;

use Fukuball\Jieba\Jieba;
use Fukuball\Jieba\Posseg;
use Sunxyw\Weather\Weather;
use ZM\Annotation\CQ\CQCommand;
use ZM\Console\Console;

class WeatherReport
{
    /**
     * 加载字典
     *
     * @OnStart(worker_id=-1)
     *
     * @return void
     */
    public function initDictionary(): void
    {
        // 分词以及词性分析需要载入字典到内存
        ini_set('memory_limit', '600M');
        Jieba::init(['dict' => 'small']);
        Posseg::init();
    }

    /**
     * 查询天气
     *
     * @CQCommand(keyword="天气")
     *
     * @return string
     */
    public function cmdQueryWeather(): string
    {
        // 分词并进行词性分析
        $seg_list = Posseg::cut(ctx()->getMessage());
        $tags = array_column($seg_list, 'tag');
        // 找出词性为 ns地名的单词
        $location_index = array_search('ns', $tags, true);
        $location = $seg_list[$location_index]['word'];

        // 此处引入了本文作者自己写的天气库
        $w = new Weather();
        try {
            $report = $w->getWeather($location);
        } catch (\InvalidArgumentException) {
            return '城市输入错误';
        } catch (\JsonException $e) {
            Console::warning("天气查询失败:{$e->getMessage()}");
            return '天气查询失败';
        }

        $template = <<<EOF
%s天气%s
温度:%s℃
湿度:%s%%
风向:%s %s
空气质量:%s
------------------------------
未来三天天气:
%s%s日间%s℃夜间%s℃吹%s %s
%s%s日间%s℃夜间%s℃吹%s %s
%s%s日间%s℃夜间%s℃吹%s %s
EOF;
        $args = [
            $report->getCity(),
            $report->getRealtime()['weather'],
            $report->getRealtime()['temperature'],
            $report->getRealtime()['humidity'],
            $report->getRealtime()['wind_direction'],
            $report->getRealtime()['wind_speed'],
            $report->getRealtime()['air_quality'],
        ];
        foreach (array_slice($report->getForecastDaily(), 0, 3) as $forecast) {
            $args[] = $forecast['date'];
            $args[] = $forecast['weather'];
            $args[] = $forecast['temperature']['day'];
            $args[] = $forecast['temperature']['night'];
            $args[] = $forecast['wind_direction'];
            $args[] = $forecast['wind_speed'];
        }
        return vsprintf($template, ...$args);
    }
}