Джарвис снова в деле

в 17:54, , рубрики: diy или сделай сам, python, Raspberry Pi

Наверняка, каждый мечтает о своем голосовом ассистенте, под катом еще одна реализация «Джарвиса» из известного фильма.

image

Давно не покидала мысль о своем «Jarvis» и управлении техникой в доме голосом. И вот, наконец, роки дошли до создания сего чуда. Над «мозгами» долго думать не пришлось, Raspberry Pi подходит идеально.

Итак, железо:

  • Raspberry pi 3 model b
  • USB камера logitech

Реализация

Работать наш ассистент будет по принципу Alexa/Hub:

  1. Активироваться оффлайн по определенному слову
  2. Распознать команду в облаке
  3. Выполнить команду
  4. Отчитаться о проделай работе либо сообщить запрашиваем информацию

Т.к. моя камера поддерживается из коробки, с драйверами возиться не пришлось, поэтому сразу переходим к программной части.

Оффлайн активация

Активация будет происходить с помощью CMU Sphinx, и все бы хорошо, но из коробки распознание происходит очень медленно, больше 10 сек, что абсолютно не подходит, для решения проблемы нужно очистить словарь от ненужных слов.

Устанавливаем все необходимое:

pip3 install SpeechRecognition
pip3 install pocketsphinx

далее

sudo nano /usr/local/lib/python3.4/dist-packages/speech_recognition/pocketsphinx-data/en-US
/pronounciation-dictionary.dict

удаляем все кроме нужного нам Джарвиса:

 jarvis JH AA R V AH S

Теперь pocketsphinx распознает довольно быстро.

Распознавание речи

Сначала была идея воспользоваться сервисом гугла, к тому же его поддержка есть в SpeechRecognition. Но как оказалось гугл берет за это деньги и не работает с физ. лицами.

Благо Яндекс тоже предоставляет такую возможность, бесплатно и предельно просто.

Регистрируемся, получаем API KEY. Все работу можно производить curl’om.

curl -X POST -H "Content-Type: audio/x-wav" --data-binary "@file" «https://asr.yandex.net/asr_xml?uuid=ya_uid&key=yf_api_key&topic=queries»

Синтер речи

Тут нам опять поможет Яндекс. Посылаем текст в ответ получаем файл с синтезированным текстом

curl «https://tts.voicetech.yandex.net/generate?format=wav&lang=ru-RU&speaker=zahar&emotion=good&key=ya_api_key» -G --data-urlencode "text=text" > file

Jarvis

Собираем все вместе и получаем такой скрипт.

#! /usr/bin/env python
# -*-coding:utf-8-*-
import os
import speech_recognition as sr
from xml.dom import minidom
import sys
import random

r = sr.Recognizer()
ya_uuid = ''
ya_api_key = ''


# os.system('echo "Ассист+ент зап+ущен" |festival --tts --language russian')


def convert_ya_asr_to_key():
    xmldoc = minidom.parse('./asr_answer.xml')
    itemlist = xmldoc.getElementsByTagName('variant')
    if len(itemlist) > 0:
        return itemlist[0].firstChild.nodeValue
    else:
        return False


def jarvis_on():
    with sr.WavFile("send.wav") as source:
        audio = r.record(source)

    try:
        t = r.recognize_sphinx(audio)
        print(t)
    except LookupError:
        print("Could not understand audio")

    return t == ("jarvis")


def jarvis_say(phrase):
    os.system(
        'curl "https://tts.voicetech.yandex.net/generate?format=wav&lang=ru-RU&speaker=zahar&emotion=good&key='+ya_api_key+'" -G --data-urlencode "text=' + phrase + '" > jarvis_speech.wav')
    os.system('aplay jarvis_speech.wav')


def jarvis_sya_good():
    phrases = ["Готово", "Сделано", "Слушаюсь", "Есть", "Что-то еще?", ]
    randitem = random.choice(phrases)
    jarvis_say(randitem)





try:
    while True:
        os.system('arecord -B --buffer-time=1000000 -f dat -r 16000 -d 3 -D plughw:1,0 send.wav')
        if jarvis_on():
            os.system('aplay jarvis_on.wav')
            os.system('arecord -B --buffer-time=1000000 -f dat -r 16000 -d 3 -D plughw:1,0 send.wav')
            os.system(
                'curl -X POST -H "Content-Type: audio/x-wav" --data-binary "@send.wav" "https://asr.yandex.net/asr_xml?uuid='+ya_uuid+'&key='+ya_api_key+'&topic=queries" > asr_answer.xml')
            command_key = convert_ya_asr_to_key()
            if (command_key):
                if (command_key in [‘key_word', ‘key_word1’, ‘key_word2']):
                    os.system(‘’)
                    jarvis_sya_good()
                    continue

              

except Exception:
jarvis_say('Что-то пошло не так')

Что тут происходит. Запускаем бесконечный цикл, arecord’om записываем три секунды и отправляем sphinx на распознание, если в файле встречается слово «jarvis»

 if jarvis_on():

проигрываем заранее записанный фаил оповещения об активации.

Опять записываем 3 секунды и отправляем Яндексу, в ответ получаем нашу команду. Далее выполняем действия исходя из команды.

На этом собственно все. Сценариев выполнения можно придумать великое множество.

Use-case

Теперь немного примеров реального моего использования

Philips Hue

Устанавливаем

pip install phue

В приложении Hue устанавливаем статический IP:

image

Запускаем:


#!/usr/bin/python
import sys
from phue import Bridge

b = Bridge('192.168.0.100') # Enter bridge IP here.

#If running for the first time, press button on bridge and run with b.connect() uncommented
#b.connect()

print (b.get_scene())

Выписываем ID нужных схем, вида «470d4c3c8-on-0»

Конечный вариант скрипта:

#!/usr/bin/python
import sys
from phue import Bridge


b = Bridge('192.168.0.100') # Enter bridge IP here.

#If running for the first time, press button on bridge and run with b.connect() uncommented
#b.connect()


if (sys.argv[1] == 'off'):
    b.set_light([1,2,3],'on', False)
else:
    b.activate_scene(1,sys.argv[1])

В джарвиса добавляем:

                if (command_key in ['включи свет', 'включить свет', 'свет']):
                    os.system('python3 /home/pi/smarthome/hue/hue.py a1167aa91-on-0')
                    jarvis_sya_good()
                    continue

                if (command_key in ['приглуши свет', 'приглушить свет']):
                    os.system('python3 /home/pi/smarthome/hue/hue.py ac637e2f0-on-0')
                    jarvis_sya_good()
                    continue

                if (command_key in ['выключи свет', 'выключить свет']):
                    os.system('python3 /home/pi/smarthome/hue/hue.py  "off"')
                    jarvis_sya_good()
                    continue

LG TV

Берем скрипт отсюда. После первого запуска и ввода кода сопряжения, сам код не меняется, поэтому можно выпилить эту часть из скрипта и оставить только управляющую.

В джарвиса добавляем:

 
                #1 - POWER 
                #24 - VOLUNE_UP
                #25 - VOLUME_DOWN
                #400 - 3D_VIDEO
                if (command_key in ['выключи телевизор', 'выключить телевизор']):
                    os.system('python3 /home/pi/smarthome/TV/tv2.py 1')
                    jarvis_sya_good()
                    continue

	        if (command_key in [‘прибавь громкость', 'громче']):
                    os.system('python3 /home/pi/smarthome/TV/tv2.py 24')
                    jarvis_sya_good()
                    continue

Радио

sudo apt-get install mpg123

В джарвиса добавляем:

 
               if (command_key in ['новости', ‘выключи новости’,’что происходит’]):
                    os.system(‘mpg123 URL')
                    continue

Еще можно поставить homebridge и управлять всем через Siri, в случае если до джарвиса не докричаться.

Что касается качества распознавания речи, не Alexa конечно, но на расстоянии до 5 метров процент верного попадания приличный. Главная проблема — речь из телевизораколонок записывается вместе с командами и мешает распознаванию.

На этом все, спасибо.

Автор: WSN3

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js