""" _on_open {'action': 'started', 'data': '', 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'apd', 'sn': 1, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}]}, 'result_id': 1, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'apd', 'service': 'raw', 'rawText': '今天天气'} {'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'rpl', 'rg': [1, 1], 'sn': 2, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '怎么样'}]}]}, 'result_id': 2, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '今天天气怎么样'} {'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'rpl', 'rg': [1, 2], 'sn': 3, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '怎么样'}]}]}, 'result_id': 3, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '今天天气怎么样'} {'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'apd', 'sn': 4, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': ''}]}]}, 'result_id': 4, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'apd', 'service': 'raw', 'rawText': ''} {'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': True, 'pgs': 'rpl', 'rg': [4, 4], 'sn': 5, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '?'}]}]}, 'result_id': 5, 'is_last': True, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'iat', 'is_last': True, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '?'} {'action': 'result', 'data': {'sub': 'nlp', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'intent': {'answer': {'text': '我昨天忘记看天气预报了', 'type': 'T'}, 'category': 'IFLYTEK.weather', 'data': {'error': {'code': 0, 'message': ''}, 'result': []}, 'dialog_stat': 'DataValid', 'rc': 3, 'save_history': True, 'semantic': [{'intent': 'QUERY', 'slots': [{'name': 'datetime', 'normValue': '{"datetime":"2023-11-28","suggestDatetime":"2023-11-28"}', 'value': '今天'}, {'name': 'location.city', 'normValue': 'CURRENT_CITY', 'value': 'CURRENT_CITY'}, {'name': 'location.poi', 'normValue': 'CURRENT_POI', 'value': 'CURRENT_POI'}, {'name': 'location.type', 'normValue': 'LOC_POI', 'value': 'LOC_POI'}, {'name': 'queryType', 'value': '内容'}, {'name': 'subfocus', 'value': '天气状态'}]}], 'service': 'weather', 'shouldEndSession': 'true', 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'state': {'fg::weather::default::default': {'state': 'default'}}, 'text': '今天天气怎么样?', 'uuid': 'awa027d6d87@dx000118c0e4f8a15800', 'version': '173.0'}, 'result_id': 1, 'is_last': True, 'is_finish': True}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'} {'code': '0', 'sub': 'nlp', 'is_last': True, 'is_finish': True, 'service': 'weather', 'rawText': '今天天气怎么样?'} _on_error 1 _on_error 1 _on_close """ from PyQt5.QtCore import QObject, QUrl, pyqtSignal from PyQt5.QtWebSockets import QWebSocket, QWebSocketProtocol import base64 import hashlib import json import time import uuid from util import my_util, constants ORIGIN = "http://wsapi.xfyun.cn" BASE_URL = "ws://wsapi.xfyun.cn/v1/aiui" # BASE_URL = "wss://wsapi.xfyun.cn/v1/aiui" # 结束标识 END_TAG = "--end--" def get_auth_id(): mac = uuid.UUID(int=uuid.getnode()).hex[-12:] return hashlib.md5(":".join([mac[e:e + 2] for e in range(0, 11, 2)]).encode("utf-8")).hexdigest() class AiuiManager(QObject): trigger = pyqtSignal(dict) _app_id = "ab154863" _api_key = "5a584b63730d3450d64cdd65f17f56d0" def __init__(self): super(AiuiManager, self).__init__() self._last_status = 0 self._last_raw_text = "" self._last_pgs = None self._param = {"result_level": "complete", "auth_id": get_auth_id(), "data_type": "audio", "aue": "raw", "scene": "main", "sample_rate": "16000", "cloud_vad_eos": "60000"} self.ws = None def regist_engine(self, aue="raw"): self.update_params({"aue": aue}) def update_params(self, params): if params: self._param.update(params) def start_speech(self): print("start_speech 1") # try: # self.ws.close() # except: # pass self.ws = QWebSocket(origin=ORIGIN, version=QWebSocketProtocol.VersionLatest) # 信号连接 self.ws.connected.connect(self._on_open) self.ws.error.connect(self._on_error) self.ws.disconnected.connect(self._on_close) self.ws.textMessageReceived.connect(self._on_message) self._create_url() self.ws.open(QUrl(f"{self.ws_url}")) print("start_speech 2") def _callback(self, data: dict): self.trigger.emit(data) def _create_url(self): _param_b64 = base64.b64encode(json.dumps(self._param).encode('utf-8')) _cur_time = str(int(time.time())) _tmp = self._api_key + _cur_time + _param_b64.decode() _md5 = hashlib.md5() _md5.update(_tmp.encode(encoding='utf-8')) check_sum = _md5.hexdigest() self.ws_url = BASE_URL + "?appid=" + self._app_id + "&checksum=" + check_sum + "&curtime=" + _cur_time + "¶m=" + _param_b64.decode() # 连接建立时 def _on_open(self): print('_on_open') pass # 连接异常时 def _on_error(self, error_code): print('_on_error') print(error_code) # self.ws.close() # self._callback(my_util.gen_q_data(constants.AITEST_AIUI_ERROR, self.ws.errorString())) pass # 接收到文本消息时 def _on_message(self, message): data = json.loads(str(message)) print(data) _action = data["action"] self._sid = data["sid"] if _action == "started": # 正常连接 d = f"连接已建立,sid:{self._sid}" self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d)) self._callback(my_util.gen_q_data(constants.AITEST_AIUI_START, True)) elif _action == "result": _data = my_util.parse_aiui_v2_result(data) print(_data) # text = self.parse_aiui_engine_stream_result(_data) # if text: # self._callback(my_util.gen_q_data(constants.AITEST_AIUI_RESULT, text)) if _data.get("is_finish"): self._callback( my_util.gen_q_data(constants.AITEST_AIUI_NLP, json.dumps(data["data"], ensure_ascii=False))) self._callback(my_util.gen_q_data(constants.AITEST_AIUI_RESULT, _data["rawText"])) else: self._callback(my_util.gen_q_data(constants.AITEST_AIUI_ERROR, data)) # 连接断开时 def _on_close(self): print('_on_close') d = f"连接已断开!,sid:{self._sid}" self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d)) def audio_write(self, buf: bytes): if self.ws: self.ws.sendBinaryMessage(buf) def stop_speech(self): if self.ws: d = f"sid:{self._sid},发送结束标识!!!" self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d)) self.ws.sendBinaryMessage(bytes(END_TAG.encode("utf-8"))) def parse_aiui_engine_stream_result(self, data: dict): sub = data.get("sub") if sub != "iat": return "" raw_text = data.get("rawText") is_last = data.get("is_last") last_text = data.get("last_text") pgs = data.get("pgs") status = 0 if pgs == "apd": if my_util.symbol_in_word(raw_text): status = 1 if not self._last_status: # 短句 text = self._last_raw_text + raw_text else: text = raw_text elif self._last_pgs == "rpl" and not self._last_status: status = 1 text = self._last_raw_text else: status = 0 text = raw_text else: if my_util.symbol_in_word(raw_text): status = 1 text = raw_text else: status = 0 text = raw_text self._last_status = status self._last_pgs = pgs self._last_raw_text = text if status == 1: _text = text else: _text = "" return _text