|
@@ -5,40 +5,13 @@ import os
|
|
|
import json
|
|
|
import threading
|
|
|
import traceback
|
|
|
+from src.core.callcenter import registry
|
|
|
|
|
|
import nls # 引入阿里云语音识别库
|
|
|
from aliyunsdkcore.client import AcsClient
|
|
|
from aliyunsdkcore.request import CommonRequest
|
|
|
import time
|
|
|
|
|
|
-# 获取Token的函数
|
|
|
-def get_token():
|
|
|
- ak_id = "LTAI5tQ2HmiHCygZkt5BYrYR"
|
|
|
- ak_secret = "KhmxTd14SUcXafpFk5yofA43FoeM99"
|
|
|
- client = AcsClient(ak_id, ak_secret, "cn-shanghai")
|
|
|
- request = CommonRequest()
|
|
|
- request.set_method('POST')
|
|
|
- request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
|
|
|
- request.set_version('2019-02-28')
|
|
|
- request.set_action_name('CreateToken')
|
|
|
-
|
|
|
- try:
|
|
|
- response = client.do_action_with_exception(request)
|
|
|
- jss = json.loads(response)
|
|
|
- if 'Token' in jss and 'Id' in jss['Token']:
|
|
|
- token = jss['Token']['Id']
|
|
|
- expire_time = jss['Token']['ExpireTime']
|
|
|
- print(f"Token: {token}, ExpireTime: {expire_time}")
|
|
|
- return token, int(expire_time) # 返回Token和过期时间
|
|
|
- else:
|
|
|
- print("Token获取失败,响应内容: ", response)
|
|
|
- except Exception as e:
|
|
|
- print(f"获取Token时发生错误: {e}")
|
|
|
- return None, None
|
|
|
-
|
|
|
-# WebSocket服务地址
|
|
|
-URL = "wss://nls-gateway-cn-beijing.aliyuncs.com/ws/v1"
|
|
|
-APPKEY = "OKt6jogp6fRjHQVp" # 你的Appkey
|
|
|
|
|
|
# 定义实时转写类
|
|
|
class TestSt:
|
|
@@ -48,6 +21,32 @@ class TestSt:
|
|
|
"expire_time": None
|
|
|
}
|
|
|
|
|
|
+ # 获取Token的函数
|
|
|
+ @classmethod
|
|
|
+ def get_token(cls):
|
|
|
+ ak_id = "LTAI5tQ2HmiHCygZkt5BYrYR"
|
|
|
+ ak_secret = "KhmxTd14SUcXafpFk5yofA43FoeM99"
|
|
|
+ client = AcsClient(ak_id, ak_secret, "cn-shanghai")
|
|
|
+ request = CommonRequest()
|
|
|
+ request.set_method('POST')
|
|
|
+ request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
|
|
|
+ request.set_version('2019-02-28')
|
|
|
+ request.set_action_name('CreateToken')
|
|
|
+
|
|
|
+ try:
|
|
|
+ response = client.do_action_with_exception(request)
|
|
|
+ jss = json.loads(response)
|
|
|
+ if 'Token' in jss and 'Id' in jss['Token']:
|
|
|
+ token = jss['Token']['Id']
|
|
|
+ expire_time = jss['Token']['ExpireTime']
|
|
|
+ print(f"Token: {token}, ExpireTime: {expire_time}")
|
|
|
+ return token, int(expire_time) # 返回Token和过期时间
|
|
|
+ else:
|
|
|
+ print("Token获取失败,响应内容: ", response)
|
|
|
+ except Exception as e:
|
|
|
+ print(f"获取Token时发生错误: {e}")
|
|
|
+ return None, None
|
|
|
+
|
|
|
@classmethod
|
|
|
def get_cached_token(cls):
|
|
|
# 检查是否已有缓存的Token且未过期s):
|
|
@@ -60,7 +59,7 @@ class TestSt:
|
|
|
return cls.token_cache["token"]
|
|
|
|
|
|
# 如果没有缓存Token或者Token已过期,重新获取
|
|
|
- new_token, expire_time = get_token()
|
|
|
+ new_token, expire_time = cls.get_token()
|
|
|
if new_token:
|
|
|
cls.token_cache["token"] = new_token
|
|
|
cls.token_cache["expire_time"] = expire_time
|
|
@@ -80,6 +79,10 @@ class TestSt:
|
|
|
self.message_receiver = message_receiver
|
|
|
self._Token = self.get_cached_token()
|
|
|
self.sr = None
|
|
|
+
|
|
|
+ # WebSocket服务地址
|
|
|
+ self.URL = "wss://nls-gateway-cn-beijing.aliyuncs.com/ws/v1"
|
|
|
+ self.APPKEY = "OKt6jogp6fRjHQVp" # 你的Appkey
|
|
|
self.logger.debug("开始")
|
|
|
|
|
|
def start(self):
|
|
@@ -102,9 +105,9 @@ class TestSt:
|
|
|
self.__event.clear()
|
|
|
while not self.__event.is_set():
|
|
|
self.sr = nls.NlsSpeechTranscriber(
|
|
|
- url=URL,
|
|
|
+ url=self.URL,
|
|
|
token=self._Token,
|
|
|
- appkey=APPKEY,
|
|
|
+ appkey=self.APPKEY,
|
|
|
on_sentence_begin=self.test_on_sentence_begin,
|
|
|
on_sentence_end=self.test_on_sentence_end,
|
|
|
on_start=self.test_on_start,
|
|
@@ -136,12 +139,12 @@ class TestSt:
|
|
|
def test_on_sentence_begin(self, message, *args):
|
|
|
self.logger.debug("[%s]test_on_sentence_begin:%s", self.__id, message)
|
|
|
if self.message_receiver:
|
|
|
- self.message_receiver(message, *args)
|
|
|
+ self.message_receiver(self.convert_message(message), *args)
|
|
|
|
|
|
def test_on_sentence_end(self, message, *args):
|
|
|
self.logger.debug("[%s]test_on_sentence_end:%s", self.__id, message)
|
|
|
if self.message_receiver:
|
|
|
- self.message_receiver(message, *args)
|
|
|
+ self.message_receiver(self.convert_message(message), *args)
|
|
|
|
|
|
def test_on_start(self, message, *args):
|
|
|
self.__event.set()
|
|
@@ -153,7 +156,7 @@ class TestSt:
|
|
|
if not self.__event.is_set():
|
|
|
self.__event.set()
|
|
|
if self.message_receiver:
|
|
|
- self.message_receiver(message, *args)
|
|
|
+ self.message_receiver(self.convert_message(message), *args)
|
|
|
|
|
|
def test_on_close(self, *args):
|
|
|
self.logger.debug("on_close: args=>%s", args)
|
|
@@ -164,8 +167,145 @@ class TestSt:
|
|
|
def test_on_result_chg(self, message, *args):
|
|
|
# self.logger.debug("test_on_chg:{}".format(message))
|
|
|
if self.message_receiver:
|
|
|
- self.message_receiver(message, *args)
|
|
|
+ self.message_receiver(self.convert_message(message), *args)
|
|
|
|
|
|
def test_on_completed(self, message, *args):
|
|
|
# self.logger.debug("on_completed:args=>{} message=>{}".format(args, message))
|
|
|
pass
|
|
|
+
|
|
|
+ def convert_message(self, message):
|
|
|
+ final_result = {}
|
|
|
+ message = json.loads(message)
|
|
|
+ if message["header"]["status"] == 20000000:
|
|
|
+ if message["header"]["name"] == "SentenceBegin":
|
|
|
+ final_result['name'] = 'SentenceBegin'
|
|
|
+ if message["header"]["name"] == "SentenceEnd":
|
|
|
+ result = message["payload"]["result"]
|
|
|
+ # self.logger.info("asr返回内容Result:%s", result)
|
|
|
+ final_result['name'] = 'SentenceEnd'
|
|
|
+ final_result['result'] = result
|
|
|
+ elif message["header"]["name"] == "TranscriptionResultChanged":
|
|
|
+ final_result['name'] = 'TranscriptionResultChanged'
|
|
|
+ else:
|
|
|
+ final_result['name'] = 'TranscriptionResultError'
|
|
|
+ final_result['status'] = message['header']['status']
|
|
|
+ final_result['result'] = ''
|
|
|
+ self.logger.info(f"Status is not {message['header']['status']}")
|
|
|
+ registry.ASR_ERRORS.labels(message['header']['status']).inc()
|
|
|
+
|
|
|
+ self.logger.error("aliyun.Asr.recv: call_id:%s, final_result: %s", self.__id, final_result)
|
|
|
+ return final_result
|
|
|
+
|
|
|
+
|
|
|
+# 讯飞ASR实时转写
|
|
|
+class XfAsr:
|
|
|
+
|
|
|
+ def __init__(self, tid, logger, message_receiver=None):
|
|
|
+ self.end_tag = "{\"end\": true}"
|
|
|
+ self.tid = tid
|
|
|
+ self.logger = logger
|
|
|
+ self.message_receiver = message_receiver
|
|
|
+ self.ws = self.new_connection()
|
|
|
+ self.logger.info(f"xunfei.Asr: call_id: {tid}, ws.connected:{self.ws.connected}")
|
|
|
+ self.trecv = threading.Thread(target=self.recv)
|
|
|
+
|
|
|
+ def new_connection(self, base_url = "ws://rtasr.xfyun.cn/v1/ws", app_id = "1ec1097b", api_key = "60b7d2d8d172b065b1c3e723e5ba0696"):
|
|
|
+ import hashlib
|
|
|
+ import hmac
|
|
|
+ import base64
|
|
|
+ # from socket import *
|
|
|
+ # import json, time, threading
|
|
|
+
|
|
|
+ from websocket import create_connection
|
|
|
+ # import websocket
|
|
|
+ from urllib.parse import quote
|
|
|
+ # import logging
|
|
|
+
|
|
|
+ # logging.basicConfig()
|
|
|
+
|
|
|
+ ts = str(int(time.time()))
|
|
|
+ tt = (app_id + ts).encode('utf-8')
|
|
|
+ md5 = hashlib.md5()
|
|
|
+ md5.update(tt)
|
|
|
+ baseString = md5.hexdigest()
|
|
|
+ baseString = bytes(baseString, encoding='utf-8')
|
|
|
+
|
|
|
+ apiKey = api_key.encode('utf-8')
|
|
|
+ signa = hmac.new(apiKey, baseString, hashlib.sha1).digest()
|
|
|
+ signa = base64.b64encode(signa)
|
|
|
+ signa = str(signa, 'utf-8')
|
|
|
+
|
|
|
+ count = 10
|
|
|
+ _ws = None
|
|
|
+ while count > 0:
|
|
|
+ try:
|
|
|
+ _ws = create_connection(base_url + "?appid=" + app_id + "&ts=" + ts + "&signa=" + quote(signa))
|
|
|
+ break
|
|
|
+ except Exception as e:
|
|
|
+ count -= 1
|
|
|
+ self.logger.info("new_connection:exception, call_id: %s, count=%s, message=%s", self.tid, count, e)
|
|
|
+ time.sleep(.010)
|
|
|
+ return _ws
|
|
|
+
|
|
|
+ def start(self):
|
|
|
+ self.trecv.start()
|
|
|
+
|
|
|
+ def send_audio(self, chunk):
|
|
|
+ # self.logger.debug('xunfei.Asr.send_audio: call_id: %s, chunk:%s, %s', self.tid, len(chunk), chunk)
|
|
|
+ if self.ws:
|
|
|
+ self.ws.send(chunk)
|
|
|
+
|
|
|
+ def close(self):
|
|
|
+ if self.ws:
|
|
|
+ self.ws.send(bytes(self.end_tag.encode('utf-8')))
|
|
|
+ self.ws.close()
|
|
|
+ self.logger.info("connection closed call_id: %s", self.tid)
|
|
|
+
|
|
|
+ def recv(self):
|
|
|
+ try:
|
|
|
+ self.logger.info(f"xunfei.Asr.recv: call_id: {self.tid}, ws.connected:{self.ws.connected}")
|
|
|
+ while self.ws and self.ws.connected:
|
|
|
+ message = str(self.ws.recv())
|
|
|
+ if len(message) == 0:
|
|
|
+ self.logger.info("xunfei.Asr.recv: receive result end call_id: %s", self.tid)
|
|
|
+ break
|
|
|
+
|
|
|
+ self.logger.info("xunfei.Asr.recv: call_id: %s, message :%s", self.tid, message)
|
|
|
+ if self.message_receiver:
|
|
|
+ self.message_receiver(self.convert_message(message))
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ traceback.print_exc()
|
|
|
+ self.logger.error("xunfei.Asr.recv: receive result end, call_id: %s, message: %s", self.tid, e)
|
|
|
+
|
|
|
+ def convert_message(self, message):
|
|
|
+ final_result = {}
|
|
|
+ result_dict = json.loads(message)
|
|
|
+ if result_dict["code"] == "0":
|
|
|
+ if result_dict["action"] == "started":
|
|
|
+ final_result['name'] = 'SentenceBegin'
|
|
|
+ elif result_dict["action"] == "result":
|
|
|
+ result_dict = json.loads(message)
|
|
|
+ result_1 = json.loads(result_dict["data"])
|
|
|
+ st = result_1["cn"]["st"]
|
|
|
+ rt = st["rt"]
|
|
|
+ if st['type'] == "1":
|
|
|
+ final_result['name'] = 'TranscriptionResultChanged'
|
|
|
+ if st['type'] == "0":
|
|
|
+ final_result['name'] = 'SentenceEnd'
|
|
|
+ final_result['result'] = ''.join(cw["w"] for item in rt for ws in item["ws"] for cw in ws["cw"]).strip()
|
|
|
+ elif result_dict["action"] == "error":
|
|
|
+ self.logger.error("xunfei.Asr.recv: call_id: %s, action is error: %s", self.tid, message)
|
|
|
+ final_result['name'] = 'TranscriptionResultError'
|
|
|
+ final_result['result'] = message
|
|
|
+ if self.ws:
|
|
|
+ self.ws.close()
|
|
|
+ else:
|
|
|
+ self.logger.error("xunfei.Asr.recv: call_id: %s, Status is not: %s", self.tid, result_dict["code"])
|
|
|
+ final_result['name'] = 'TranscriptionResultError'
|
|
|
+ final_result['status'] = result_dict["code"]
|
|
|
+ registry.ASR_ERRORS.labels(result_dict["code"]).inc()
|
|
|
+ if self.ws:
|
|
|
+ self.ws.close()
|
|
|
+ self.logger.error("xunfei.Asr.recv: call_id: %s, final_result: %s", self.tid, final_result)
|
|
|
+ return final_result
|