tencentASR.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # -*- coding: utf-8 -*-
  2. # 参数配置参考: https://cloud.tencent.com/document/api/1093/35646
  3. from ..builder import ASREngines
  4. from ..engineBase import BaseASREngine
  5. import hashlib
  6. import hmac
  7. import time
  8. import json
  9. import base64
  10. from datetime import datetime, timezone
  11. from typing import Tuple, Dict
  12. from digitalHuman.protocol import *
  13. from digitalHuman.utils import logger, httpxAsyncClient
  14. from pydantic import BaseModel
  15. __all__ = ["TencentApiAsr"]
  16. def sign(key, msg: str):
  17. return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
  18. class TencentCloudApiKey(BaseModel):
  19. secret_id: str
  20. secret_key: str
  21. @ASREngines.register("Tencent-API")
  22. class TencentApiAsr(BaseASREngine):
  23. def setup(self):
  24. self._url = "https://asr.tencentcloudapi.com"
  25. def _buildRequest(self, input: AudioMessage, tencentApiKey: TencentCloudApiKey) -> Tuple[Dict, str]:
  26. VoiceFormat = "mp3" if input.type == AUDIO_TYPE.MP3 else "wav"
  27. service = "asr"
  28. host = "asr.tencentcloudapi.com"
  29. version = "2019-06-14"
  30. action = "SentenceRecognition"
  31. algorithm = "TC3-HMAC-SHA256"
  32. timestamp = int(time.time())
  33. date = datetime.fromtimestamp(timestamp, timezone.utc).strftime("%Y-%m-%d")
  34. params = {
  35. "EngSerViceType": "16k_zh-PY",
  36. "SourceType": 1,
  37. "VoiceFormat": VoiceFormat,
  38. "Data": input.data,
  39. "DataLen": len(input.data)
  40. }
  41. payload = json.dumps(params)
  42. # ************* 步骤 1:拼接规范请求串 *************
  43. http_request_method = "POST"
  44. canonical_uri = "/"
  45. canonical_querystring = ""
  46. ct = "application/json; charset=utf-8"
  47. canonical_headers = "content-type:%s\nhost:%s\nx-tc-action:%s\n" % (ct, host, action.lower())
  48. signed_headers = "content-type;host;x-tc-action"
  49. hashed_request_payload = hashlib.sha256(payload.encode("utf-8")).hexdigest()
  50. canonical_request = (http_request_method + "\n" +
  51. canonical_uri + "\n" +
  52. canonical_querystring + "\n" +
  53. canonical_headers + "\n" +
  54. signed_headers + "\n" +
  55. hashed_request_payload)
  56. # ************* 步骤 2:拼接待签名字符串 *************
  57. credential_scope = date + "/" + service + "/" + "tc3_request"
  58. hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
  59. string_to_sign = (algorithm + "\n" +
  60. str(timestamp) + "\n" +
  61. credential_scope + "\n" +
  62. hashed_canonical_request)
  63. # ************* 步骤 3:计算签名 *************
  64. secret_date = sign(("TC3" + tencentApiKey.secret_key).encode("utf-8"), date)
  65. secret_service = sign(secret_date, service)
  66. secret_signing = sign(secret_service, "tc3_request")
  67. signature = hmac.new(secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
  68. # ************* 步骤 4:拼接 Authorization *************
  69. authorization = (algorithm + " " +
  70. "Credential=" + tencentApiKey.secret_id + "/" + credential_scope + ", " +
  71. "SignedHeaders=" + signed_headers + ", " +
  72. "Signature=" + signature)
  73. # ************* 步骤 5:构造并发起请求 *************
  74. headers = {
  75. "Authorization": authorization,
  76. "Content-Type": "application/json; charset=utf-8",
  77. "Host": host,
  78. "X-TC-Action": action,
  79. "X-TC-Timestamp": str(timestamp),
  80. "X-TC-Version": version
  81. }
  82. return (headers, payload)
  83. async def run(self, input: AudioMessage, **kwargs) -> TextMessage:
  84. if isinstance(input.data, bytes):
  85. input.data = base64.b64encode(input.data).decode("utf-8")
  86. # 参数校验
  87. paramters = self.checkParameter(**kwargs)
  88. SECRECT_ID = paramters["secret_id"]
  89. SECRECT_KEY = paramters["secret_key"]
  90. headers, payload = self._buildRequest(input, TencentCloudApiKey(secret_id=SECRECT_ID, secret_key=SECRECT_KEY))
  91. response = await httpxAsyncClient.post(self._url, headers=headers, data=payload)
  92. if response.status_code != 200:
  93. raise RuntimeError(f"Tencet asr api error: {response.status_code}")
  94. result = response.json()["Response"]["Result"]
  95. logger.debug(f"[ASR] Engine response: {result}")
  96. message = TextMessage(data=result)
  97. return message