From 44cb7c0dca7f5515f81e2e3702e81cce9dd8ca47 Mon Sep 17 00:00:00 2001 From: qcloud Date: Sat, 19 Jul 2025 22:44:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=86=E5=A4=87=E5=AF=B9AI=E6=B5=81=E5=BC=8F?= =?UTF-8?q?=E9=9F=B3=E9=A2=91=E5=8F=91=E5=9B=9E=E7=BB=99=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=9A=84=E6=9C=BA=E5=88=B6=E5=81=9A=E8=BE=83=E5=A4=A7=E7=9A=84?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=8C=E5=85=88=E6=8F=90=E4=BA=A41?= =?UTF-8?q?=E4=B8=AA=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/apps/sdk/dale_extra.py | 9 +- api/db/services/dialog_service.py | 27 +- asr-monitor-test/.env | 1 + asr-monitor-test/app.log | 468 +------------------- asr-monitor-test/app/database.py | 241 ++++++++-- asr-monitor-test/app/payment_service.py | 35 +- asr-monitor-test/app/tts_service.py | 558 +++++++++++++++++++++--- asr-monitor-test/backup.txt | 263 ----------- asr-monitor/Dockerfile.bk | 32 -- 9 files changed, 766 insertions(+), 868 deletions(-) delete mode 100644 asr-monitor-test/backup.txt delete mode 100644 asr-monitor/Dockerfile.bk diff --git a/api/apps/sdk/dale_extra.py b/api/apps/sdk/dale_extra.py index e88f4bd0..56766672 100644 --- a/api/apps/sdk/dale_extra.py +++ b/api/apps/sdk/dale_extra.py @@ -152,10 +152,11 @@ def upload_file(tenant_id,mesum_id): prompt = ( f"作为图片识别和理解助手,您的任务是:" - f"\n1. 精确识别图片中的文字内容" - f"\n2. 理解文字语义" - f"\n3. 从以下候选标题中选择最佳匹配项:" - f"\n [{antiques_selected}]" + f"\n1. 图片基本上就是展品标题、历史人物或者历史事件" + f"\n2. 精确识别图片中的文字内容,理解文字语义,重点分析字体较大的文字" + f"\n3. 识别出的文字包含标题或者接近于标题的文字" + f"\n4. 从以下候选标题中选择最佳匹配项:" + f"\n {antiques_selected}" f"\n\n### 输出要求:" f"\n- 以严格JSON格式输出,包含3个字段:" f"\n • `antique`: 匹配的标题(多个用英文分号';'分割,最多匹配3个,无匹配则空字符串)" diff --git a/api/db/services/dialog_service.py b/api/db/services/dialog_service.py index 03af6c3f..7d035139 100644 --- a/api/db/services/dialog_service.py +++ b/api/db/services/dialog_service.py @@ -71,7 +71,9 @@ class StreamSessionManager: 'finished': threading.Event(), # 添加事件对象 'sample_rate':sample_rate, 'stream_format':stream_format, - "tts_chunk_data_valid":False + "tts_chunk_data_valid":False, + "sentence_complete_event": threading.Event(), + "current_processing": False # 标记是否正在处理句子 } # 启动任务处理线程 threading.Thread(target=self._process_tasks, args=(session_id,), daemon=True).start() @@ -127,7 +129,7 @@ class StreamSessionManager: except Exception as e: logging.error(f"Task processing error: {str(e)}") - def _generate_audio(self, session_id, text): + def _generate_audio1(self, session_id, text): """实际生成音频(线程池执行)""" session = self.sessions.get(session_id) if not session: return @@ -157,6 +159,27 @@ class StreamSessionManager: session['buffer'].put(f"ERROR:{str(e)}") logging.info(f"--_generate_audio--error {str(e)}") + def _generate_audio(self, session_id, text): + """实际生成音频(顺序执行)- 用于非流式引擎""" + session = self.sessions.get(session_id) + if not session: + return + + try: + # 调用 TTS + session['tts_model'].text_tts_call(text) + + # 标记完成 + session['sentence_complete_event'].set() + session['last_active'] = time.time() + session['audio_chunk_count'] += 1 + + if not session['tts_chunk_data_valid']: + session['tts_chunk_data_valid'] = True + + except Exception as e: + session['buffer'].put(f"ERROR:{str(e)}".encode()) + session['sentence_complete_event'].set() # 确保事件被设置 def close_session(self, session_id): with self.lock: diff --git a/asr-monitor-test/.env b/asr-monitor-test/.env index 4e7b48fe..62a3fce7 100644 --- a/asr-monitor-test/.env +++ b/asr-monitor-test/.env @@ -1,4 +1,5 @@ TIMEZONE=Asia/Shanghai DASHSCOPE_API_KEY = sk-a47a3fb5f4a94f66bbaf713779101c75 +DOUBAO_APP_ID = 7282190702 diff --git a/asr-monitor-test/app.log b/asr-monitor-test/app.log index e957e7fb..dc8857b9 100644 --- a/asr-monitor-test/app.log +++ b/asr-monitor-test/app.log @@ -1,467 +1,15 @@ -INFO: Started server process [50175] +INFO: Started server process [2877053] INFO: Waiting for application startup. -21:51:05.972 - INFO - 监控服务已启动 +16:01:53.789 - INFO - 监控服务已启动 INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:9580 (Press CTRL+C to quit) +WARNING: Invalid HTTP request received. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ASR & Monitor Service Start ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -INFO: 35.203.210.77:60796 - "GET / HTTP/1.1" 404 Not Found +INFO: 91.196.152.109:33535 - "GET / HTTP/1.1" 404 Not Found +INFO: 220.196.160.51:32110 - "GET / HTTP/1.1" 404 Not Found +INFO: 180.101.245.250:54556 - "GET / HTTP/1.1" 404 Not Found +INFO: 220.196.160.75:44896 - "GET / HTTP/1.1" 404 Not Found +INFO: 91.196.152.210:40043 - "GET /favicon.ico HTTP/1.1" 404 Not Found WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:45448 - "GET / HTTP/1.0" 404 Not Found -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:45526 - "OPTIONS / HTTP/1.0" 404 Not Found -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:45640 - "GET /nice%20ports%2C/Trinity.txt.bak HTTP/1.0" 404 Not Found -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:38084 - "GET /api HTTP/1.0" 404 Not Found -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:38098 - "GET /hazelcast/rest/cluster HTTP/1.0" 404 Not Found -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -WARNING: Invalid HTTP request received. -INFO: 221.238.94.141:38374 - "GET / HTTP/1.1" 404 Not Found -06:57:54.681 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 106.55.206.109:0 - "GET /auth/verify HTTP/1.1" 200 OK -06:57:55.071 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.144.107.210:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -06:59:18.037 - INFO - Creating TTS request: {'text': '陶鬲形猪首盖盉,商,通高27厘米,腹径20.5厘米,2010年安钢大道M78出土,中国社会科学院考古研究所藏。器型呈猪首状,长嘴,圆眼微凸,双耳直立,憨态可掬。肩部饰三角绳纹,腹及袋足饰细绳纹,作为温酒的容器,加热后美酒从它的口中流出。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 48000, 'tts_stream_format': 'mp3', 'model_name': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'sample_rate': 48000, 'stream_format': 'mp3'} -INFO: 43.144.107.28:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17513727656058688719 HTTP/1.1" 200 OK -INFO: ('1.13.185.116', 50174) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/d45fdb6d-9bcb-4458-9b83-d63f3eb69720" [accepted] -06:59:19.472 - INFO - 新连接建立: 414fa19a-4425-4b60-b172-ec661a3457b2 -06:59:19.472 - INFO - 已经启动 start tts task {audio_stream_id} -06:59:19.473 - INFO - ---begin--init QwenTTS-- mp3 48000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -06:59:19.473 - INFO - QwenTTS--get_audio_format-- mp3 48000 -06:59:19.473 - INFO - setup_tts longyuan MP3 with 48000Hz sample rate, mono channel, 256kbps -INFO: connection open -06:59:19.617 - INFO - Websocket connected -06:59:19.729 - INFO - Qwen CosyVoice tts open -06:59:28.170 - INFO - --data_handler on_complete -06:59:28.170 - INFO - Qwen CosyVoice tts close -06:59:28.170 - INFO - --tts task event set error = None -INFO: connection closed -07:00:54.600 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 43.144.107.210:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:00:54.946 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.44:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:04:53.633 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 43.144.107.28:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:04:53.793 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.44:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:04:57.090 - INFO - Creating TTS request: {'text': '1945年10月,通县民主政府成立,机关设在潮白河西岸侯各庄西北角的一座菩萨庙(圆通庵)内,领导全县人民进行反蒋解放斗争。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 48000, 'tts_stream_format': 'mp3', 'model_name': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'sample_rate': 48000, 'stream_format': 'mp3'} -INFO: 43.140.60.33:0 - "POST /tts/chats/9cb04ecead5111ef99e80242ac120006/tts?device_id=17513727656058688719 HTTP/1.1" 200 OK -INFO: ('1.13.185.116', 33684) - "WebSocket /tts/chats/9cb04ecead5111ef99e80242ac120006/tts/c83abcdf-225e-41a1-a20d-0cc228b7c547" [accepted] -07:04:57.520 - INFO - 新连接建立: 2025badf-3414-48c6-8382-76c51673d9ef -07:04:57.520 - INFO - 已经启动 start tts task {audio_stream_id} -07:04:57.520 - INFO - ---begin--init QwenTTS-- mp3 48000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -07:04:57.520 - INFO - QwenTTS--get_audio_format-- mp3 48000 -07:04:57.520 - INFO - setup_tts longyuan MP3 with 48000Hz sample rate, mono channel, 256kbps -INFO: connection open -07:04:57.639 - INFO - Websocket connected -07:04:57.768 - INFO - Qwen CosyVoice tts open -07:05:01.717 - INFO - --data_handler on_complete -07:05:01.717 - INFO - Qwen CosyVoice tts close -07:05:01.717 - INFO - --tts task event set error = None -INFO: connection closed -07:06:17.189 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 43.140.60.44:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:06:17.383 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.33:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:06:20.644 - INFO - Creating TTS request: {'text': '元大都水利建设最终形成了金水河、高梁河两进,坝河、通惠河两出,瓮山泊、积水潭两大蓄水水面格局,水利景观呈现“一心、一廊”的发展特征。城内供水区以积水潭为核心,通惠河漕运走廊连接北运河与白浮泉,串联起自然山水、寺庙、集市、私园、公共桥闸等景观,充分体现了城市、水利、景观三者之间的相互作用。元代水利建设对北京城市水利景观和生态环境具有深远的影响。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 48000, 'tts_stream_format': 'mp3', 'model_name': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'sample_rate': 48000, 'stream_format': 'mp3'} -INFO: 43.140.60.33:0 - "POST /tts/chats/9cb04ecead5111ef99e80242ac120006/tts?device_id=17513727656058688719 HTTP/1.1" 200 OK -INFO: ('1.13.185.116', 47246) - "WebSocket /tts/chats/9cb04ecead5111ef99e80242ac120006/tts/7d2bd2dd-dfc0-43e6-9b23-08e5251bb954" [accepted] -07:06:21.077 - INFO - 新连接建立: caa0458b-7662-4ebe-9a6b-480c57c400b6 -07:06:21.077 - INFO - 已经启动 start tts task {audio_stream_id} -07:06:21.077 - INFO - ---begin--init QwenTTS-- mp3 48000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -07:06:21.078 - INFO - QwenTTS--get_audio_format-- mp3 48000 -07:06:21.078 - INFO - setup_tts longyuan MP3 with 48000Hz sample rate, mono channel, 256kbps -INFO: connection open -07:06:21.194 - INFO - Websocket connected -07:06:21.324 - INFO - Qwen CosyVoice tts open -07:06:32.422 - INFO - --data_handler on_complete -07:06:32.422 - INFO - Qwen CosyVoice tts close -07:06:32.422 - INFO - --tts task event set error = None -INFO: connection closed -07:44:06.202 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:44:06.290 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:44:52.287 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:44:52.440 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:45:23.056 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:45:23.159 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:54:21.106 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:54:21.161 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:54:28.720 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:54:28.799 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:54:35.913 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:54:36.001 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:54:36.411 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:54:36.509 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:55:22.522 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:55:22.582 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -07:56:58.308 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -07:56:58.385 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:07:38.414 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:07:38.499 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:10:57.429 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:10:57.486 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:11:53.340 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:11:53.398 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:16:33.756 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:16:33.813 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:17:30.384 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:17:30.490 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:18:33.644 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:18:33.709 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:19:50.951 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:19:51.034 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:21:37.950 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:21:38.023 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:22:05.386 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:22:05.441 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:23:13.075 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:23:13.153 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:24:49.462 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:24:49.563 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:26:08.181 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:26:08.282 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:26:49.301 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:26:49.374 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:27:41.833 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:27:41.893 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:28:50.023 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:28:50.083 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:29:21.179 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:29:21.387 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:30:19.839 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:30:20.031 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:31:11.560 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:31:11.723 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:33:16.896 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:33:17.108 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:33:51.413 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:33:51.479 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:35:10.447 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:35:10.505 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:36:24.091 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:36:24.187 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:37:18.392 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:37:18.507 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:38:42.906 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 106.55.206.109:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:38:43.148 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.33:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:49:31.793 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 106.55.206.109:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:49:31.991 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.33:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:51:30.837 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:51:30.938 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:55:28.363 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:55:28.421 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -08:56:53.353 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -08:56:53.419 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:00:01.531 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:00:01.590 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:00:07.397 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:00:07.486 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:00:47.232 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:00:47.306 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:01:19.694 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:01:19.959 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:02:46.650 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:02:46.718 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:03:29.115 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:03:29.384 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:05:12.089 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:05:12.145 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:10:24.333 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:10:24.586 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:11:14.693 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:11:14.781 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:11:45.666 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:11:45.755 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -09:12:29.573 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -09:12:29.813 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -10:36:24.208 - INFO - verify_token user={'user_id': '689cac0d-062e-45df-88bf-d7c4b16ff226', 'openid': 'obKSz7bHxzDFWnLHmOrnY_-8D6fI', 'phone': '13810887276', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2ODljYWMwZC0wNjJlLTQ1ZGYtODhiZi1kN2M0YjE2ZmYyMjYiLCJleHAiOjE3NTIwMzM3NzV9.Go3vld8ijajTsYSwzA45YS47O9thXdnLtrF0G7x1BAM', 'balance': 0, 'status': 1, 'last_login_time': 1751428975, 'create_time': 1748951630, 'create_date': datetime.datetime(2025, 6, 3, 19, 53, 50), 'update_time': 1751428975, 'update_date': datetime.datetime(2025, 7, 2, 12, 2, 55)} -INFO: 223.104.41.17:0 - "GET /auth/verify HTTP/1.1" 200 OK -10:36:24.285 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 223.104.41.17:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -10:36:34.664 - INFO - verify_token user={'user_id': '689cac0d-062e-45df-88bf-d7c4b16ff226', 'openid': 'obKSz7bHxzDFWnLHmOrnY_-8D6fI', 'phone': '13810887276', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2ODljYWMwZC0wNjJlLTQ1ZGYtODhiZi1kN2M0YjE2ZmYyMjYiLCJleHAiOjE3NTIwMzM3NzV9.Go3vld8ijajTsYSwzA45YS47O9thXdnLtrF0G7x1BAM', 'balance': 0, 'status': 1, 'last_login_time': 1751428975, 'create_time': 1748951630, 'create_date': datetime.datetime(2025, 6, 3, 19, 53, 50), 'update_time': 1751428975, 'update_date': datetime.datetime(2025, 7, 2, 12, 2, 55)} -INFO: 223.104.41.17:0 - "GET /auth/verify HTTP/1.1" 200 OK -10:36:34.746 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 223.104.41.17:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -10:36:38.066 - INFO - Creating TTS request: {'text': '铜条形驭马器,商,长18.3厘米,宽1.4厘米,高2.2厘米,2021年邵家棚M109出土,安阳市文物考古研究院藏。\n', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 48000, 'tts_stream_format': 'mp3', 'model_name': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'sample_rate': 48000, 'stream_format': 'mp3'} -INFO: 223.104.41.17:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17507669394291632844 HTTP/1.1" 200 OK -INFO: ('1.13.185.116', 36130) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/de035ae4-81d8-408b-b551-2eac17b07e50" [accepted] -10:36:38.312 - INFO - 新连接建立: 733148f7-d2ac-4fa2-ad3a-b41fb684d08e -10:36:38.312 - INFO - 已经启动 start tts task {audio_stream_id} -INFO: connection open -10:36:38.313 - INFO - ---begin--init QwenTTS-- mp3 48000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -10:36:38.313 - INFO - QwenTTS--get_audio_format-- mp3 48000 -10:36:38.313 - INFO - setup_tts longyuan MP3 with 48000Hz sample rate, mono channel, 256kbps -10:36:38.425 - INFO - Websocket connected -10:36:38.560 - INFO - Qwen CosyVoice tts open -10:36:42.366 - INFO - --data_handler on_complete -10:36:42.366 - INFO - Qwen CosyVoice tts close -10:36:42.366 - INFO - --tts task event set error = None -INFO: connection closed -10:36:49.363 - INFO - verify_token user={'user_id': '689cac0d-062e-45df-88bf-d7c4b16ff226', 'openid': 'obKSz7bHxzDFWnLHmOrnY_-8D6fI', 'phone': '13810887276', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2ODljYWMwZC0wNjJlLTQ1ZGYtODhiZi1kN2M0YjE2ZmYyMjYiLCJleHAiOjE3NTIwMzM3NzV9.Go3vld8ijajTsYSwzA45YS47O9thXdnLtrF0G7x1BAM', 'balance': 0, 'status': 1, 'last_login_time': 1751428975, 'create_time': 1748951630, 'create_date': datetime.datetime(2025, 6, 3, 19, 53, 50), 'update_time': 1751428975, 'update_date': datetime.datetime(2025, 7, 2, 12, 2, 55)} -INFO: 223.104.41.17:0 - "GET /auth/verify HTTP/1.1" 200 OK -10:36:49.440 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 223.104.41.17:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -10:36:53.851 - INFO - Creating TTS request: {'text': '铜铙,商,①高18厘米,口长13.2厘米,口宽10.1厘米;②高13厘米,口长11.6厘米,口宽8.7厘米;③高11.9厘米,口长9.4厘米,口宽7厘米;1983年戚家庄东地出土,安阳市文物考古研究院藏。\n', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 48000, 'tts_stream_format': 'mp3', 'model_name': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'sample_rate': 48000, 'stream_format': 'mp3'} -INFO: 223.104.41.17:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17507669394291632844 HTTP/1.1" 200 OK -INFO: ('1.13.185.116', 49668) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/c6355d58-9d94-4726-bf00-0581bcdb0e28" [accepted] -10:36:54.094 - INFO - 新连接建立: fc397484-625d-4db9-9fba-6d5a8949a57a -10:36:54.094 - INFO - 已经启动 start tts task {audio_stream_id} -10:36:54.094 - INFO - ---begin--init QwenTTS-- mp3 48000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -10:36:54.094 - INFO - QwenTTS--get_audio_format-- mp3 48000 -10:36:54.094 - INFO - setup_tts longyuan MP3 with 48000Hz sample rate, mono channel, 256kbps -INFO: connection open -10:36:54.202 - INFO - Websocket connected -10:36:54.341 - INFO - Qwen CosyVoice tts open -10:37:05.913 - INFO - --data_handler on_complete -10:37:05.914 - INFO - Qwen CosyVoice tts close -10:37:05.914 - INFO - --tts task event set error = None -INFO: connection closed -INFO: ('1.13.185.116', 59460) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/9d5e77cc-ad9b-4a60-812f-880d2f182543" [accepted] -10:37:23.067 - INFO - 新连接建立: d3f6a319-1597-4283-8330-a26c2582c91c -INFO: connection open -10:37:23.121 - INFO - 代理文本流: completions_url=http://localhost:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions {'question': '请介绍铜铙', 'stream': True, 'tts_model': 'cosyvoice-v1/longyuan@Tongyi-Qianwen', 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'tts_disable': True} -10:37:23.121 - INFO - ---begin--init QwenTTS-- mp3 8000 cosyvoice-v1/longyuan@Tongyi-Qianwen cosyvoice-v1/longyuan -10:37:23.121 - INFO - QwenTTS--get_audio_format-- mp3 8000 -10:37:23.121 - INFO - setup_tts longyuan MP3 with 8000Hz sample rate, mono channel, 128kbps -10:37:26.511 - INFO - HTTP Request: POST http://localhost:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions "HTTP/1.1 200 OK" -10:37:26.511 - INFO - 响应状态: HTTP 200 -10:37:26.511 - INFO - 开始处理SSE流 -10:37:26.651 - INFO - Websocket connected -10:37:26.775 - INFO - Qwen CosyVoice tts open -INFO: ('1.13.185.116', 49122) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/64880966-3b94-4fae-ac7e-e37e16768c2a" [accepted] -10:37:26.927 - INFO - 新连接建立: f666fc5e-48bd-4451-ac13-65c656784d3f -INFO: connection open -10:37:39.969 - INFO - SSE流处理完成,事件数: 23 -INFO: connection closed -INFO: connection closed -10:37:45.801 - INFO - 发送时检测到断开连接: f666fc5e-48bd-4451-ac13-65c656784d3f, -10:38:00.989 - ERROR - error from callback >: {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -10:38:00.989 - ERROR - error from callback >: websocket closed due to websocket closed due to {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -10:38:00.989 - INFO - tearing down on exception websocket closed due to websocket closed due to websocket closed due to {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -10:38:00.989 - ERROR - close status: 1007 -Qwen tts error {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -websocket closed due to {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -websocket closed due to websocket closed due to {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -websocket closed due to websocket closed due to websocket closed due to {"header":{"task_id":"8ed5859fd51746068babf1776c7c84df","event":"task-failed","error_code":"InvalidParameter","error_message":"request timeout after 23 seconds.","attributes":{}},"payload":{}} -INFO: 183.163.60.214:0 - "GET /auth/get_museum_list HTTP/1.1" 401 Unauthorized -Exception in thread Thread-1544 (_process_tasks): -Traceback (most recent call last): - File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner - self.run() - File "/usr/lib/python3.10/threading.py", line 953, in run - self._target(*self._args, **self._kwargs) - File "/home/ubuntu/ragflow/asr-monitor-test/app/tts_service.py", line 192, in _process_tasks - session['tts_model'].end_streaming_call() - File "/home/ubuntu/ragflow/asr-monitor-test/app/tts_service.py", line 1005, in end_streaming_call - self.synthesizer.streaming_complete() - File "/home/ubuntu/ragflow/asr-monitor/venv/lib/python3.10/site-packages/dashscope/audio/tts_v2/speech_synthesizer.py", line 374, in streaming_complete - self.__send_str(request) - File "/home/ubuntu/ragflow/asr-monitor/venv/lib/python3.10/site-packages/dashscope/audio/tts_v2/speech_synthesizer.py", line 285, in __send_str - self.ws.send(data) - File "/home/ubuntu/ragflow/asr-monitor/venv/lib/python3.10/site-packages/websocket/_app.py", line 291, in send - raise WebSocketConnectionClosedException("Connection is already closed.") -websocket._exceptions.WebSocketConnectionClosedException: Connection is already closed. -INFO: 183.163.60.214:0 - "GET /auth/get_museum_list HTTP/1.1" 401 Unauthorized -INFO: 123.115.202.182:0 - "GET /auth/get_museum_list HTTP/1.1" 401 Unauthorized -11:23:13.037 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:23:13.104 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:25:03.125 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:25:03.187 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:26:37.995 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:26:38.077 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:27:45.347 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:27:45.695 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:28:25.996 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 61.141.77.65:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:28:26.062 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 61.141.77.65:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:29:40.340 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:29:40.639 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:30:15.537 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 61.141.77.65:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:30:15.603 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 61.141.77.65:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:30:52.210 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 61.141.77.65:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:30:52.288 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 61.141.77.65:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:35:02.399 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:35:02.737 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:36:02.938 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:36:03.034 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:37:17.719 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:37:17.802 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:37:47.273 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 61.141.77.65:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:37:47.367 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 61.141.77.65:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:39:13.999 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:39:14.337 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:41:51.134 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:41:51.495 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:43:01.977 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 163.125.202.178:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:43:02.050 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 163.125.202.178:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:44:30.162 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 43.144.107.210:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:44:30.345 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.44:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK -11:45:40.101 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTI1ODI1ODN9.GONQPAzcWnYQN2i14zfNhjU8OT1to7fWn6ZA6lNdSHY', 'balance': 0, 'status': 1, 'last_login_time': 1751977783, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1751977783, 'update_date': datetime.datetime(2025, 7, 8, 20, 29, 43)} -INFO: 43.144.107.210:0 - "GET /auth/verify HTTP/1.1" 200 OK -11:45:40.260 - INFO - get_museum_id_auth=[1, 2, 3] -INFO: 43.140.60.44:0 - "GET /auth/get_museum_id_auth HTTP/1.1" 200 OK diff --git a/asr-monitor-test/app/database.py b/asr-monitor-test/app/database.py index bc6fad8e..9f5f885a 100644 --- a/asr-monitor-test/app/database.py +++ b/asr-monitor-test/app/database.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from config import DATABASE_CONFIG from datetime import datetime,timedelta import logging +from zoneinfo import ZoneInfo # Python 3.9+ 内置 from typing import Union, List, Dict, Optional from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type from dateutil.relativedelta import relativedelta @@ -415,6 +416,21 @@ def get_users(status: int = None, email: str = None, phone: str = None,openid: s # 按用户ID获取用户 def get_user_by_id(user_id: str): + """ + 根据用户ID获取用户信息 + + 功能说明: + - 通过用户ID查询用户基本信息 + + 参数说明: + - user_id: 用户ID + + 返回: + - 用户信息的字典,如果不存在则返回None + + 重要逻辑: + - 直接查询用户表的所有字段 + """ sql = "SELECT * FROM rag_flow.users_info WHERE user_id = %s" result = execute_query(sql, (user_id,)) return result[0] if result else None @@ -720,7 +736,7 @@ def update_order(order_id: str, update_data: dict) -> int: from typing import Union, List, Dict, Optional -def get_order_by_id(order_id: str = None, user_id: str = None,combined = None) -> Union[Dict, List[Dict], None]: +def get_order_by_id(order_id: str = None, user_id: str = None,combined:bool = False,museum_id:int = None) -> Union[Dict, List[Dict], None]: """ 根据订单ID或用户ID查询订单信息 @@ -742,9 +758,25 @@ def get_order_by_id(order_id: str = None, user_id: str = None,combined = None) - - 使用参数化查询防止 SQL 注入 - 当同时传入 order_id 和 user_id 时,优先使用 order_id """ - if not order_id and not user_id: - return None # 两个参数都未传入,直接返回 None - sql_wo_condition= """ + # 无任何参数时返回 None + if not any([order_id, user_id, museum_id]): + return None + # ========== 简单查询模式 ========== + if not combined: + # 优先使用 order_id 查询 + if order_id: + sql = "SELECT * FROM subscription_orders WHERE order_id = %s" + result = execute_query(sql, (order_id,)) + return result[0] if result and len(result) > 0 else None + + # 使用 user_id 查询 + if user_id: + sql = "SELECT * FROM subscription_orders WHERE user_id = %s" + result = execute_query(sql, (user_id,)) + return result if result else [] + + # ========== 复杂查询模式 ========== + base_sql= """ SELECT o.order_id, o.user_id, @@ -774,25 +806,39 @@ def get_order_by_id(order_id: str = None, user_id: str = None,combined = None) - LEFT JOIN rag_flow.user_subscriptions us ON o.order_id = us.order_id LEFT JOIN rag_flow.mesum_overview mo ON ms.museum_id = mo.id """ - # 优先使用 order_id 查询 - if order_id and not combined: - sql = "SELECT * FROM subscription_orders WHERE order_id = %s" - result = execute_query(sql, (order_id,)) - return result[0] if result and len(result) > 0 else None # 返回单个订单 + # 构建查询条件和参数 + conditions = [] + params = [] - # 如果 order_id 不存在,使用 user_id 查询 - if user_id and not combined: - sql = "SELECT * FROM subscription_orders WHERE user_id = %s" - result = execute_query(sql, (user_id,)) - return result if result else [] # 返回所有订单(列表) - if user_id and combined: - sql = sql_wo_condition + f"\n WHERE o.user_id = %s" - result = execute_query(sql, (user_id,)) - return result if result else [] # 返回所有订单(列表) - if order_id and combined: - sql = sql_wo_condition + f"\n WHERE o.order_id = %s" - result = execute_query(sql, (order_id,)) - return result[0] if result and len(result) > 0 else None # 返回单个订单 + # 添加条件(按优先级) + if order_id: + conditions.append("o.order_id = %s") + params.append(order_id) + elif user_id: + conditions.append("o.user_id = %s") + params.append(user_id) + + # 新增博物馆ID条件(可与其他条件组合) + if museum_id: + conditions.append("ms.museum_id = %s") + params.append(museum_id) + + # 构建完整SQL + if conditions: + where_clause = " WHERE " + " AND ".join(conditions) + sql = base_sql + where_clause + else: + sql = base_sql + + # 执行查询 + result = execute_query(sql, tuple(params)) + + # 处理返回结果 + if not result: + return [] if user_id or museum_id else None + + # 当有order_id时返回单个对象,否则返回列表 + return result[0] if order_id and not museum_id else result def create_user_subscription(data: dict) -> int: """ @@ -875,27 +921,6 @@ def deactivate_previous_subscriptions(user_id: str, museum_subscription_id: str) return execute_query(sql, (user_id, museum_subscription_id), autocommit=True) -def get_user_by_id(user_id: str) -> dict: - """ - 根据用户ID获取用户信息 - - 功能说明: - - 通过用户ID查询用户基本信息 - - 参数说明: - - user_id: 用户ID - - 返回: - - 用户信息的字典,如果不存在则返回None - - 重要逻辑: - - 直接查询用户表的所有字段 - """ - sql = "SELECT * FROM users_info WHERE user_id = %s" - result = execute_query(sql, (user_id,)) - return result[0] if result else None - - def get_subscription_template_by_id(template_id: int) -> dict: """ 根据模板ID获取订阅模板信息 @@ -1175,6 +1200,75 @@ def check_user_subscription(user_id: str, museum_id: int) -> dict: return None +def is_museum_free_period(museum_id: int) -> bool: + """ + 检查博物馆当前是否处于免费时段 + + 参数: + - museum_id: 博物馆ID + + 返回: + - True: 当前是免费时段 + - False: 当前不是免费时段 + """ + # 查询博物馆的免费时段配置 + sql = """ + SELECT t.validity_type, t.valid_time_range, t.valid_week_days + FROM museum_subscriptions ms + JOIN subscription_templates t ON ms.template_id = t.id + WHERE ms.museum_id = %s + AND t.validity_type = 'free_interval' + AND t.is_active = 1 + AND ms.is_active = 1 + LIMIT 1 + """ + result = execute_query(sql, (museum_id,)) + if not result: + return False + + subscription = result[0] + return is_subscription_valid(subscription) + + +def get_user_valid_subscription(user_id: str, museum_id: int) -> bool: + """ + 检查用户是否有有效的博物馆订阅 + + 参数: + - user_id: 用户ID + - museum_id: 博物馆ID + + 返回: + - True: 用户有有效订阅 + - False: 用户无有效订阅 + """ + # 查询用户的有效订阅 + sql = """ + SELECT + t.validity_type, + t.valid_time_range, + t.valid_week_days, + us.start_date, + us.end_date + FROM user_subscriptions us + JOIN museum_subscriptions ms ON us.museum_subscription_id = ms.sub_id + JOIN subscription_templates t ON ms.template_id = t.id + WHERE us.user_id = %s + AND ms.museum_id = %s + AND us.is_active = 1 + AND ms.is_active = 1 + AND t.is_active = 1 + AND us.start_date <= NOW() + AND us.end_date >= NOW() + """ + subscriptions = execute_query(sql, (user_id, museum_id)) + + # 检查每个订阅是否在当前时间有效 + for sub in subscriptions: + if is_subscription_valid(sub): + return True + + return False def calculate_subscription_expiry(start_date: datetime, validity_type: str) -> datetime: """ @@ -1203,3 +1297,64 @@ def calculate_subscription_expiry(start_date: datetime, validity_type: str) -> d # 未知类型默认30天 logger.warning(f"未知有效期类型: {validity_type}, 使用默认30天") return start_date + timedelta(days=30) + + +def is_subscription_valid(subscription: dict) -> bool: + """ + 检查订阅在当前时间是否有效 + + 参数: + subscription: 包含订阅信息的字典,包含以下字段: + - validity_type: 有效期类型 + - valid_time_range: 有效时间段 (格式: "08:00-20:00") + - valid_week_days: 有效星期 (格式: "1,3,5") + - start_date: 订阅开始日期 (datetime 对象) + - end_date: 订阅结束日期 (datetime 对象) + """ + # 设置时区(根据服务器实际时区调整) + tz = ZoneInfo('Asia/Shanghai') + now = datetime.now(tz) + + # 1. 检查永久免费订阅 + if subscription['validity_type'] == 'free': + return True + + # 2. 检查时间间隔类型订阅 + if subscription['validity_type'] == 'free_interval': + # 时间间隔类型不需要检查有效期范围 + pass + else: + # 3. 检查有效期是否在范围内 + if subscription['validity_type'] in ['1month', '1year', 'permanent']: + start_date = subscription['start_date'].astimezone(tz) + end_date = subscription['end_date'].astimezone(tz) + + if not (start_date <= now <= end_date): + return False + + # 4. 检查星期限制 + if subscription.get('valid_week_days'): + week_day = now.isoweekday() # 1=周一, 7=周日 + valid_days = [int(d) for d in str(subscription['valid_week_days']).split(',')] + if week_day not in valid_days: + return False + + # 5. 检查时间范围限制 + if subscription.get('valid_time_range'): + try: + start_str, end_str = subscription['valid_time_range'].split('-') + start_time = datetime.strptime(start_str, '%H:%M').time() + end_time = datetime.strptime(end_str, '%H:%M').time() + current_time = now.time() + # 处理跨夜时段 + if end_time < start_time: + if not (current_time >= start_time or current_time <= end_time): + return False + else: + if not (start_time <= current_time <= end_time): + return False + except (ValueError, AttributeError): + # 时间格式无效,跳过时间检查 + pass + + return True \ No newline at end of file diff --git a/asr-monitor-test/app/payment_service.py b/asr-monitor-test/app/payment_service.py index 6f42c295..896ea082 100644 --- a/asr-monitor-test/app/payment_service.py +++ b/asr-monitor-test/app/payment_service.py @@ -468,12 +468,14 @@ async def get_museum_subscriptions_by_museum_id( result = get_museum_subscriptions_by_museum(museum_id) return CustomJSONResponse(result) -@payment_router.get("/get_order_list") +@payment_router.post("/get_order_list") async def get_order_list( request: Request, current_user: dict = Depends(get_current_user) ): - result = get_order_by_id(user_id = current_user["user_id"],combined=True) + data = await request.json() + museum_id = data.get("museum_id") + result = get_order_by_id(user_id = current_user["user_id"],combined=True,museum_id=museum_id) return CustomJSONResponse({ "code": 0, "msg": "success", @@ -490,6 +492,35 @@ async def get_order_detial( "code": 0, "msg": "success", "data": result}) + +@payment_router.post("/get_user_museum_subscriptions") +async def get_user_museum_subscriptions( + request: Request, + current_user: dict = Depends(get_current_user) +): + data = await request.json() + museum_id = data.get("museum_id") + user_id = current_user["user_id"] # 用户id + is_free = False + museum_info = get_museum_by_id(museum_id=museum_id) + if museum_info and museum_info['free']: + is_free = True + is_free_period = is_museum_free_period(museum_id) + is_subscription_valid = get_user_valid_subscription(user_id, museum_id) + can_access = False + can_access = is_free or is_free_period or is_subscription_valid + result = { + 'can_access': can_access, + 'is_free': is_free, + 'is_free_period': is_free_period, + 'is_subscription_valid': is_subscription_valid + } + return CustomJSONResponse({ + "code": 0, + "msg": "success", + "data": result}) + + # --- 支付工具函数 --- async def generate_wx_prepay_params_v2(order_id: str, total_fee: int, openid: str, body: str): diff --git a/asr-monitor-test/app/tts_service.py b/asr-monitor-test/app/tts_service.py index 6e2de9e5..af367aa5 100644 --- a/asr-monitor-test/app/tts_service.py +++ b/asr-monitor-test/app/tts_service.py @@ -14,6 +14,9 @@ from typing import Optional, Dict, Any import asyncio, httpx from collections import deque +import websockets +import uuid + from fastapi import WebSocket, APIRouter, WebSocketDisconnect, Request, Body, Query from fastapi import FastAPI, UploadFile, File, Form, Header from fastapi.responses import StreamingResponse, JSONResponse, Response @@ -90,12 +93,23 @@ class StreamSessionManager: try: self.sessions[session_id]['last_active'] = time.time() self.sessions[session_id]['buffer'].put(data) + self.sessions[session_id]['audio_chunk_size'] += len(data) + #logging.info(f"StreamSessionManager on_data {len(data)} {self.sessions[session_id]['audio_chunk_size']}") except queue.Full: logging.warning(f"Audio buffer full for session {session_id}") - + """ + elif data is None: # 结束信号 + # 仅对非流式引擎触发完成事件 + if not streaming_call: + logging.info(f"StreamSessionManager on_data sentence_complete_event set") + self.sessions[session_id]['sentence_complete_event'].set() + self.sessions[session_id]['current_processing'] = False + """ + # 创建完成事件 + completion_event = threading.Event() # 设置TTS流式传输 - tts_instance.setup_tts(on_data) - + tts_instance.setup_tts(on_data,completion_event) + # 创建会话 self.sessions[session_id] = { 'tts_model': tts_model, 'buffer': queue.Queue(maxsize=300), # 线程安全队列 @@ -103,6 +117,7 @@ class StreamSessionManager: 'active': True, 'last_active': time.time(), 'audio_chunk_count': 0, + 'audio_chunk_size': 0, 'finished': threading.Event(), # 添加事件对象 'sample_rate': sample_rate, 'stream_format': stream_format, @@ -110,7 +125,9 @@ class StreamSessionManager: "text_buffer": "", # 新增文本缓冲区 "last_text_time": time.time(), # 最后文本到达时间 "streaming_call": streaming_call, - "tts_stream_started": False # 标记是否已启动流 + "tts_stream_started": False, # 标记是否已启动流 + "sentence_complete_event": completion_event, #threading.Event(), + "current_processing": False # 标记是否正在处理句子 } # 启动任务处理线程 threading.Thread(target=self._process_tasks, args=(session_id,), daemon=True).start() @@ -129,7 +146,7 @@ class StreamSessionManager: except queue.Full: logging.warning(f"Session {session_id} task queue full") - def _process_tasks(self, session_id): + def _process_tasks1(self, session_id): """任务处理线程(每个会话独立)""" session = self.sessions.get(session_id) if not session or not session['active']: @@ -204,7 +221,138 @@ class StreamSessionManager: # 休眠避免CPU空转 time.sleep(0.05) # 50ms检查间隔 - def _generate_audio(self, session_id, text): + def _process_tasks(self, session_id): # 20250718 新更新 + """任务处理线程(每个会话独立)- 保留原有处理逻辑""" + session = self.sessions.get(session_id) + if not session or not session['active']: + return + + # 根据引擎类型选择处理函数 + if session.get('streaming_call'): + gen_tts_audio_func = self._stream_audio + else: + gen_tts_audio_func = self._generate_audio + + while session['active']: + current_time = time.time() + text_to_process = "" + + # 1. 获取待处理文本 + with self.lock: + if session['text_buffer']: + text_to_process = session['text_buffer'] + + + # 2. 处理文本 + if text_to_process and not session['current_processing'] : + session['text_buffer'] = "" + # 分割完整句子 + complete_sentences, remaining_text = self._split_and_extract(text_to_process) + + # 保存剩余文本 + if remaining_text: + with self.lock: + session['text_buffer'] = remaining_text + session['text_buffer'] + + # 合并并处理完整句子 + if complete_sentences: + # 智能合并句子(最长300字符) + buffer = [] + current_length = 0 + + # 处理每个句子 + for sentence in complete_sentences: + sent_length = len(sentence) + + # 添加到当前缓冲区 + if current_length + sent_length <= 300: + buffer.append(sentence) + current_length += sent_length + else: + # 处理已缓冲的文本 + if buffer: + combined_text = "".join(buffer) + + # 重置完成事件状态 + session['sentence_complete_event'].clear() + session['current_processing'] = True + + # 生成音频 + gen_tts_audio_func(session_id, combined_text) + + # 等待完成 + if not session['sentence_complete_event'].wait(timeout=120.0): + logging.warning(f"Timeout waiting for TTS completion: {combined_text}") + # 重置处理状态 + time.sleep(5.0) + session['current_processing'] = False + logging.info(f"StreamSessionManager _process_tasks 转换结束!!!") + # 重置缓冲区 + buffer = [sentence] + current_length = sent_length + + # 处理剩余的缓冲文本 + if buffer: + combined_text = "".join(buffer) + + # 重置完成事件状态 + session['sentence_complete_event'].clear() + session['current_processing'] = True + + # 生成音频 + gen_tts_audio_func(session_id, combined_text) + + # 等待完成 + if not session['sentence_complete_event'].wait(timeout=120.0): + logging.warning(f"Timeout waiting for TTS completion: {combined_text}") + # 重置处理状态 + time.sleep(1.0) + session['current_processing'] = False + logging.info(f"StreamSessionManager _process_tasks 转换结束!!!") + + # 3. 检查超时未处理的文本 + if current_time - session['last_text_time'] > self.sentence_timeout: + with self.lock: + if session['text_buffer']: + # 直接处理剩余文本 + session['sentence_complete_event'].clear() + session['current_processing'] = True + gen_tts_audio_func(session_id, session['text_buffer']) + session['text_buffer'] = "" + + # 等待完成 + if not session['sentence_complete_event'].wait(timeout=120.0): + logging.warning(f"Timeout waiting for TTS completion: {combined_text}") + # 重置处理状态 + session['current_processing'] = False + + # 4. 会话超时检查 + if current_time - session['last_active'] > self.gc_interval: + # 处理剩余文本 + with self.lock: + if session['text_buffer']: + # 重置完成事件状态 + session['sentence_complete_event'].clear() + session['current_processing'] = True + + # 处理最后一段文本 + gen_tts_audio_func(session_id, session['text_buffer']) + session['text_buffer'] = "" + + # 等待完成 + if not session['sentence_complete_event'].wait(timeout=120.0): + logging.warning(f"Timeout waiting for TTS completion: {combined_text}") + # 重置处理状态 + session['current_processing'] = False + + # 关闭会话 + self.close_session(session_id) + break + + # 5. 休眠避免CPU空转 + time.sleep(0.05) # 50ms检查间隔 + + def _generate_audio1(self, session_id, text): """实际生成音频(线程池执行)""" session = self.sessions.get(session_id) if not session: return @@ -236,6 +384,26 @@ class StreamSessionManager: except Exception as e: session['buffer'].put(f"ERROR:{str(e)}") + def _generate_audio(self, session_id, text): # 20250718 新更新 + """实际生成音频(顺序执行)- 用于非流式引擎""" + session = self.sessions.get(session_id) + if not session: + return + + try: + logging.info(f"StreamSessionManager _generate_audio--0 {text}") + # 调用 TTS + session['tts_model'].text_tts_call(text) + session['last_active'] = time.time() + session['audio_chunk_count'] += 1 + + if not session['tts_chunk_data_valid']: + session['tts_chunk_data_valid'] = True + + except Exception as e: + session['buffer'].put(f"ERROR:{str(e)}".encode()) + session['sentence_complete_event'].set() # 确保事件被设置 + def _stream_audio(self, session_id, text): """流式传输文本到TTS服务""" session = self.sessions.get(session_id) @@ -247,9 +415,12 @@ class StreamSessionManager: # 使用流式调用发送文本 session['tts_model'].streaming_call(text) session['last_active'] = time.time() + # 流式引擎不需要等待完成事件 + session['sentence_complete_event'].set() except Exception as e: logging.error(f"Error in streaming_call: {str(e)}") session['buffer'].put(f"ERROR:{str(e)}".encode()) + session['sentence_complete_event'].set() async def get_tts_buffer_data(self, session_id): """异步流式返回 TTS 音频数据(适配同步 queue.Queue,带 10 秒超时)""" @@ -298,6 +469,8 @@ class StreamSessionManager: # 标记会话为不活跃 self.sessions[session_id]['active'] = False + # 设置完成事件(确保任何等待的线程被唤醒) + self.sessions[session_id]['sentence_complete_event'].set() # 延迟2秒后清理资源 threading.Timer(1, self._clean_session, args=[session_id]).start() @@ -827,7 +1000,8 @@ from dashscope.audio.tts_v2 import ( class QwenTTS: - def __init__(self, key, format="mp3", sample_rate=44100, model_name="cosyvoice-v1/longxiaochun"): + def __init__(self, key, format="mp3", sample_rate=44100, model_name="cosyvoice-v1/longxiaochun", + special_characters: Optional[Dict[str, str]] = None): import dashscope import ssl logging.info(f"---begin--init QwenTTS-- {format} {sample_rate} {model_name} {model_name.split('@')[0]}") # cyx @@ -844,14 +1018,22 @@ class QwenTTS: if '/' in self.model_name: parts = self.model_name.split('/', 1) # 返回分离后的两个字符串parts[0], parts[1] - if parts[0] == 'cosyvoice-v1': + if parts[0] == 'cosyvoice-v1' or parts[0] == 'cosyvoice-v2': self.is_cosyvoice = True self.voice = parts[1] + self.completion_event = None # 新增:用于通知任务完成 + # 特殊字符及其拼音映射 + self.special_characters = special_characters or { + "㼽": "chuang3", + "䡇": "yue4" + # 可以添加更多特殊字符的映射 + } class Callback(TTSResultCallback): - def __init__(self) -> None: + def __init__(self,data_callback=None,completion_event=None) -> None: self.dque = deque() - + self.data_callback = data_callback + self.completion_event = completion_event # 新增完成事件引用 def _run(self): while True: if not self.dque: @@ -867,7 +1049,13 @@ class QwenTTS: pass def on_complete(self): + logging.info(f"---QwenTTS Callback on_complete--") self.dque.append(None) + if self.data_callback: + self.data_callback(None) # 发送结束信号 + # 通知任务完成 + if self.completion_event: + self.completion_event.set() def on_error(self, response: SpeechSynthesisResponse): print("Qwen tts error", str(response)) @@ -877,15 +1065,22 @@ class QwenTTS: pass def on_event(self, result: TTSSpeechSynthesisResult): - if result.get_audio_frame() is not None: - self.dque.append(result.get_audio_frame()) + data =result.get_audio_frame() + if data is not None: + if len(data) > 0: + if self.data_callback: + self.data_callback(data) + else: + self.dque.append(data) + #self.dque.append(result.get_audio_frame()) # -------------------------- class Callback_Cosy(CosyResultCallback): - def __init__(self, data_callback=None) -> None: + def __init__(self, data_callback=None,completion_event=None) -> None: self.dque = deque() self.data_callback = data_callback + self.completion_event = completion_event # 新增完成事件引用 def _run(self): while True: @@ -906,6 +1101,9 @@ class QwenTTS: self.dque.append(None) if self.data_callback: self.data_callback(None) # 发送结束信号 + # 通知任务完成 + if self.completion_event: + self.completion_event.set() def on_error(self, response: SpeechSynthesisResponse): print("Qwen tts error", str(response)) @@ -938,23 +1136,28 @@ class QwenTTS: # -------------------------- - def tts(self, text): + def tts(self, text, on_data = None,completion_event=None): + # logging.info(f"---QwenTTS tts begin-- {text} {self.is_cosyvoice} {self.voice}") # cyx + # text = self.normalize_text(text) print(f"--QwenTTS--tts_stream begin-- {text} {self.is_cosyvoice} {self.voice}") # cyx # text = self.normalize_text(text) try: # if self.model_name != 'cosyvoice-v1': if self.is_cosyvoice is False: - self.callback = self.Callback() + self.callback = self.Callback( + data_callback=on_data, + completion_event=completion_event + ) TTSSpeechSynthesizer.call(model=self.model_name, text=text, callback=self.callback, - format="wav") # format="mp3") + format=self.format) # format="mp3") else: self.callback = self.Callback_Cosy() format = self.get_audio_format(self.format, self.sample_rate) self.synthesizer = CosySpeechSynthesizer( - model='cosyvoice-v1', + model='cosyvoice-v2', # voice="longyuan", #"longfei", voice=self.voice, callback=self.callback, @@ -974,26 +1177,68 @@ class QwenTTS: except Exception as e: raise RuntimeError(f"**ERROR**: {e}") - def setup_tts(self, on_data): - """设置 TTS 回调,返回配置好的 synthesizer""" - if not self.is_cosyvoice: - raise NotImplementedError("Only CosyVoice supported") + def setup_tts(self, on_data,completion_event=None): - # 创建 CosyVoice 回调 - self.callback = self.Callback_Cosy(on_data) + """设置 TTS 回调,返回配置好的 synthesizer""" + #if not self.is_cosyvoice: + # raise NotImplementedError("Only CosyVoice supported") + + if self.is_cosyvoice: + # 创建 CosyVoice 回调 + self.callback = self.Callback_Cosy( + data_callback=on_data, + completion_event=completion_event) + else: + self.callback = self.Callback( + data_callback=on_data, + completion_event=completion_event) format_val = self.get_audio_format(self.format, self.sample_rate) - logging.info(f"setup_tts {self.voice} {format_val}") - self.synthesizer = CosySpeechSynthesizer( - model='cosyvoice-v1', - voice=self.voice, # voice="longyuan", #"longfei", - callback=self.callback, - format=format_val - ) + logging.info(f"Qwen setup_tts {self.voice} {format_val}") + if self.is_cosyvoice: + self.synthesizer = CosySpeechSynthesizer( + model='cosyvoice-v1', + voice=self.voice, # voice="longyuan", #"longfei", + callback=self.callback, + format=format_val + ) + return self.synthesizer + def apply_phoneme_tags(self, text: str) -> str: + """ + 在文本中查找特殊字符并用标签包裹它们 + """ + # 如果文本已经是SSML格式,直接返回 + if text.strip().startswith("") and text.strip().endswith(""): + return text + + # 为特殊字符添加SSML标签 + for char, pinyin in self.special_characters.items(): + # 使用正则表达式确保只替换整个字符(避免部分匹配) + pattern = r'([^<]|^)' + re.escape(char) + r'([^>]|$)' + replacement = r'\1' + char + r'\2' + text = re.sub(pattern, replacement, text) + + # 如果文本中已有SSML标签,直接返回 + if "" in text: + return text + + # 否则包裹在标签中 + return f"{text}" + def text_tts_call(self, text): - if self.synthesizer: + if self.special_characters and self.is_cosyvoice is False: + text = self.apply_phoneme_tags(text) + #logging.info(f"Applied SSML phoneme tags to text: {text}") + + if self.synthesizer and self.is_cosyvoice: self.synthesizer.call(text) + if self.is_cosyvoice is False: + logging.info(f"Qwen text_tts_call {text}") + TTSSpeechSynthesizer.call(model=self.model_name, + text=text, + callback=self.callback, + format=self.format) def streaming_call(self, text): if self.synthesizer: @@ -1027,22 +1272,178 @@ class QwenTTS: return format_map.get((sample_rate, format), AudioFormat.MP3_16000HZ_MONO_128KBPS) -import threading -import uuid -import time -import asyncio -import logging -from concurrent.futures import ThreadPoolExecutor -from io import BytesIO +class DoubaoTTS: + def __init__(self, key, format="mp3", sample_rate=8000, model_name="doubao-tts"): + logging.info(f"---begin--init DoubaoTTS-- {format} {sample_rate} {model_name}") + # 解析豆包认证信息 (appid, token, cluster, voice_type) + try: + self.appid = "7282190702" + self.token = "v64Fj-fwLLKIHBgqH2_fWx5dsBEShXd9" + self.cluster = "volcano_tts" + self.voice_type ="zh_female_qingxinnvsheng_mars_bigtts" # "zh_male_jieshuonansheng_mars_bigtts" #"zh_male_ruyaqingnian_mars_bigtts" #"zh_male_jieshuonansheng_mars_bigtts" + except Exception as e: + raise ValueError(f"Invalid Doubao key format: {str(e)}") -import threading -import uuid -import time -import asyncio -import logging -from concurrent.futures import ThreadPoolExecutor -from collections import deque -from io import BytesIO + self.format = format + self.sample_rate = sample_rate + self.model_name = model_name + self.callback = None + self.ws = None + self.loop = None + self.task = None + self.event = threading.Event() + self.data_queue = deque() + self.host = "openspeech.bytedance.com" + self.api_url = f"wss://{self.host}/api/v1/tts/ws_binary" + self.default_header = bytearray(b'\x11\x10\x11\x00') + self.total_data_size = 0 + self.completion_event = None # 新增:用于通知任务完成 + + + class Callback: + def __init__(self, data_callback=None,completion_event=None): + self.data_callback = data_callback + self.data_queue = deque() + self.completion_event = completion_event # 完成事件引用 + + def on_data(self, data): + if self.data_callback: + self.data_callback(data) + else: + self.data_queue.append(data) + # 通知任务完成 + if self.completion_event: + self.completion_event.set() + + def on_complete(self): + if self.data_callback: + self.data_callback(None) + + def on_error(self, error): + if self.data_callback: + self.data_callback(f"ERROR:{error}".encode()) + + def setup_tts(self, on_data,completion_event): + + """设置回调,返回自身(因为豆包需要异步启动)""" + self.callback = self.Callback( + data_callback=on_data, + completion_event=completion_event + ) + return self + + def text_tts_call(self, text): + """同步调用,启动异步任务并等待完成""" + self.total_data_size = 0 + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + self.task = self.loop.create_task(self._async_tts(text)) + try: + self.loop.run_until_complete(self.task) + except Exception as e: + logging.error(f"DoubaoTTS--0 call error: {e}") + self.callback.on_error(str(e)) + + async def _async_tts(self, text): + """异步执行TTS请求""" + header = {"Authorization": f"Bearer; {self.token}"} + request_json = { + "app": { + "appid": self.appid, + "token": "access_token", # 固定值 + "cluster": self.cluster + }, + "user": { + "uid": str(uuid.uuid4()) # 随机用户ID + }, + "audio": { + "voice_type": self.voice_type, + "encoding": self.format, + "speed_ratio": 1.0, + "volume_ratio": 1.0, + "pitch_ratio": 1.0, + }, + "request": { + "reqid": str(uuid.uuid4()), + "text": text, + "text_type": "plain", + "operation": "submit" # 使用submit模式支持流式 + } + } + + # 构建请求数据 + payload_bytes = str.encode(json.dumps(request_json)) + payload_bytes = gzip.compress(payload_bytes) + full_client_request = bytearray(self.default_header) + full_client_request.extend(len(payload_bytes).to_bytes(4, 'big')) + full_client_request.extend(payload_bytes) + + try: + async with websockets.connect(self.api_url, extra_headers=header, ping_interval=None) as ws: + self.ws = ws + await ws.send(full_client_request) + + # 接收音频数据 + while True: + res = await ws.recv() + done = self._parse_response(res) + if done: + self.callback.on_complete() + break + except Exception as e: + logging.error(f"DoubaoTTS--1 WebSocket error: {e}") + self.callback.on_error(str(e)) + finally: + # 通知任务完成 + if self.completion_event: + self.completion_event.set() + + + def _parse_response(self, res): + """解析豆包返回的二进制响应""" + # 协议头解析 (4字节) + header_size = res[0] & 0x0f + message_type = res[1] >> 4 + payload = res[header_size * 4:] + + # 音频数据响应 + if message_type == 0xb: # audio-only server response + message_flags = res[1] & 0x0f + + # ACK消息,忽略 + if message_flags == 0: + return False + + # 音频数据消息 + sequence_number = int.from_bytes(payload[:4], "big", signed=True) + payload_size = int.from_bytes(payload[4:8], "big", signed=False) + audio_data = payload[8:8 + payload_size] + + if audio_data: + self.total_data_size = self.total_data_size + len(audio_data) + self.callback.on_data(audio_data) + + #logging.info(f"doubao _parse_response: {sequence_number} {len(audio_data)} {self.total_data_size}") + # 序列号为负表示结束 + return sequence_number < 0 + + # 错误响应 + elif message_type == 0xf: + code = int.from_bytes(payload[:4], "big", signed=False) + msg_size = int.from_bytes(payload[4:8], "big", signed=False) + error_msg = payload[8:8 + msg_size] + + try: + # 尝试解压错误消息 + error_msg = gzip.decompress(error_msg).decode() + except: + error_msg = error_msg.decode(errors='ignore') + + logging.error(f"DoubaoTTS error: {error_msg}") + self.callback.on_error(error_msg) + return False + + return False class UnifiedTTSEngine: @@ -1144,13 +1545,29 @@ class UnifiedTTSEngine: return try: + # 创建完成事件 + completion_event = threading.Event() # 创建TTS实例 - tts = QwenTTS( - key=task['key'], - format=task['format'], - sample_rate=task['sample_rate'], - model_name=task['model_name'] - ) + # 根据model_name选择TTS引擎 + # 前端传入 cosyvoice-v1/longhua@Tongyi-Qianwen + model_name_wo_brand = task['model_name'].split('@')[0] + model_name_version = model_name_wo_brand.split('/')[0] + if "longhua" in task['model_name'] or "zh_female_qingxinnvsheng_mars_bigtts" in task['model_name']: + # 豆包TTS + tts = DoubaoTTS( + key=task['key'], + format=task['format'], + sample_rate=task['sample_rate'], + model_name=task['model_name'] + ) + else: + # 通义千问TTS + tts = QwenTTS( + key=task['key'], + format=task['format'], + sample_rate=task['sample_rate'], + model_name=task['model_name'] + ) # 定义同步数据处理函数 def data_handler(data): @@ -1165,20 +1582,28 @@ class UnifiedTTSEngine: else: # 音频数据 task['data_queue'].append(data) - # 设置并执行TTS - synthesizer = tts.setup_tts(data_handler) - synthesizer.call(task['text']) + # 设置并执行TTS + synthesizer = tts.setup_tts(data_handler,completion_event) + #synthesizer.call(task['text']) + tts.text_tts_call(task['text']) # 等待完成或超时 - if not task['event'].wait(timeout=300): # 5分钟超时 + # 等待完成或超时 + if not completion_event.wait(timeout=300): # 5分钟超时 task['error'] = "TTS generation timeout" task['completed'] = True logging.info(f"--tts task event set error = {task['error']}") except Exception as e: + logging.info(f"UnifiedTTSEngine _run_tts_sync ERROR: {str(e)}") task['error'] = f"ERROR:{str(e)}" task['completed'] = True + finally: + # 确保清理TTS资源 + logging.info("UnifiedTTSEngine _run_tts_sync finally") + if hasattr(tts, 'loop') and tts.loop: + tts.loop.close() def _merge_audio_data(self, audio_stream_id): """将任务的所有音频数据合并到ByteIO缓冲区""" @@ -1219,7 +1644,7 @@ class UnifiedTTSEngine: # 如果是延迟任务且未启动,现在启动 status 为 pending if task['delay_gen_audio'] and task['status'] == 'pending': self._start_tts_task(audio_stream_id) - + total_audio_data_size = 0 # 等待任务启动 while task['status'] == 'pending': await asyncio.sleep(0.1) @@ -1228,7 +1653,8 @@ class UnifiedTTSEngine: while not task['completed'] or task['data_queue']: while task['data_queue']: data = task['data_queue'].popleft() - # logging.info(f"yield data {len(data)}") + total_audio_data_size += len(data) + #logging.info(f"yield audio data {len(data)} {total_audio_data_size}") yield data # 短暂等待新数据 @@ -1318,6 +1744,7 @@ async def proxy_aichat_audio_stream(client_id: str, audio_url: str): # 代理函数 - 文本流 +# 在微信小程序中,原来APK使用的SSE机制不能正常工作,需要使用WebSocket async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload: dict): """代理大模型文本流请求 - 兼容现有Flask实现""" try: @@ -1328,13 +1755,19 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload "Content-Type": "application/json", 'Authorization': 'Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm' } + tts_model_name = payload.get('tts_model', 'cosyvoice-v1/longyuan@Tongyi-Qianwen') + #if 'longyuan' in tts_model_name: + # tts_model_name = "cosyvoice-v2/longyuan_v2@Tongyi-Qianwen" # 创建TTS实例 tts_model = QwenTTS( key=ALI_KEY, format=payload.get('tts_stream_format', 'mp3'), sample_rate=payload.get('tts_sample_rate', 48000), - model_name=payload.get('tts_model', 'cosyvoice-v1/longyuan@Tongyi-Qianwen') + model_name=tts_model_name ) + streaming_call = False + if tts_model.is_cosyvoice: + streaming_call = True # 创建流会话 tts_stream_session_id = stream_manager.create_session( @@ -1342,7 +1775,7 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload sample_rate=payload.get('tts_sample_rate', 48000), stream_format=payload.get('tts_stream_format', 'mp3'), session_id=None, - streaming_call=True + streaming_call= streaming_call ) # logging.info(f"---tts_stream_session_id = {tts_stream_session_id}") tts_stream_session_id_sent = False @@ -1399,7 +1832,6 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload data_obj.get('data')['audio_stream_url'] = f"/tts_stream/{tts_stream_session_id}" data_str = json.dumps(data_obj) tts_stream_session_id_sent = True - # 直接转发原始数据 await manager.send_text(client_id, json.dumps({ "type": "text", @@ -1717,12 +2149,14 @@ async def websocket_tts_endpoint( audio_url = f"http://localhost:9380/api/v1/tts_stream/{audio_stream_id}" # await proxy_aichat_audio_stream(connection_id, audio_url) sample_rate = stream_manager.get_session(audio_stream_id).get('sample_rate') + audio_data_size =0 await manager.send_json(connection_id, {"command": "sample_rate", "params": sample_rate}) async for data in stream_manager.get_tts_buffer_data(audio_stream_id): + audio_data_size += len(data) if not await manager.send_bytes(connection_id, data): break completed_successfully = True - + logging.info(f"--- proxy AiChatTts audio_data_size={audio_data_size}") elif service_type == "AiChatText": # 文本代理服务 # 等待客户端发送初始请求数据 进行大模型对话代理时,需要前端连接后发送payload diff --git a/asr-monitor-test/backup.txt b/asr-monitor-test/backup.txt deleted file mode 100644 index 14c0b965..00000000 --- a/asr-monitor-test/backup.txt +++ /dev/null @@ -1,263 +0,0 @@ -""" -ALI_KEY = "sk-a47a3fb5f4a94f66bbaf713779101c75" -class QwenTTS: - def __init__(self, key,format="mp3",sample_rate=44100, model_name="cosyvoice-v1/longxiaochun"): - import dashscope - print("---begin--init dialog_service QwenTTS--") # cyx - self.model_name = model_name - dashscope.api_key = key - self.synthesizer = None - self.callback = None - self.is_cosyvoice = False - self.voice = "" - self.format = format - self.sample_rate = sample_rate - if '/' in model_name: - parts = model_name.split('/', 1) - # 返回分离后的两个字符串parts[0], parts[1] - if parts[0] == 'cosyvoice-v1': - self.is_cosyvoice = True - self.voice = parts[1] - - def init_streaming_call(self, audio_call_back): - from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse - # cyx 2025 01 19 测试cosyvoice 使用tts_v2 版本 - from dashscope.audio.tts_v2 import ResultCallback, SpeechSynthesizer, AudioFormat # , SpeechSynthesisResult - from dashscope.audio.tts import SpeechSynthesisResult - from collections import deque - - print(f"--QwenTTS--tts_stream begin-- {self.is_cosyvoice} {self.voice}") # cyx - - class Callback_v2(ResultCallback): - def __init__(self) -> None: - self.dque = deque() - - def _run(self): - while True: - if not self.dque: - time.sleep(0) - continue - val = self.dque.popleft() - if val: - yield val - else: - break - - def on_open(self): - logging.info("Qwen tts open") - pass - - def on_complete(self): - self.dque.append(None) - - def on_error(self, response: SpeechSynthesisResponse): - print("Qwen tts error", str(response)) - raise RuntimeError(str(response)) - - def on_close(self): - # print("---Qwen call back close") # cyx - logging.info("Qwen tts close") - pass - - # canceled for test 语音大模型CosyVoice - #def on_event(self, result: SpeechSynthesisResult): - # if result.get_audio_frame() is not None: - # self.dque.append(result.get_audio_frame()) - # - - def on_event(self, message): - # print(f"recv speech synthsis message {message}") - pass - - # 以下适合语音大模型CosyVoice - def on_data(self, data: bytes) -> None: - if len(data) > 0: - #self.dque.append(data) - if audio_call_back: - audio_call_back(data) - # -------------------------- - - # text = self.normalize_text(text) - - try: - self.callback = Callback_v2() - format =self.get_audio_format(self.format,self.sample_rate) - self.synthesizer = SpeechSynthesizer( - model='cosyvoice-v1', - # voice="longyuan", #"longfei", - voice=self.voice, - callback=self.callback, - format=format - ) - #self.synthesizer.call(text) - except Exception as e: - print(f"---dale---20 error {e}") # cyx - # ----------------------------------- - # print(f"---Qwen return data {num_tokens_from_string(text)}") - # yield num_tokens_from_string(text) - - except Exception as e: - raise RuntimeError(f"**ERROR**: {e}") - - def get_audio_format(self, format: str, sample_rate: int): - # 动态获取音频格式 - from dashscope.audio.tts_v2 import AudioFormat - logging.info(f"QwenTTS--get_audio_format-- {format} {sample_rate}") - format_map = { - (8000, 'mp3'): AudioFormat.MP3_8000HZ_MONO_128KBPS, - (8000, 'pcm'): AudioFormat.PCM_8000HZ_MONO_16BIT, - (8000, 'wav'): AudioFormat.WAV_8000HZ_MONO_16BIT, - (16000, 'pcm'): AudioFormat.PCM_16000HZ_MONO_16BIT, - (22050, 'mp3'): AudioFormat.MP3_22050HZ_MONO_256KBPS, - (22050, 'pcm'): AudioFormat.PCM_22050HZ_MONO_16BIT, - (22050, 'wav'): AudioFormat.WAV_22050HZ_MONO_16BIT, - (44100, 'mp3'): AudioFormat.MP3_44100HZ_MONO_256KBPS, - (44100, 'pcm'): AudioFormat.PCM_44100HZ_MONO_16BIT, - (44100, 'wav'): AudioFormat.WAV_44100HZ_MONO_16BIT, - (48800, 'mp3'): AudioFormat.MP3_48000HZ_MONO_256KBPS, - (48800, 'pcm'): AudioFormat.PCM_48000HZ_MONO_16BIT, - (48800, 'wav'):AudioFormat.WAV_48000HZ_MONO_16BIT - - } - return format_map.get((sample_rate, format), AudioFormat.MP3_16000HZ_MONO_128KBPS) - def streaming_call(self,text): - if self.synthesizer: - self.synthesizer.streaming_call(text) - def end_streaming_call(self): - if self.synthesizer: - self.synthesizer.streaming_complete() - -class StreamSessionManager1: - def __init__(self): - self.sessions = {} # {session_id: {'tts_model': obj, 'buffer': queue, 'task_queue': Queue}} - self.lock = threading.Lock() - self.executor = ThreadPoolExecutor(max_workers=30) # 固定大小线程池 - self.gc_interval = 300 # 5分钟清理一次 5 x 60 300秒 - self.gc_tts = 10 # 10s 大模型开始输出文本有可能需要比较久,2025年5 24 从3s->10s - self.inited = False - self.tts_model = None - def create_session(self, tts_model,sample_rate =8000, stream_format='mp3'): - session_id = str(uuid.uuid4()) - with self.lock: - self.sessions[session_id] = { - 'tts_model': tts_model, - 'buffer': queue.Queue(maxsize=300), # 线程安全队列 - 'task_queue': queue.Queue(), - 'active': True, - 'last_active': time.time(), - 'audio_chunk_count':0, - 'finished': threading.Event(), # 添加事件对象 - 'sample_rate':sample_rate, - 'stream_format':stream_format, - "tts_chunk_data_valid":False - } - # 启动任务处理线程 - threading.Thread(target=self._process_tasks, args=(session_id,), daemon=True).start() - - - return session_id - - def append_text(self, session_id, text): - with self.lock: - session = self.sessions.get(session_id) - if not session: return - # 将文本放入任务队列(非阻塞) - #logging.info(f"StreamSessionManager append_text {text}") - try: - session['task_queue'].put(text, block=False) - except queue.Full: - logging.warning(f"Session {session_id} task queue full") - - def _process_tasks(self, session_id): - #任务处理线程(每个会话独立) - session = self.sessions.get(session_id) - def audio_call_back(chunk): - logging.info(f"audio_call_back {len(chunk)}") - if session['stream_format'] == 'wav': - if first_chunk: - chunk_len = len(chunk) - if chunk_len > 2048: - session['buffer'].put(audio_fade_in(chunk, 1024)) - else: - session['buffer'].put(audio_fade_in(chunk, chunk_len)) - first_chunk = False - else: - session['buffer'].put(chunk) - else: - session['buffer'].put(chunk) - session['last_active'] = time.time() - session['audio_chunk_count'] = session['audio_chunk_count'] + 1 - if session['tts_chunk_data_valid'] is False: - session['tts_chunk_data_valid'] = True # 20250510 增加,表示连接TTS后台已经返回,可以通知前端了 - while True: - if not session or not session['active']: - break - if not self.inited: - self.inited = True - self.tts_model = QwenTTS(ALI_KEY, session['stream_format'], session['sample_rate']) - self.tts_model.init_streaming_call(audio_call_back) - try: - #logging.info(f"StreamSessionManager _process_tasks {session['task_queue'].qsize()}") - # 合并多个文本块(最多等待50ms) - texts = [] - while len(texts) < 5: # 最大合并5个文本块 - try: - text = session['task_queue'].get(timeout=0.1) - #logging.info(f"StreamSessionManager _process_tasks --0 {len(texts)}") - texts.append(text) - except queue.Empty: - break - - if texts: - session['last_active'] = time.time() # 如果有处理文本,重置活跃时间 - # 提交到线程池处理 - future=self.executor.submit( - self._generate_audio, - session_id, - ' '.join(texts) # 合并文本减少请求次数 - ) - future.result() # 等待转换任务执行完毕 - session['last_active'] = time.time() - # 会话超时检查 - if time.time() - session['last_active'] > self.gc_interval: - self.close_session(session_id) - break - if time.time() - session['last_active'] > self.gc_tts: - session['finished'].set() - if self.tts_model: - self.tts_model.end_streaming_call() - break - - except Exception as e: - logging.error(f"Task processing error: {str(e)}") - - def _generate_audio(self, session_id, text): - #实际生成音频(线程池执行) - session = self.sessions.get(session_id) - if not session: return - # logging.info(f"_generate_audio:{text}") - first_chunk = True - - try: - self.tts_model.streaming_call(text) - except Exception as e: - session['buffer'].put(f"ERROR:{str(e)}") - logging.info(f"--streaming_call--error {str(e)}") - - - def close_session(self, session_id): - with self.lock: - if session_id in self.sessions: - # 标记会话为不活跃 - self.sessions[session_id]['active'] = False - # 延迟2秒后清理资源 - threading.Timer(1, self._clean_session, args=[session_id]).start() - - def _clean_session(self, session_id): - with self.lock: - if session_id in self.sessions: - del self.sessions[session_id] - - def get_session(self, session_id): - return self.sessions.get(session_id) -""" diff --git a/asr-monitor/Dockerfile.bk b/asr-monitor/Dockerfile.bk deleted file mode 100644 index 18f6ae70..00000000 --- a/asr-monitor/Dockerfile.bk +++ /dev/null @@ -1,32 +0,0 @@ -# ------------- 第一阶段:构建依赖 ------------- -FROM python:3.10-slim AS builder - -# 安装系统依赖 -RUN apt update && apt install -y --no-install-recommends \ - libsndfile1 ffmpeg \ - && rm -rf /var/lib/apt/lists/* - -# 安装Python依赖 -WORKDIR /app -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -# ------------- 第二阶段:运行时镜像 ------------- -FROM python:3.10-slim - -# 从构建阶段复制已安装的依赖 -COPY --from=builder /usr/lib /usr/lib # 共享系统库 -COPY --from=builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages - -# 设置工作目录和Python路径 -WORKDIR /app -ENV PYTHONPATH=/app - -# 复制代码 -COPY app ./app - -# 暴露端口 -EXPOSE 9480 - -# 启动命令 -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9480"] \ No newline at end of file