mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-30 19:13:55 +08:00
修复test_page.html没有hello消息,导致缺失audio_format的bug (#1151)
This commit is contained in:
@@ -17,12 +17,14 @@ from config.logger import setup_logging
|
||||
TAG = __name__
|
||||
logger = setup_logging()
|
||||
|
||||
|
||||
class ASRProvider(ASRProviderBase):
|
||||
API_URL = "https://asr.tencentcloudapi.com"
|
||||
API_VERSION = "2019-06-14"
|
||||
FORMAT = "pcm" # 支持的音频格式:pcm, wav, mp3
|
||||
|
||||
def __init__(self, config: dict, delete_audio_file: bool = True):
|
||||
super().__init__()
|
||||
self.secret_id = config.get("secret_id")
|
||||
self.secret_key = config.get("secret_key")
|
||||
self.output_dir = config.get("output_dir")
|
||||
@@ -45,7 +47,9 @@ class ASRProvider(ASRProviderBase):
|
||||
|
||||
return file_path
|
||||
|
||||
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]]:
|
||||
"""将语音数据转换为文本"""
|
||||
if not opus_data:
|
||||
logger.bind(tag=TAG).warn("音频数据为空!")
|
||||
@@ -72,7 +76,7 @@ class ASRProvider(ASRProviderBase):
|
||||
self.save_audio_to_file(pcm_data, session_id)
|
||||
|
||||
# 将音频数据转换为Base64编码
|
||||
base64_audio = base64.b64encode(combined_pcm_data).decode('utf-8')
|
||||
base64_audio = base64.b64encode(combined_pcm_data).decode("utf-8")
|
||||
|
||||
# 构建请求体
|
||||
request_body = self._build_request_body(base64_audio)
|
||||
@@ -85,7 +89,9 @@ class ASRProvider(ASRProviderBase):
|
||||
result = self._send_request(request_body, timestamp, authorization)
|
||||
|
||||
if result:
|
||||
logger.bind(tag=TAG).debug(f"腾讯云语音识别耗时: {time.time() - start_time:.3f}s | 结果: {result}")
|
||||
logger.bind(tag=TAG).debug(
|
||||
f"腾讯云语音识别耗时: {time.time() - start_time:.3f}s | 结果: {result}"
|
||||
)
|
||||
|
||||
return result, file_path
|
||||
|
||||
@@ -102,7 +108,7 @@ class ASRProvider(ASRProviderBase):
|
||||
"SourceType": 1, # 音频数据来源为语音文件
|
||||
"VoiceFormat": self.FORMAT, # 音频格式
|
||||
"Data": base64_audio, # Base64编码的音频数据
|
||||
"DataLen": len(base64_audio) # 数据长度
|
||||
"DataLen": len(base64_audio), # 数据长度
|
||||
}
|
||||
return json.dumps(request_map)
|
||||
|
||||
@@ -135,9 +141,11 @@ class ASRProvider(ASRProviderBase):
|
||||
action = "SentenceRecognition" # 接口名称
|
||||
|
||||
# 构建规范头部信息,注意顺序和格式
|
||||
canonical_headers = f"content-type:{content_type.lower()}\n" + \
|
||||
f"host:{host.lower()}\n" + \
|
||||
f"x-tc-action:{action.lower()}\n"
|
||||
canonical_headers = (
|
||||
f"content-type:{content_type.lower()}\n"
|
||||
+ f"host:{host.lower()}\n"
|
||||
+ f"x-tc-action:{action.lower()}\n"
|
||||
)
|
||||
|
||||
signed_headers = "content-type;host;x-tc-action"
|
||||
|
||||
@@ -145,21 +153,25 @@ class ASRProvider(ASRProviderBase):
|
||||
payload_hash = self._sha256_hex(request_body)
|
||||
|
||||
# 构建规范请求字符串
|
||||
canonical_request = f"{http_request_method}\n" + \
|
||||
f"{canonical_uri}\n" + \
|
||||
f"{canonical_query_string}\n" + \
|
||||
f"{canonical_headers}\n" + \
|
||||
f"{signed_headers}\n" + \
|
||||
f"{payload_hash}"
|
||||
canonical_request = (
|
||||
f"{http_request_method}\n"
|
||||
+ f"{canonical_uri}\n"
|
||||
+ f"{canonical_query_string}\n"
|
||||
+ f"{canonical_headers}\n"
|
||||
+ f"{signed_headers}\n"
|
||||
+ f"{payload_hash}"
|
||||
)
|
||||
|
||||
# 计算规范请求的哈希值
|
||||
hashed_canonical_request = self._sha256_hex(canonical_request)
|
||||
|
||||
# 构建待签名字符串
|
||||
string_to_sign = f"{algorithm}\n" + \
|
||||
f"{timestamp}\n" + \
|
||||
f"{credential_scope}\n" + \
|
||||
f"{hashed_canonical_request}"
|
||||
string_to_sign = (
|
||||
f"{algorithm}\n"
|
||||
+ f"{timestamp}\n"
|
||||
+ f"{credential_scope}\n"
|
||||
+ f"{hashed_canonical_request}"
|
||||
)
|
||||
|
||||
# 计算签名密钥
|
||||
secret_date = self._hmac_sha256(f"TC3{self.secret_key}", date)
|
||||
@@ -167,13 +179,17 @@ class ASRProvider(ASRProviderBase):
|
||||
secret_signing = self._hmac_sha256(secret_service, "tc3_request")
|
||||
|
||||
# 计算签名
|
||||
signature = self._bytes_to_hex(self._hmac_sha256(secret_signing, string_to_sign))
|
||||
signature = self._bytes_to_hex(
|
||||
self._hmac_sha256(secret_signing, string_to_sign)
|
||||
)
|
||||
|
||||
# 构建授权头
|
||||
authorization = f"{algorithm} " + \
|
||||
f"Credential={self.secret_id}/{credential_scope}, " + \
|
||||
f"SignedHeaders={signed_headers}, " + \
|
||||
f"Signature={signature}"
|
||||
authorization = (
|
||||
f"{algorithm} "
|
||||
+ f"Credential={self.secret_id}/{credential_scope}, "
|
||||
+ f"SignedHeaders={signed_headers}, "
|
||||
+ f"Signature={signature}"
|
||||
)
|
||||
|
||||
return timestamp, authorization
|
||||
|
||||
@@ -181,7 +197,9 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).error(f"生成认证头失败: {e}", exc_info=True)
|
||||
raise RuntimeError(f"生成认证头失败: {e}")
|
||||
|
||||
def _send_request(self, request_body: str, timestamp: str, authorization: str) -> Optional[str]:
|
||||
def _send_request(
|
||||
self, request_body: str, timestamp: str, authorization: str
|
||||
) -> Optional[str]:
|
||||
"""发送请求到腾讯云API"""
|
||||
headers = {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
@@ -190,7 +208,7 @@ class ASRProvider(ASRProviderBase):
|
||||
"X-TC-Action": "SentenceRecognition",
|
||||
"X-TC-Version": self.API_VERSION,
|
||||
"X-TC-Timestamp": timestamp,
|
||||
"X-TC-Region": "ap-shanghai"
|
||||
"X-TC-Region": "ap-shanghai",
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -221,16 +239,16 @@ class ASRProvider(ASRProviderBase):
|
||||
|
||||
def _sha256_hex(self, data: str) -> str:
|
||||
"""计算字符串的SHA256哈希值"""
|
||||
digest = hashlib.sha256(data.encode('utf-8')).digest()
|
||||
digest = hashlib.sha256(data.encode("utf-8")).digest()
|
||||
return self._bytes_to_hex(digest)
|
||||
|
||||
def _hmac_sha256(self, key, data: str) -> bytes:
|
||||
"""计算HMAC-SHA256"""
|
||||
if isinstance(key, str):
|
||||
key = key.encode('utf-8')
|
||||
key = key.encode("utf-8")
|
||||
|
||||
return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest()
|
||||
return hmac.new(key, data.encode("utf-8"), hashlib.sha256).digest()
|
||||
|
||||
def _bytes_to_hex(self, bytes_data: bytes) -> str:
|
||||
"""字节数组转十六进制字符串"""
|
||||
return ''.join(f"{b:02x}" for b in bytes_data)
|
||||
return "".join(f"{b:02x}" for b in bytes_data)
|
||||
|
||||
Reference in New Issue
Block a user