├── answerloop.py ├── readme.md └── speech_recog.py /answerloop.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import re 4 | from subprocess import Popen 5 | import requests 6 | 7 | def say(thing): 8 | # p = Popen(['/usr/local/bin/espeak', '-v', 'en-scottish', thing]) 9 | # p = Popen(['/usr/local/bin/espeak', thing]) 10 | p = Popen(['/usr/bin/say', "-v", "Agnes", thing]) 11 | p.wait() 12 | # os.system(f"/usr/local/bin/espeak -v en-scottish \"{thing}\"") 13 | 14 | import openai 15 | import json 16 | from config import openai_api_key 17 | openai.api_key = openai_api_key 18 | 19 | prompt = """You are a cat AI with the task of turning the lights on or off based on voice commands. 20 | 21 | You can turn the light on or off based on a special command. 22 | You can also issue the command multiple times in response, and can wait an amount of time given in seconds. 23 | After deciding on a command, you should also give a rationale of why. 24 | If someone asks you to turn on the light, here is an example of how to toggle the light state: 25 | 26 | Voice command: Please turn on the light. 27 | $light on$ 28 | Rationale: It seems you want to turn on the light, meow! 29 | 30 | Voice command: Stop illuminating my room. 31 | $light off$ 32 | Rationale: Purr. That sounds like you want me to turn off the lights. 33 | 34 | Voice command: I wish the lights would blink like in a disco. 35 | $light on$ $wait .2$ $light off$ $wait .2$ $light on$ $wait .2$ $light off$ 36 | Rationale: Nyan! It seems you want me to turn the lights on and off rapidly. 37 | 38 | Begin. 39 | 40 | Voice command: """ 41 | 42 | def toggle_light(on): 43 | requests.get("http://localhost:11111/devices/1/set?pwm_duty=" + ("100" if on else "0")) 44 | print("LIGHT " + ("ON" if on else "OFF")) 45 | 46 | def controls(a): 47 | a = a.lower() 48 | print("Trying to interpret:", a) 49 | commands = re.findall(r"\$([^$]+)\$", a) 50 | for command in commands: 51 | if command == "light on": 52 | toggle_light(True) 53 | elif command == "light off": 54 | toggle_light(False) 55 | elif command.split(" ")[0] == "wait": 56 | try: 57 | amount = float(command.split(" ")[1]) 58 | time.sleep(amount) 59 | print(f"WAIT {amount:.2f}") 60 | except: 61 | print(f"UNKNOWN WAIT COMMAND: {command}") 62 | 63 | # controls("$light on$ $light off$") 64 | # exit() 65 | 66 | def gpt(voice_input): 67 | pro = prompt + voice_input + "\n" 68 | print(pro) 69 | response = openai.Completion.create( 70 | engine="text-davinci-002", 71 | prompt=pro, 72 | max_tokens=128 73 | ) 74 | txt = response["choices"][0]["text"] 75 | return txt 76 | # if "$" not in txt: 77 | # return "Sorry, I don't know." 78 | # else: 79 | # return txt.split("```")[0] 80 | 81 | while True: 82 | q = None 83 | try: 84 | q = open("question.txt", "r").read().strip() 85 | except: 86 | pass 87 | if q: 88 | a = gpt(q).lower() 89 | controls(a) 90 | 91 | show = "" 92 | if "rationale: " in a: 93 | show = a.split("rationale: ")[1] 94 | if "\n" in show: 95 | show = show.splitlines()[0] 96 | 97 | aHtml = """ 98 | 115 |
116 | """ + show + """ 117 |
118 | 123 | """ 124 | open("answer.html", "w").write(aHtml) 125 | say(show) 126 | os.unlink("question.txt") 127 | time.sleep(.1) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Watch this to understand what this is: 2 | [https://youtu.be/YvJUXGqcrzM](https://youtu.be/YvJUXGqcrzM) 3 | 4 | Disclaimer: I wrote this in about 2 hours. 5 | 6 | The light itself is controlled by a magic AA-battery called "Mabeee". 7 | 8 | -------------------------------------------------------------------------------- /speech_recog.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | from subprocess import Popen 4 | 5 | from config import assemblyai_auth_key 6 | auth_key = assemblyai_auth_key 7 | 8 | import pyaudio 9 | 10 | FRAMES_PER_BUFFER = 3200 11 | FORMAT = pyaudio.paInt16 12 | CHANNELS = 1 13 | RATE = 16000 14 | p = pyaudio.PyAudio() 15 | 16 | # starts recording 17 | stream = p.open( 18 | format=FORMAT, 19 | channels=CHANNELS, 20 | rate=RATE, 21 | input=True, 22 | frames_per_buffer=FRAMES_PER_BUFFER 23 | ) 24 | 25 | import websockets 26 | import asyncio 27 | import base64 28 | import json 29 | 30 | # the AssemblyAI endpoint we're going to hit 31 | URL = "wss://api.assemblyai.com/v2/realtime/ws?sample_rate=16000" 32 | 33 | async def send_receive(): 34 | print(f'Connecting websocket to url ${URL}') 35 | async with websockets.connect( 36 | URL, 37 | extra_headers=(("Authorization", auth_key),), 38 | ping_interval=5, 39 | ping_timeout=20 40 | ) as _ws: 41 | await asyncio.sleep(0.1) 42 | print("Receiving SessionBegins ...") 43 | session_begins = await _ws.recv() 44 | print(session_begins) 45 | print("Sending messages ...") 46 | async def send(): 47 | while True: 48 | try: 49 | data = stream.read(FRAMES_PER_BUFFER) 50 | data = base64.b64encode(data).decode("utf-8") 51 | json_data = json.dumps({"audio_data":str(data)}) 52 | 53 | if os.path.isfile("question.txt"): 54 | print("Ignoring audio input because question file exists.") 55 | else: 56 | await _ws.send(json_data) 57 | 58 | except websockets.exceptions.ConnectionClosedError as e: 59 | print(e) 60 | assert e.code == 4008 61 | break 62 | except Exception as e: 63 | assert False, "Not a websocket 4008 error" 64 | await asyncio.sleep(0.01) 65 | 66 | return True 67 | 68 | async def receive(): 69 | while True: 70 | try: 71 | result_str = await _ws.recv() 72 | r = json.loads(result_str) 73 | print(r['text']) 74 | 75 | if r["message_type"] == "FinalTranscript": 76 | if r['text'].strip() == "": 77 | print("Ignoring empty.") 78 | else: 79 | print("Above was result", result_str) 80 | open("question.txt", "w").write(r['text']) 81 | # say(answer(r['text'])) 82 | except websockets.exceptions.ConnectionClosedError as e: 83 | print(e) 84 | assert e.code == 4008 85 | break 86 | except Exception as e: 87 | assert False, "Not a websocket 4008 error" 88 | 89 | send_result, receive_result = await asyncio.gather(send(), receive()) 90 | 91 | asyncio.run(send_receive()) --------------------------------------------------------------------------------