Skip to content

Commit b2f718f

Browse files
committed
* add asr online app
1 parent a8a085c commit b2f718f

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed

projects/demo_asr_online/app.png

2.62 KB
Loading

projects/demo_asr_online/app.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
id: app_asr_online
2+
name: ASR Online
3+
version: 1.0.0
4+
author: lxowalle
5+
icon: app.png
6+
desc: >-
7+
Connecting to an ASR server built on Sherpa-ONNX to use online speech
8+
recognition.
9+
files:
10+
- app_asr_online.py

projects/demo_asr_online/main.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
from wave import Error
2+
from maix import camera, display, app, time, image, audio
3+
from maix._maix.err import Err
4+
import asyncio, json, websockets
5+
import numpy as np
6+
7+
STATUS_OK = 0
8+
STATUS_EXIT = 1
9+
STATUS_SCAN_QRCODE = 2
10+
STATUS_SHOW_ASR = 3
11+
12+
class AsrOnlineClient:
13+
def __init__(self, exit_event):
14+
self.recorder = audio.Recorder(sample_rate=16000, channel=1)
15+
self.recorder.volume(100)
16+
self.audio_queue = asyncio.Queue()
17+
self.result_queue = asyncio.Queue()
18+
self.exit_event = exit_event
19+
pass
20+
21+
async def read_audio_queue(self):
22+
while not app.need_exit():
23+
indata, status = await self.audio_queue.get()
24+
yield indata, status
25+
26+
async def read_asr_result(self):
27+
while not app.need_exit():
28+
res, status = await self.result_queue.get()
29+
yield res, status
30+
31+
async def receive_results(self, socket):
32+
last_message = ""
33+
async for message in socket:
34+
if message != "Done!":
35+
if last_message != message:
36+
last_message = message
37+
38+
if last_message:
39+
decode_message = last_message.encode().decode('unicode_escape')
40+
status = STATUS_OK if not app.need_exit() else STATUS_EXIT
41+
await self.result_queue.put((json.loads(decode_message), status))
42+
print("Received: %s" % decode_message)
43+
else:
44+
return last_message
45+
46+
async def record_audio(self):
47+
while True:
48+
data = self.recorder.record(50)
49+
status = STATUS_OK if not app.need_exit() else STATUS_EXIT
50+
await self.audio_queue.put((data, status))
51+
await asyncio.sleep(0.005)
52+
53+
async def run(self, queues):
54+
while not app.need_exit():
55+
ip, port = await queues[0].get()
56+
print(f'recv ip:{ip} port:{port}')
57+
server_url = f"ws://{ip}:{port}"
58+
try:
59+
async with websockets.connect(server_url) as websocket:
60+
await queues[1].put('OK')
61+
self.receive_task = asyncio.create_task(self.receive_results(websocket))
62+
self.audio_task = asyncio.create_task(self.record_audio())
63+
print("Started! Please Speak")
64+
async for indata, status in self.read_audio_queue():
65+
if status == STATUS_EXIT:
66+
return
67+
samples_int16 = np.frombuffer(indata, dtype=np.int16)
68+
samples_float32 = samples_int16.astype(np.float32)
69+
samples_float32 = samples_float32 / 32768
70+
send_bytes = samples_float32.tobytes()
71+
await websocket.send(send_bytes)
72+
except websockets.exceptions.ConnectionClosedError as e:
73+
await queues[1].put('SCAN AGAIN')
74+
print(f'websockets exception {e}')
75+
except websockets.exceptions.WebSocketException as e:
76+
await queues[1].put('SCAN AGAIN')
77+
print(f'websockets exception {e}')
78+
except Exception as e:
79+
await queues[1].put('SCAN AGAIN')
80+
print(f'exception {e}')
81+
82+
async def ui(cam, disp, client, queues):
83+
detector = image.QRCodeDetector()
84+
status = 1 # 0, standby 1,scan qrcode 2,show the result of asr
85+
err_msg = ''
86+
ip = ''
87+
port = 0
88+
while not app.need_exit():
89+
if status == 0:
90+
msg = await queues[1].get()
91+
if msg == 'OK':
92+
status = 2
93+
elif msg == 'SCAN AGAIN':
94+
status = 1
95+
err_msg = f'connect ws://{ip}:{port} failed!'
96+
elif status == 1:
97+
img = cam.read()
98+
qrcodes = detector.detect(img)
99+
if len(qrcodes) > 0:
100+
payload = qrcodes[0].payload()
101+
try:
102+
json_res = json.loads(payload)
103+
ip = json_res["ip"]
104+
port = int(json_res["port"])
105+
print(f'send ip:{ip} port:{port}')
106+
img.clear()
107+
img.draw_string(10, 10, f"connect to ws://{ip}:{port}..")
108+
disp.show(img)
109+
await queues[0].put((ip, port))
110+
status = 0
111+
continue
112+
except Exception as e:
113+
print(f'Parse {payload} falied, except:{e}')
114+
continue
115+
title = "Scan QRCode"
116+
msg1='1. Prepare a json string generated QR code.'
117+
msg2='the format of json: {"ip":"127.0.0.1","port":6006}'
118+
msg3='2. Put the qrcode in the screen.'
119+
img.draw_string(10, 10, title)
120+
img.draw_string(10, 40, msg1)
121+
img.draw_string(10, 70, msg2)
122+
img.draw_string(10, 100, msg3)
123+
img.draw_string(10, 130, err_msg, image.COLOR_RED)
124+
disp.show(img)
125+
else:
126+
base_img = image.Image(480, 320)
127+
base_img.draw_string(10, 10, "Please Speak..(Press the uesr key to exit)", font="sourcehansans")
128+
disp.show(base_img)
129+
try:
130+
async for res, status in client.read_asr_result():
131+
if status == STATUS_EXIT:
132+
return
133+
print(f'res:{res}')
134+
img = base_img.copy()
135+
img.draw_string(10, 60, res['text'], image.COLOR_WHITE, font="sourcehansans")
136+
disp.show(img)
137+
except:
138+
print('something exit')
139+
return
140+
141+
142+
async def main():
143+
image.load_font("sourcehansans", "/maixapp/share/font/SourceHanSansCN-Regular.otf")
144+
cam = camera.Camera(480, 320)
145+
disp = display.Display()
146+
qrcode_queues = [asyncio.Queue(), asyncio.Queue()]
147+
exit_event = asyncio.Event()
148+
client = AsrOnlineClient(exit_event)
149+
150+
ui_task = asyncio.create_task(ui(cam, disp, client, qrcode_queues))
151+
client_task = asyncio.create_task(client.run(qrcode_queues))
152+
tasks = [ui_task, client_task]
153+
try:
154+
await asyncio.gather(*tasks)
155+
except Exception as e:
156+
print(f'Exception caught: {e}')
157+
158+
if __name__ == '__main__':
159+
asyncio.run(main())

0 commit comments

Comments
 (0)