Compare commits

...
59 Commits
Author SHA1 Message Date
IrvingGao ecf8180661 [tool] spi ws2812 2024-06-26 23:40:26 +08:00
IrvingGao 0e647e2e53 [tool] spi ws2812 2024-06-26 22:42:20 +08:00
IrvingGao 2040e3384c [tool] spi ws2812 2024-06-26 22:40:42 +08:00
IrvingGao 947a031a59 [tool] spi ws2812 2024-06-26 22:35:04 +08:00
IrvingGao 274b7235bc [tool] uart 2024-06-26 13:01:45 +08:00
IrvingGao a8a069e543 [tool] uart 2024-06-26 12:49:22 +08:00
IrvingGao 2a53c2d149 [tool] uart 2024-06-26 12:48:24 +08:00
IrvingGao 82d4840213 [tool] uart 2024-06-26 12:46:32 +08:00
IrvingGao 21e2055adc [tool] uart 2024-06-26 12:42:44 +08:00
IrvingGao 6a4834a186 [tool] uart 2024-06-26 12:20:40 +08:00
IrvingGao f4f45e1391 [tool] adc io 2024-06-25 23:09:14 +08:00
IrvingGao d95885295b [tool] adc io 2024-06-25 23:08:24 +08:00
IrvingGao 41bf558654 [log] print 2024-06-21 17:04:00 +08:00
IrvingGao 47ceb6abc4 [log] print 2024-06-21 14:56:20 +08:00
IrvingGao 0f234d730f [log] print 2024-06-21 14:55:04 +08:00
IrvingGao 0d68b3b490 [log] print 2024-06-21 14:37:40 +08:00
IrvingGao 4578d30ae4 [keyword] 2024-06-21 00:23:49 +08:00
IrvingGao 9223a1dde2 [led] speaking blue 2024-06-20 14:38:50 +08:00
IrvingGao eed3fdc064 [key] clear 2024-06-19 23:58:22 +08:00
IrvingGao d99dc07868 [key] clear 2024-06-19 00:00:31 +08:00
IrvingGao 29507e676e [shutdown] fix bugs 2024-06-18 23:43:25 +08:00
IrvingGao 800724cb54 [shutdown] fix bugs 2024-06-18 23:10:05 +08:00
IrvingGao bf2b8c2625 [event] fix bugs 2024-06-18 22:36:03 +08:00
IrvingGao fd78acf698 [event] fix bugs 2024-06-18 22:27:39 +08:00
IrvingGao 4044e2b3e6 [event] fix bugs 2024-06-18 22:25:52 +08:00
IrvingGao cc5009f368 [button] fix bugs 2024-06-18 22:18:31 +08:00
IrvingGao 70b3cc9a62 [button] fix bugs 2024-06-18 22:13:08 +08:00
IrvingGao bf5e27f9e0 [button] fix bugs 2024-06-18 22:04:58 +08:00
IrvingGao ae5d9bb3f5 [client] fix bugs 2024-06-18 21:57:18 +08:00
IrvingGao b47fe8d21e [client] fix bugs 2024-06-18 21:37:14 +08:00
IrvingGao b0651bdc55 [client] fix bugs 2024-06-18 21:29:35 +08:00
IrvingGao d24c928cd4 [client] fix bugs 2024-06-18 21:00:39 +08:00
IrvingGao 75445f84c5 [client] fix bugs 2024-06-18 20:57:56 +08:00
IrvingGao 9f36c06428 [client] fix bugs 2024-06-18 20:50:36 +08:00
IrvingGao 32b8fb5b71 [client] fix bugs 2024-06-18 20:43:50 +08:00
IrvingGao f430bf17e5 [client] fix bugs 2024-06-18 20:34:59 +08:00
IrvingGao 032c295d0c [client] fix bugs 2024-06-18 20:32:30 +08:00
IrvingGao 4c58ce3ce5 [client] fix bugs 2024-06-18 20:31:00 +08:00
IrvingGao 5a300c5140 [client] fix bugs 2024-06-18 20:30:03 +08:00
IrvingGao 9836499b3e [client] fix bugs 2024-06-18 20:17:19 +08:00
IrvingGao 6f25ca8aab [client] fix bugs 2024-06-18 20:16:57 +08:00
IrvingGao 4f24836626 [client] fix bugs 2024-06-18 20:09:41 +08:00
IrvingGao 240db3ef5a [client] fix bugs 2024-06-18 18:10:22 +08:00
IrvingGao 3c44dd8def [client] fix bugs 2024-06-18 18:09:12 +08:00
IrvingGao b71775faba [client] fix bugs 2024-06-18 17:56:32 +08:00
IrvingGao 016719cf75 [client] fix bugs 2024-06-18 17:48:59 +08:00
IrvingGao 9770d5b156 [client] fix bugs 2024-06-18 17:45:59 +08:00
IrvingGao 2968c16167 [client] fix bugs 2024-06-18 17:45:19 +08:00
IrvingGao b8e0c137a5 [client] fix bugs 2024-06-18 17:42:07 +08:00
IrvingGao 91f04da2aa [client] fix bugs 2024-06-18 17:40:43 +08:00
IrvingGao ada3fee80f [client] fix bugs 2024-06-18 17:38:01 +08:00
IrvingGao 1e037854fd [client] fix bugs 2024-06-18 17:31:00 +08:00
IrvingGao b431f2611b [client] fix bugs 2024-06-18 17:24:37 +08:00
IrvingGao 5370242726 [client] fix bugs 2024-06-18 17:14:01 +08:00
IrvingGao 30292e096b [client] fix bugs 2024-06-18 17:12:02 +08:00
IrvingGao af541c7a0f [client] fix bugs 2024-06-18 17:03:00 +08:00
IrvingGao 5c67ef58ff [bug] fix listening lock bugs 2024-06-18 16:10:11 +08:00
IrvingGao 0fd76583a1 [led] long off all led 2024-06-18 00:00:27 +08:00
IrvingGao 6bf8b53c64 [picovoice] update key 2024-06-17 23:34:38 +08:00
9 changed files with 902 additions and 88 deletions

No files matched your search

+14 -13
View File
@@ -2,6 +2,7 @@ from takway.board.base_hd import BaseHardware
import threading import threading
from datetime import datetime from datetime import datetime
import time import time
import subprocess
try: try:
import wiringpi import wiringpi
from wiringpi import GPIO from wiringpi import GPIO
@@ -41,7 +42,7 @@ class OrangePi(BaseHardware):
self.power_status = False # 单次触发按键状态 self.power_status = False # 单次触发按键状态
self.long_power_status = False self.long_power_status = False
self.short_power_status = False # self.short_power_status = False
self.button_init() self.button_init()
self.init_hd_thread() self.init_hd_thread()
@@ -76,16 +77,14 @@ class OrangePi(BaseHardware):
elif button_status_1 and not last_status_1: elif button_status_1 and not last_status_1:
if press_time_1: if press_time_1:
press_duration = (datetime.now() - press_time_1).total_seconds() press_duration = (datetime.now() - press_time_1).total_seconds()
print(f"{datetime.now()}: press_duration: {press_duration}") # if press_duration > 0.01:
if press_duration > 1: if press_duration > 3:
self.long_power_status = not self.long_power_status self.set_led_on('red')
# print(f"{datetime.now()}: long_power_status: {self.long_power_status} {self.short_power_status}")
elif press_duration > 5:
time.sleep(1) # 防止短按误触发
subprocess.Popen('sudo shutdown now', shell=True) subprocess.Popen('sudo shutdown now', shell=True)
else: else:
self.short_power_status = True self.long_power_status = not self.long_power_status
# print(f"{datetime.now()}: short_power_status: {self.short_power_status} {self.long_power_status}") # self.short_power_status = True
print(f"{datetime.now()}: press_duration: {press_duration}")
print(f"{datetime.now()}: button_status: {button_status_1}, last_button_status: {last_status_1}, power_status: {self.long_power_status}, interrupt_status: {self.short_power_status}") print(f"{datetime.now()}: button_status: {button_status_1}, last_button_status: {last_status_1}, power_status: {self.long_power_status}, interrupt_status: {self.short_power_status}")
press_time_1 = None press_time_1 = None
# TODO: 如果button_status_1和上一帧都是True or False,则判断为无效按键,忽略 # TODO: 如果button_status_1和上一帧都是True or False,则判断为无效按键,忽略
@@ -94,13 +93,15 @@ class OrangePi(BaseHardware):
# 更新LED状态 # 更新LED状态
if self.long_power_status: if self.long_power_status:
self.set_led_on('green') self.set_led_on('green')
if self.short_power_status: # if self.short_power_status:
self.set_led_on('blue') # self.set_led_on('blue')
else: # else:
self.set_led_off('blue') # self.set_led_off('blue')
else: else:
self.short_power_status = False self.short_power_status = False
self.set_led_off('green') self.set_led_off('green')
self.set_led_off('blue')
self.set_led_off('red')
def set_led_on(self, color='red'): def set_led_on(self, color='red'):
+6 -18
View File
@@ -1,7 +1,7 @@
import os import os
import json import json
import time import time
import datetime from datetime import datetime
import requests import requests
import struct import struct
from takway.common_utils import encode_bytes2str, decode_str2bytes from takway.common_utils import encode_bytes2str, decode_str2bytes
@@ -152,21 +152,9 @@ class BaseWebSocketClient:
def receive_per_data(self): def receive_per_data(self):
try: try:
recv_data = self.websocket.recv() recv_data = self.websocket.recv()
print(f"{datetime.now()}: receive websocket data.")
except websocket._exceptions.WebSocketConnectionClosedException: except websocket._exceptions.WebSocketConnectionClosedException:
return None, None return None, None
'''
try:
recv_data = json.loads(recv_data)
#解析头信息,假设头信息前 8 个字节包含两个长度字段
except json.JSONDecodeError as e:
# print(f"JSONDecodeError: {e}")
# is_end = True
pass
except Exception as e:
# print(f"receive_per_data error: {e}")
assert isinstance(recv_data, bytes), ValueError(f"Received data is not bytes, got {type(recv_data)}.")
return recv_data, type(recv_data)
'''
try: try:
#解析头信息,假设头信息前 8 个字节包含两个长度字段 #解析头信息,假设头信息前 8 个字节包含两个长度字段
@@ -178,15 +166,15 @@ class BaseWebSocketClient:
audio = recv_data[8 + text_length:8 + text_length + audio_length] audio = recv_data[8 + text_length:8 + text_length + audio_length]
text = json.loads(text_bytes.decode('utf-8')) text = json.loads(text_bytes.decode('utf-8'))
print("Received text:",text) # print("Received text:",text)
#处理音频数据,例如播放音频 #处理音频数据,例如播放音频
print("Received audio(length):",len(audio)) # print("Received audio(length):",len(audio))
return [text, audio], list return [text, audio], list
except TypeError as e: except TypeError as e:
try: try:
recv_data = json.loads(recv_data) recv_data = json.loads(recv_data)
print(f"json: {recv_data}") # print(f"json: {recv_data}")
return recv_data, type(recv_data) return recv_data, type(recv_data)
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
pass return None, None
+85 -50
View File
@@ -59,6 +59,10 @@ class WebSocketClinet:
# 唤醒事件 # 唤醒事件
self.wakeup_event = manager.Event() self.wakeup_event = manager.Event()
self.sleep_event = manager.Event()
# 打断事件
# self.interrupt_event = manager.Event()
# 监听事件 # 监听事件
self.listening_event = manager.Event() self.listening_event = manager.Event()
@@ -134,20 +138,21 @@ class WebSocketClinet:
recorder: takway.audio_utils.Recorder, recorder object recorder: takway.audio_utils.Recorder, recorder object
""" """
print("Hardware trigger thread started.") print("Hardware trigger thread started.")
last_short_power_status = False # last_short_power_status = False
board = self.board board = self.board
while True: while True:
# 开关按键被按下 # 开关按键被按下
if recorder.hardware.long_power_status: if recorder.hardware.long_power_status:
self.wakeup_event.set() self.wakeup_event.set()
'''
# 短时按键被按下,打断 # 短时按键被按下,打断
if recorder.hardware.short_power_status and not last_short_power_status: if recorder.hardware.short_power_status and not last_short_power_status:
self.speaking_event.clear() # self.interrupt_event.set()
self.listening_event.set()
recorder.hardware.short_power_status = False recorder.hardware.short_power_status = False
print("Interrupt conversation.") # print("Interrupt conversation.")
last_short_power_status = recorder.hardware.short_power_status last_short_power_status = recorder.hardware.short_power_status
'''
else: else:
self.wakeup_event.clear() self.wakeup_event.clear()
time.sleep(0.01) time.sleep(0.01)
@@ -170,25 +175,27 @@ class WebSocketClinet:
record_chunk_size = recorder.vad_chunk_size record_chunk_size = recorder.vad_chunk_size
# 开关按键被按下或被关键词唤醒 # 开关按键被按下或被关键词唤醒
if self.wakeup_event.is_set(): if self.wakeup_event.is_set():
print(f"{datetime.now()}: Wake up by button.") print(f"{datetime.now()}: Wake up by button.")
else: else:
if self.sleep_event.is_set():
print(f"{datetime.now()}: stay sleep mode.")
recorder.hardware.long_power_status = False
self.sleep_event.clear()
continue
if recorder.is_wakeup(data): if recorder.is_wakeup(data):
recorder.hardware.long_power_status = True recorder.hardware.long_power_status = True
self.wakeup_event.set() self.wakeup_event.set()
print(f"{datetime.now()}: wake up by voice.") print(f"{datetime.now()}: wake up by voice.")
else: else:
recorder.hardware.long_power_status = False
continue continue
# 设置为倾听模式 # 设置为倾听模式
self.listening_event.set() self.listening_event.set()
self.speaking_event.clear() self.speaking_event.clear()
# if board == 'orangepi':
# recorder.hardware.set_led_on("blue")
# wake up # wake up
is_bgn = True is_bgn = True
is_end = False is_end = False
@@ -200,6 +207,12 @@ class WebSocketClinet:
print("Start recording...") print("Start recording...")
# 准备对话状态 # 准备对话状态
while True: while True:
if self.sleep_event.is_set():
print(f"{datetime.now()}: sleep mode.")
recorder.hardware.long_power_status = False
self.sleep_event.clear()
break
if not self.wakeup_event.is_set(): if not self.wakeup_event.is_set():
break break
@@ -254,17 +267,22 @@ class WebSocketClinet:
single_chat_finish = False single_chat_finish = False
print(f"{datetime.now()}: single conversation finish, reset frames.") print(f"{datetime.now()}: single conversation finish, reset frames.")
# if board == 'orangepi':
# recorder.hardware.set_led_off("blue")
elif self.speaking_event.is_set(): elif self.speaking_event.is_set():
print(f"{datetime.now()}: wait for speaking close and listening start.") print(f"{datetime.now()}: wait for speaking finished and listening started or sleep mode.")
if board == 'orangepi': if board == 'orangepi':
recorder.hardware.set_led_on("red") recorder.hardware.set_led_on("blue")
self.listening_event.wait() while self.wakeup_event.is_set():
# 睡眠 or 监听状态
if self.sleep_event.is_set() or self.listening_event.is_set():
break
# if self.interrupt_event.is_set():
# print(f"{datetime.now()}: button interrupt (input).")
# break
if board == 'orangepi': if board == 'orangepi':
recorder.hardware.set_led_off("red") recorder.hardware.set_led_off("blue")
# 重新计时 # 重新计时
slience_bgn_t = time.time() slience_bgn_t = time.time()
print(f"{datetime.now()}: restart listening.")
def stream_record_process(self, def stream_record_process(self,
bytes_frames: bytes, bytes_frames: bytes,
@@ -300,6 +318,7 @@ class WebSocketClinet:
if is_end: if is_end:
# print("put None to client queue.") # print("put None to client queue.")
self.client_queue.put(None) self.client_queue.put(None)
print(f"{datetime.now()}: conversation is end.")
return True return True
else: else:
return False return False
@@ -348,6 +367,7 @@ class WebSocketClinet:
audio_dict = queue_data[1] audio_dict = queue_data[1]
try:
client.send_per_data( client.send_per_data(
audio=audio_dict['frames'], audio=audio_dict['frames'],
stream=True, stream=True,
@@ -355,14 +375,25 @@ class WebSocketClinet:
is_end=audio_dict['is_end'], is_end=audio_dict['is_end'],
encoding='base64', encoding='base64',
) )
except BrokenPipeError:
print(f"{datetime.now()}: web socket connection broken, skip send data.")
self.listening_event.set()
self.speaking_event.clear()
client.close_client()
break
# is_end后切换播放模式 # is_end后切换播放模式
if audio_dict['is_end']: if audio_dict['is_end']:
self.listening_event.clear() self.listening_event.clear()
self.speaking_event.set() self.speaking_event.clear()
print(f"{datetime.now()}: Finished send data.")
if not self.wakeup_event.is_set(): if not self.wakeup_event.is_set():
continue continue
if self.listening_event.is_set():
print(f"{datetime.now()}: listening or speaking, skip setup web socket connection.")
continue
# 接收数据 # 接收数据
while True: while True:
# 当唤醒状态被关闭时,退出循环 # 当唤醒状态被关闭时,退出循环
@@ -371,42 +402,44 @@ class WebSocketClinet:
self.speaking_event.clear() self.speaking_event.clear()
client.close_client() client.close_client()
break break
'''
# 当正在说话时接收到时,默认全是废消息
if self.listening_event.is_set() and not self.speaking_event.is_set():
client.close_client()
break
'''
print(f"{datetime.now()}: wait for receive data.")
response, data_type = client.receive_per_data() response, data_type = client.receive_per_data()
if data_type == dict: if data_type == dict:
print(f"{datetime.now()}: receive json data: {response}") # 打印接收到的消息 print(f"{datetime.now()}: receive json data: {response}") # 打印接收到的消息
# 误识别情况 # 5xx: 结束错误码处理
if response['code'] in [201, 501, 502, 503, 504, 505] : if response['code'] in [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545]:
# 恢复对话状态 # 恢复录音状态
self.listening_event.set() self.listening_event.set()
self.speaking_event.clear() self.speaking_event.clear()
break break
# 200: 正常结束
elif response['code'] == 200: elif response['code'] == 200:
self.audio_play_queue.put(('audio_json', response)) self.audio_play_queue.put(('audio_json', response))
if response['type'] == 'close':
break
# 201: 切换沉默模式
elif response['code'] == 201:
self.listening_event.clear()
self.speaking_event.clear()
self.sleep_event.set() # 沉默状态下,关闭唤醒状态
self.wakeup_event.clear()
elif data_type == list:
print(f"{datetime.now()}: receive text_audio_data")
# 切换播放模式 # 切换播放模式
self.listening_event.clear() self.listening_event.clear()
self.speaking_event.set() self.speaking_event.set()
if response['type'] == 'close': self.audio_play_queue.put(('text_audio_data', response))
break
elif data_type == list:
# ####################### 更新后的代码 #
print(f"{datetime.now()}: receive audio_list")
self.audio_play_queue.put(('audio_list', response))
elif data_type == bytes:
# 开始播放
# print(f"{datetime.now()}: receive audio data")
self.audio_play_queue.put(('audio_bytes', response))
elif data_type == None: elif data_type == None:
print(f"{datetime.now()}: receive None data, break loop.") print(f"{datetime.now()}: receive None data, break loop.")
# 切换录音模式
self.listening_event.set()
self.speaking_event.clear()
# print(f"listening_event: {self.listening_event.is_set()}, speaking_event: {self.speaking_event.is_set()}") # print(f"listening_event: {self.listening_event.is_set()}, speaking_event: {self.speaking_event.is_set()}")
break # 如果没有接收到消息,则退出循环 break # 如果没有接收到消息,则退出循环
client.close_client()
print(f"{datetime.now()}: web socket client closed.")
def audio_play_process(self): def audio_play_process(self):
@@ -419,19 +452,19 @@ class WebSocketClinet:
print("Audio play process started.") print("Audio play process started.")
audio_list = [] audio_list = []
while True: while True:
print("wait for audio data.")
item = self.audio_play_queue.get() item = self.audio_play_queue.get()
# 唤醒状态 # 唤醒状态
if not self.wakeup_event.is_set(): if not self.wakeup_event.is_set():
continue continue
if item[0] == 'audio_list': if item[0] == 'text_audio_data':
# TODO: 判断bytes是否是最后一个,如果是最后一个,则播放完毕,切换监听模式 # TODO: 判断bytes是否是最后一个,如果是最后一个,则播放完毕,切换监听模式
audio_info, audio_data = item[1] audio_text, audio_data = item[1]
data_type = audio_info['type']
print(f"{datetime.now()}: receive {data_type} data, start playing audio.")
print(f"{datetime.now()}: start playing audio.") print(f"{datetime.now()}: start playing audio.")
print(f"{datetime.now()}: audio text: {audio_text}")
if self.listening_event.is_set(): if self.listening_event.is_set():
continue continue
@@ -444,30 +477,29 @@ class WebSocketClinet:
# 播放音频 # 播放音频
try: try:
tts_audio = audio_list[0] # 取出第一个音频 tts_audio = audio_list[0] # 取出第一个音频
tts_audio = audio_player.check_audio_type(tts_audio, return_type=None) # tts_audio = audio_player.check_audio_type(tts_audio, return_type=None)
for i in range(0, len(tts_audio), audio_player.CHUNK): for i in range(0, len(tts_audio), audio_player.CHUNK):
audio_player.stream.write(tts_audio[i:i+audio_player.CHUNK]) audio_player.stream.write(tts_audio[i:i+audio_player.CHUNK])
# print("Playing {} data...{}/{}".format(item[0], i, len(tts_audio))) # print("Playing {} data...{}/{}".format(item[0], i, len(tts_audio)))
# 关闭状态 # 关闭状态
if not self.wakeup_event.is_set(): if not self.wakeup_event.is_set():
print(f"{datetime.now()}: speaker close.") print(f"{datetime.now()}: microphone and speaker close.")
self.listening_event.clear() self.listening_event.clear()
self.speaking_event.clear() self.speaking_event.clear()
break self.sleep_event.set() # 沉默状态下,关闭唤醒状态
# 按键打断播放
if self.listening_event.is_set() and not self.speaking_event.is_set():
print(f"{datetime.now()}: speaker interrupt.")
break break
if self.speaking_event.is_set():
if not self.speaking_event:
audio_list = [] # 清空音频列表
continue
# 播放最后一段音频 # 播放最后一段音频
audio_player.stream.write(tts_audio[i+audio_player.CHUNK:]) audio_player.stream.write(tts_audio[i+audio_player.CHUNK:])
audio_list.pop(0) # 弹出第一个音频 audio_list = [] # 清空音频列表
# audio_list.pop(0) # 弹出已播放音频
print(f"{datetime.now()}: audio data played.") print(f"{datetime.now()}: audio data played.")
else:
audio_list = [] # 清空音频列表
print(f"{datetime.now()}: audio data clear.")
continue
except TypeError as e: except TypeError as e:
print(f"audio play error: {e}") print(f"audio play error: {e}")
continue continue
@@ -477,12 +509,14 @@ class WebSocketClinet:
print(f"data_type: {data_type}") print(f"data_type: {data_type}")
if self.wakeup_event.is_set(): if self.wakeup_event.is_set():
if data_type == 'text': if data_type == 'text':
if self.wakeup_event.is_set():
# 切换播放模式 # 切换播放模式
self.listening_event.clear() self.listening_event.clear()
self.speaking_event.set() self.speaking_event.set()
if data_type in ['close', 'end']: if data_type in ['close', 'end']:
# 虽然程序到这里,但是扬声器不一定播放完毕,延迟用来避免问题 # 虽然程序到这里,但是扬声器不一定播放完毕,延迟用来避免问题
time.sleep(0.8) time.sleep(0.8)
if self.wakeup_event.is_set():
# 启动监听状态 # 启动监听状态
self.speaking_event.clear() self.speaking_event.clear()
self.listening_event.set() self.listening_event.set()
@@ -490,7 +524,7 @@ class WebSocketClinet:
"""
def excute_process(self): def excute_process(self):
''' '''
Args: Args:
@@ -512,4 +546,5 @@ class WebSocketClinet:
self.audio_play_queue.put((instruct, content)) self.audio_play_queue.put((instruct, content))
self.speaker_active_set.clear() self.speaker_active_set.clear()
"""
@@ -0,0 +1,557 @@
# ############################################### #
# 具备短按打断,长按切换唤醒问题
# ############################################### #
# basic
import io
import os
import sys
import time
import json
import random
from collections import deque
from datetime import datetime
# log
import logging
import warnings
# multiprocessing
import queue
import threading
import multiprocessing
# web request
import requests
import pyaudio
# hot words detection
import pvporcupine
from takway.apps.data_struct import QueueIterator
from takway.common_utils import *
from takway.audio_utils import PicovoiceRecorder, HDRecorder
from takway.clients.client_utils import BaseWebSocketClient
from takway.audio_utils import AudioPlayer
class WebSocketClinet:
def __init__(self,
board,
server_args,
recorder_args,
player_args,
log_args,
excute_args=None,
):
self.board = board
# server_args
self.server_args = server_args
# self.recorder_args
self.recorder_args = recorder_args
# player_args
self.player_args = player_args
# excute_args
self.excute_args = excute_args
# log_args
self.log_args = log_args
def process_init(self):
# multiprocessing
manager = multiprocessing.Manager()
self.trigger_queue = manager.Queue()
self.client_queue = manager.Queue()
self.audio_play_queue = manager.Queue()
self.excute_queue = manager.Queue()
# 唤醒事件
self.wakeup_event = manager.Event()
self.sleep_event = manager.Event()
# 打断事件
self.interrupt_event = manager.Event()
# 监听事件
self.listening_event = manager.Event()
# 播放事件
self.speaking_event = manager.Event()
processes = [
multiprocessing.Process(target=self.audio_process),
multiprocessing.Process(target=self.web_socket_client_process),
multiprocessing.Process(target=self.audio_play_process),
]
if self.excute_args.get('enable', False):
processes.append(
multiprocessing.Process(target=self.excute_process),
)
for process in processes:
time.sleep(0.5)
# time.sleep(2)
process.start()
for process in processes:
process.join()
def audio_process(self):
"""audio_process
Args:
trigger_queue: multiprocessing.Queue, trigger queue
client_queue: multiprocessing.Queue, client queue
"""
min_stream_record_time = self.recorder_args.pop('min_stream_record_time')
voice_trigger = self.recorder_args.pop('voice_trigger')
max_slience_time = self.recorder_args.pop('max_slience_time')
if voice_trigger:
recorder = PicovoiceRecorder(**self.recorder_args)
else:
voice_keys = ['access_key', 'keywords', 'keyword_paths', 'model_path','sensitivities', 'library_path']
for key in voice_keys:
self.recorder_args.pop(key)
recorder = HDRecorder(**self.recorder_args)
recorder.min_stream_record_time = min_stream_record_time
recorder.max_slience_time = max_slience_time
# self.hardware = recorder.hardware
# self.long_power_status = recorder.hardware.long_power_status
print(f"recorder.min_act_time: {recorder.min_act_time}")
print(f"recorder.max_slience_time: {recorder.max_slience_time}")
print("Audio Process started.")
# create threads
threads = [threading.Thread(target=self.hardware_trigger_thread, args=(recorder,))]
if voice_trigger:
vioce_threads = [
threading.Thread(target=self.voice_trigger_thread, args=(recorder,)),
]
threads.extend(vioce_threads)
for thread in threads:
thread.start()
print("Audio Process started.")
while True:
for thread in threads:
thread.join()
print(f"audio process exit") ; exit()
def hardware_trigger_thread(self, recorder):
"""hardware_trigger_thread
Args:
recorder: takway.audio_utils.Recorder, recorder object
"""
print("Hardware trigger thread started.")
last_short_power_status = False
board = self.board
while True:
# 开关按键被按下
if recorder.hardware.long_power_status:
self.wakeup_event.set()
# 短时按键被按下,打断
if recorder.hardware.short_power_status and not last_short_power_status:
self.interrupt_event.set()
recorder.hardware.short_power_status = False
print("Interrupt conversation.")
last_short_power_status = recorder.hardware.short_power_status
else:
self.wakeup_event.clear()
time.sleep(0.01)
def voice_trigger_thread(self, recorder):
"""voice_trigger_thread
Args:
recorder: takway.audio_utils.Recorder, recorder object
"""
board = self.board
print("Waiting for wake up...")
while True:
data = recorder.record_chunk_voice(
CHUNK=recorder.porcupine.frame_length,
return_type=None,
exception_on_overflow=False,
queue=None)
record_chunk_size = recorder.vad_chunk_size
# 开关按键被按下或被关键词唤醒
if self.wakeup_event.is_set():
print(f"{datetime.now()}: Wake up by button.")
else:
if self.sleep_event.is_set():
print(f"{datetime.now()}: stay sleep mode.")
recorder.hardware.long_power_status = False
self.sleep_event.clear()
continue
if recorder.is_wakeup(data):
recorder.hardware.long_power_status = True
self.wakeup_event.set()
print(f"{datetime.now()}: wake up by voice.")
else:
recorder.hardware.long_power_status = False
continue
# 设置为倾听模式
self.listening_event.set()
self.speaking_event.clear()
# wake up
is_bgn = True
is_end = False
frames = []
# status buffer
single_chat_finish = False
slience_bgn_t = time.time()
slience_time = 0
print("Start recording...")
# 准备对话状态
while True:
if self.sleep_event.is_set():
print(f"{datetime.now()}: sleep mode.")
recorder.hardware.long_power_status = False
self.sleep_event.clear()
break
if not self.wakeup_event.is_set():
break
if self.listening_event.is_set():
# 语音活动检测
data = recorder.record_chunk_voice(
CHUNK=record_chunk_size,
return_type=None,
exception_on_overflow=False)
is_speech = recorder.is_speech(data)
# 判断状态
if is_speech:
# print(f"{datetime.now()}: valid voice")
slience_bgn_t = time.time()
frames.append(data)
slience_time = time.time() - slience_bgn_t
# 长时沉默关闭唤醒状态:如果唤醒后超过一定时间没有说话/关闭按键被按下,则认为是结束
if slience_time > recorder.max_slience_time:
recorder.hardware.long_power_status = False
self.wakeup_event.clear()
break
# 短时沉默结束单次对话:沉默时间超过一定时间段(0.5s左右),则发送数据
if slience_time > recorder.min_act_time:
single_chat_finish = True
if single_chat_finish:
is_end = True
is_bgn = False
# print(f"{datetime.now()}: slience_time: {slience_time}")
# 流式发送数据
stream_reset_status = self.stream_record_process(
bytes_frames=recorder.write_wave_bytes(frames),
frames_size=len(frames),
record_chunk_size=record_chunk_size,
sample_rate=recorder.RATE,
min_stream_record_time=recorder.min_stream_record_time,
is_bgn=is_bgn,
is_end=is_end)
# print(f"stream_reset_status: {stream_reset_status}, is_bgn: {is_bgn}, is_end: {is_end}, frame: {len(frames)}")
if stream_reset_status:
frames.clear()
is_bgn = False
if single_chat_finish:
is_bgn = True
is_end = False
single_chat_finish = False
print(f"{datetime.now()}: single conversation finish, reset frames.")
elif self.speaking_event.is_set():
print(f"{datetime.now()}: wait for speaking close and listening start or sleep mode.")
if board == 'orangepi':
recorder.hardware.set_led_on("red")
while True:
# 睡眠 or 监听状态
if self.sleep_event.is_set() or self.listening_event.is_set():
break
if self.interrupt_event.is_set():
print(f"{datetime.now()}: button interrupt (input).")
break
if board == 'orangepi':
recorder.hardware.set_led_off("red")
# 重新计时
slience_bgn_t = time.time()
print(f"{datetime.now()}: restart listening.")
def stream_record_process(self,
bytes_frames: bytes,
frames_size: int,
record_chunk_size: int,
sample_rate: int,
min_stream_record_time: int,
is_bgn: bool,
is_end: bool):
'''
Args:
bytes_frames: bytes, audio data
frames_size: int, audio data size
record_chunk_size: int, audio data chunk size
is_bgn: bool, is begin of stream
is_end: bool, is end of stream
Returns:
bool, if stream reset status
'''
if len(bytes_frames) == 0:
return False
if frames_size*record_chunk_size >= min_stream_record_time*sample_rate or is_end:
if is_bgn and is_end:
return False
stream_data = dict(
frames=bytes_frames,
frames_size=frames_size,
chunk_size=record_chunk_size,
is_bgn=is_bgn,
is_end=is_end)
self.client_queue.put(('audio', stream_data))
if is_end:
# print("put None to client queue.")
self.client_queue.put(None)
return True
else:
return False
def web_socket_client_process(self):
client = BaseWebSocketClient(self.server_args['server_url'], self.server_args['session_id'])
print("Web socket client process started.")
# print("Web socket client process started.")
while True:
if self.client_queue.empty():
continue
print(f"{datetime.now()}: start setup web socket connection.")
# 第一级:唤醒状态下,连接服务器
if self.wakeup_event.is_set():
client.wakeup_client()
else:
print(f"not wake up, skip setup web socket connection.")
self.client_queue.get(block=False)
continue
# 播放状态下,不连接服务器
if self.speaking_event.is_set():
print(f"speaking, skip setup web socket connection.")
self.client_queue.get(block=False)
continue
# 发送数据
for queue_data in QueueIterator(self.client_queue):
# 发送音频数据
if queue_data[0] == 'audio':
# 当唤醒状态被关闭时,退出循环
if not self.wakeup_event.is_set():
self.listening_event.clear()
self.speaking_event.clear()
client.close_client()
break
# 播放时不得发送数据,默认废消息
if self.speaking_event.is_set() and not self.listening_event.is_set():
client.close_client()
break
audio_dict = queue_data[1]
client.send_per_data(
audio=audio_dict['frames'],
stream=True,
voice_synthesize=True,
is_end=audio_dict['is_end'],
encoding='base64',
)
# is_end后切换播放模式
if audio_dict['is_end']:
self.listening_event.clear()
self.speaking_event.set()
if not self.wakeup_event.is_set():
continue
# 接收数据
while True:
# 当唤醒状态被关闭时,退出循环
if not self.wakeup_event.is_set():
self.listening_event.clear()
self.speaking_event.clear()
client.close_client()
break
if self.interrupt_event.is_set():
self.listening_event.set()
self.speaking_event.clear()
break
response, data_type = client.receive_per_data()
if data_type == dict:
print(f"{datetime.now()}: receive json data: {response}") # 打印接收到的消息
# 5xx: 结束错误码处理
if response['code'] in [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545]:
# 恢复录音状态
self.listening_event.set()
self.speaking_event.clear()
break
# 200: 正常结束
elif response['code'] == 200:
self.audio_play_queue.put(('audio_json', response))
if response['type'] == 'close':
break
# 201: 切换沉默模式
elif response['code'] == 201:
self.listening_event.clear()
self.speaking_event.clear()
self.sleep_event.set() # 沉默状态下,关闭唤醒状态
self.wakeup_event.clear()
elif data_type == list:
print(f"{datetime.now()}: receive text_audio_data")
# 切换播放模式
self.listening_event.clear()
self.speaking_event.set()
self.audio_play_queue.put(('text_audio_data', response))
elif data_type == bytes:
# 开始播放
print(f"{datetime.now()}: receive audio bytes")
self.audio_play_queue.put(('audio_bytes', response))
elif data_type == None:
print(f"{datetime.now()}: receive None data, break loop.")
# 切换录音模式
self.listening_event.set()
self.speaking_event.clear()
# print(f"listening_event: {self.listening_event.is_set()}, speaking_event: {self.speaking_event.is_set()}")
break # 如果没有接收到消息,则退出循环
client.close_client()
print(f"{datetime.now()}: web socket client closed.")
def audio_play_process(self):
'''
Args:
audio_play_queue: multiprocessing.Queue, audio play queue
share_time_dict: multiprocessing.Manager.dict, shared time dict
'''
audio_player = AudioPlayer(**self.player_args)
print("Audio play process started.")
audio_list = []
while True:
print("wait for audio data.")
item = self.audio_play_queue.get()
# 唤醒状态
if not self.wakeup_event.is_set():
continue
if item[0] == 'text_audio_data':
# TODO: 判断bytes是否是最后一个,如果是最后一个,则播放完毕,切换监听模式
audio_text, audio_data = item[1]
print(f"{datetime.now()}: start playing audio.")
print(f"{datetime.now()}: audio text: {audio_text}")
if self.listening_event.is_set():
continue
if not self.speaking_event.is_set():
continue
audio_list.append(audio_data)
# 播放音频
try:
tts_audio = audio_list[0] # 取出第一个音频
tts_audio = audio_player.check_audio_type(tts_audio, return_type=None)
for i in range(0, len(tts_audio), audio_player.CHUNK):
audio_player.stream.write(tts_audio[i:i+audio_player.CHUNK])
# print("Playing {} data...{}/{}".format(item[0], i, len(tts_audio)))
# 关闭状态
if not self.wakeup_event.is_set():
print(f"{datetime.now()}: microphone and speaker close.")
self.listening_event.clear()
self.speaking_event.clear()
self.sleep_event.set() # 沉默状态下,关闭唤醒状态
break
# 按键打断播放
if self.interrupt_event.is_set():
print(f"{datetime.now()}: button interrupt (output).")
time.sleep(0.3) # 虽然程序到这里,但是扬声器不一定播放完毕,延迟用来避免问题
while not self.audio_play_queue.empty(): # 清空队列
self.audio_play_queue.get()
self.listening_event.set()
self.speaking_event.clear()
self.interrupt_event.clear()
break
if self.speaking_event.is_set():
# 播放最后一段音频
audio_player.stream.write(tts_audio[i+audio_player.CHUNK:])
audio_list = [] # 清空音频列表
# audio_list.pop(0) # 弹出已播放音频
print(f"{datetime.now()}: audio data played.")
else:
audio_list = [] # 清空音频列表
print(f"{datetime.now()}: audio data clear.")
continue
except TypeError as e:
print(f"audio play error: {e}")
continue
elif item[0] == 'audio_json':
data_type = item[1]['type']
print(f"data_type: {data_type}")
if self.wakeup_event.is_set():
if data_type == 'text':
if self.wakeup_event.is_set():
# 切换播放模式
self.listening_event.clear()
self.speaking_event.set()
if data_type in ['close', 'end']:
# 虽然程序到这里,但是扬声器不一定播放完毕,延迟用来避免问题
time.sleep(0.8)
if self.wakeup_event.is_set():
# 启动监听状态
self.speaking_event.clear()
self.listening_event.set()
def excute_process(self):
'''
Args:
excute_queue: multiprocessing.Queue, excute display queue
'''
print("Excute process started.")
while True:
if self.excute_queue.empty():
continue
if self.speaker_active_set.is_set():
instruct, content = self.excute_queue.get()
print(f"Got speaker info: {instruct, content}")
print(f"Playing {instruct} {content}...")
print(f"play {instruct} time: {datetime.now()}")
self.audio_play_queue.put((instruct, content))
self.speaker_active_set.clear()
+15
View File
@@ -0,0 +1,15 @@
from takway.board import OrangePi
import time
import wiringpi
from wiringpi import GPIO
if __name__ == '__main__':
ADC_Pin = 6
wiringpi.wiringPiSetup()
wiringpi.pinMode(ADC_Pin, GPIO.INPUT)
while True:
print(wiringpi.digitalRead(ADC_Pin))
time.sleep(0.1)
+36
View File
@@ -0,0 +1,36 @@
from rpi_ws281x import PixelStrip, Color
import time
# LED strip configuration:
LED_COUNT = 8 # Number of LED pixels.
LED_PIN = 16 # GPIO pin connected to the pixels (18 uses PWM!).
# LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
# Create NeoPixel object with appropriate configuration.
strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
# Intialize the library (must be called once before other functions).
strip.begin()
def color_chase(color, wait):
"""颜色追逐效果"""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait)
try:
while True:
# 渐变色追逐效果
for j in range(3):
color_chase(Color(255, 0, 0), 0.1) # 红色
color_chase(Color(0, 255, 0), 0.1) # 绿色
color_chase(Color(0, 0, 255), 0.1) # 蓝色
except KeyboardInterrupt:
color_chase(Color(0, 0, 0), 0.1) # 关闭时变为黑色
exit(0)
+133
View File
@@ -0,0 +1,133 @@
import wiringpi
import argparse
import time
parser = argparse.ArgumentParser(description='')
parser.add_argument("--channel", type=int, default=1, help='specify the spi channel')
parser.add_argument("--port", type=int, default=0, help='specify the spi port')
parser.add_argument("--speed", type=int, default=6400000, help='specify the spi speed')
parser.add_argument("--mode", type=int, default=0, help='specify the spi mode')
args = parser.parse_args()
# 0码 t0H 220ns~380ns
#(python 中GPIO口无法翻转这么快,python 可能执行一行代码需要800ns)
# ws2812 波特率如果设置为800kHZ, 1/0.8M=1.25us (0码或者1码所需要的时间)
# 方案1.
# 使用SPI产生ws2812时序,产生1码和0码,则可以使用传输一个byte 来代表一个0码或者1码,如下:
# 1111 1000 0xF8 #1码 高电平时间长,低电平时间短
# 1100 0000 0xC0 #0码 高电平时间短,低电平时间长
# 则得出SPI 波特率应该设置为800K*8
# 方案2. 见led_bak.py
# 使用SPI产生ws2812时序,产生1码和0码,则可以使用传输一个半个byte 来代表一个0码或者1码,如下:
# 1100 0x0c #1码 高电平时间长,低电平时间短
# 1000 0x08 #0码 高电平时间短,低电平时间长
# 则得出SPI 波特率应该设置为800K*4
sig_1 = 0xf8
sig_0 = 0xc0
def flatten_arrays(arrays):
return [element for sublist in arrays for element in sublist]
class WS2812:
def __init__(self, led_num=10):
self.led_num = led_num
self.ws2812_data = [[sig_0 for _ in range(24)] for _ in range(led_num)]
wiringpi.wiringPiSPISetupMode(args.channel, args.port, args.speed, args.mode)
# 设置一下下拉,否则第一盏灯的时序可能不正确
wiringpi.wiringPiSetup()
wiringpi.pullUpDnControl(11, 1)
print("ws2812_data len", len(self.ws2812_data))
print("spi mode: 0x%x" % args.mode)
print("max speed: %d Hz (%d KHz)\n" % (args.speed, args.speed / 1000), end='')
def ws2812_send_data(self):
default_tx = self.ws2812_data
wiringpi.wiringPiSPIDataRW(args.channel, bytes(flatten_arrays(default_tx)))
def ws2812_light_led(self, red, green, blue, pix_led):
default_tx = self.ws2812_data
color = green << 16 | red << 8 | blue
for i in range(24):
if color >> (24 - i - 1) & 1:
default_tx[pix_led][i] = sig_1
else:
default_tx[pix_led][i] = sig_0
def ws2812_light_one_led(self, red, green, blue, pix_led):
self.ws2812_light_led(red, green, blue, pix_led)
self.ws2812_send_data()
def ws2812_light_all_led(self, red, green, blue):
for i in range(self.led_num):
self.ws2812_light_led(red, green, blue, i)
self.ws2812_send_data()
def ws2812_rainbow(self):
colors = [[0xff, 0, 0], [0, 0xff, 0], [0, 0, 0xff]]
for i in range(self.led_num):
cur_color = colors[i % 3]
self.ws2812_light_led(cur_color[0], cur_color[1], cur_color[2], i)
self.ws2812_send_data()
def ws2812_water_lamp(self, red, green, blue, interval_time):
self.ws2812_shutoff_all()
for i in range(self.led_num):
self.ws2812_light_one_led(red, green, blue, i)
time.sleep(interval_time)
self.ws2812_shutoff_all()
def ws2812_shutoff_led(self, n):
self.ws2812_light_led(0, 0, 0, n)
self.ws2812_send_data()
def ws2812_shutoff_all(self):
for i in range(self.led_num):
self.ws2812_light_led(0, 0, 0, i)
self.ws2812_send_data()
def ws2812_gradient_run(self, start_red, start_green, start_blue, end_red, end_green, end_blue, steps, delay):
for step in range(steps):
# 计算当前步的颜色
curr_red = start_red + (end_red - start_red) * step // steps
curr_green = start_green + (end_green - start_green) * step // steps
curr_blue = start_blue + (end_blue - start_blue) * step // steps
# 清除当前颜色并应用新的渐变色
self.ws2812_shutoff_all()
for i in range(self.led_num):
self.ws2812_light_led(curr_red, curr_green, curr_blue, (i + step) % self.led_num) # 循环显示渐变色
self.ws2812_send_data()
time.sleep(delay)
if __name__ == '__main__':
ws2812 = WS2812(8)
while True:
# 示例:从蓝色渐变到红色,再从红色渐变回蓝色,每种颜色渐变10步,每步间隔0.1秒
ws2812.ws2812_gradient_run(0, 0, 0xff, 0xff, 0, 0, 10, 0.02)
time.sleep(1) # 等待1秒后开始反向渐变
ws2812.ws2812_gradient_run(0xff, 0, 0, 0, 0, 0xff, 10, 0.02)
time.sleep(1) # 再次等待1秒,形成完整的循环
ws2812.ws2812_light_all_led(0, 0, 0xff)
time.sleep(0.5)
ws2812.ws2812_light_all_led(0xff, 0, 0)
time.sleep(0.5)
ws2812.ws2812_light_all_led(0, 0xff, 0)
time.sleep(0.5)
ws2812.ws2812_shutoff_all()
time.sleep(0.5)
ws2812.ws2812_water_lamp(0xff, 0, 0, 0.2)
time.sleep(0.5)
+40
View File
@@ -0,0 +1,40 @@
import serial
import time
# UART配置
uart_port = '/dev/ttyS5' # UART端口路径
baud_rate = 115200 # 波特率
try:
# 初始化串口连接
ser = serial.Serial(uart_port, baud_rate, timeout=1)
print("UART初始化成功,开始读取数据...")
while True:
# 尝试读取一行数据
ori_data = ser.readline() # 读取一行原始数据
print(f"原始数据: {ori_data}")
data = ori_data.decode('utf-8').strip() # 读取一行并解码
print(f"解码后数据: {data}, 类型: {type(data)}")
if data: # 如果读取到数据
try:
num = int(data) # 尝试将读取的数据转换为整数
print(f"接收到的数字: {num}")
# print(f"接收到的字符串: {data}")
battery_level = num / 4096 * 4.8 /4.2 * 100 # 计算电池电量
print(f"电池电量: {battery_level}%")
except ValueError: # 如果转换失败,说明不是有效的数字
print("接收到的数据无法转换为数字")
time.sleep(1) # 每隔一秒检查一次新数据
except KeyboardInterrupt:
print("程序被中断,正在关闭UART连接...")
ser.close()
print("UART连接已关闭。")
except Exception as e:
print(f"发生错误: {e}")
if 'ser' in locals():
ser.close()
+16 -7
View File
@@ -10,10 +10,16 @@ if __name__ == '__main__':
# session_id = 'de9dc06c-2d74-42f8-9c11-9797f9fe0d01' # 麓旬 # session_id = 'de9dc06c-2d74-42f8-9c11-9797f9fe0d01' # 麓旬
# session_id = '3f7c2d8f-dc8a-4f1b-9fe0-6bf56c759a41' # 砚文 # session_id = '3f7c2d8f-dc8a-4f1b-9fe0-6bf56c759a41' # 砚文
session_id = '1fd56ce7-f21e-4eb4-8dc8-3a17960ae328' # 越哥 # session_id = '1fd56ce7-f21e-4eb4-8dc8-3a17960ae328' # 越哥
# session_id = 'bfcc4bbc-ac94-4604-8fd7-50545b8c6a5f' # 楼总 # session_id = 'bfcc4bbc-ac94-4604-8fd7-50545b8c6a5f' # 楼总
# session_id = '469f4a99-12a5-45a6-bc91-353df07423b6' # 鸿志 # session_id = '469f4a99-12a5-45a6-bc91-353df07423b6' # 鸿志
# session_id = '9ad8f855-f87c-41c8-a1f3-12e39d013c8c' # 1 积木 刚木
# session_id = '13e14fd9-a212-4cf1-a09b-5890344c769c' # 2
# session_id = 'e6e76e50-cb4c-4fe7-8660-8278e712c49b' # 3
# session_id = '6cbbfa55-58e3-437a-94c4-65eee1fa88a6' # 4
# session_id = 'c14cfd9f-3609-46f9-90aa-ba5a80b65015' # 5
excute_args = {} excute_args = {}
# excute_args = {'enable': True} # excute_args = {'enable': True}
@@ -27,9 +33,10 @@ if __name__ == '__main__':
# board = 'v329' # board = 'v329'
board = 'orangepi' board = 'orangepi'
# ACCESS_KEY = 'neOpatzY/mTzSyxdHs+ajNfpY/7SX1WrlqP/D6+5Km8THUxfZdcauQ==' # luxun # ACCESS_KEY = 'neOpatzY/mTzSyxdHs+ajNfpY/7SX1WrlqP/D6+5Km8THUxfZdcauQ==' # luxun
ACCESS_KEY = 'KwdWw3V5X9Dz0c9x+5HmGAMi7GbW0kvnaGOAPloIAYwhp06jNt5baw==' # yuyue # ACCESS_KEY = 'KwdWw3V5X9Dz0c9x+5HmGAMi7GbW0kvnaGOAPloIAYwhp06jNt5baw==' # yuyue
# ACCESS_KEY = 'hqNqw85hkJRXVjEevwpkreB8n8so3w9JPQ27qnCR5qTH8a3+XnkZTA==' # gaohz # ACCESS_KEY = 'GPFKn+Z9LHGh8yZNfWkLUYRixnrsyY+5w8KN3rpl6sw+Bi7XIqbgTw==' # gaohz (hzgao2000@gmail.com)
# ACCESS_KEY = 'Zo6Vx8YElrjMuA30K9yWMZvD06gcgOfyTi4rC6PPoqWL9mkhA/N/Lg==' # loujc # ACCESS_KEY = 'Zo6Vx8YElrjMuA30K9yWMZvD06gcgOfyTi4rC6PPoqWL9mkhA/N/Lg==' # loujc
# ACCESS_KEY = 'Ce5DkiDBQ9B7QNhebpQJyw/f3nhlqO5960yDUfkNAcl9gSj7RzIt6w==' # jinzc
mircophone_device = None mircophone_device = None
speaker_device = None speaker_device = None
@@ -51,11 +58,13 @@ if __name__ == '__main__':
elif board == 'orangepi': elif board == 'orangepi':
# keywords = ['hey google'] # keywords = ['hey google']
keywords = ['hey google', '芭比', '哔卡', '刚木', '星云'] keywords = ['哔卡', '刚木'] # '芭比', , '星云'
keyword_paths = None keyword_paths = None
model_path = None model_path = None
# #
keyword_paths = ["models/芭比_zh_raspberry-pi_v3_0_0/芭比_zh_raspberry-pi_v3_0_0.ppn", 'models/哔卡_zh_raspberry-pi_v3_0_0/哔卡_zh_raspberry-pi_v3_0_0.ppn', 'models/刚木_zh_raspberry-pi_v3_0_0/刚木_zh_raspberry-pi_v3_0_0.ppn', 'models/星云_zh_raspberry-pi_v3_0_0/星云_zh_raspberry-pi_v3_0_0.ppn'] keyword_paths = ['models/哔卡_zh_raspberry-pi_v3_0_0/哔卡_zh_raspberry-pi_v3_0_0.ppn', 'models/刚木_zh_raspberry-pi_v3_0_0/刚木_zh_raspberry-pi_v3_0_0.ppn']
# "models/芭比_zh_raspberry-pi_v3_0_0/芭比_zh_raspberry-pi_v3_0_0.ppn",
# , 'models/星云_zh_raspberry-pi_v3_0_0/星云_zh_raspberry-pi_v3_0_0.ppn'
model_path = "models/porcupine_params_zh.pv" model_path = "models/porcupine_params_zh.pv"
hd_trigger = 'button' hd_trigger = 'button'
@@ -116,12 +125,12 @@ if __name__ == '__main__':
parser.add_argument('--IN_frames_per_buffer', type=int, default=512, help='Frames per buffer') parser.add_argument('--IN_frames_per_buffer', type=int, default=512, help='Frames per buffer')
parser.add_argument('--min_stream_record_time', type=float, default=0.5, help='Min stream record time, sec') parser.add_argument('--min_stream_record_time', type=float, default=0.5, help='Min stream record time, sec')
parser.add_argument('--max_slience_time', type=int, default=10, help='Max slient time when recording, sec') parser.add_argument('--max_slience_time', type=int, default=10, help='Max slient time when recording, sec')
parser.add_argument('--min_act_time', type=float, default=0.6, help='Min inactive time, sec') # 等待多少秒沉默就发送音频 parser.add_argument('--min_act_time', type=float, default=0.3, help='Min inactive time, sec') # 等待多少秒沉默就发送音频
parser.add_argument('--mircophone_device', type=int, default=mircophone_device, help='Microphone device index') parser.add_argument('--mircophone_device', type=int, default=mircophone_device, help='Microphone device index')
# player paramters # player paramters
parser.add_argument('--speaker_device', type=int, default=speaker_device, help='Speaker device index') parser.add_argument('--speaker_device', type=int, default=speaker_device, help='Speaker device index')
parser.add_argument('--OUT_CHUNK', type=int, default=1024, help='Player chunk size') parser.add_argument('--OUT_CHUNK', type=int, default=512, help='Player chunk size')
parser.add_argument('--OUT_RATE', type=int, default=22050, help='Player audio rate') parser.add_argument('--OUT_RATE', type=int, default=22050, help='Player audio rate')
parser.add_argument('--OUT_FORMAT', type=int, default=16, help='Player audio format') parser.add_argument('--OUT_FORMAT', type=int, default=16, help='Player audio format')
parser.add_argument('--OUT_CHANNELS', type=int, default=1, help='Player audio channels') parser.add_argument('--OUT_CHANNELS', type=int, default=1, help='Player audio channels')