├── 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())
--------------------------------------------------------------------------------