DINGDANG_Write a plugin

Original: https://www.v2ex.com/t/364588

DingDang is an open-source Chinese voice dialogue robot/smart speaker project that can work on Raspberry Pi. The purpose is to allow Chinese Hackers to quickly create personalized smart speakers similar to Amazon Echo.

Since Dingdong is completely open source, writing plug-ins to meet your own personalized needs has become the greatest joy of using Dingdong. You can freely access the services you need and let DingDong serve you better.

This article will teach you step by step how to write a weather plugin and finally publish it to dingdang-contrib.

Interactive example:

  • User: Weather
  • Jingle: Shenzhen weather. Today: sunny. Maximum temperature: 25 to 30 degrees Celsius; tomorrow: sunny. 26 to 31 degrees Celsius; the day after tomorrow: light rain. Maximum temperature: 23 to 29 degrees Celsius.

Ready to work

Install dingdang-contrib

First you need to make sure you have installed the clang third-party plugin library dingdang-contrib :

cd /home/pi/.dingdang
git clone http://github.com/wzpan/dingdang-contrib contrib
pip install -r contrib/requirements.txt
sudo apt-get install sox  # 用于播放音乐
sudo apt-get install libsox-fmt-mp3 # 添加 sox 的 mp3 格式支持

You can then develop your plugins in this plugin repository.

Understanding the Weather API

To implement the weather forecast function, it is necessary to understand the weather API. Through searching, I found a free weather API - Know the Weather . XinzhiWeather provides a variety of data information such as weather, air quality, and living index. The daily weather forecast is free and can be used to implement a weather forecast query plug-in.

Another reason to choose SenseWeather is that their API documentation is very detailed and demos are available in multiple languages . The following is an example of the official Python version:

import requests
from utils.const_value import API, KEY, UNIT, LANGUAGE
from utils.helper import getLocation

def fetchWeather(location):
    result = requests.get(API, params={
        'key': KEY,
        'location': location,
        'language': LANGUAGE,
        'unit': UNIT
    }, timeout=1)
    return result.text

if __name__ == '__main__':
    location = getLocation()
    result = fetchWeather(location)
    print(result)

Among them, APIis the address of the API, the API address of the daily weather forecast is https://api.seniverse.com/v3/weather/daily.json ; KEYit is the API key of knowing the weather, each registered account can get one The key; locationis the city name, for example, Shenzhen is 深圳or shenzhen; and languageand unitrepresent the language and unit respectively. Since they are optional parameters, they will not be introduced in detail here. Interested friends please read the official documentation.

There is nothing special to say about the entire code: first, a fetchWeatherfunction is , which uses the requests module to initiate an API request, and the request timeout is set to 1 second. Then call this function and print the returned result.

Write a weather plugin

After understanding the API of knowing the weather, writing a plug-in is a matter of course.

When writing a plug-in, the following issues should be considered:

  • What keywords should plugins use as user directives?
  • What configuration items need to be exposed?
  • How to process the user's input and get the required information?

Below we will address these issues as we write this plugin.

New plugin file

~/.dingdang/contribFirst create a new file Weather.py in :

# -*- coding: utf-8-*-                                                                                                                                                         # 天气插件
import sys

reload(sys)
sys.setdefaultencoding('utf8')

# Standard module stuff                                                                                                                                                        WORDS = []

def handle(text, mic, profile, wxbot=None):
    """
	Responds to user-input, typically speech text
	Arguments:
	    text -- user-input, typically transcribed speech
		mic -- used to interact with the user (for both input and output)
		profile -- contains information related to the user (e.g., phone
		number)
		wxbot -- wechat bot instance
	"""
    pass

def isValid(text):
    """
	    Returns True if the input is related to weather.
        Arguments:
		text -- user-input, typically transcribed speech
	"""
    pass

This is the template file for the plugin. A standard plugin contains at least three parts WORDS, isValidfunction and handlefunction . The following will introduce them one by one.

keyword setting

WORDSis a keyword list used to store the instruction keywords (pinyin) of this plugin. When the SST engine of Active Listening is set as an offline engine, the keywords set here will be automatically added to the voice command set of PocketSphinx, so that PocketSphinx can recognize this command.

WORDSAnother function of is as a criterion for judging whether it is a plug-in. If a .pyfile does not have a WORDSvariable, the file will be treated as an invalid plugin and will not respond to it.

Also related to the keyword is the isValidfunction , which is used to determine whether the command input by the user should be processed by this plugin. If the isValidreturn result is true, the handlefunction will be called to process the instruction. For the weather plugin, the keyword can be set to weather, that is, as long as the input contains "weather", this plugin will be used for processing. Therefore, the WORDSand isValidfunctions can be rewritten as:

...

WORDS = ["TIANQI"]

...

def isValid(text):
    """
	    Returns True if the input is related to weather.
        Arguments:
		text -- user-input, typically transcribed speech
	"""
    return u"天气" in text

handle function implementation

The next step is to implement the handle()function .

def handle(text, mic, profile, wxbot=None):
    """
	Responds to user-input, typically speech text
	Arguments:
	    text -- user-input, typically transcribed speech
		mic -- used to interact with the user (for both input and output)
		profile -- contains information related to the user (e.g., phone
		number)
		wxbot -- wechat bot instance
	"""
    pass

This function accepts four parameters:

  • textis the user instruction recognized by STT;
  • micIt is a microphone and speaker module, the most commonly used is to make the speaker speak by calling the mic.say()function ;
  • profileis the user configuration information, it is a dictionary that records ~/.dingdang/profile.ymlthe entire content of ;
  • wxbotIt is an instance of a WeChat robot, which can be used to send WeChat messages to users. The Camera plugin provides an example of sending photos to users via WeChat.

We can make a little adjustment to the fetchWeatherfunction , and put it into the code for easy reuse:

def fetch_weather(api, key, location):
    result = requests.get(api, params={
	'key': key,
        'location': location
    }, timeout=3)
    res = json.loads(result.text, encoding='utf-8')
    return res

Obviously, KEYand locationshould be configured as a user's configuration item, allowing the user to set it in the configuration file. So we can add the following configuration to the profile.yml configuration file:

# 天气
# 使用心知天气的接口
# https://www.seniverse.com/
weather:
    key: 'etxzx9abupxplhic' # 心知天气 API Key
    location: '深圳'

Next, call handlethe function in the fetch_weatherfunction to get the weather information:

def handle(text, mic, profile, wxbot=None):
    """
	Responds to user-input, typically speech text
	Arguments:
	    text -- user-input, typically transcribed speech
		mic -- used to interact with the user (for both input and output)
		profile -- contains information related to the user (e.g., phone
		number)
		wxbot -- wechat bot instance
	"""
    logger = logging.getLogger(__name__)
    # get config                                                                                                                                                                   if 'weather' not in profile or \
       not profile['weather'].has_key('key') or \
       not profile['weather'].has_key('location'):
        mic.say('天气插件配置有误,插件使用失败')
        return
    key = profile['weather']['key']
    location = profile['weather']['location']
    WEATHER_API = 'https://api.seniverse.com/v3/weather/daily.json'
    try:
        weather = fetch_weather(WEATHER_API, key, location)
        logger.debug("Weather report: ", weather)
        if weather.has_key('results'):
            daily = weather['results'][0]['daily']
            day_text = [u'今天', u'明天', u'后天']
            responds = u'%s 天气:' % location
            for day in range(len(day_text)):
                responds += u'%s:%s,%s 到%s 摄氏度。' % (day_text[day], daily[day]['text_day'], daily[day]['low'], daily[day]['high'])
            mic.say(responds)
        else:
            mic.say('抱歉,我获取不到天气数据,请稍后再试')
    except Exception, e:
        logger.error(e)
        mic.say('抱歉,我获取不到天气数据,请稍后再试')

Once done, you can restart clang to see if the plugin works properly.

Publish plugin

After the plugin is working properly, you can publish the plugin to dingdang-contrib so that more people can use your plugin.

First, visit the Github homepage of dingdang-contrib , click the [ fork ] button in the upper right corner, and fork the repository to your own account. If it has been forked before, this step can be skipped.

After forking the repository, there will also be a dingdang-contrib project under your account, click the green [ Clone or download ] button and write down the address of the new repository.

Copy the new warehouse address

Then execute the following command on the Raspberry Pi to add a new warehouse address:

cd ~/.dingdang/contrib
git remote add mine 新的仓库地址

Push the newly created plugin commit to your dingdang-contrib repository:

git add Weather.py
git commit -m "新增天气插件"
git push -u mine master

Visit your dingdang-contrib repository home page when you're done, and you'll see a prompt to create a pull request:

Tips for creating pull requests

Click the [ compare and pull request ] button to enter the pull request creation page and apply for merging your changes into the dingdang-contrib project:

Create a pull request

Fill in the purpose, usage examples and configuration items of the plugin carefully. After completion, click [Create pull requset] to complete the creation and wait for the review of the dingdang-robot organization.

Create a pull request

Once approved, your plugin is published successfully.

In order to let more people know the purpose of your plugin, you should also add the purpose of the plugin to the dingdang-contrib wiki . First add a plugin record to the home page:

Add plugin record

After completion, the home page will add a record of the plugin you created:

Add plugin record

Click the link of the plugin to enter the plugin details page creation page, fill in the same content as when you just created the pull request, that is, the purpose of the plugin, usage examples and configuration items (you can also add more information as needed).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324948541&siteId=291194637