python

Голосовое управление компьютером и Python

  • пятница, 24 июля 2015 г. в 02:10:59
http://habrahabr.ru/post/263423/

Начитавшись разных постов о Google Voice и его использовании, решил написать что-то свое. А именно — голосовое управление компьютером. Сразу оговорюсь, что ОС — Windows.

Нам понадобится:

— Python 2.7
— библиотеки:
pyaudio
pycurl
pywin32
+ набор стандартных библиотек
— какой-либо аудиоконвертер поддерживающий flac и wav, а также работу из командной строки, я использовал этот.

Как это работает

Мы записываем аудиофайл, отправляем Google Voice-у, получаем ответ в виде:
{«status»:0,«id»:«5e34348f2887c7a3cc27dc3695ab4575-1»,«hypotheses»:[{«utterance»:«пример»,«confidence»:0.7581704}]},
и далее его обрабатываем, также научим компьютер «разговаривать», с помощью того-же Google Voice.

Начинаем

Для начала нам необходимо подключить все модули, чтобы потом к этому не возвращаться:

import time, pyaudio, wave, os, urllib,urllib2,pycurl,httplib,sys,win32api,win32con,string
from ctypes import *

Окей, теперь напишем функцию Talk, которая позволит компьютеру разговаривать с нами.

def Talk(text):
 
 def downloadFile(url, fileName):
    fp = open(fileName, "wb")
    curl = pycurl.Curl()
    curl.setopt(pycurl.URL, url)
    curl.setopt(pycurl.WRITEDATA, fp)
    curl.perform()
    curl.close()
    fp.close()

 def getGoogleSpeechURL(phrase):
    googleTranslateURL = "http://translate.google.com/translate_tts?tl=en&"
    parameters = {'q': phrase}
    data = urllib.urlencode(parameters)
    googleTranslateURL = "%s%s" % (googleTranslateURL,data)
    return googleTranslateURL

 def speakSpeechFromText(phrase):
    googleSpeechURL = getGoogleSpeechURL(phrase)
    downloadFile(googleSpeechURL,"ans.mp3")#файл, полученный с сервера сохраняется под именем ans.mp3


 speakSpeechFromText(text)
 
#используем кодеки, чтобы воспроизвести речь

 winmm = windll.winmm
 winmm.mciSendStringA('Open "ans.mp3" Type MPEGVideo Alias theMP3',0,0,0)
 winmm.mciSendStringA('Play theMP3 Wait',0,0,0)
 winmm.mciSendStringA("Close theMP3","",0,0)

В общем, получаем функцию Talk(text), которая соответственно «говорит» нам text.
Кодеки были единственным решением, которое позволило мне воспроизвести mp3 из Python.

Ах, да, еще Google общается с нами исключительно на английском (и воспринимает только англ.), т.к мне не удалось подружить Python и utf-8.

Запись

Следующий шаг — запись речи, которую будет обрабатывать Google. Смело копипастим:

def Record():
    CHUNK = 1024
    FORMAT = pyaudio.paInt16
    CHANNELS = 2
    RATE = 16000
    RECORD_SECONDS = 5
    WAVE_OUTPUT_FILENAME = "output.wav"

    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

    print("Recording...")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)

    print("Done recording.")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

Этот код находится на сайте pyaudio и я его оставил практически без изменений.

Но, вот и первая проблема, мы получили файл wav, а Google понимает flac… Непорядок.
Здесь нас выручит конверетер и модуль os:

def Convert():
    print "Converting"
    os.system('C:\Users\Егор\Desktop\Расширение\TotalAudioConverter\AudioConverter.exe C:\Users\Егор\Desktop\Расширение\output.wav C:\Users\Егор\Desktop\Расширение\output.flac')
    print "Done"

Здесь поясню, мы указываем путь к установленному конвертеру, а затем в качестве параметров передаем сначала входной файл, затем выходной (пути указывать полностью).

Посылаем нашу запись на сервер

def Send():
    global ANSWER
    url = 'https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en-EN'#Здесь можно выбрать язык
    flac=open('output.flac',"rb").read()
    header = {'Content-Type' : 'audio/x-flac; rate=16000'}
    req = urllib2.Request(url, flac, header)
    data = urllib2.urlopen(req)
    a = data.read()
    ANSWER = eval(a)
    if ANSWER['status'] == 5:
        print 'Sorry, I do not understand you.'
        Talk('Sorry, I do not understand you.')
        ANSWER = 0

    else:
     ANSWER = ANSWER['hypotheses'][0]['utterance']#Отбираем то что google нам ответил(можно иначе)
     print ANSWER
    os.remove('C:\Users\Егор\Desktop\Расширение\output.wav')#Удаляем ненужные записи
    os.remove('C:\Users\Егор\Desktop\Расширение\output.flac')
    return ANSWER


Обработка

Получив ответ, мы можем ее использовать. Здесь все зависит исключительно от вашей фантазии.

Просто приведу несколько примеров:

def Processing():

 global ANSWER
 if ANSWER == 0:
     return 0

elif 'chrome' in ANSWER.lower():
    os.system('C:\Users\Егор\AppData\Local\Google\Chrome\Application\chrome.exe')#Запускаем Google Chrome, если он услышал слово chrome)

elif 'skype' in ANSWER.lower():
    os.system('C:\Users\Егор\Downloads\SkypePortable\SkypePortable.exe')#аналогично


elif 'cd rom' in ANSWER.lower() or\
   'cd-rom' in ANSWER.lower() or\
   'open d' in ANSWER.lower() or\
   'dvd' in ANSWER.lower() or\
   'dvd-rom' in ANSWER.lower() or\
   'dvd rom' in ANSWER.lower() or\
   'cdrom' in ANSWER.lower() or\
   'cd - rom' in ANSWER.lower():
    winmm = windll.winmm
    winmm.mciSendStringA("set cdaudio door open", "", 0,0)#Если слышит что- то связанное с dvd то открывает лоток дисковода

Также еще я добавил функцию, которая на указанное время останавливала выполнение программы, но там большой код и я не вижу смысла выкладывать его здесь, т.к польза от него стремится к нолю.

Запускаем

После того, как мы описали эти функции, добавим следующий код:

print 'Hi, what do you want?'
Talk('Hi, what do you want?')
Record()
Convert()
print ('Sending...')
Send()
print 'Done'
Processing()

while True:
 ANSWER = None
 #Talk('Done.')
 print 'Do you want something else? (Your command\No)'
 Talk('Do you want something else??')
 Record()
 Convert()
 print 'Sending...'
 Send()
 print 'Done'

 #print ANSWER
 if ANSWER == 0:
     continue
 
 if ANSWER.lower()== 'no' or\#Если ответили нет, завершаем программу
    ANSWER.lower()== 'nope' or\
    ANSWER.lower()== 'not' or\
    ANSWER.lower()== 'nay':
     break
 else:
     Processing()

print 'Okay, bye'
Talk('Okay, bye')

Готово!

На этом хотелось бы закончить. Я рад, если кому-то помог.

Спасибо за внимание.