Minor API fixes for OH3
[voicecontrol.git] / voicecontrol
index fafda2c756ffc60ec5848b31be73698823cfb622..703e109f9920b3858979ebf37d5ea5b0b7835bc8 100755 (executable)
@@ -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
@@ -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)
@@ -148,7 +155,14 @@ def RunCommand(command, pyaud, mic = None):
           PlayBack(pyaud, res, mic=mic)
         elif res=="NULL":
           PlayBack(pyaud, "Сервер не ответил", mic=mic)  
-      http.request('POST',command_url, headers=my_headers, body="")
+      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'))
     except KeyboardInterrupt:
       raise
     except:
@@ -207,11 +221,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 +233,57 @@ 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:
+        pass
              
 def get_config(path):
   
@@ -379,7 +400,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(