123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- """
- _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
|