-#!/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
import webrtcvad
+from pprint import pprint
+
@contextmanager
def _pyaudio() -> Generator[PyAudio, None, None]:
p = PyAudio()
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)
decoder = MP3Decoder(req)
speaker = pyaud.open(output=True, format=paInt16, channels=decoder.num_channels, rate=decoder.sample_rate)
+ pprint(speaker)
for chunk in decoder:
speaker.write(chunk)
last_time = time()
if mic:
- SkipSource(mic, elapsed + 0.5)
+ SkipSource(mic, elapsed + 0.2)
return elapsed
raise
except:
- pass
+ raise
else:
return 0
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
sz = int(mic._rate*frame)
sp = int(pause/frame)
- try:
-
- phrase = ""
- voice = False
+ phrase = ""
+ voice = False
- while not phrase:
- data = mic.read(sz)
- if len(data) == 0:
- break
- vd = vad.is_speech(data, mic._rate)
- if vd and not voice:
- voice = True
- if config["debug"]:
- print("+", end="")
+ while not phrase:
+ data = mic.read(sz)
+ if len(data) == 0:
+ break
+ vd = vad.is_speech(data, mic._rate)
+ if vd and not voice:
+ voice = True
+ if config["debug"]:
+ print("+", end="")
+ cnt = 0
+ if voice and not vd:
+ cnt = cnt + 1
+ if cnt > sp:
cnt = 0
- if voice and not vd:
- cnt = cnt + 1
- if cnt > sp:
- cnt = 0
- voice = False
- if config["debug"]:
- print("-")
- if voice:
- print("*",end="")
- await server.send(data)
- datatxt = await server.recv()
- data = json.loads(datatxt)
- try:
- phrase = data["text"]
- confidence = min(map(lambda x: x["conf"], data["result"]))
- except:
- pass
+ voice = False
+ if config["debug"]:
+ print("-")
+ if voice:
+ print("*",end="")
+ await server.send(data)
+ datatxt = await server.recv()
+ data = json.loads(datatxt)
+ try:
+ phrase = data["text"]
+ except:
+ pass
- last_time = time()
-
- return phrase, confidence
-
- except KeyboardInterrupt:
- raise
- except websockets.exceptions.ConnectionClosedError:
- raise
- except:
- raise
- return '',0
+ last_time = time()
+ return phrase
-async def hello(uri):
+async def main_loop(uri):
global config, last_time
keyphrase = config["keyphrase"]
- confidence_treshold = config["confidence_treshold"]
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 = await ListenPhrase(s, ws)
+ if config["debug"]:
+ print(phrase)
+ if phrase == keyphrase :
+ print("COMMAND!")
+ PlayBack(p, "Слушаю!", mic=s)
+ command = ""
+
+ for i in range(rec_attempts):
+ phrase = await ListenPhrase(s, ws)
+ if config["debug"]:
+ print(phrase)
+ 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):
except:
rec_attempts = 4
- try:
- confidence_treshold = float(config['vosk']['confidence_treshold'])
- except:
- confidence_treshold = 0.4
-
try:
vosk_server = config['vosk']['server']
except:
"asr_server": vosk_server,
"keyphrase": keyphrase,
"rec_attempts": rec_attempts,
- "confidence_treshold": confidence_treshold,
"tts_url": tts_url,
"tts_param": tts_param,
"api_attempts": api_attempts,
server = config['asr_server']
vad = webrtcvad.Vad(config['vad_mode'])
+last_time = time()
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:
+ raise
loop.run_until_complete(
loop.shutdown_asyncgens())
if isinstance(e, KeyboardInterrupt):