准备对AI流式音频发回给前端的机制做较大的修改,先提交1个版本

This commit is contained in:
qcloud
2025-07-19 22:44:28 +08:00
parent 74899acab9
commit 44cb7c0dca
9 changed files with 766 additions and 868 deletions

View File

@@ -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个无匹配则空字符串"

View File

@@ -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:

View File

@@ -1,4 +1,5 @@
TIMEZONE=Asia/Shanghai
DASHSCOPE_API_KEY = sk-a47a3fb5f4a94f66bbaf713779101c75
DOUBAO_APP_ID = 7282190702

View File

@@ -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 <bound method SpeechSynthesizer.on_message of <dashscope.audio.tts_v2.speech_synthesizer.SpeechSynthesizer object at 0x7f25f18a86a0>>: {"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 <bound method SpeechSynthesizer.on_error of <dashscope.audio.tts_v2.speech_synthesizer.SpeechSynthesizer object at 0x7f25f18a86a0>>: 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

View File

@@ -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

View File

@@ -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):

View File

@@ -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:
"""
在文本中查找特殊字符并用<phoneme>标签包裹它们
"""
# 如果文本已经是SSML格式直接返回
if text.strip().startswith("<speak>") and text.strip().endswith("</speak>"):
return text
# 为特殊字符添加SSML标签
for char, pinyin in self.special_characters.items():
# 使用正则表达式确保只替换整个字符(避免部分匹配)
pattern = r'([^<]|^)' + re.escape(char) + r'([^>]|$)'
replacement = r'\1<phoneme alphabet="py" ph="' + pinyin + r'">' + char + r'</phoneme>\2'
text = re.sub(pattern, replacement, text)
# 如果文本中已有SSML标签直接返回
if "<speak>" in text:
return text
# 否则包裹在<speak>标签中
return f"<speak>{text}</speak>"
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

View File

@@ -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)
"""

View File

@@ -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"]