X-Git-Url: https://git.rvb.name/voicecontrol.git/blobdiff_plain/fa707ac30c7a66e4888012415590917f6e5cfa34..40d3028fd97291c60a966792ef2efdde114b8e71:/voicecontrol?ds=sidebyside diff --git a/voicecontrol b/voicecontrol index fafda2c..7216fef 100755 --- a/voicecontrol +++ b/voicecontrol @@ -1,9 +1,9 @@ -#!/usr/bin/env python3.8 +#!/usr/bin/env python3 import websockets,asyncio import sys from pyaudio import PyAudio, Stream, paInt16 -from contextlib import asynccontextmanager, contextmanager, AsyncExitStack +from contextlib import asynccontextmanager, contextmanager, AsyncExitStack, ExitStack from typing import AsyncGenerator, Generator from urllib.parse import urlencode, quote @@ -48,7 +48,7 @@ def SkipSource(source,seconds): global config try: if config["debug"]: - print("Skipping: ", seconds) + print("Skipping: ", seconds) bufs = int((seconds)*source._rate/source._frames_per_buffer) for i in range(bufs): buffer = source.read(source._frames_per_buffer) @@ -57,6 +57,12 @@ def SkipSource(source,seconds): except: pass +def Silence(speaker, seconds): + buf = bytes(speaker._frames_per_buffer) + bufs = int((seconds)*speaker._rate/speaker._frames_per_buffer) + for i in range(bufs): + speaker.write(buf) + def PlayBack(pyaud, text, mic = None): global config, last_time @@ -78,6 +84,7 @@ def PlayBack(pyaud, text, mic = None): decoder = MP3Decoder(req) speaker = pyaud.open(output=True, format=paInt16, channels=decoder.num_channels, rate=decoder.sample_rate) + Silence(speaker, 0.3) for chunk in decoder: speaker.write(chunk) @@ -117,42 +124,68 @@ def RunCommand(command, pyaud, mic = None): if command_url: try: + if config["debug"]: + print('Preparing command') if command_user: my_headers = urllib3.util.make_headers(basic_auth=command_user+':'+command_pwd) else: my_headers = urllib3.util.make_headers() my_headers['Content-Type']='text/plain' my_headers['Accept']='apllication/json' - http.request('POST',command_url,headers=my_headers,body=command.encode('UTF-8')) - if reply_url: - sleep(0.5) - res="NULL" - for i in range(api_attempts): - try: - if command_user: - my_headers = urllib3.util.make_headers(basic_auth=command_user+':'+command_pwd) - else: - my_headers = urllib3.util.make_headers() - req=http.request('GET',reply_url,headers=my_headers).data - res = json.loads(req)['state'].strip() - if config["debug"]: - print(res) - if not(res == 'NULL'): - break - sleep(1) - except KeyboardInterrupt: - raise - except: - sleep(1) - if res and not(res=="NULL"): - PlayBack(pyaud, res, mic=mic) - elif res=="NULL": - PlayBack(pyaud, "Сервер не ответил", mic=mic) - http.request('POST',command_url, headers=my_headers, body="") + if config["debug"]: + print('Sending command') + sent = False + for i in range(api_attempts): + try: + http.request('POST',command_url,headers=my_headers,body=command.encode('UTF-8')) + sent = True + break + except Exception as e: + print('Exception: '+str(e)) + sleep(0.5) + if sent: + if config["debug"]: + print('Command sent') + if reply_url: + sleep(0.5) + res="NULL" + for i in range(api_attempts): + try: + if command_user: + my_headers = urllib3.util.make_headers(basic_auth=command_user+':'+command_pwd) + else: + my_headers = urllib3.util.make_headers() + req=http.request('GET',reply_url,headers=my_headers).data + res = json.loads(req)['state'].strip() + if config["debug"]: + print(res) + if not(res == 'NULL'): + break + sleep(1) + except KeyboardInterrupt: + raise + except Exception as e: + print('Exception: '+str(e)) + sleep(1) + if res and not(res=="NULL"): + PlayBack(pyaud, res, mic=mic) + elif res=="NULL": + PlayBack(pyaud, "Сервер не ответил", mic=mic) + if command_user: + my_headers = urllib3.util.make_headers(basic_auth=command_user+':'+command_pwd) + else: + my_headers = urllib3.util.make_headers() + my_headers['Content-Type']='text/plain' + my_headers['Accept']='apllication/json' + command="" + http.request('POST',command_url, headers=my_headers, body=command.encode('UTF-8')) + else: + PlayBack(pyaud, "Сервер недоступен", mic=mic) except KeyboardInterrupt: raise - except: + except Exception as e: try: + print('Exception: '+str(e)) http.request('POST',command_url, headers=my_headers, body="") except: pass @@ -207,11 +240,10 @@ async def ListenPhrase(mic, server): except websockets.exceptions.ConnectionClosedError: raise except: - raise return '',0 -async def hello(uri): +async def main_loop(uri): global config, last_time @@ -220,49 +252,58 @@ async def hello(uri): rec_attempts = config["rec_attempts"] commands = config["commands"] - async with AsyncExitStack() as stack: - ws = await stack.enter_async_context(websockets.connect(uri)) - print('Type Ctrl-C to exit') - phrases = config["commands"] - phrases.append(config["keyphrase"]) - phrases = json.dumps(phrases, ensure_ascii=False) - await ws.send('{"config" : { "phrase_list" : '+phrases+', "sample_rate" : 16000.0}}') - - ws = await stack.enter_async_context(_polite_websocket(ws)) - p = stack.enter_context(_pyaudio()) - s = stack.enter_context(_pyaudio_open_stream(p, + + with ExitStack() as audio_stack: + p = audio_stack.enter_context(_pyaudio()) + s = audio_stack.enter_context(_pyaudio_open_stream(p, format = paInt16, channels = 1, rate = 16000, input = True, frames_per_buffer = 2000)) - while True: - phrase, confidence = await ListenPhrase(s, ws) - if config["debug"]: - print(phrase,confidence) - if phrase == keyphrase and confidence>=confidence_treshold : - PlayBack(p, "Я жду команду", mic=s) - command = "" - - for i in range(rec_attempts): - phrase, confidence = await ListenPhrase(s, ws) - if config["debug"]: - print(phrase,confidence) - if confidence > confidence_treshold: - if (not commands) or (phrase in commands): - if config["debug"]: - print("Command: ", phrase) - command = phrase - RunCommand(command, p, s) - break - else: - PlayBack(p, "Не знаю такой команды: "+phrase, mic=s) - else: - PlayBack(p, "Не поняла, слишком неразборчиво", mic=s) - - if not command: - PlayBack(p, "Так команду и не поняла...", mic=s) + while True: + try: + async with AsyncExitStack() as web_stack: + ws = await web_stack.enter_async_context(websockets.connect(uri)) + print('Type Ctrl-C to exit') + phrases = [] + config["commands"] + phrases.append(config["keyphrase"]) + phrases = json.dumps(phrases, ensure_ascii=False) + await ws.send('{"config" : { "phrase_list" : '+phrases+', "sample_rate" : 16000.0}}') + + ws = await web_stack.enter_async_context(_polite_websocket(ws)) + while True: + phrase, confidence = await ListenPhrase(s, ws) + if config["debug"]: + print(phrase,confidence) + if phrase == keyphrase and confidence>=confidence_treshold : + PlayBack(p, "Я жду команду", mic=s) + command = "" + + for i in range(rec_attempts): + phrase, confidence = await ListenPhrase(s, ws) + if config["debug"]: + print(phrase,confidence) + if confidence > confidence_treshold: + if (not commands) or (phrase in commands): + if config["debug"]: + print("Command: ", phrase) + command = phrase + RunCommand(command, p, s) + break + else: + PlayBack(p, "Не знаю такой команды: "+phrase, mic=s) + else: + PlayBack(p, "Не поняла, слишком неразборчиво", mic=s) + + if not command: + PlayBack(p, "Так команду и не поняла...", mic=s) + except KeyboardInterrupt: + raise + except Exception as e: + print('Exception: '+str(e)) + pass def get_config(path): @@ -379,7 +420,7 @@ while True: loop = asyncio.get_event_loop() loop.run_until_complete( - hello(f'ws://' + server)) + main_loop(f'ws://' + server)) except (Exception, KeyboardInterrupt) as e: loop.run_until_complete(