mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 01:53:53 +08:00
update:去除print
This commit is contained in:
@@ -45,14 +45,14 @@ def parse_response(res):
|
|||||||
payload 类似与http 请求体
|
payload 类似与http 请求体
|
||||||
"""
|
"""
|
||||||
protocol_version = res[0] >> 4
|
protocol_version = res[0] >> 4
|
||||||
header_size = res[0] & 0x0f
|
header_size = res[0] & 0x0F
|
||||||
message_type = res[1] >> 4
|
message_type = res[1] >> 4
|
||||||
message_type_specific_flags = res[1] & 0x0f
|
message_type_specific_flags = res[1] & 0x0F
|
||||||
serialization_method = res[2] >> 4
|
serialization_method = res[2] >> 4
|
||||||
message_compression = res[2] & 0x0f
|
message_compression = res[2] & 0x0F
|
||||||
reserved = res[3]
|
reserved = res[3]
|
||||||
header_extensions = res[4:header_size * 4]
|
header_extensions = res[4 : header_size * 4]
|
||||||
payload = res[header_size * 4:]
|
payload = res[header_size * 4 :]
|
||||||
result = {}
|
result = {}
|
||||||
payload_msg = None
|
payload_msg = None
|
||||||
payload_size = 0
|
payload_size = 0
|
||||||
@@ -61,13 +61,13 @@ def parse_response(res):
|
|||||||
payload_msg = payload[4:]
|
payload_msg = payload[4:]
|
||||||
elif message_type == SERVER_ACK:
|
elif message_type == SERVER_ACK:
|
||||||
seq = int.from_bytes(payload[:4], "big", signed=True)
|
seq = int.from_bytes(payload[:4], "big", signed=True)
|
||||||
result['seq'] = seq
|
result["seq"] = seq
|
||||||
if len(payload) >= 8:
|
if len(payload) >= 8:
|
||||||
payload_size = int.from_bytes(payload[4:8], "big", signed=False)
|
payload_size = int.from_bytes(payload[4:8], "big", signed=False)
|
||||||
payload_msg = payload[8:]
|
payload_msg = payload[8:]
|
||||||
elif message_type == SERVER_ERROR_RESPONSE:
|
elif message_type == SERVER_ERROR_RESPONSE:
|
||||||
code = int.from_bytes(payload[:4], "big", signed=False)
|
code = int.from_bytes(payload[:4], "big", signed=False)
|
||||||
result['code'] = code
|
result["code"] = code
|
||||||
payload_size = int.from_bytes(payload[4:8], "big", signed=False)
|
payload_size = int.from_bytes(payload[4:8], "big", signed=False)
|
||||||
payload_msg = payload[8:]
|
payload_msg = payload[8:]
|
||||||
if payload_msg is None:
|
if payload_msg is None:
|
||||||
@@ -78,8 +78,8 @@ def parse_response(res):
|
|||||||
payload_msg = json.loads(str(payload_msg, "utf-8"))
|
payload_msg = json.loads(str(payload_msg, "utf-8"))
|
||||||
elif serialization_method != NO_SERIALIZATION:
|
elif serialization_method != NO_SERIALIZATION:
|
||||||
payload_msg = str(payload_msg, "utf-8")
|
payload_msg = str(payload_msg, "utf-8")
|
||||||
result['payload_msg'] = payload_msg
|
result["payload_msg"] = payload_msg
|
||||||
result['payload_size'] = payload_size
|
result["payload_size"] = payload_size
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -122,7 +122,9 @@ class ASRProvider(ASRProviderBase):
|
|||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _generate_header(message_type=CLIENT_FULL_REQUEST, message_type_specific_flags=NO_SEQUENCE) -> bytearray:
|
def _generate_header(
|
||||||
|
message_type=CLIENT_FULL_REQUEST, message_type_specific_flags=NO_SEQUENCE
|
||||||
|
) -> bytearray:
|
||||||
"""Generate protocol header."""
|
"""Generate protocol header."""
|
||||||
header = bytearray()
|
header = bytearray()
|
||||||
header_size = 1
|
header_size = 1
|
||||||
@@ -143,11 +145,7 @@ class ASRProvider(ASRProviderBase):
|
|||||||
"user": {
|
"user": {
|
||||||
"uid": str(uuid.uuid4()),
|
"uid": str(uuid.uuid4()),
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {"reqid": reqid, "show_utterances": False, "sequence": 1},
|
||||||
"reqid": reqid,
|
|
||||||
"show_utterances": False,
|
|
||||||
"sequence": 1
|
|
||||||
},
|
|
||||||
"audio": {
|
"audio": {
|
||||||
"format": "raw",
|
"format": "raw",
|
||||||
"rate": 16000,
|
"rate": 16000,
|
||||||
@@ -158,18 +156,23 @@ class ASRProvider(ASRProviderBase):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _send_request(self, audio_data: List[bytes], segment_size: int) -> Optional[str]:
|
async def _send_request(
|
||||||
|
self, audio_data: List[bytes], segment_size: int
|
||||||
|
) -> Optional[str]:
|
||||||
"""Send request to Volcano ASR service."""
|
"""Send request to Volcano ASR service."""
|
||||||
try:
|
try:
|
||||||
auth_header = {'Authorization': 'Bearer; {}'.format(self.access_token)}
|
auth_header = {"Authorization": "Bearer; {}".format(self.access_token)}
|
||||||
async with websockets.connect(self.ws_url, additional_headers=auth_header) as websocket:
|
async with websockets.connect(
|
||||||
|
self.ws_url, additional_headers=auth_header
|
||||||
|
) as websocket:
|
||||||
# Prepare request data
|
# Prepare request data
|
||||||
request_params = self._construct_request(str(uuid.uuid4()))
|
request_params = self._construct_request(str(uuid.uuid4()))
|
||||||
print(request_params)
|
|
||||||
payload_bytes = str.encode(json.dumps(request_params))
|
payload_bytes = str.encode(json.dumps(request_params))
|
||||||
payload_bytes = gzip.compress(payload_bytes)
|
payload_bytes = gzip.compress(payload_bytes)
|
||||||
full_client_request = self._generate_header()
|
full_client_request = self._generate_header()
|
||||||
full_client_request.extend((len(payload_bytes)).to_bytes(4, 'big')) # payload size(4 bytes)
|
full_client_request.extend(
|
||||||
|
(len(payload_bytes)).to_bytes(4, "big")
|
||||||
|
) # payload size(4 bytes)
|
||||||
full_client_request.extend(payload_bytes) # payload
|
full_client_request.extend(payload_bytes) # payload
|
||||||
|
|
||||||
# Send header and metadata
|
# Send header and metadata
|
||||||
@@ -177,22 +180,29 @@ class ASRProvider(ASRProviderBase):
|
|||||||
await websocket.send(full_client_request)
|
await websocket.send(full_client_request)
|
||||||
res = await websocket.recv()
|
res = await websocket.recv()
|
||||||
result = parse_response(res)
|
result = parse_response(res)
|
||||||
if 'payload_msg' in result and result['payload_msg']['code'] != self.success_code:
|
if (
|
||||||
|
"payload_msg" in result
|
||||||
|
and result["payload_msg"]["code"] != self.success_code
|
||||||
|
):
|
||||||
logger.bind(tag=TAG).error(f"ASR error: {result}")
|
logger.bind(tag=TAG).error(f"ASR error: {result}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for seq, (chunk, last) in enumerate(self.slice_data(audio_data, segment_size), 1):
|
for seq, (chunk, last) in enumerate(
|
||||||
|
self.slice_data(audio_data, segment_size), 1
|
||||||
|
):
|
||||||
if last:
|
if last:
|
||||||
audio_only_request = self._generate_header(
|
audio_only_request = self._generate_header(
|
||||||
message_type=CLIENT_AUDIO_ONLY_REQUEST,
|
message_type=CLIENT_AUDIO_ONLY_REQUEST,
|
||||||
message_type_specific_flags=NEG_SEQUENCE
|
message_type_specific_flags=NEG_SEQUENCE,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
audio_only_request = self._generate_header(
|
audio_only_request = self._generate_header(
|
||||||
message_type=CLIENT_AUDIO_ONLY_REQUEST
|
message_type=CLIENT_AUDIO_ONLY_REQUEST
|
||||||
)
|
)
|
||||||
payload_bytes = gzip.compress(chunk)
|
payload_bytes = gzip.compress(chunk)
|
||||||
audio_only_request.extend((len(payload_bytes)).to_bytes(4, 'big')) # payload size(4 bytes)
|
audio_only_request.extend(
|
||||||
|
(len(payload_bytes)).to_bytes(4, "big")
|
||||||
|
) # payload size(4 bytes)
|
||||||
audio_only_request.extend(payload_bytes) # payload
|
audio_only_request.extend(payload_bytes) # payload
|
||||||
# Send audio data
|
# Send audio data
|
||||||
await websocket.send(audio_only_request)
|
await websocket.send(audio_only_request)
|
||||||
@@ -201,9 +211,12 @@ class ASRProvider(ASRProviderBase):
|
|||||||
response = await websocket.recv()
|
response = await websocket.recv()
|
||||||
result = parse_response(response)
|
result = parse_response(response)
|
||||||
|
|
||||||
if 'payload_msg' in result and result['payload_msg']['code'] == self.success_code:
|
if (
|
||||||
if len(result['payload_msg']['result']) > 0:
|
"payload_msg" in result
|
||||||
return result['payload_msg']['result'][0]["text"]
|
and result["payload_msg"]["code"] == self.success_code
|
||||||
|
):
|
||||||
|
if len(result["payload_msg"]["result"]) > 0:
|
||||||
|
return result["payload_msg"]["result"][0]["text"]
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.bind(tag=TAG).error(f"ASR error: {result}")
|
logger.bind(tag=TAG).error(f"ASR error: {result}")
|
||||||
@@ -231,7 +244,7 @@ class ASRProvider(ASRProviderBase):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def read_wav_info(data: io.BytesIO = None) -> (int, int, int, int, int):
|
def read_wav_info(data: io.BytesIO = None) -> (int, int, int, int, int):
|
||||||
with io.BytesIO(data) as _f:
|
with io.BytesIO(data) as _f:
|
||||||
wave_fp = wave.open(_f, 'rb')
|
wave_fp = wave.open(_f, "rb")
|
||||||
nchannels, sampwidth, framerate, nframes = wave_fp.getparams()[:4]
|
nchannels, sampwidth, framerate, nframes = wave_fp.getparams()[:4]
|
||||||
wave_bytes = wave_fp.readframes(nframes)
|
wave_bytes = wave_fp.readframes(nframes)
|
||||||
return nchannels, sampwidth, framerate, nframes, len(wave_bytes)
|
return nchannels, sampwidth, framerate, nframes, len(wave_bytes)
|
||||||
@@ -247,17 +260,19 @@ class ASRProvider(ASRProviderBase):
|
|||||||
data_len = len(data)
|
data_len = len(data)
|
||||||
offset = 0
|
offset = 0
|
||||||
while offset + chunk_size < data_len:
|
while offset + chunk_size < data_len:
|
||||||
yield data[offset: offset + chunk_size], False
|
yield data[offset : offset + chunk_size], False
|
||||||
offset += chunk_size
|
offset += chunk_size
|
||||||
else:
|
else:
|
||||||
yield data[offset: data_len], True
|
yield data[offset:data_len], True
|
||||||
|
|
||||||
async def speech_to_text(self, opus_data: List[bytes], session_id: str) -> Tuple[Optional[str], Optional[str]]:
|
async def speech_to_text(
|
||||||
|
self, opus_data: List[bytes], session_id: str
|
||||||
|
) -> Tuple[Optional[str], Optional[str]]:
|
||||||
"""将语音数据转换为文本"""
|
"""将语音数据转换为文本"""
|
||||||
try:
|
try:
|
||||||
# 合并所有opus数据包
|
# 合并所有opus数据包
|
||||||
pcm_data = self.decode_opus(opus_data, session_id)
|
pcm_data = self.decode_opus(opus_data, session_id)
|
||||||
combined_pcm_data = b''.join(pcm_data)
|
combined_pcm_data = b"".join(pcm_data)
|
||||||
|
|
||||||
# 直接使用PCM数据
|
# 直接使用PCM数据
|
||||||
# 计算分段大小 (单声道, 16bit, 16kHz采样率)
|
# 计算分段大小 (单声道, 16bit, 16kHz采样率)
|
||||||
@@ -268,7 +283,9 @@ class ASRProvider(ASRProviderBase):
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
text = await self._send_request(combined_pcm_data, segment_size)
|
text = await self._send_request(combined_pcm_data, segment_size)
|
||||||
if text:
|
if text:
|
||||||
logger.bind(tag=TAG).debug(f"语音识别耗时: {time.time() - start_time:.3f}s | 结果: {text}")
|
logger.bind(tag=TAG).debug(
|
||||||
|
f"语音识别耗时: {time.time() - start_time:.3f}s | 结果: {text}"
|
||||||
|
)
|
||||||
return text, None
|
return text, None
|
||||||
return "", None
|
return "", None
|
||||||
|
|
||||||
|
|||||||
@@ -153,21 +153,17 @@ def parse_weather_info(soup):
|
|||||||
def get_weather(conn, location: str = None, lang: str = "zh_CN"):
|
def get_weather(conn, location: str = None, lang: str = "zh_CN"):
|
||||||
api_key = conn.config["plugins"]["get_weather"]["api_key"]
|
api_key = conn.config["plugins"]["get_weather"]["api_key"]
|
||||||
default_location = conn.config["plugins"]["get_weather"]["default_location"]
|
default_location = conn.config["plugins"]["get_weather"]["default_location"]
|
||||||
print("用户设置的default_location为:", default_location)
|
|
||||||
client_ip = conn.client_ip
|
client_ip = conn.client_ip
|
||||||
print("用户提供的location为:", location)
|
|
||||||
# 优先使用用户提供的location参数
|
# 优先使用用户提供的location参数
|
||||||
if not location:
|
if not location:
|
||||||
# 通过客户端IP解析城市
|
# 通过客户端IP解析城市
|
||||||
if client_ip:
|
if client_ip:
|
||||||
# 动态解析IP对应的城市信息
|
# 动态解析IP对应的城市信息
|
||||||
ip_info = get_ip_info(client_ip, logger)
|
ip_info = get_ip_info(client_ip, logger)
|
||||||
print("解析用户IP后的城市为:", ip_info)
|
|
||||||
location = ip_info.get("city") if ip_info and "city" in ip_info else None
|
location = ip_info.get("city") if ip_info and "city" in ip_info else None
|
||||||
else:
|
else:
|
||||||
# 若IP解析失败或无IP,使用默认位置
|
# 若IP解析失败或无IP,使用默认位置
|
||||||
location = default_location
|
location = default_location
|
||||||
print("解析失败,将使用默认地址", location)
|
|
||||||
|
|
||||||
city_info = fetch_city_info(location, api_key)
|
city_info = fetch_city_info(location, api_key)
|
||||||
if not city_info:
|
if not city_info:
|
||||||
@@ -179,8 +175,6 @@ def get_weather(conn, location: str = None, lang: str = "zh_CN"):
|
|||||||
return ActionResponse(Action.REQLLM, None, "请求失败")
|
return ActionResponse(Action.REQLLM, None, "请求失败")
|
||||||
city_name, current_abstract, current_basic, temps_list = parse_weather_info(soup)
|
city_name, current_abstract, current_basic, temps_list = parse_weather_info(soup)
|
||||||
|
|
||||||
print(f"当前查询的城市名称是: {city_name}")
|
|
||||||
|
|
||||||
weather_report = f"您查询的位置是:{city_name}\n\n当前天气: {current_abstract}\n"
|
weather_report = f"您查询的位置是:{city_name}\n\n当前天气: {current_abstract}\n"
|
||||||
|
|
||||||
# 添加有效的当前天气参数
|
# 添加有效的当前天气参数
|
||||||
|
|||||||
Reference in New Issue
Block a user