From e6644a52623491f6104b69be9c3533744b9e9e29 Mon Sep 17 00:00:00 2001 From: qcloud Date: Sun, 27 Jul 2025 21:37:28 +0800 Subject: [PATCH] =?UTF-8?q?=E9=92=88=E5=AF=B9=E5=BE=AE=E4=BF=A1=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=9A=84=E5=90=8E=E5=8F=B0=E7=BB=8F=E8=BF=87?= =?UTF-8?q?5=E5=A4=A9=E6=B5=8B=E8=AF=95=EF=BC=8C=E5=85=B7=E5=A4=87?= =?UTF-8?q?=E4=B8=80=E5=AE=9A=E7=9A=84=E7=A8=B3=E5=AE=9A=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=89=88=E6=9C=AC=E7=94=A8=E4=BA=8E=E4=BF=9D?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/apps/sdk/dale_extra.py | 92 +- api/apps/sdk/session.py | 1 + api/db/db_models.py | 1 + asr-monitor-test/Dockerfile | 4 +- asr-monitor-test/app.log | 145 +- asr-monitor-test/app/config.py | 4 +- asr-monitor-test/app/database.py | 2 +- asr-monitor-test/app/login_service.py | 2 +- asr-monitor-test/app/main.py | 26 +- asr-monitor-test/app/payment_service.py | 3 +- asr-monitor-test/app/run.sh | 3 - asr-monitor-test/app/test.wav | Bin 377644 -> 0 bytes asr-monitor-test/app/tts_service.py | 891 ++++++--- asr-monitor-test/bk/tts_service.py | 2328 +++++++++++++++++++++++ asr-monitor-test/docker-compose.yml | 4 +- asr-monitor-test/requirements.txt | 2 + asr-monitor-test/run_app.sh | 4 +- asr-monitor-test/start.sh | 11 +- 18 files changed, 3147 insertions(+), 376 deletions(-) delete mode 100755 asr-monitor-test/app/run.sh delete mode 100644 asr-monitor-test/app/test.wav create mode 100644 asr-monitor-test/bk/tts_service.py diff --git a/api/apps/sdk/dale_extra.py b/api/apps/sdk/dale_extra.py index 56766672..6491357d 100644 --- a/api/apps/sdk/dale_extra.py +++ b/api/apps/sdk/dale_extra.py @@ -31,7 +31,7 @@ from api.utils.api_utils import get_result from api.utils.file_utils import get_project_base_directory from rag.utils.minio_conn import RAGFlowMinio import logging -import base64, gzip +import base64, gzip,json import io, re, json from io import BytesIO import queue,time,uuid,os,array @@ -135,13 +135,13 @@ def upload_file(tenant_id,mesum_id): mesum_id_str = str(mesum_id) labels_with_id = get_labels_with_id(mesum_id) - antique_labels = ','.join([item['label'] for item in labels_with_id]) + antique_labels = ';'.join([item['label'] for item in labels_with_id]) # 使用分号分隔 joined_string = antique_labels antiques_selected = f"{joined_string}" #logging.info(f"mesumid={mesum_id} {joined_string}") - prompt1 = (f"你是一名图片识别和理解助手" + prompt1= (f"你是一名图片识别和理解助手" f"任务是先识别图片中文字,然后理解文字中包含的内容,分析哪一项可以作为识别出文字的标题," f"你的回答有3个结果,第一个结果匹配出的结果,JSON键值为antique" f"从下面的候选项:{antiques_selected}进行匹配,每一个候选项中间以';'分割,如果没有任何匹配则结果为'',以免误触发讲解,匹配成功则输出匹配出的内容" @@ -151,25 +151,29 @@ def upload_file(tenant_id,mesum_id): f"原始数据的键值为text,输出是1个完整的JSON数据,不要有多余的前置和后置内容,确保前端能正确解析出JSON数据") prompt = ( - f"作为图片识别和理解助手,您的任务是:" - f"\n1. 图片基本上就是展品标题、历史人物或者历史事件" - f"\n2. 精确识别图片中的文字内容,理解文字语义,重点分析字体较大的文字" - f"\n3. 识别出的文字包含标题或者接近于标题的文字" - f"\n4. 从以下候选标题中选择最佳匹配项:" - f"\n {antiques_selected}" - f"\n\n### 输出要求:" - f"\n- 以严格JSON格式输出,包含3个字段:" - f"\n • `antique`: 匹配的标题(多个用英文分号';'分割,最多匹配3个,无匹配则空字符串)" - f"\n • `text`: 识别出的完整文字" - f"\n • `match_score`: 整体匹配度(0-1的浮点数),1=完全匹配" - f"\n\n### 匹配规则:" - f"\n1. 语义匹配优先于字面匹配" - f"\n2. 考虑同义词、近义词和描述性匹配" - f"\n3. 允许部分匹配(如'青铜酒器'匹配'青铜器')" - f"\n4. 若无明确匹配项,`antique`返回空字符串" - f"\n\n### 重要:" - f"\n- 输出必须是可直接解析的JSON,无任何前置/后置文本" - f"\n- 匹配度评分需客观反映文本与候选标题的相似度" + f"作为博物馆展品识别专家,您的任务是:" + f"\n1. 识别图片中的文字内容,重点关注展品标题(通常是最大/最显眼的文字)" + f"\n2. 从以下候选标题中匹配最佳项:{antiques_selected}" + f"\n3. 匹配规则:" + f"\n - 优先匹配完整标题(如'铜踵饰残片'匹配'铜踵饰残片')" + f"\n - 其次匹配关键词(如'刻辞卜骨'可匹配'刻辞卜骨')" + f"\n - 允许部分匹配(如'铜器'匹配'青铜器')" + f"\n - 忽略拼音、英文和次要描述文字" + f"\n - 如果近似,不好区分,则输出数组供前端选择,如:青铜车䡇匹配青铜车䡇;青铜车軛一对" + f"\n4. 输出要求:" + f"\n - 匹配结果最多不超过5个" + f"\n - 用英文分号';'分隔多个匹配项" + f"\n\n输出严格JSON格式:" + f"\n{'{'}" + f"\n \"antique\": \"匹配结果(多个用分号分隔)\"," + f"\n \"text\": \"识别出的完整文字\"," + f"\n \"match_score\": 整体匹配度(0-1)" + f"\n{'}'}" + f"\n\n示例:" + f"\n候选标题:青铜车䡇;玉虎;甲骨文;刻辞卜骨" + f"\n识别文字:『青铜车䡇』商代..." + f"\n正确输出:" + f"\n{'{'}\"antique\": \"青铜车轼\", \"text\": \"青铜车轼 (yue)...\", \"match_score\": 0.95{'}'}" ) file = request.files['file'] @@ -212,7 +216,7 @@ def upload_file(tenant_id,mesum_id): ] ) - """ + client = OpenAI( api_key="sk-a47a3fb5f4a94f66bbaf713779101c75", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", @@ -238,20 +242,58 @@ def upload_file(tenant_id,mesum_id): }, ], ) + """ + vl_model = "doubao-1-5-thinking-vision-pro-250428" + client = OpenAI( + api_key="1e04d30a-0c56-4dbd-b873-53f26649c64f", + base_url="https://ark.cn-beijing.volces.com/api/v3", + ) + response = client.chat.completions.create( + # 指定您创建的方舟推理接入点 ID,此处已帮您修改为您的推理接入点 ID + model=vl_model, + messages=[ + { + "role": "system", + "content": [{"type": "text", "text": prompt}], + }, + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{img_base}" + }, + } + ], + } + ], + ) message = response.choices[0].message - parsed_json_res = parse_markdown_json(message.content) parsed_json_data = {"antique": "", "text": "", "match_score": 0} matchedArray = [] + try: + if isinstance(message.content, str): + parsed_json_res = parse_markdown_json(message.content) # 优先识别带有markdown格式 + if parsed_json_res.get('success') is False: # 如果识别失败,再识别普通json格式(字符串) + parsed_json_data = json.loads(message.content) + parsed_json_res['success'] = True + parsed_json_res['data'] = parsed_json_data + except Exception as e: + pass + #logging.info(f"识别完成 {message.content} {parsed_json_data} ") + if parsed_json_res.get('success') is True: parsed_json_data = parsed_json_res.get('data') matchedAntiqueArray = parsed_json_data.get('antique').split(';') # 识别出的文物的数组,中间以';'分割,可能有多个 if len(matchedAntiqueArray) ==1: # 只有一个匹配项,直接返回 + logging.info(f"识别完成 得到1个,{parsed_json_data.get('antique')} {labels_with_id} ") for item in labels_with_id: if item['label'] == parsed_json_data.get('antique'): parsed_json_data['id'] = item.get('id') else: # 有多个匹配项,需要进行多个匹配 - for label in matchedAntiqueArray: + for label in matchedAntiqueArray[:5]: antique= {'label':label} for item in labels_with_id: if item['label'] == label: diff --git a/api/apps/sdk/session.py b/api/apps/sdk/session.py index dfcac843..b42a60c4 100644 --- a/api/apps/sdk/session.py +++ b/api/apps/sdk/session.py @@ -115,6 +115,7 @@ def update(tenant_id, chat_id, session_id): @token_required def completion(tenant_id, chat_id): # chat_id 和 别的文件中的dialog_id 应该是一个意思? cyx 2025-01-25 req = request.json + logging.info(f"/chats/{chat_id}/completions--0 req={req}") # cyx if not req.get("session_id"): # session_id 和 别的文件中的conversation_id 应该是一个意思? cyx 2025-01-25 conv = { "id": get_uuid(), diff --git a/api/db/db_models.py b/api/db/db_models.py index 8edf3c7b..f7b4a06b 100644 --- a/api/db/db_models.py +++ b/api/db/db_models.py @@ -1042,6 +1042,7 @@ class MesumOverview(DataBaseModel): index=False) free = IntegerField(default=0, index=False) + hotspot_rank = IntegerField(default=50, index=False) def __str__(self): return self.name diff --git a/asr-monitor-test/Dockerfile b/asr-monitor-test/Dockerfile index 27967302..490b3442 100644 --- a/asr-monitor-test/Dockerfile +++ b/asr-monitor-test/Dockerfile @@ -34,5 +34,5 @@ COPY app ./app EXPOSE 9580 # 启动命令 -CMD ["python3", "-m", "app.main"] -# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9480"] +#CMD ["python3", "-m", "app.main"] +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9580"] diff --git a/asr-monitor-test/app.log b/asr-monitor-test/app.log index dc8857b9..52a2d065 100644 --- a/asr-monitor-test/app.log +++ b/asr-monitor-test/app.log @@ -1,15 +1,142 @@ -INFO: Started server process [2877053] +INFO: Started server process [175422] INFO: Waiting for application startup. -16:01:53.789 - INFO - 监控服务已启动 +14:09:53.459 - 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. +14:10:04.372 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTM2NzkxMzB9.k-lALo9ulLGnu5O9qZALEp45F2loDnfdBZ09C9vglIw', 'balance': 0, 'status': 1, 'last_login_time': 1753074330, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1753074330, 'update_date': datetime.datetime(2025, 7, 21, 13, 5, 30)} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ASR & Monitor Service Start ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -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. +tts_service路由器正在启动... +INFO: 43.140.60.33:0 - "GET /auth/verify HTTP/1.1" 200 OK +INFO: 43.144.107.28:0 - "POST /payment/get_user_museum_subscriptions HTTP/1.1" 200 OK +14:10:08.416 - INFO - Creating TTS request: {'text': '提梁三足铜盉,5.2749,商,通梁高22.5厘米,高19.5厘米,口径4.8厘米,腹径11.0厘米,平谷区南独乐河公社刘家河大队出土,首都博物馆藏。铜盉为长颈,圆鼓腹,三足,有一绦状提梁,肩部附一圆柱形流。提梁盉在郑州和湖北盘龙城的二里岗期铜器中均未见。安阳殷墟妇好墓中出有一件, 其 制与此盉有所不同,花纹亦比较精美。 此盉可能是与殷墟二期提梁盉的过渡形态。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'model_name': 'sambert-zhichu-v1@Tongyi-Qianwen', 'sample_rate': 8000, 'stream_format': 'mp3'} +INFO: 43.140.60.33:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17528308107741998517 HTTP/1.1" 200 OK +INFO: ('1.13.185.116', 40190) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/9dd9cff1-093c-4b9f-a3d6-a701fdcf7ad3" [accepted] +14:10:09.160 - INFO - 新连接建立: b9980686-a10d-4082-9d13-bf1260ea95b7 +14:10:09.160 - INFO - 已经启动 start tts task {audio_stream_id} +14:10:09.161 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:10:09.161 - INFO - Qwen text_tts_call 提梁三足铜盉,5.2749,商,通梁高22.5厘米,高19.5厘米,口径4.8厘米,腹径11.0厘米,平谷区南独乐河公社刘家河大队出土,首都博物馆藏。铜盉为长颈,圆鼓腹,三足,有一绦状提梁,肩部附一圆柱形流。提梁盉在郑州和湖北盘龙城的二里岗期铜器中均未见。安阳殷墟妇好墓中出有一件, 其 制与此盉有所不同,花纹亦比较精美。 此盉可能是与殷墟二期提梁盉的过渡形态。 +INFO: connection open +INFO: connection closed +14:10:11.978 - INFO - 发送时检测到断开连接: b9980686-a10d-4082-9d13-bf1260ea95b7, +14:10:11.978 - WARNING - Send failed, connection closed: b9980686-a10d-4082-9d13-bf1260ea95b7 +14:10:11.978 - WARNING - 尝试向不存在的连接发送数据: b9980686-a10d-4082-9d13-bf1260ea95b7 +14:10:12.091 - INFO - --data_handler on_complete +14:10:12.091 - INFO - --tts task event set error = None +14:10:12.091 - INFO - UnifiedTTSEngine _run_tts_sync finally +INFO: ('1.13.185.116', 40194) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/0770c61f-3a83-4c68-9ac8-e304405c0eef" [accepted] +14:10:12.371 - INFO - 新连接建立: eb86ddd7-224b-45a9-a0d0-081c52b5b17e +INFO: connection open +14:10:12.493 - INFO - 代理文本流: completions_url=http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions {'question': '请介绍提梁三足铜盉', 'stream': True, 'tts_model': 'sambert-zhichu-v1@Tongyi-Qianwen', 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'tts_disable': True} +14:10:15.632 - INFO - HTTP Request: POST http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions "HTTP/1.1 200 OK" +14:10:15.632 - INFO - 响应状态: HTTP 200 +14:10:15.632 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:10:15.632 - INFO - --StreamSessionManager create_session last_active=1753078215.632958 +14:10:15.633 - INFO - 开始处理SSE流 +14:10:15.633 - INFO - --proxy_aichat_text_stream 发送audio_stream_url +14:10:15.683 - INFO - Qwen text_tts_call 提梁三足铜盉是商代文物, +INFO: ('1.13.185.116', 54072) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/06af3ad0-024e-4e6d-a3ea-71373ff05280" [accepted] +14:10:16.294 - INFO - 新连接建立: be24c0be-8a30-460c-99ff-747745d2c522 +INFO: connection open +14:10:17.144 - INFO - Qwen text_tts_call 通梁高22.5厘米,高19.5厘米,口径4.8厘米,腹径11.0厘米。出土于平谷区南独乐河公社刘家河大队,现藏于首都博物馆。 +14:10:19.318 - INFO - Qwen text_tts_call 其特征为长颈圆鼓腹三足,有一绦状提梁,肩部附一圆柱形流。 +14:10:20.791 - INFO - SSE流处理完成,事件数: 12 +INFO: connection closed +14:10:21.059 - INFO - Qwen text_tts_call 此盉在郑州和湖北盘龙城的二里岗期铜器中未见,与安阳殷墟妇好墓出土的提梁盉有所不同,花纹较精美,可能是殷墟二期提梁盉的过渡形态。 +INFO: connection closed +14:10:21.394 - INFO - 发送时检测到断开连接: be24c0be-8a30-460c-99ff-747745d2c522, +14:10:21.394 - INFO - --- proxy AiChatTts audio_data_size=94212 +14:10:23.002 - INFO - 清理资源: 0会话 +14:10:24.462 - INFO - Creating TTS request: {'text': '玉牛首,商,通长3.7厘米,宽2.7厘米,河南省信阳市罗山县天湖墓地出土,信阳博物馆藏。\n', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'model_name': 'sambert-zhichu-v1@Tongyi-Qianwen', 'sample_rate': 8000, 'stream_format': 'mp3'} +INFO: 43.140.60.44:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17528308107741998517 HTTP/1.1" 200 OK +INFO: ('1.13.185.116', 33942) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/5286022d-3c15-4aa0-a11d-6af6823c89ae" [accepted] +14:10:24.737 - INFO - 新连接建立: 0f8be756-1592-4fe2-958e-074819796722 +14:10:24.737 - INFO - 已经启动 start tts task {audio_stream_id} +14:10:24.737 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:10:24.737 - INFO - Qwen text_tts_call 玉牛首,商,通长3.7厘米,宽2.7厘米,河南省信阳市罗山县天湖墓地出土,信阳博物馆藏。 +INFO: connection open +14:10:25.734 - INFO - --data_handler on_complete +14:10:25.734 - INFO - --tts task event set error = None +14:10:25.734 - INFO - UnifiedTTSEngine _run_tts_sync finally +INFO: connection closed +INFO: ('1.13.185.116', 33958) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/d3fe9c0c-45ab-4821-98b4-ef28ad6b7264" [accepted] +14:10:30.629 - INFO - 新连接建立: 64ac60ed-59ee-4d39-ab67-c92a583aacd6 +INFO: connection open +14:10:30.690 - INFO - 代理文本流: completions_url=http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions {'question': '请介绍玉牛首', 'stream': True, 'tts_model': 'sambert-zhichu-v1@Tongyi-Qianwen', 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'tts_disable': True} +14:10:33.444 - INFO - HTTP Request: POST http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions "HTTP/1.1 200 OK" +14:10:33.444 - INFO - 响应状态: HTTP 200 +14:10:33.444 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:10:33.445 - INFO - --StreamSessionManager create_session last_active=1753078233.4450512 +14:10:33.445 - INFO - 开始处理SSE流 +14:10:33.446 - INFO - --proxy_aichat_text_stream 发送audio_stream_url +14:10:33.495 - INFO - Qwen text_tts_call 玉牛首是商代的一件玉器,通长3.7厘米, +INFO: ('1.13.185.116', 33966) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/dfa471ae-b608-48f8-aa38-f3da27aa9da9" [accepted] +14:10:33.919 - INFO - 新连接建立: 2cb47c8b-842c-47a8-b221-42caf74e089a +INFO: connection open +14:10:35.077 - INFO - Qwen text_tts_call 宽2.7厘米,出土于河南省信阳市罗山县天湖墓地,现藏于信阳博物馆。 +14:10:36.370 - INFO - SSE流处理完成,事件数: 9 +INFO: connection closed +14:10:36.911 - INFO - Qwen text_tts_call 这件玉器以牛首为题材,雕刻精细,形象生动,反映了商代玉器工艺的高超水平。玉牛首不仅是珍贵的文物,也是研究商代文化和艺术的重要资料。 +INFO: connection closed +14:10:37.301 - INFO - 发送时检测到断开连接: 2cb47c8b-842c-47a8-b221-42caf74e089a, +14:10:37.301 - INFO - --- proxy AiChatTts audio_data_size=49671 +14:10:38.255 - INFO - verify_token user={'user_id': '76538cf0-a6cf-4aa8-8440-382dd2330384', 'openid': 'obKSz7V6a-avAF-vtQrnk_rnuSGE', 'phone': '18676776176', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3NjUzOGNmMC1hNmNmLTRhYTgtODQ0MC0zODJkZDIzMzAzODQiLCJleHAiOjE3NTM2NzkxMzB9.k-lALo9ulLGnu5O9qZALEp45F2loDnfdBZ09C9vglIw', 'balance': 0, 'status': 1, 'last_login_time': 1753074330, 'create_time': 1748960538, 'create_date': datetime.datetime(2025, 6, 3, 22, 22, 18), 'update_time': 1753074330, 'update_date': datetime.datetime(2025, 7, 21, 13, 5, 30)} +INFO: 43.144.107.210:0 - "GET /auth/verify HTTP/1.1" 200 OK +INFO: 43.144.107.28:0 - "POST /payment/get_user_museum_subscriptions HTTP/1.1" 200 OK +14:10:53.032 - INFO - 清理资源: 0会话 +14:11:23.062 - INFO - 清理资源: 0会话 +14:11:53.090 - INFO - 清理资源: 0会话 +14:12:23.118 - INFO - 清理资源: 0会话 +14:12:53.136 - INFO - 清理资源: 0会话 +14:13:02.462 - INFO - verify_token user={'user_id': '9d0ba2ee-6821-4245-aadc-ea270313d92b', 'openid': 'obKSz7csdQWD7l4tqm7w_aoySrkM', 'phone': '18146525018', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5ZDBiYTJlZS02ODIxLTQyNDUtYWFkYy1lYTI3MDMxM2Q5MmIiLCJleHAiOjE3NTMwODcwMTd9.6z1_LMFK0vebxkel1H27Nx9OCyeHaOzASpNhL27Gjkk', 'balance': 0, 'status': 1, 'last_login_time': 1752482217, 'create_time': 1751012368, 'create_date': datetime.datetime(2025, 6, 27, 16, 19, 28), 'update_time': 1752482217, 'update_date': datetime.datetime(2025, 7, 14, 16, 36, 57)} +INFO: 43.140.60.33:0 - "GET /auth/verify HTTP/1.1" 200 OK +INFO: 43.144.107.28:0 - "POST /payment/get_user_museum_subscriptions HTTP/1.1" 200 OK +14:13:23.162 - INFO - 清理资源: 0会话 +14:13:53.168 - INFO - 清理资源: 0会话 +14:14:23.194 - INFO - 清理资源: 0会话 +14:14:43.262 - INFO - wechat login data={'code': '0f1tbl1w35mEh530lf2w37qmFg4tbl1w', 'encryptedData': 'gBWrIB+qeddiOPRlaawf6ChAd2LqpA/4RxSwdeAr8JhDbHz2csnNl6QY0sWegHddLh4gUr5b3EZmWlTigEZIQa7PNqRVJviQczmGymKSU/X+iL7msmSbpPAcO7RZc6tzd8LdZYbYNcACW0qeCqmv7iyXx4FJzTFrKMF2L821N/F/xFe7yR2Sjf/w29/R9Rodqa4NnZNpUZ5QNRIOEwA8OQ==', 'iv': '5xb8I5Lx6PGh4zK2lwanpg=='} +14:14:43.896 - INFO - get_wx_session return {'session_key': 'Zx4n4H7AUgo18OKGcxTZ9w==', 'openid': 'obKSz7cpajH1Z6wECKSOLKXJ_XS8'} +14:14:43.900 - INFO - 解密数据: {'phoneNumber': '15901055018', 'purePhoneNumber': '15901055018', 'countryCode': '86', 'watermark': {'timestamp': 1753078481, 'appid': 'wx446813bfb3a6985a'}} +14:14:43.900 - INFO - decrypt_data return 15901055018 +14:14:43.909 - INFO - login return {'user_id': '6dd06c74-902e-4f42-b226-d93b9ee5c1df', 'openid': 'obKSz7cpajH1Z6wECKSOLKXJ_XS8', 'phone': '15901055018', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2ZGQwNmM3NC05MDJlLTRmNDItYjIyNi1kOTNiOWVlNWMxZGYiLCJleHAiOjE3NTM0MzU4Mjh9.mZSLMkE5eDpJeIpurl3B2PFwxPPbwEkS-q3zPyhvqfo', 'balance': 0, 'status': 1, 'last_login_time': 1752831028, 'create_time': 1748941778, 'create_date': datetime.datetime(2025, 6, 3, 17, 9, 38), 'update_time': 1752831028, 'update_date': datetime.datetime(2025, 7, 18, 17, 30, 28)} +INFO: 43.144.107.210:0 - "POST /auth/login HTTP/1.1" 200 OK +14:14:44.535 - INFO - verify_token user={'user_id': '6dd06c74-902e-4f42-b226-d93b9ee5c1df', 'openid': 'obKSz7cpajH1Z6wECKSOLKXJ_XS8', 'phone': '15901055018', 'email': None, 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2ZGQwNmM3NC05MDJlLTRmNDItYjIyNi1kOTNiOWVlNWMxZGYiLCJleHAiOjE3NTM2ODMyODN9.xBIu5A1efp5xcF10mH-GrJeSi_56BAMzfP3qVfugfhU', 'balance': 0, 'status': 1, 'last_login_time': 1753078483, 'create_time': 1748941778, 'create_date': datetime.datetime(2025, 6, 3, 17, 9, 38), 'update_time': 1753078483, 'update_date': datetime.datetime(2025, 7, 21, 14, 14, 43)} +INFO: 43.144.107.28:0 - "GET /auth/verify HTTP/1.1" 200 OK +INFO: 106.55.206.109:0 - "POST /payment/get_user_museum_subscriptions HTTP/1.1" 200 OK +14:14:53.223 - INFO - 清理资源: 0会话 +14:14:58.786 - INFO - Creating TTS request: {'text': '提梁卣,商,口径13.6厘米,最大腹径22.2厘米,通高26.8厘米,2008年安阳刘家庄北地H326出土,中国社会科学院考古研究所藏。器身扁圆形,直口微敛,长颈、鼓腹下垂,矮圈足,绹索状提梁两端饰小兽首。盖面饰两组独立兽面纹,相背排列;颈部饰八条勾喙夔纹,腹部两组兽面纹以倒夔纹补空,圈足饰八条夔纹。H326位于刘家庄北地两座商代夯土建筑间的通道中,打破路土层,推测为房主仓促撤离时埋藏。此卣填补了商末周初青铜器形制演变的空白。卣的器型特征为:敛口,颈部两侧有提梁,鼓腹,上有盖,盖上有钮,下有圈足。它的命名来自宋人,器物上并不见自名。在不同时期的西周铭文,涉及到有大量赏赐时多有“秬鬯一卣”的记录,在这里“卣”是用作度量单位。鬯是酒的一种,是黍与香草酿制,用以降神。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'model_name': 'sambert-zhichu-v1@Tongyi-Qianwen', 'sample_rate': 8000, 'stream_format': 'mp3'} +INFO: 43.144.107.210:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17530784708251252320 HTTP/1.1" 200 OK +INFO: ('1.13.185.116', 37746) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/0f7bb773-8933-462a-805f-42f1adbc00fc" [accepted] +14:14:58.967 - INFO - 新连接建立: 1c2ac13f-9a2c-4bec-9241-13b5357c56f6 +14:14:58.967 - INFO - 已经启动 start tts task {audio_stream_id} +14:14:58.967 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +INFO: connection open +14:14:58.967 - INFO - Qwen text_tts_call 提梁卣,商,口径13.6厘米,最大腹径22.2厘米,通高26.8厘米,2008年安阳刘家庄北地H326出土,中国社会科学院考古研究所藏。器身扁圆形,直口微敛,长颈、鼓腹下垂,矮圈足,绹索状提梁两端饰小兽首。盖面饰两组独立兽面纹,相背排列;颈部饰八条勾喙夔纹,腹部两组兽面纹以倒夔纹补空,圈足饰八条夔纹。H326位于刘家庄北地两座商代夯土建筑间的通道中,打破路土层,推测为房主仓促撤离时埋藏。此卣填补了商末周初青铜器形制演变的空白。卣的器型特征为:敛口,颈部两侧有提梁,鼓腹,上有盖,盖上有钮,下有圈足。它的命名来自宋人,器物上并不见自名。在不同时期的西周铭文,涉及到有大量赏赐时多有“秬鬯一卣”的记录,在这里“卣”是用作度量单位。鬯是酒的一种,是黍与香草酿制,用以降神。 +14:15:04.257 - INFO - --data_handler on_complete +14:15:04.257 - INFO - --tts task event set error = None +14:15:04.257 - INFO - UnifiedTTSEngine _run_tts_sync finally +INFO: connection closed +14:15:29.264 - INFO - Creating TTS request: {'text': '提梁卣,商,口径13.6厘米,最大腹径22.2厘米,通高26.8厘米,2008年安阳刘家庄北地H326出土,中国社会科学院考古研究所藏。器身扁圆形,直口微敛,长颈、鼓腹下垂,矮圈足,绹索状提梁两端饰小兽首。盖面饰两组独立兽面纹,相背排列;颈部饰八条勾喙夔纹,腹部两组兽面纹以倒夔纹补空,圈足饰八条夔纹。H326位于刘家庄北地两座商代夯土建筑间的通道中,打破路土层,推测为房主仓促撤离时埋藏。此卣填补了商末周初青铜器形制演变的空白。卣的器型特征为:敛口,颈部两侧有提梁,鼓腹,上有盖,盖上有钮,下有圈足。它的命名来自宋人,器物上并不见自名。在不同时期的西周铭文,涉及到有大量赏赐时多有“秬鬯一卣”的记录,在这里“卣”是用作度量单位。鬯是酒的一种,是黍与香草酿制,用以降神。', 'session_id': '0b4cdbaeaf9111efa53df171065841e8', 'delay_gen_audio': True, 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'model_name': 'sambert-zhichu-v1@Tongyi-Qianwen', 'sample_rate': 8000, 'stream_format': 'mp3'} +INFO: 43.140.60.33:0 - "POST /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts?device_id=17510123186117505004 HTTP/1.1" 200 OK +INFO: ('1.13.185.116', 45602) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/1b664897-37ab-46c9-9140-70c44bd23d15" [accepted] +14:15:29.562 - INFO - 新连接建立: 344077b2-343f-4ac6-a37d-b83e81403078 +14:15:29.562 - INFO - 已经启动 start tts task {audio_stream_id} +14:15:29.562 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:15:29.562 - INFO - Qwen text_tts_call 提梁卣,商,口径13.6厘米,最大腹径22.2厘米,通高26.8厘米,2008年安阳刘家庄北地H326出土,中国社会科学院考古研究所藏。器身扁圆形,直口微敛,长颈、鼓腹下垂,矮圈足,绹索状提梁两端饰小兽首。盖面饰两组独立兽面纹,相背排列;颈部饰八条勾喙夔纹,腹部两组兽面纹以倒夔纹补空,圈足饰八条夔纹。H326位于刘家庄北地两座商代夯土建筑间的通道中,打破路土层,推测为房主仓促撤离时埋藏。此卣填补了商末周初青铜器形制演变的空白。卣的器型特征为:敛口,颈部两侧有提梁,鼓腹,上有盖,盖上有钮,下有圈足。它的命名来自宋人,器物上并不见自名。在不同时期的西周铭文,涉及到有大量赏赐时多有“秬鬯一卣”的记录,在这里“卣”是用作度量单位。鬯是酒的一种,是黍与香草酿制,用以降神。 +INFO: connection open +14:15:34.797 - INFO - --data_handler on_complete +14:15:34.797 - INFO - --tts task event set error = None +14:15:34.797 - INFO - UnifiedTTSEngine _run_tts_sync finally +INFO: connection closed +14:15:34.848 - INFO - 发送时检测到断开连接: 344077b2-343f-4ac6-a37d-b83e81403078, +INFO: ('1.13.185.116', 48856) - "WebSocket /tts/chats/39e9a2ba5a4711f0865bbb55c66f9471/tts/54697bbc-a6ca-49c3-97a5-b73ac4e30bc9" [accepted] +14:16:25.962 - INFO - 新连接建立: e030143e-537e-4b14-a3ee-6594e50a1711 +INFO: connection open +14:16:25.995 - INFO - 代理文本流: completions_url=http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions {'question': '请简单介绍兽面纹铜觚,字符不超过150字', 'stream': True, 'tts_model': 'sambert-zhichu-v1@Tongyi-Qianwen', 'tts_sample_rate': 8000, 'tts_stream_format': 'mp3', 'tts_disable': True} +14:16:28.918 - INFO - HTTP Request: POST http://127.0.0.1:9380/api/v1/chats/39e9a2ba5a4711f0865bbb55c66f9471/completions "HTTP/1.1 200 OK" +14:16:28.918 - INFO - 响应状态: HTTP 200 +14:16:28.918 - INFO - ---begin--init QwenTTS-- mp3 8000 sambert-zhichu-v1@Tongyi-Qianwen +14:16:31.918 - ERROR - create_session Timeout acquiring lock for session creation +14:16:31.919 - INFO - 开始处理SSE流 +14:16:31.919 - INFO - --proxy_aichat_text_stream 发送audio_stream_url diff --git a/asr-monitor-test/app/config.py b/asr-monitor-test/app/config.py index e364696d..c7d4fe13 100644 --- a/asr-monitor-test/app/config.py +++ b/asr-monitor-test/app/config.py @@ -1,8 +1,8 @@ from pymysql.cursors import DictCursor DATABASE_CONFIG = { - "host": "localhost", - "port": 5455, + "host": "localhost",#"ragflow-mysql",#"localhost", + "port": 5455,#3306, #5455, "user": "root", "password": "infini_rag_flow", "database": "rag_flow", diff --git a/asr-monitor-test/app/database.py b/asr-monitor-test/app/database.py index 9f5f885a..fd91a5e1 100644 --- a/asr-monitor-test/app/database.py +++ b/asr-monitor-test/app/database.py @@ -2,7 +2,7 @@ import pymysql from pymysql import Connection from pymysql.err import OperationalError, InterfaceError from contextlib import contextmanager -from config import DATABASE_CONFIG +from app.config import DATABASE_CONFIG from datetime import datetime,timedelta import logging from zoneinfo import ZoneInfo # Python 3.9+ 内置 diff --git a/asr-monitor-test/app/login_service.py b/asr-monitor-test/app/login_service.py index 0598f003..c363ac63 100644 --- a/asr-monitor-test/app/login_service.py +++ b/asr-monitor-test/app/login_service.py @@ -9,7 +9,7 @@ from Crypto.Cipher import AES import base64,uuid,asyncio import requests from datetime import datetime,timedelta -from database import * +from app.database import * login_router = APIRouter() logger = logging.getLogger("login") diff --git a/asr-monitor-test/app/main.py b/asr-monitor-test/app/main.py index 79d67fa7..e79278a7 100644 --- a/asr-monitor-test/app/main.py +++ b/asr-monitor-test/app/main.py @@ -9,10 +9,18 @@ import json from contextlib import asynccontextmanager from dotenv import load_dotenv - - import uvicorn +# 加载 .env 文件中的环境变量 +load_dotenv() # 默认加载项目根目录的 .env 文件 + +from app.asr_service import asr_router +from app.monitor_service import monitor_router +from app.tts_service import tts_router,tts_lifespan +from app.login_service import login_router +from app.chat_service import chat_router +from app.payment_service import payment_router + @asynccontextmanager async def lifespan(app: FastAPI): """生命周期管理""" @@ -20,21 +28,17 @@ async def lifespan(app: FastAPI): print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") print(" ASR & Monitor Service Start") print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + # 启动TTS路由器的生命周期 + tts_lifespan_ctx = tts_lifespan(app) + await tts_lifespan_ctx.__aenter__() yield + # 关闭TTS路由器的生命周期 + await tts_lifespan_ctx.__aexit__(None, None, None) # 服务停止清理 print("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") print(" Service Stopped Cleanly") print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") -# 加载 .env 文件中的环境变量 -load_dotenv() # 默认加载项目根目录的 .env 文件 - -from app.asr_service import asr_router -from app.monitor_service import monitor_router -from app.tts_service import tts_router -from app.login_service import login_router -from app.chat_service import chat_router -from app.payment_service import payment_router # 创建应用实例 app = FastAPI(lifespan=lifespan) diff --git a/asr-monitor-test/app/payment_service.py b/asr-monitor-test/app/payment_service.py index 896ea082..0752026f 100644 --- a/asr-monitor-test/app/payment_service.py +++ b/asr-monitor-test/app/payment_service.py @@ -12,9 +12,8 @@ from decimal import Decimal from uuid import UUID import json import logging -from database import * +from app.database import * from jose import JWTError, jwt -from database import * import base64 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding diff --git a/asr-monitor-test/app/run.sh b/asr-monitor-test/app/run.sh deleted file mode 100755 index 603f9b77..00000000 --- a/asr-monitor-test/app/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -export PYTHONPATH=. -python3 -m main.py diff --git a/asr-monitor-test/app/test.wav b/asr-monitor-test/app/test.wav deleted file mode 100644 index e689f964d4fa1c45db240f135567487d0badabb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 377644 zcmY)1b=+1(_Xhe+cXxL;(kX%-QDoeUHg33 z{X6H6BOl~>?tAZ<71z4fn%Oh6`}XYKz2=l$Nxv>vo`35-4_7UkBuO@Zp6ld?r;{Xm zQZ%`F;KKtG*ZlwgJDdK0zn@Lh|M%y(Gn;#I_>()ym89vJ^lWglB!8b(&zA7eZQSbOD2b0mp3Vv zo6Osl(NgI3EW9qF1QsZPVJbiBSQCO@U$u<^0<)AXmbtTsmKryRRa zAw#F6tez_*4U#qK@N@&u9p{r{X(1LUnOvZk?3sRBBz4KyExCry%hQ$VrgUpspY127 zOVe&XFYo%Y`kdqbh9ufg$HGZv7B1wf-aa{%o||+hUE$L|Ti_-Wr1iDYUry~DsN=qb{kS2x3n)J-U_Z7*XkJn2k>(hmN+7VXL zv_M9#f^b(M>72CXt#-8CL(7|z>-n=jcFI3e@f1FNekca zq5rt{0h5E%ztcZ>U|RZD`mffDYk8mcn$v4o zS~cmUrRie166^l$-yZs0o32f(LG2__-a=nf(qG6>IoX&lfrl1sFiE7B=INCr-U>s9 z#d;QxZ-BxdwY!=Wao0pGjY(&-ZYc=;m#!WByF&k2?mDEEMl{;0pJ0}0qNg?=Ey_e? zb+H!c+o-4Bv_6wwmR!NZ>-5!}tqZYZGjT93?Ug*iCTF3sna?UE_a|L^UV@Hi#Z(qA zo|kM%CySH5v|LZue59D9-J6qhld#eupS6LA+8E;u=BXrVBjVSvYkQv-gQgluBbx7H z!=>&lnw&_h_RDj0$#n&2^I0;pg#r$SAC?LWLkZ2QDJnEBOEWHkkY-Wj#th&No>(ZCg z|GKL>#u_7<%E9qa2wj|hE5???RF!1DXbcIDv)QgR_;DdrEYreR@p^#I$|uXyPsG$U zWZa1%>nDGZy^1T>;DiLmi^KHj^g->U`uSBPFZ1(AOn*RsGqFONc898Bq%AB;BOiYOL(BPZ#vMZFzo+VB!@50hwv=%zaJh~kS3o`nkFsXS4GUW%|t*&K6$~P zN_uN7HVX4X%3hmTsXWAPk{$B%Q7(APrPq^MN%?EC9?K+uyS5E~kDybZ;Wy4?Hd7;YK*) zv}ih*-kn@b?uBUsR-4G`m1wh8OX2T5v_FWMy1_^(99tr3?Al$tx(U{Hh^PW`#@}MI zcJcrW_D`Nk&VkZ=EL0c^oRxj6@KN;J5+ZBzeRKF(NxzE8BD!s(+e28oBx@H>TFHA8 z=vyE5gGYMF4olggN7BbPjglLn>Uq*%!@u`HX*a$djraGZb^Nr8g@RQ^r(eisyVLFI z3sBkz>R(9T!OL~U`*$R&N|U$9JU~tw1P^&c%2swSpM1xD1;~3?oK`1qBeHcBpBIt5 zC)ta@(Gloq2A3yMn04@-kbi+H`Cc?Gu?J-aU+`zOJ7UhO-K3rN%|WWSS5@8>8@$~U5S)8 z@qc9CQy8x_PZs6p&a%*D$?No-%|d5k?h7pygs|c?>y+H4^$+-|v|L#jFFh^>^C$n% ze>+4Ur0EST*^EU$PCkRA!`QkCU5D^)_T;T}0Q8?E%>dYa1&TJae?K<=2HLBV<|o|N zDH%ZLpV)jZeX{AdHNRBnm5}x@o6q9OYT|r}9MDK^`_oU=*lmo~Zo%U{+5XPtf1>A* zD+=R_dA`34&UQh;R+!l)>l9|;3;3?G|940tOV@WrAO9Z0qjjL`Ls4Fsrpv^@BE7C> z$y4HSh5p{gh~d#1_+mbp7W-^ETYa0}FGdgRWwzf}r4Of1K<%ZFw^u9wRTBg+v?lE* z{C^GquH&t!-Li?sCdsSpSB$mGvEHr>x2%VeoUBmO_wVZA3}!ma-}!vMFMTk%l{Qa9 zKnUA2w3UGt!HArx@*; z%C&VxaA8&p9A;zBQ#hbwGE8JF(Ch2`b`nS2o!kd8W!Q8v-NJLZU|^LB>MJ=eOU_#= z^L$C-Eo7(z#r0ruB+sLe*4?i+eFR~$=zoW$V*D{4 z_N$RPKRjHZjr&;R4zYTitPSY6fsLxk6JMwy_CxMo7;6mIC0)N3f@=FWa_0c{>&Q0^ zw6!G@8+XeYTUhZi9GHi%KVjF_@ZSlZr$a@I;%4yoL3lfet?ps}TU4d9M8QUSf32FH ztHRjAw^8qp#=lpx-*S1Up|)p|rJ;!e zU#1U0dJ&uu^;%Jkm>o+M#}&a-r{uw{s+LVMSbKMV0Y#-{nYY{@HOKA8!eN|A@(=5!*ssL<=Qo{2(`2S*AChEmElPgs(hvk*^>77355B(jI?{Rcpt?p#~59I8bB#n`9Rn=H_ zIdUp}3np{%V;30wj;HsD%$G34cK?2z-o#JkXgeO0R~JRI()W|^#LAz3{}zJ!^WRJQ zS(5S3QQ2odX-}t*;`1Bu&4TnfvTVU)BYhKN$Ze3@+w~ulwKd#~p+_syR3+7F9=(D^ zR3r;|t1f$E>$e7cEUYT%LA z)sf$(m!)@$+x7l_r?sQ{U+(W>7LS~Cj|!o=yXz;vv-@t9Tc=D7oI~YNoW{juq7Y_b*F4q&-9=_#=zARA%+YN*A zU8Gp78hAOARj$F>$5nFQh_)CT*H%q^;J%$cdq=gL8XK+iTU#xTPyZ*5bKr@8$=Vm9 zXUp{ERE#@B#9=($KRtAIBwyxE%A`G1shf=U56PP6vP2#ce=*IUW52s#w32@RX7_WA zp|f~)AEc&OvtjbEh&-*e4~_EnKvXmO?+}fb`+OY@^NPmO?ylzZvb=UyHP(Z53gg8B z5IK?TF~a>>o1Z4*Sh}Ff`82kfWgPjQsJM`QW88B+efr83o!H}A^-iLN^JUi}`Y6wj zE%fvu`)!8Im($zj_hYKAioDs(_;|W_@9AzFEY~beuZH{j>gJ7dQhBVjRE2t>?>}PE z+ECV(<~7CiLb_Cz&%TGRlsBl&SCqSw0%l{ zx3JJW2ydZQe~$#c@n2`&`ow)}#7rru$fcUu!Vag>XJqlq+5D`WQCOeZl3%dWaoG6> zf>!YNNYz)){9q{UoWZ*26v(Zg_dJ&D6dkiRX=kL8`5TD}B&ci@j| zr0wILeb6{j)>|x67W3BqP}Pv;<@f(E{SWnH!9#ZqB2-3 z#hiKM-!o$L4t}YFF+LLG`^9PvKbOTE$LYgB=%Zf6HmjlABZmWnGuDL>&>b#dT%bvraOIe)TX#)nqUkFO+9@Vw+Dab(Sga-&yc`m+r_a zr0PeWb^H?b`)KGp0S)!FyHs2Z!ckT5&9O|aekp$VN507qeRE-~BMqXuJSL(JiGWFJ zr%y!IvGh*5$7ptRG8en8GX8tt=OvQy$yB{fg{w#C`aih12j8v{9q%QB$llcd=VRXL z$ydox5^aT@nlf8ij9QKyJ6WlV>qhd~G~bj>2KuSGD^}@$g?5%;z@zfY6LR=bmO4s< zRV+6j|12f(4&$(2#q}(IUrX;wpY;0*Z1)f3jqz#B+vE^a6S3$~Is60GnSy`xG z;mXm_7c;Y~wNR2jF7WwE9B~F_2PPlzZ5<4Ah+PY@>`8Nb9bx(zRcm>e?539`T9^wN z#pHm^vfePZs00h+)mArUMm9~gFqVHl6EiQQ?eRv8-d{-XBl+iK{F+T0s#v><_2oqxE;!zUYg+oeFw7P9?@KDZhBUp9fBX7mGz%1m+H*-X4l)kA;}D;&_W%Eg zz7;gAXAJZoTD8{t|FByd{SFgP^VGi8Nf!0*Ocve@0f(S=n|Y(W@N}OVZ5=C4z|v({ zY!As}*6zc!J4@_=x@q`g75z(Q_`j90=PtHwOV%0eTt!5z#{5n6unAKX<)5Ce&F9~# zym<-D3d7iGx#JR})HW*e}iIDkhe3)(%)XH_BbfjwaAch_Y zcSS@=aklA(-S$IFWSk0GA1W(vg{Pv}_E%3v&K1SwU9n1B#r#S<2OHt~I%GV9(H66J z4>4UWgl7v+W1DuIsTBM;um&Et(kO)k1;C0ZbA%EcCqdxDdji}mg$8gWU!rx-DFRvxqs9?r-gZ5)?V?2Dv2)QWR=Y@c( zICU-_9VI>s`|OnVHjDSh#ti#izgM+=mmdF>)6S+B>v@ThXctUTj4Z9?)bgsF{i^)B z<{DO;A&i;)Wv=}_?MIGlStggO;~8N-c_n5cVlJ{Pe~ecJv{ZG*lZRs}q61>>It(|J zJ+IDOTbjRfk^dI{nn&)-T^r90=Bl`Zi*MD+NtQStdq-4N7K!Jp4Xg4+mXXT2D!e(Y zbDM0?mbK60jU`59!_ynI5+j1f!Sww84vxK5>q8)*zLEL$GRw_+eUi^cX6731qs;vrc3E8*cn({o{Uhgr!FJa_3Rn{J%$9O(@oG%KgLOS8# zf7t69lHH)sf8i{myCg5HWyy1BeV^DX0vjb=U%;o?++Rc;*_D^G`Fw@e%R}NQxuu?O zj^c^RqNbv1WlQ=PpWUotT|?4F{8E&Dv*h?*tWXfkUdDR&CO_iZm?`Sw=j-)e-8W6; zk}T3b!ERTO;Ys)Igpb|nr6TfHQTt$KTwa2u8^YKu73W@0He%-EXADqYRq_bC<$$OE z@jxYB{T=qNNQN6_7gA|`>Z;2`$6j%`BfTQM5r(R1X9P(*vc*`s&BOZfRACFNT*~Hi zu)=*ZZamXEYvGx;-ERa{4p!m;^&5#dO6g0!C?D6eS82vRdw|#)xrhha<~4U zO}>HD6XNVTSZ*pmpU1aXL4O^x$FsQ>$;&j%C!02<-F343ORT$s=O(BJ?lxz$Smt<1 z4V5K>&m-lXs=*w5xH1!~&*>=;bR|x|3JZQB#@DdeTX3I4KNV=Xo|Nb7`v}cqG_`^k z>d@+dX#Ei0-(`p2cww#@dk`dVg0|<`yC2^Vr}5Kp*ps)W80%k4h9b%9?r4nxCdht| zv*cuV&cw2-c`VDl*QzjD>*HlLYZ1C!q_=`RA1zmxclMI$X*I(_44WMr&x4F}ApL+D zldmz~B2l)-r$4df^)%c7mFwh*Ls%|mhVvT3RKxUjlQ-n8k!srOGfX}&nWpl-L7%r{ zuAym97T7OOW+TI`s*t|oAT`6cQ*^zNUZBcbPxBh0qOzH_nDy=|1AZa`+Cy{}S?^cD zY%?=BRz1W1Rt21>`TWwa-!&S0UHq}i^w){}gi7Yil#z_bt4*Pjot_r`O zA#p=}50$x|P3DOBv9i;e^d9z0Sa~>4cX#hH5`7O7^YGtJ*X9wK%SGM}zc1EvtSOnI zYTcNbRhWkJ^OGni_RNjBvZ-TM;K^}3`@Smjddw56PxiR~B9W3WlT)UWZH_iJ!}DW! z|8ltB!;W1<<_f+$1#646cN*$Tk?DKbh$n6Du+Jh4kVlIjsq2>U+GBnj3Qw2G*>B*H z_9S^yl)Ql7%Bqj=6+K&hex-P7=iB~bZvphxAnnEYvlsnt5;Jw6^I;k2ZPGM_*1@zb z;hRBXyARen34P_nayzq-ciI0h|^6a)%G)%xvx5@s?;Ozy~ zZLC}=1wYeyZ!6o!6Tvci9))K&`SuV$?bpgU_1EiW?f;in!JlPS@mG?uk5+%cc{zAv z6PC;E_woEa91h>eFzIL!+7SAW(&MM(U3M;FOm-_Nr)hTvzy66UkLhcZ?EO|UB$F}j za>XFeAhP43gZw?8W>3)a7dd-~XxT;nVi;gM)NeAE(8-@4lG$*+CA~WNnI$8_7m%zx zf2@JS`;&<<*#|ei0xR3ov0`HaTb5Qy?qRPZMqnc_)f34SF%?h7YGcM)IAjClX33yK zSgRBEcti!)6aHg_Fis87NuT+{})3MW=`WeEy4dLl~ zEnEj@2|V2C?@re03!j&eyaYeS+{ZkAKLFP;^Y$OrT_achN`^O$zNeUzJVymEUaVct zm+=hmA+hwWDB3Lp&&SWd`>l;Ob7baOi(>Z@>ZRqd@U9VXf0}+u%G0uRIV^b=KU8D8 z>ewv{E5zu&w0fZ(T;0g4FDH+(UrYD(!E+O#KO1S^7d3yeVI|c>Q=V?%?qIFvCGJY+!?sL%p49xsj z{(qmOqPM4Qtk(ABb$*LaLiM3ST|3Rp3}!sRqsb;>6fL?vi?N?AE7=K3ndn2q~Gt+t*fTV;`B>21jtnokxn z7wBcJHWK#gA@j8I?OOJ~AEv6P*1OB-yVDmiM-eEj^^Orq$|DcSculNC7%WR(B2)aKo_QMX zKcs7n-B)S10HpmQALORZB^a`Y$k~!U4Cg~IW=a}id{4~-x4+rx5ePZ3mroJF)#4kmJn+UwYPG^@U#wtq>a z-hwellDeom{l5^FS9}eTtqbCd&&@Jk3-JYU^g}$-l>RaAHX6F0=bfkkCa~j59{)zH zWQVKlMjmCvRa<|0Xmz^Y+r#Y#xNkY$+bi!?quW7|{2}kgI*S{y`EtD!hnBHer6vx` zf~Xr<=x-Rh4xd*e`Ryg!pS3FOO+z_i}t`-SLvDs04nHy8(NUl*M9S|w6 z(eY_M{nE8hV54cG>|w13(dwyNTyf3V#NS>P=!vcc%_b|Ztm?D7eH8jxqOJTV`m4`%uMwK*4m#Js?x znP+Xq{d6Tn7E(vf(c;IvlN+8t)>Ay6nXT1MDzm9{ZVHpDu~z}L`b!yE&#>#`eBGZf zdeGn$FFYWVHdnj82v2(<@opA7NXLHa%c87*w|E?+l`r69b|!B&mJdq7K~!)*lkOHw zUe*1T{lC99=J49h*1!%nyE%Z*mzafW1-BjG_)D|FKdC&r!P^A9mMytF?TvYV!kHhi zYd*Eo_o||TbXcdxD#5Eu@KtekxSNf3!(~3B!dG~yBP=Y0x4J5+cxF_Bwa$TzG9)bp zKecGN-W^Sor{t?iupaBdOS8uu7&u0kSK+QqW-R;z{I-=}?uO2`EZIyo*Fo&of{eNF z7f;U%K~#(#s_HkY#pc@j%gC-3`wpSghvI6Qd@)chccUyHa!=;VY3i?!MbdKdb^;Rj zs=~&L!YMpohQ%styQ*FzH&%tXjks-{ob`~5w%9oEYSm^ABez~~w1rmr;U`Np7o*ev zST2~pDr>cp^}Z1gwdwSdb_yD!uTlH%!Fex<-FI=%Of2+_Joqum*Q%mpRnD387kpBY zrRRB?c2d@0{9~+=Uu+Cvxe~D7OaxD1jmW4YA-NE~Yc4m= zfuNmOX^YRY>3fv={SvY-%5Y(ET7ApHF^a4SSEX>>$3~S`>1CdJqktS9&z9!ms-<{- zftEIDYZN?ng}gm7=qYREY9%k~=UV>#m*(&2d5enf92u}0)Wr&;fks$eRA3jeXj|W0 z0`vXkkl2ARUtWA&wG@02D}VDRPxvODmj1}^(=p{knCMQq;ecB9uqSBGvT_mLZbQS< zbdIOcU9i%AvAc+!j-=nXVyu6!#Tl_SvY2nb(Lx8;4TFZ)czB~3(yhEbS6}avYbiY6 z#h!IC2=6DykCm-TvchuF@{IbRx=5ab6^6j)I==3z*7-(mx?B&h;N*zTTw7nW2< z#+snbEVo{q%_sRWKgF7{zdiXGib}n2p<&X&AR4L^RjC^vwcJk7iTJ!g2oQN zxH`PFT5q}hI|HL;;m`}^r_01gU$WGpV~V%WRi(6oikMefB|c(~ezCaAl9PX6!+GW! zW2A8d2D)6#b@2aubgqk;@~N<_YK5MKqTw*)#a@kj)p2#KsruYgjB|~T3-EAVu~g2O zxVqIjH(|b5dAgOgO7Zz6tXvsyCn9YR7CSPVv|_Em!D)+MBm%kr<0be^6&3j%}Mr{#qTN(EAiehJ{?E4iYkch z?(0B~O7xEvR}El3Rvhfd1hG!JxZiuy@MgH1;QJf3-$<_|@Z&|QhR1!knwAU5`71OW zcSmkK^$*EciK#Vev{;FdjSoIkc~-}>b+JTq_Ae^0cZRAzJe%xm+_uVGVKd%%L`0|T zHr>C?uzdybkX`R1u~h7^I;qOOP<0vnQHr%<{v)jS3cjy^EvB$dN1Sj7TbC1)C9%U$ zR;%aJswC(OL9uE+54@H3r#xBK!Nd$%aG^dnXEJ*Ue!s(W|HIn6B`v3y3Tznr2i}wm zN*R&9Vgz&^*`C5`w~O1NEb}WbPo~kgVj{O(`xp*Bj^EC8#};k1AkThyTE%8-#8vFy zIHc|7tlWa#x8mr+n4~e8B03(C+xD_yYg{--O<7l;N1%LzK1!<|9>8R~jb`FWP%gM{ zD;g%ydlc-i*V_P@X9S&^vHMeSSy4UrF|1x7y4J#R7xw*^w;xoIl)_U*c-8{%*t0pQYH<%e|h#NkzMy`_ndYg&v#tQeEg=}KfKgRc4FvLcf z>L_koY9SHJd(?niWTPG8pcHPOD(}ZLiWi}vrtcT6sd$KH>TbS%mfM`hdwGS*J^jT&X2@y<0W zgr@5IOUZUz^iG5SG<}l&j_}5d_^>rOu4Ltyqo{+)zB8iuimvlzx3%)kT&(>HR{V&T z`FU%vDzB2b-k`Tla{5?(KO^F*WY)RF3Y4kti4{V1Ns%AJ9TL;aFv%a}Tm~s0@!CH; zQ=L~^L07DZiP^$$q3=OYzR4Qo`nsZ|Uyx{5jZ;(WQsZ--Rc-AS=szk!oV@iSU1`Y}ABxAEfbV*|4Y6p zo`zAF@u1Q70QK;0>ugpS^}d(<4jsL;kz(}XJbjvFI$)<5zuXSrJ^e{lF_-b&A{@7q zecr>N@2dF!k+-(sqOV2GN!TCBzg>(swrk;U_}rs%J4bZI&WXCJrb)hu-40o1MrNwH z4;pbD6JgsuJDbPCr(ix-V02}P;MMKEufm&$wLe2l{*5V?+lDRGB_ut>Q8owldDxtkSqvWIQJ(jze-2?AF2DWIG6tU7xea(NUxy zqUjF)jurgZv2xwa807#S$u7oDXU1bUkvq#ZtFXcu)m!AZ>{{x_XM3Tg49sNLdLhpd zC#x{Z7(c8r;(J2$E>%A?G?(z0NY5j7^6B9=y%vCwPFl#}-cshG^7CiphWh#(kIi!% z=RI!TaHrN!nKif*qr8EGx6@`L+|`k>=CQyitlLlAorauZ5IO*d#YnX$ycELlo!uSJ zvzD^U47ht!CLiJV*v*_rq>L4Bv39Zmyj5bcnr12f=9}1?I9B_6R9!WBJk}vJBi%8% zadTR|42Sq_woU_}fec2}V-=wOZzsVkR4zIJvS-)S2 z`>tYx$LKYU|LWkt;JiKN$oi0{3+8FZ)-f-zkz83uBDM6BSM6{XY8Q$BW1fWHFJjME zW1cX!>df!A$~d)+saBeykFmiZ+_{fF)6{Nr@Jt@HRWV+TH4@b!^gO&&TdZHsYmIrg zkt*|QEjNMPeJpldyu`Ya_87HtChr_!(~>kSMULg-w}ISlf}xZNSE-}U*@P+8)_l{FL$GWdwqHCL6kXI%i0Y^h2 z;a5nTAv5mr^GdC!Vrw%A=ZVMIJKU8IPP(f+9LFB?AN;?S?D!BHKCh)G#qb$(MLRG> zZJB#M7N~)dhOl(>xRG4B;bc0DH)rpy`cnbGQJGA1#y+{0nB)k5tkM46{I(U+U*M(K z{hrNrH_Kkv`rA{~mD0mhTob!fi{ZYCMhm6n=MUBY(`AEG81b095;@{&EqtAPuJ!ZT zbAViwUF-jmsbeo?pUj%py!^QccIKK>d4wfu;m}R`PxN?}bv|U{66So)h=%{M|2lkF z66YL(y2tgI4}v;E*H~41tf|_?(y?dYh{|cTI-{&8ZKL;rFg2Wwj$o1X+8vFbKk@%9 zWR0;$aa_6tuf$5OrTQ$+i&-j~^Vx1R)*dFe^i_Q<zT_)E~dek}+FTK{VZqW8THg>ty(tgD>Wp{vfe_L54$PMddKD++9>JmBU-(@)JD2 z9rrB6##MRykUFk0%b&#s2SofKoP9(C!;7w#^gQ?$8pe3kN{ajiT;235$un&Tz0_f45-C*#G;o?_!PkEh@`v`88II z^~Me{u5O7_%8At1j6Wjwo+bTpUTDK=*+fe0Yptl~8g$s>^AqZbhgm$ZQ$~i}2z8=3koBhq!TMo{NP$@%tL1fflS0tFfDi zz@ut{DeCF^^ts&c@ho$y%var&TcJK?YW@=8rSbVRk<}NobV~ko{V=1I7J8q6rv_lg zIO||O?*2+`P=z0R>Mdq9VwKtk2%jMfRP~JWJDQ#+P78_SyLccgy-zHcpu<4etnI%1 z+FFQ>mg1qv!i9Nvm{my6;Gv}~)dLH~UXNPZ-$AyTJQQmTdziiZSk+Ym)2&d2zLPs}ha$Wlc`ba{RL%F>f$!xe0K5F#&Uf&1C%2#my88{=7W2NYz3oUzgYp1GLAJbxcfEeM0B zMA2TY^~A4v#p!jTJ5JzeEi3hqL$4C6MfeQz0B8>%I7C zyLkJ;JivS6GxnR$VUq&*B|8*V_iq7hyo|BqIpR9Gyj3y=LJs4Dw@5eD)ph09n0v3{ z)5V_Fv@pKOqw0MNiuYrVA+WGd>>u`NKHf;wx=Urim7;7GO+NDc;9aBerp6wj`2}z= zoLz$#i;0qoaI%_}Hu7Ohqo2?GT!+uUz=l8hvqWT{lp|j^1_@+;0c*M4d(8N{v7M@4 zs1DzPfgiO{h_@dn$s=$PJMgY$*$wh=4bgVL8gvb*f8f{Ov=b}aCz9?rQvIwd{1f8p zK<>k4K-=j*o)4E&d)>n#5p5?_#(7lrXT@?2xoCx))QxqjyC%yVXHWM8yTm+S4)PVo z<7Ig84QsgW3-9ia%n-L~~b8R=LEC|DST@Ox5u?wa!0yDRvk(q-&g% za~T`$l4Ii3je2;gj5&mLIJBgeTH@*V#ZWhv86pa+vBnABxLMyb)N=8xzZhH8lUsg; zm#*&Lf$=`Xl?BOkF$C6vkf?#<433KWn6KBR@KjXvcgC=#*r77p-hvBCt6Os7&m3gh zEr%8JZ#N#@LZ8^tSz4CQhKZ`e{jYQ@N4{COVzwEro9Va-yX|7XSuoKQ&a;WKlCJp& zvSQEABv$;1{_9*ZhbQ7>o0aTbl+Bi#UHz}oXC*tUzHr@q$QnSGsp`n#9W*a$gkvrL!BAu*r50bh@U z`FD&>&XB3OI_d#>wpPuRVb=$sE+=NMz(y@tsVR%zg-z;+n-GpbiYb0R`l}oIbjk9zbh_?moKV8OXgG-LWQaK!yij1N#U!CU5 zY1@!B|1_&rnq?NiVFCLsUY7kDsjQ~b?LO99>feEo*d2l%WA%$6<|JGFL(9T?>q*MO zY%z~cg)mS{==~NZCc1N|tG3$r6;C<}LD)5Ly-}rBQPfotx3NAvs;qdj+DxC**{=e; z=Yo;qWSgOmnCTg05BXye3%rRDHj1Hs_`WrE`I`628iB+)K(|Bo_3DZN;viV3sW@1G zb@%c4FXoazS z1nj@T+taW`K0f&u`<;f#>~iOuxcUJ+ID-D&)tJBY&F%2>4Q+eq|CH~CS-IOzKiy#b zgc@-)4`rj*08tTRfpbXtiAcHukM?DWyLc_;W@=)Qn1QJZ_4j$wS6#gq=OdlL`G3oJ z<$3cjb;-LBFjG9mtWcb76}ztT!+IYaAJ5hf;=+CW7L`ani2Xuk6_vscLNygoV4VM@{ z)Wam(AR(9PVzBj~<@MDXVs6RQ(81ilv-8_@jXI+lbdKb!l02WC1zWi;RfYWK-dMpo zfSp#bb48=rHF`U3o^}w~7n9{6KfIY{R}WXGTRa2K!P0ZYaXjCAk?vobA^INX-j^$O zLrqP+O{Z55>kHbrvIs`5&N}D0?<`9lQI)JA-D%MlCo=8BwmTteEgq;T8e&IaX*ivy zZae8IdyEV^xO*wP3|BXv#6~-{vzn!Gdp@d-w^Xbi=~& zbSii*)*@~Z&x`c8kA|^AZMrr}vcqFID+hm_FJfcQXtn9`Ia%)SZLrWE zFO`JmCs^`XJ-34Mek>DbxWt%mmVU1?Ct9B$eub-pxZ+p%ze%5^)aG4{hMHjG9=NWl zUdHprSl^Tvg?Y?|EHOLuGuw>CjV^F&7`)sE1y1Kt#rDIKG)(9~C#BcG{j*ne}n)5sbGTPV1Us$S0rFz_ew_xJOQU zfZw*jTo>BKc?+>V`g{J(rX27bh9|Qrx$c@HDYM$x-+bLI}ffRUwwBE=htz3 zHrHK&rBb4NJe`~4xrL;Tnk4GrWg>gOYJ8`fp$w^OKx3B-5B|im#nl2WGf})!93Fgvr*TznmdIkI3F4-2Uu&YZv+`Fw(Y~Do zBiN)fq-{$dBiTfJUrtT;4TR=q!}Iv9M1~K>z{W{E*2bVI*69YX&Dd-JO=B%X>~P2} zrb~;7s%*a@!%olOve>PDlxOCsPgn3`Gr3|EZ!BbwSr{;{@%$N)T$%1sMIClk%(}JW z<&X5aPfU+6qFDr=89;kQh1T68?*Ms7kKMPu3UAjLr7!poQo>0T)v+Wi6jC6!|A$CT3mQ!O|WTQUP_u zzoPfBEb^)R@Fk=~6u)bxY&2eIK$17{_-21TWtn!c)EQql5M2+d&zI2ac^U5!>x`bx zJdv8sE}O;uD;TsKubooS#9rblo(i87GvmeHBz*oVzSu?A6Rw}Y?{U)1a#?S)ILRY= zo3T-NYnytyn|S&I{*K7iF?zl(Q*TF|_l0%W#jstRcY40D$0zg&ncKRe0N$z2qOoGE zBh2^FUMI}?h1OfM>gVpSDbns?#U8$?ueXb=N-WE#dGr&q7Bq9;UM1ZPFZRVFvHqly z-YQv9@G8G=6eF!wyw%|61Z&3GN4v=RugL#KopM(GJ&9>z4rM4ED~N*0a2YE#hFhoF zNzMO}Phw`P7fanGa_(jMs%8f!zomcrz7!aYEhIMkTZTl!w)h^Hod#t`$ptwS1JkM~(Pft6YYdd%nq4ZH-2+ z5|tILq1a)z?-Q)H&>H5p(D5f-hs#1Slh}?nk-_7<+akV=^Fa&p$3rx#;FDPKF@xV@ zKhsg3{+>*6>S>&Rca*+=>f>V9pUhODm7yngzpQnt#YenRTcs8AVTl+%?)UN-aKC5U z1#sgEx)t>AGM~qZmBrYjfZQ?%24ZY*hwNQK{g_SM)Mv2^R17`!^ew!c;Eiit)7;Os z*fdU|J)g8gwN`X#z|TmdFVM&7PHK8hGCrA5vv)`l0R1F#2FjC z_4=!7W+88_g}BOm@R9FJv2WwQf>%sGax-q3OysX;}pV0uri*6x#2JN1IFo-t8i~+dA+4J zWBx5posF|u^3rq(&102wJ~cxQ(#5Fv5`E2c&)3!mo>U{JEc=6sGS0$^wc#<+iL>!? z&^~5w7O{D(nTzMMXMMWaCowmd1zi=)xqYeni?yd`e7;cskq=Aa)9RwTti1G{w%!%1 z^UMa`M*BEHJ1T~#HO}Gdc)E2L1Qddqx_&R_-Xpx&NAq*K_UB?OMvPwXAsqYjQU)oPlNh&ic~D(?3D5Id@?>HQ_uMC{~> zS+9j6b}5TSo~ml5ZM~in+Uz8CC%+pq zyj2tKXUZB)pmnhsxM`xZzZfax^RwEFYBSD9+~vvqE$&-Hs=1=zCKfuXYK?PxD`MxD zF+gvYiqmpy;kOSn&%Do-1>^MFT`Jt{yjqrB8p&s|o9T6&8T+)yn>jixMwXBPLg@-IP=IC&eOnFR?%=gj?A9uSg0;RaNuHlXM^R{weaAn^R9C~*cC!*2 z`MNIt{#cC7^XIrK4XoRM_C47VR9r_#9^ zJ{pR-gB$b7ys-uWw-6K!LYS-EBU&4FK$*`8?51Z-ff`^Z?$N_oy zQ<*rP`^DHHPOjhP_oLWl1mwKJ-n;2i5l6;(%WJh_t)I2cyWRV~j8+70#w7W&ea%|0 zTV>xXvseE(Z;mqB`UEmov+XwdsxbS+S-CM|5?<_~hU?D`3o{+KG$N(a?|x1XTirg2W{l=IBz;ehvUfGOfPGAV{V3*J~5> zCnn}#k#V$*li*@@au{x_<(c;55T0FM*F#tbtTEQS;bshfn|Lbgsm(3CSWFCl$P#fL z+ySjDV2`(ri-tqfM2O2p-ch0|cJ-dXGY5Gmo@{-`nzQv%l5Ky0*#kUZ1ZQ0gb!Azn z9Y5_5zp?TxR@+{V-FJBwewzJCn%#X?*0_$(;#AvG`1WNj4>zjKB16pyp`Qp_!e6CC+#raJ`JQWy-v;_~om|ilKgF~4Yv{Bq!$L6^ z8qdkfm=)_LzF)x|Kl|irEv_T^yE64V>^)5l7EdLoiKhRFz-rpdMTb~_5~n1+2#2#s z8tk>&HM3#!7&{GS(>V1zo@X6b122K=bu1t2!Yb%B&dvS?Z?E9@cQX6~fjIjlI`Ou&419i_!_S*(UwYOm*W zp?12@UW44VnYochT01HN&V!#;T6viNVx%0W7{?Q=*a4Kv0I9oLv)nuMid`=84v5%E zzhAbjf^CQ6ovvbIrf=)%i)~U~BnLOes#_O?jVv?xo&CV~f+-kFmqj<8v*o{-28o}#JApXSPh-vO5}(I&&C=Eh-lm1wEcvXy z?o#V4%vk?ITIHu#74n_I3+G|Z8AeT4uv#%p@d+;I23d1?Zx;V=5CySj{v2}t$EY=S z*F26loA@j>`kJfHmYAR*>&Fwh0p?GiWtA2N^kAw68}gtPnDtbdc9fc3(3*rAuhkW^N!A8P{RnPFb}IR}K5lSkKy@K^)T()T^I+6Df96l-N<>}N2` zQkqU8MX*GyRmd&!H$rj;=!sM2+QpYS!(EgLrqmIi}|CqX#cOZF>(6Y@{I55*^PQ9o`|y-uZREEs-K&U&NgZBc5#>+a+<(y zHvU}hPt4eU!jn1Ww&9s)tws3d1v1ygF0YtNz1WO(`wTDd(`xX@cwE&@%(U?|qc@%F z$wA$*K~bL_BwY?Vw{%Yhcw5Js`yn+>>OU#kU*WB7B5FQgRWNH9W2UVl@hnMmtJ~rn zZ0ix>p&tLmYJ+Ro?r-`85|d*j|Q-`0|QKggNsMxeEC%J}i{UTZ>d3?f5U=JM(RS*FO9%W>%s<`HMRZW#ou^ZRsC6^5kZ#^S%>(hZn1%Tww&kv;ZP@1sNP zvudx;8;rtY^e|9+oB8$vUcSnow(7bKu3H6}BWVy%(qr9zU9II3=kr-}nm7ple#dyb zA=%?p%33Vi&Q-CN?@L~6&3iFZm!19hh|#ekIQBRk*Y+%2hX-Zted2YpzfB;1Fh<`> zgU7YKK{N&H|Es5CEEAQ4Gr7d-Q599JT!TEdm$WdWTAX;wkyLkXIc1=ky#1v!NFwYYrAZ z0Oe0*IPj>mRtBlbR;c>cvF2g8YCpn*H-##vr-VBik9V)Ob2wRdu}W_v zpt9YU;{8+I?a_@{$e10Eb@KzwZnf7_oUFe@p3YDD ziZI$*jwuFvu{&`QyvGW?SR)>9_ZUoyILWgYx$|O^pW!z?2#1 z;o@!3`yTt9**fGWiEBPkg6cXpb#A*7ajgBVsQk=506MpZ( z^6|c>33`e1X@2$8GUh!>m^=Sm3wL>TT~$oP>`W;dO>%dvUmj+5Hl8=f{-rqCz+N)- zUd&pqfueX8cp8S{Ic0bFEC+F&jeTSF@-23FbtGR;7QBPMW9NJ)(bE+!yQ;*pi@Cup z-^446zS%EUz9g zQhS2b^|cYF5)a8d&mLhUGM;_sLdF4d-zu)+4GC+^Zr#Hc7xU2oNR8cEz05t4*udGO?BO!+>&`v#th#UQSufpiZG?TwrJ&Ik^PH^Y|R4W z<)VXX$~g1+Cf~*moLXd#YP^d3=kjVL=sv2xStg#hnGsp7?N~`r7Gu;hPVCCkZFnj6 z4E0x!9EYmh{J+7t<33)DeZ4pE|L1D9)=*s%8lQLSS0R4}ijk8t$0b@%)lO>8AMitrCv!scdR&%Wc06O2 zCsqo^NqDo_Y!}IzL)AW>KFrHkXAm1}ZVE!nem0-Vr^Q(+YQv}KT}URlL+**)QG3Lv zb<*znzf*vo_cSY>$HZQpeQcJ6d*bBfm11+Ao$~qFy^8*4;fZ)B;A$w1iunxGO?34Z zF|`7Z4)SwzT=o{dV%#0`;(xNj0%!=CUQzjuljUCU_ZBR<2s-lfV?D8QCxq5D#(4y9 zHWrVumS7PX;#}CR#zJnq&2Srir0c;1WeO&*(cB-nCKPE}c$uHp9Sl?BgM`Gu4 zQ!#tLGp~Ph^^2;=dT?@wF+rRdS3&NHcMb5Es=k>>!)Ln-TXNN=f=Ar;{1meIPe@fuOu$}4Zp-W$v;3;4jA5q z3BRLNd8`^w06t~Y<0|1ZerqV|@<35(nIm?*#vb0-)$t4t7=wr273)=@Kjy%e;LxQq z&(`z{XLK}xxc=~e7#|FDMIN6#sv0US%3=hb3(B_h+P5^_Lz^#g!K1vC3x57f$5NR1 z9vu0UxbDchvClG(`HiCxd9HZ6LY-J%ZjHBtoxp&7jB@KnltM~bNO}t^7cx&8=WKQN zdv~q267jJYXN+9j&HXLNFwQQRYanyC+%#D1JP1GK(sOt!&ijvZMRw8bM8=!Dc=58# znW;lzrjDy%H?8_TnMFl^X6+eO1y(-=~ zi}6NLkqrXAE=P~cKjP}2OUg@ zv+f`6PcgYYn|dWyOT>9d;nhYg){Tc3Xnie7=ga)@hR9g?)KG-~iV@$D!>(h^82OjZ zWZ!SxIe=fPsG?$@WiH--ROEDVeGRyZx-s_S{@=Msu`V@E3oULp+Mm!cL;SD9ZSfo_ zPUNki#}0n$r^1M*@XOdDR`jiA)ep?g%;c?O^ogqF6LDJ#@7^djV=l1=|8~dJ75qQW z0F3#m4xatrN2}N2aXW9tNHA7-l@|Fm`QtsG?A7K7^-5)ovOe>kfhR@hZ({#p-=C#L zoRJ*w*7?loJ^$dPGOmo%Bvy%*IL|uXR#RW46=S_8%o@d$qRG4!XBkg+N4$k`sJym@ zhhnwKHW-alc{aeoHxLqUh5K7f9+NQ#^JUB_#Qx@%Vr!n=A!B6Dw)_=mB*gRNc&owz zBfjO3o?X=w=aWSRT0@jC=Jzewbu_Mdz|+M_aP$C4$M9;LP@%5>jj%}41|(7jjjZVlB;?5nJ$qNzgn!5AXm9vUZ#=Q4g8 z2L>7P0(0Dz{QTIZsV7hKBud)TsYj1}Sy zT(NuXQ$5B^V<%pIn|D_7Pd8(x>*S!{(nd}^*d|`$U1PCt;A@N(Z}Xe&&UnY&T$YVI zyGVR@!&vLFe!Nk3g*v34(R{4XTB=@*l?^GMY^Ga0?Wicn3@2N4QFDoGlncJw$s%#~ z*A*-oqp71TG0pW;U?42jm{u3@QS3^Kv-&5H{|?+*;s5o;2ber&He&7UKrtG7kIsSX zEqcE#BTXHiJYu{Sb2{zB;=givRU?au(69k+quz+O@OFfXIDMmvY}&|!g@0n_W1J`#D_Ew8p)Im#yy52< zj)|GHld6@-;e}Z1D;8dW-43|xgt7U}a%V9f?r5eo-saGhzvFDEcye?u`|pL3*jHSX zPo9R?jv34!ZiFRMkXv6gyK_lRb76j)#TpWQ(^- zbQg6ohgeUmJ^1U0R$_%->_E@Yga6=wgBY`lm|bM`b&M#Q@Me+ZR+f2`_dbQ}a{RT1 zCOx&2*E~$DLfC2C5+mQ(jS);5yMuDbRI?%MTuALE2Ahhlwd@_wZ}!n+9gTuND#CUk z;TZdDQu)Sy>e#6qZy{N)-+dYXzYBw3@M*jqB;NEJZzlZ_FEkPP)nMo%aWGUaD1nc1 z$bWZ>#2qBd!+Xc&`fBoCoZEaMspGxIl{2yV3?`k=g5S%t^|0%+kb8oL#YkG-&#(A2 z*6~&2)w-&c0e%Wjn~v*##CCDEYn*)?JE#|m#nzBHU2Mi%FPdVLee8dVUh&SyrBJaU z`Fy2MnROX2{K*SUDII;gr zwa)t@;UBI3#qT+Jr~!M&Y}Qfpy|)_e^^_M|%TamEny(WN6;vcuc_DVVY=Mt>^HWKZ&xD59yAx0POKBla<1ej# zjTJw!n*1b7eMaNo;OuE=8!To=V5Q&SuO$?$)l$s<&JeLx>}eYU$(`kfE&Ol=HjlUE z#yj!Wvubs=$m^cItWbmYzpM7XhsaJMI?kw!H!A<>%9*VDhBp7gKk@FD8%6rRqA92O z?5Tbl!k@9P>MmYxFG}9$xypJP!?!hg^;*?pXQQY`Nn4){W0txAwrSzir+%_SyaPJc z;{O7-U19zezU(a<95JgD>$0zvpT02v-9SEiO>R2?Z?WI=9PAi77yCi|`D%@*5-Pyw zd9p~n$7UPLt|ngv+Eo^<@&1XFKi5D_%%R0jgKe3y%px_+Eb`XOBxd(N^?i(U;-uX;m-lV$RyEqZ2o}4G$k^>4Z;p=>$@-Gv zW3oOVPsAR!=Vjxg_8i_UqQ~gvQqtc6nOoJA$6+JhQ`lIYaS3b}_uIFs$(7cmeq*+v zjlJ4EwLet^#;J7wck17J?kvtvKhq`F+k8ywZFK$_MrV+Di0ql&8L`8B9`EOV3{Q`h zacUd+#1p6HFpwQ`i)lMfD~V^5u?M-nIwPMbJY`JX0W#~;HK$m;5>vfMrg+bDeW)CO zk>do6jZnDK*x>@1YL5K7nVf$b3l)@e#(={%A{DvY(bELK=OLhn9Wi>H^d#^Q)m+Xh;(ThS*^ zsrjQmdr6j!-Q{0GW=o#FP&~)p=$P+|b-{5;YZYF3ShW)Sc>6)?91LDkR)}3hoA~Gt zOqWaLHHKv(YffOf8S2V-i*bL?9JbRc#+mVkuXx_LN`LKmVi|6TaZ6b}*A{R8wF0B1 z`msEOzG@DBh5VT%TG#pWr))7y8W6 z%;QHqUlISG4~?;>W2tDklz&EJhruj-QXkJ?#sA^5_WJ$><5ttcP`!^gX8oF$m7Qrk zPoF(_v9dbjGalUQ&1Zk;KL>Vs8*XE-+fM#mj{mpNsWc705tGlmXFd$w!1^z-&Up~A zf!_DY>{pZd3VH2ExEn0$mg%#)dT}G1eyXPjVYDh{dl{d9fp03%d8Sd*FElOa=crO@ z@c$-P1qa5yqj>ILR|Lfx)BRSCUoURrY_KvIJl>wLR%|`O*6~)?3vtN=nJ*iJZ-trS zWQdg;RYg_onyN0w));%`6Vv@=p*Umx2>VYa!TS&yCwa%-;#gNT$e*P?X{_HE@9kuV z9M(ikgpuhyH(x6|c>Zeq)|hXjgGT+$ zzGT^7-CZk-@kN|$wVj1yj&dDsuH=J=v@&oTZ^VdmB_oy&K<6nI->o8OE8-^N&3LQF z7LgOrr(!)(oO|BKsOA)js>u(p@zPN7_?NnMFE6bS)$z9GAKa6ht>&=iO#B_YY5ogC z3*_f#)GB$+n*0UdRXjtUf^Y1)lSkvtMNwrvNs9?EGb6DUI%2ZE*bC3L#zh-&#wN8w%&m9! z`Gvk+&Wb;=Kmie37ut5S%@)k~AMI5zM=%_6BIe@Ef;i_b-X|05-KQE?4l#>R$(+mr z_?>C~EzU&w(v#`k@?$(RJ(a$zh55X5G5eN=$9G^T<_7N6({Q=|VqRGXDc#j0LsiW2 z&cIkxUqxn#b3|&XuV3TynAbRsR|>=89KM_H_gIA=Z!|xtn!FgEVi!##UU>)ycHzGQ zSSTkO#{6|P7LHw0M{!woK8g32Z4@mZz|l4ydQe2hzNDK}W)I3qC&?Tqu*SQttGT{A zRF9_L8oK4g3&Tiy5?{m{@Mg zTWbFc+2RK~-QrA+FJ-zGa^|B>yN}bluE{)2{FgqrsaxW$9gFZyKVBQHm;Z;QvjDH^ zc-r_m=UUuIfZ*<4ptw85y-14{inNqsEyW7O3l#U_P#g*rEmqv!oj^RqlY8&k^Zh3O z@8M|)$;~;tGw-}JyE{8m0A7$iusZDQ$jwbT*B5(`n=tR#t+Ii@AhiAvM)d=0pZMf| z)V2K@{7EK<+5?mIVrHX}(+IG96a==$g4gqDSy%UfQ=>q}IlfvKF+Ane_kNHC5)$sR;Oe}mj?WqC3 z*sO?UuEc^RW)PV@#mZ`cfjw}?RaPjHH*^6$2|}y?VT++ym~^I)-Aw6Aod*vh_fj4+ zig%1ra$zn09nb9C_$D2BOFs_jg>@S%kj~|QVVmKM`#L|DljNiLnTnwJ63qAtodgk2 zl?DYqFzR3MiNva3GovQ#wCZq82I$Bl7JAK^S9;oIfUG1|9der_g-BTA_oN@M+Rq^1iCCBWDNiPojw>$Wbc7J|ZqCi1wtGW-Oj|I+1P|*x3NK^1~6S z;H^7IG+4)XMEASl-NA6MbSCcri^=!PV9$%tOdGP#TJQ$x@46MPm!2NU=)NUr=uFHg z5^fG6rOuhuJCk~}Jwf|%keC4{9^s^aHB2H^17x>CPDAAkvKIcr%`>Inxt!SwhxY?x zh0#zObVrYCkT!|EyU(#jKWtR8G>c&oWAT9j{5*HgNyX>bxSZ*gV8!1Z`%lLTX7D}f zGtmbYE)5b^^OW1Xs~lQci4@X_@#Bg6-ebv97b-Wa{o|naSdP4;8iCw*$^=hR|Me-K zo(*sPO*GjRPbc}AZWvXn{YWOkGc0ZbzkQXJ!CvP0k+^#{5@M}FoaBS8Ou@5-g4>@# zvh;zNfgdfyoGS6RtS-MqW0D0m9*njF_j}N~AHMVm$dr2ZH;B=8fGnxY^uG#iP)`!`q5vNF}_x7yPo4_J|NVOQay^Afs$D>?>^9vx0&tZjnu#nu; zsmGr&+9h!QD;!Z1|0Oq-3KErlfYasFJ{i5G;`i_2sido_+zao(GwKq34~NAsVJ)G^ z@iH@P0vbADMa76J+Y%i~R!SHsk$w=R(8NTdkr?{n!)T?i(gyDZN0lh|KrimR*)xkC8b7$bd0V9UZmH&u(s48k&1OY;m-iHBDa<+ zz@k#aaa>M(^nvKr!~64MtKrDZjcu33D|8^Id;$?lexkw`FhdLUA$bC8&`v1PrF2i0 zyv@dZIvcM$6`z&B%4`)rygScchF5TtAR!qxxRyAk1+o3 zXgUq4N;O2Ok12JFqwurU;Y7(#=!n!8g2E^yDZN0J;VTz%u5t(_`3Pey<}2w4*_G&g zK2Hn>S6j%vI1P{7!sEY0PbSPM5zi!kb3K|l4~mkIp>$9!!usPKUa%HX;dX3XZX-U% zV->>-U&N2rf(!0ryETbQBqn~#yJ|4gzA%NHCrB@YNTR;h)Fjx;ck=ML^VTLLmrRsh zm03;WR3jC9NS$n7Jlns#Re=W$Jq%-)Kz1MH&hZtvvmTg~eyhRgMe=yu%sifVEX=X#g>A1w2Y+o|{4RaswIv%1_TTLdg`p0uM-4QpqwG ziAeomSrtfre_5=tB+qVx-}#R>SL7*fY@|K$N>lu8F7T0yPd3FepJPQ`ST#%jS!*y< z9G_Sk?tTYSv(fcdEGr(VEeGGe$oC#LAm?z2M2~V7)RO(s0X)ZKZ+I4RU5u3T5j7q` z-oEH>1@a2R4?JZy<Eq@QU8 zBqP1Z-hq#=$@Z&ZQ-z9dO%S=DuU!L)M9#GU0ElDTh%KY92xbZm_9z+GJ zTVNvro?e0VUBI6SUaw)lc2>Nz(bqKmz?ZO9B={@G%2z5cJ_GC0$uA0d^u*$#L63AF zxx)+tu%Yv?awC36Dj`e7Egu+BBHBN(8M(E%1Iezyz80W!xm9)#?O1qTx#cXk1T-u` zs({r*ISp}@`(Vvv)qD|?h$+VRCB&3{Xyj3!UslL zi_zSG9i(#4C7$*ts1e?jo4v_7-;sWpG0gG~t9CgVk{lQ5-c}9^tICWGbT*!UN5O@Y z7_(IVN&;awL4I+V=1GpNN;R`RjB6XumTmCmQxuPCV-$bD*Iub&&U^DM>IH>e8ySq5?{mKkLIB2AYZxg zSi{i#kHpPCW3lN(&70AD9<1jdp3@8q9L9GgX4(sm3!|4i;PEnuJd5X$?!My72Y|HS zu*unspbYq24XP>=+q6dN75G|il$K)`Z#Xg9OC(#0821VLu(DRLfyN#DISM$? zd)aqx&u=efWmt@VU&Ch=hfkjoTfHJCx(UyiSnG5AM@@9H2}_b{a3h)H1w87X#3oX2 za~h+TdZALOLG~=CGx|jIAS=Ei?4{k{r+bi(ux>SMG#+g#EKGq-sjV@VIc$K%D&UuL zp-nFcll=FpAiWO!(Vo3ssnRf)Gv+$XswH~-$g`!MxSLp|9JV6eO{5Rge&pB(yDi2i zi-6{KSVtu!5Q-+(^LC3}sOfxN54)D0SPhX|7d}xQ49bpxoGUE`UzNb8RCj&HQ&Z8b zhqc55^tz4N$gP!g*pT#rF3B$G9FVyK&In~kL;6O~#OFNKSLi6kcHxB zfnc*fez`KTeFZwC=Ym7)!`xe-5$T*U58e1-pHlxr?l6DHp9n_Xl(&4s8nRe-?BU+| z_wY_C?9`dh zqSZo3p%APs`IK^xPkNtKiWjm%J%jjUmcxgk)mbftUK(#aRsvhS@)3CiU@0d0@_oNL=UH zEs$6Y$ZN)^OA-G|R&+W1)I97g!CJ`P=Rer2)K(B_e*>1?$TvSxK@zsso9I6R29WH; z)4V+(=V^oa&Sh|%#)zbs_9>*d9L&@O4+VK=TRhiO5KxnU-vPhUMQ9BcCA%2OyhV0( zH(}$^@UK+Cc)9tZxW*sJ9sH9&Qg8hkHoKEm_4j-wed^|c7pXWXJF(IiDhZx{ z2|M@`k1gbL_ZYoY?~n?mTABUz$IR<1(B1|Ki8prebA^6l zIopst0Exo$U=b6M#Rn|CJM!wsS&po2zotgrFtq*|+LWD!2Jobuebhky(#`Sv9JZ^E z6@SiHnqY-;k4E}``f^w7cOt8);N&65D1|LY5hr!UKR!b?efgwR>bwYZlqXlPDiyJ(K(?>Hg7_=yWUieud@VBW9B-=8uRAAK(|?g0*BMA$KvQ z#_n@iaR*Yn&N%X7izQ)cnSU?F`2_2cz9Nr!&O62>bpoZX$6(kvgYln5gO!oR4gM8@ zT#~W5V7PEU{-YVFD@rUVH307O6saU8{p&^}u@PvX4f1_~S1k!&OZ7xI_9gcMq&mW{Frkpy!9`httz;#ijLpG5Rywh5SjlA?n)#5NF;Y0{N%?zPcv#c zk*@#(r4E#fpVxs$i?JX5o_(#&Jk^1Aq}E0iV*D=rY0tk)Fop|^urDKc268Kb-%qUf zr0T5Htdk6N>8U3*dq044$;in~G~y3`{RT#C@KYp~BrEn?#iJ(PtAzBGveB;k%?uQ(p9uie4o1BMysi!c(t;_lo#r z$^BeMB;v#q$o&whxg_4;4f2$V5r6Vj57NI1!@k6yT|xe%`L5KimbHT)(!9eM%i*JB zr+f!42gKl z_IUOqpis^}=7Y5c_zStQ_!;^;4Q{0dg>*}ln^wE=q_g2_!NGaFxa9Wy18xq&2B{#R zCXs>ccSyft*)dWMvz$vJe1|{y0B;)X7mn>Nmfn=#uUU(+fCLm zUvOgDj%P?F>M?W|3MW3}okfxR1D-DxetbdFVCEw^Gg5c;ll2WuAyrR&n9*u>;tH{* zaS*9U94|GZI)cb(*wTqr?ZUbW!nu-H-7II1X){`tK7-dmST+c#iB#W%SBaCQzfBP= zeF~pBLhL3Tw*SI@9w6(1#N$hmNDDl>>{Qo9k_*viCM>X;l}`zt`WH4C#CMPIwjg38 zz5_C)LufF+GnLuMP4-;O;thC7WRB8HuQ~HB2|vkwjOH-iXUx+?k1x?iGM@|u373c; zB;P#~9=XW(U0BU^B%cPOuY8b{Fp5-ko{8k8$C2DC|G>W8WF(Y{93+D?9Q}XGEEmGKKHwlXjPMNf z6l45>jB+P3l$^kK*lI&;@(mX0$4|zwL){h$r{SG%5wW}_HY$NuJ`k@g2mca<0y&8T8$@-K<;vzrZf_|2ihfr)0b>wxsx1; z9fgDCNyI6?5_!4sXN{S^+!9=Y_s-48b`xtYVw}>Mq%^!7563kpN3Ib3Jp{X#E{Cn~ ziBi?41Rm@eS`<$|ndd!1awow+9p1ebR>{rp7a>0Cn6p|shpP3auI7MU%8Ii>o=Kv+Dx7ZEHT=qo# zng72q*hqBQK|9DPrGb755vhL*^S0ur(->Pp(AbtJ%8qH)n4i*iHb0yqx`v88*5hIQvPU*&u@l3o(D-bZBh(}H`rA~>|o4kP3FM*y^-X}ZV(w8HXXWroF z(#Q58`Abq^wkYgY3)`1BXVnp zx2lJ{CZUf#V9A5-s-vHw@JJvQD;+2HqoZT^1gUXz5}nFj^i@Q<>9FPZFz6hxZ1Q^} zvFMlZiJWkyu$pWKZ-|GMei#y)fv=PZm@!xTiASMow9!;!_^5-WqJxMjO)0OFTq1ysyDKMxhO< zJ0thkq}xR(->-r-ZzD31EL*9iRh_rnVMeM=^Rq{Ay{yorqjO_MmWEsg^PG6_?hATP zGP62hO-{n(hQ0KDlzzBxKu2xf{}AR}#_f)}NNEKUXasu(fT2zNrsPEa$olmxT-O50 zZ{vio2fTF+2}?JG8SF#tNA7FDWNFstrHBnAKUQOPDxC>!SWO4~gj8Ucdt9kJ)t9$k z!Yg~QN~u;l2YF=@4Mj1tSTvT(ZMEKTjdZKikk~g^qud4D4)Rj*B~6f$RKb>&*-hq9 z73|4=Py_fS5!SiGe#j~GBAt6=cjGEEkj~+s;99BlDr^0wJo^hc?E$>x;-=yUkS6(h za`UJt&#TPyr6PTCkSn$6yv(98NIn97{#T<$GRvCq&O%7l4tvx=N55gKe&G5u_-O!N z%Z`32WKagJNR`IE#Ahvh{BSCDvb{GtzflA4Im!KTCoU*e&J z`4_PdT>w;c#)5PtD!s>R!bzq1cP%6)E5}H@|0|-4Ox~1`6H~~!lH|w8tQB`-6G@iax_CE+E>R_(+a4KOF?{vG+3 zWYl+MhGTf@Q{-jA!cUOUdu&SX_8rT4?~|M;M|#X(g-v9aMRIexVVhgP^OrpRN4Q$* z>#ae8`FLs%{#}cAZ$z%u81p{XHb?Q{Q?RnVykjR4{>1ntTVOk%S&!_BO>q$le-*hmj0jRi}6B&qZ(yHq}4O7b3L z*V@fl{S?-LW06}0Vt5n36v7CFUDN1mvJT#`!%EFTp!`HCu*jX{_Slihiu*a=&5brf z;GHr=?UFmZkhgCkHXKjfD3&2>a2r3b!Bft{a(#K`X*6(#_+n5FXFkQI|6Iw>Dgp}DA;Sdte>8tf)yV^}mGnl~$G*xLR&i1-z9IbA5T<{^u7m84SKw{c znU$Mog%d>#0lk9Ad^u67teB+&SYx6Re{#H}d$jP&&HPo!|=VxZE1uR_NQxSI?>jZob};pq%Iv=9Uxh1@m1hi z5Bcd?m^vSkUO%MV6PBkdEB9|$s4%`Gs^06 zCsKQdbmX@GdvGWFgYn2C8eDq7T_SP)OXefFhNT&08MHE-_uGg8@-WsUBpr$mdT9L& zU;d3$B-iF!xc5CzzJ$zwMe>`OV+0l9GOTr2rjyzEF@`^p=#MbuPJXK;cz(%Kn}TP_ zh?D3dk(r0`)0MEwX%Ko8neAhBE)nM$?EMe0;lVe^eK8lOm}}8(80W!<>3;YVlKGoc zj%Yk@SF9ok{YgFf6rT0~eMs$c*)x*ZUuuXdVzQ0+xa(M?FwzrnK9+U%LuS~SvB^$f zIj}5U%%v}f+&cdnRtv>WYGT2s$&19V#iii}3_RLO78#&gu?-EuEB6&?LRhqE)xWihLQ zd|1ymJbN0 z+d{BzNh~}eXHAfRmylR}2BQjuL(9Owe<8>3@B)&R91Z96%Q;7o8a00SzeD)&+~jEw zCw8eqWbhMne23l&!2oi@OYXYLjgw+9rmXg)8(SQ{wKnI~BazVO*oW-sl!9UB5*r8c znU>lqJXjed_n0y7J8Qf`ng_e`X!VjK)|jL%o$vln=JTh_YL-?To`S^%%NMgO^A z4(Vd$L~o~=)pmMlY($d5;H@7~fYb`e1$(_kTMfYdG(KI69HNuROYSjlMGw;Hb~}=g zx|4Eyqyrw^fEnZlWDUHp>;c`z$`X;+Wb!KOVlTenMQ-8U!?)Guw?5$M;)v*8Ggrwi z%S#L-6`rIYOdUBmPRVl%*rf zc$jN5JpUJS&dpd}urs;jSfHW^8wu*)4GA#is~6RfiY;gVl6)3m0MK8Q7%U z1x?|NGqLzfoXSa*PzMxz!5s54t5%@u0L;4$lx#)9(xo*8f3_2EaEpISWubZeOKJ(- zORdM2?aCsFk)@NO|`$?U6!cBQ_? zQ#eDaN!$SYHHfZdrSyTf$n6@r1tMK28eqSr!B7V8JjrugW06Z(2Y#@Y5#vj*)UO$X zhg})jV|zuMAQ^P6S$(u1Qf-5$kUXfs;fFro>Ti(TKpS;0+3 zJLR#>)!I>$bO z7f&bI2bG9iXEXod_?90yJst{|chN)jlbn{ngCVl4quLpCBh|Aeu(2kTDOBAsPRv%>5p=bO=iug$*18`D552KEbL%IHv>>cVaoxYq}f~`Ut}0 zjAB0>lBIiLG|!UGw-aH{Ua*8ev)%=c`(t~*V%=rI>}0x5c3{^iiTT!LKfr@*FJOm5 z+2v}E#HZuCL+IH%l6b!=tF(jQ=ptva+lU(8@b^*njAn!N*C4eEE0x(f@lO+GQ;ZSG zZQ6@y{{xH>2G2bQ8$V;Q4~Vv>GqYMec`ftLi_J=3(-CA0Z`5@CcXap!ttNx@y2Lb6 zm45?q7Wrx1ey_&o=V8-B*cXy@PX_w}-=aQbFs31k+W{?2-EL_l@D0W(CP0;rx-TvLL*WmaS_qB)U|!iSlYshtQ>yuBP-Rs#F8(G_pTygv9krNMGMnO?FACLhRt*WA-};2Cy}(&hLrs8 z5}wUe3uDq02SIhi$Ew>POa;2KGD>8AxyE%Xrh#>`E5W?}2PNaSdbM zl5G=#=a#!_qrqbgoZT0Wm-WC5z8cTdukqZQ#8l&8YKzEq0Ft~*EF?0i%Gjm$(GRe4 z4SarOWcR(53-o=?6i;+rBa;q$sHC``&ZJ#~m zncPg2o1@KOpKHWY6R`6aNMa@1d=^*Oy^2XVFweW;})N5QTYWDhRKe<8!1gj6ozLeWs7#S!4~-6unFJhlgk@ z6E^t3tPUfcci2Qc+#Z1hvzhI4-o64H%WbpLjA|f^?q%#}8RbZ{A^Y(+kk3Hyy%!y6 z$nFi8=#eubskCth9Y|03SIGNMo>vSTEr>qy;~(ursAq|De@Bjz`|}aDkrPRBMX~uT z>pbiBAjVRkvDje;$pERw{8q3Fc>_*+k0)CVuS=byF4*23{M}(<`9d(Rcq_LRPF%7b z%oIoGW03VGR$cu-+G{dHm+?92v(T3~;~ek01VR zOeQz2)>|bkrKFenL%grt)11Qh?}4-lcyH+eH%K5_&xa0sK8_@pN?A5Zkvhf&5L zfqK}ERQArxe7}aXWGAj1`mKqz^|s0rYcxVzFW|6l`0WDxq#8DI8n1L7e>RVZ@jc9b z2tCN@$ya3DB!JD=c!_yPd^6E-C8R3-5a{5oJtn@9irQu1oq4cZKDetYe6<*R`yTwY zK|gZKt{bP2d$6ENAXK_sRVK=pE*9~`gXf7Bv+=RAbL>xj$sa)2InJzGVMCEHzGOn( zgTI|rd)Ik#3{_2DF|sdM&qWZ8>acr#nCb&_8V5@yfbMVc$g@FB6gHicV~@6^Zrph| zY$E$dHyL#W&@>zG+Kt_lB`|UmY-kR=I-mKSw)Qi|7Q`~si6&Ffkeme^N4~!ihn#`S zv(fZ=cxM=xD2VkmfF*{)NRl@>fbXS%epwO9`Q``WR5@$w4z^z~LYYxvtV$}YwZtFn zAXKf#F=_DBi&X<>tQ~_?%qCDDj}A4Vi;wV8kU@>@P$-3$Udb z$S0fMPeyW1cwD;APem3|1$75@+!fA_;Zr^!pZm)Aye=R_>IgR=dq65+PeSU_i~I+E z?@dmY*Hw^hk#(O7e?1@0h%5HKM1Y+u9QQ?OJy>m1Lzk=x8@;SHYTbE1(|%xx&LF2uWU!1I!4t}$z=aVptD z&Cz33bT|XKk7KWUF*bA`)~Ln~Mi$<6Jy=-ETwY( z_pCeC@w9U2HWD5Y%M`AXKHSau-k;3rZ+_k%d`V^ZU0`%6zY~SUhUH}1vF0Ndms6By z#37Zi{7#HvBesnVW2u7MZP@fRZ02wFQ3rycfjnWp_(=3#7(ITCC2ZuBgA7t^E}DJ6 zouFVJmUI?eydYYg10Dj<*K=Zk=Je+ZjeYl(#A&YxuE^@O{n7J+ofJH%>aIX+=5Z|#Pr^RoI2M4pSVWw}$g z8;0)B=ig(cg|U(sM8*{t~f9z)Vkv8u&LF%|^L9ruFN1iwq1 z)0EM@X6^NkG5-i!8|B2&4XGMFkT-1tBky2U>7-YRwdhPD>*3&W9{)dqu6|{{t@$qy zB=~W5F&lYE4|^T_U8ZN-BWnT(k(w$Wd5+Z0PeNNYhzkC~S~^>`kYX9Fz4fp99B((4 z2(JV+SNy2cumKA_3dda|>b*eREc<`|VIi4}y%%$roYX!1qz$ojd3;)RY;!z5_6{1Y z&e-SD0qq!=G(e7a~zr*f*vE6c7 zb7o%|ls*C}C1Jo(L=Wr0>|X6QBKoChjsmxxpe?;?H2MYh>P4M-D5Il~hla3|gt~{v4*C1xrfy%M*TMJ8L!_ zOP)v+pC5bpUl;GT*fsTGiEoO7xRboOA2#<9jyp~ia*i>|UP}{XA@}_yXG?C+Oa00i z#w)kp=^8+!Ar;Ms@O_i-rGiIUlS)pI&wCXwvjnEh4|ZpvHQ8^L`+aZ#)EcY~*7q@|Z}7H#vF9b&%lBAtEM7>u zDdk358##|^3C04jF4>U^M(*q~z>)3gb0FDxjqyphSsO?nCF$)VHxQ~216)92#bH^w zc{Uua^a^8GT9b)Xq^JE*Ml^=FPU;9Y1E{JJv`0 zg<0d;z~5xvnTDUrhs8g}R-^Fd$GK}%o=0FKlGSH<0Wn z{>Xim8(2gZYa;0_A$@pak+M`AjDzV%fmW%s{5#&GK3p>jdAA1Fvvabz?t!N;cu=au zX~atNk#7Khe~m16!Yti*&Y$T0bG*evq`MT)R10}ZP4u78jYNXKqZjG;EH}gC?Gr#) zHgU&${7XwL#FzDEPrj0fejU>K7Sv|323$ZSTnE`omBN3)yL3S)jknzn3UeW|RIuj( zx0!ffS(Qn(w{0-#GOYd~*p*uP`+1MtPx>8s<%Y2?A=@|nz899th5b*&ZlqR&+-&`h zr=P}B-x857MxLo?K~8US6K%>`@-0uTMtt!#5|fTP*O0UHQZ0*QCJ}M2VJyc%vs5D& zM*afdJO`c(040&gTyie&!_cR|)Mm6KH}$VzZ%06))E#po<*vN-4&H7&^AkLEX8wN6 z`+s$NgW%=%*w!MRaT06#$S3{SW0s!3FW}r6p!f{2a|FN9gQtDLYA~EX4f*{xV6q7I zQxay0$99Xu=u&TOHt)+|JhEFIj6I~nF-chKE^I!9r~ZqDEJQ*}S-b5-vr>`q2Y5>Q zDZN34rQl*8#_2$n84kfN}cZmb2Q8kip|vnuekL?idngw)BG z{U;4i{0_^OJlzS5@B!xmQi)44htK8UA{UnZ6B2Al>|()rH;`U3@9TpVmBSOz-4C9iz_mZhA9aw(P(ZPA_tpQ%*96ytuT5=;p&QMeM z(-h>$ZSAx8Md2^$()}3UTm?xi0WbZK;u=0Tn0KEc#*lhM2eA~X8Iy+@3j=$wx;eyf zGViNM*n#!P``&}DP(Gi^Z%Mt){Kz+wchmz3O&IwFEHn~%XP|kVzn9<#R)C*}JntrR zI?GqD;Fz7DMk+i1z*_JNIBgIzkP6~Ipta7tMecSU#3Q<}(2aPY3~X>3Sj@+IR%)zP zgR2{0$(6u!c_cHBn5rld;zeT3a!An^8+?x>>JsP2Glzp#5vu~f-5v{nO+?uPX-#8h z(sRK^6fhZ&CY6xiBF}QnK!f|F`m5ZolWMC+!A9Q?ReZDp)zHQ3N zBZY`D4h;Je9efUA3xbzQj6o_FO1BoV5y^jy1xbbRIR}wxQFa>c;-@a5Q74f~Ipp(< ze@V{AAZ8~gEVq$Fm7Fs?xho)b_ZqUlO!R-8-^tIXWuNy4&I4X!WgU6@ zR-`FaXZvEcu^>b4T6cr5dNA6W?95B9R#A|<8%{Fu_R`T(_Ss}LF`WP3L_^Xoup9Du zk9IQIdyu;o)QvQQhcQ0I=RX5GQrSNg{Rbf%sp@hR=9B%y z2k12hx%VcrEQPfvV#A+dJ)?5slVSL#LdgCloE6O9;$;;wosGPvF{8=gOCo-$wJvAs z39KuYfTi+$N+Ja5IWN5nWhEoIt{Kq8qGVn z4~TqA;$6pM@zRIoJLH_idp`2MH~6nLu$aj@_e-ot)=wW{d>cEu-||$sQC}0UT%R{L zBB~h3IC?S$sim!m#_J-PFmN{+){`D!Qd7PNwk_RI2jrXyd+{g(h!3QCuYrXp5pDNp zj+gONeefA_E-Skyb3u;-4xPmqQ$e4^R-534qr|vd(Yr{l6PU5{|9vosbeHzS8va4M zqp-T6Jii9a-wGc2jp#)>CiErt{sBg-hvd40b2%@R9m{_h!y*u4poxX}nFqu)a+BZ} zq#?Ie#)F|k;O9E*GnCK&g`RrDS(jj*Ff=b!`6^&pyRerT{QedYR|Xt!L8|@1|3aic z0}S6{MRJ`i4F^Ayy2|^AnD6pCJMgvB__TB(kV;3@8Q(E*c8pbL2>6-F=;g**U2tf} z#+Tt&Gg+s~-H8LRNgymVkzLEH=x-O=m0Bxf8QU4`c?Zu4!JGPkHi^4d5VLp1a+l&C zdNJa5XuC1ejKxCB!wQ@Ed^j^(i5{dHx9ohkhbyIyYAs|Ywj(wifp)ink0R)L9Q@Y{ ziO6cP3^pefHTr@4y6kYxM+4npg9%9Y2P7)>4&@BsAzDpkq`Tnm3{ZF;{M_UFQb#rb ztJK)zI>XZ?Yx7(Dn4DYoMuWld%x%~z49|NMkKci_j3}bMevGXccT(kS^d*tQ7g(L# zhH+xE{fT7dZd+IM-<(XMqyF7-!M7KWKZx7V5IHyxX($Q-1j`A4){5oSM2 zboec3lWwT-aG2Z~yUff!g0kiO9gl3^sxacH?$&)(i4m^G1{<_OCI<}Ecs_F{k1BC4^eQ(a#;F3quan4 z#}w>gAm@=!$fc0e$W>G+n+O)A)^iiy+!!FMDH+K;L8Pf{)0gPFOppr_cPMSMXOO~$hWtN9G3 z+zBJw;pIhWy>AZdk^RCuB?6OMP4$Q(x-p(}U_FT^bzp~Nj8zRu&je3>h&`tA-b>)L z7&`h5PjDVIFToq9;LTfE@oGKtyNHkPjrV?xZLNYU{jmk<{}Rp#L=WziEn;8pFzdE_ z*g;X4AcRwzXhxo)3W2NZ{A(3iYE5|03$*$R@frQZRUh_`rocWP&crGqt-au51S4(_ zVkU!*U^G1&k0m!s45H5i{G>jolvDVs94xUHUCrWcFOYaWWUp8uyt4wakgl-)DUenj z&dUqldTNV_3YPPEUtKDPY(NK(v6|6%)Vau{FK8dYd3+|Gpf-3~%2zdEn;x7`{K+VM zLChph5v1S6OuWe%a7-05-J{plQ?#}EWv!Cl9No%!p{aVQ($-{EMXgh7l-=^EC)RD% z73A%PRYzId^vacYh z#6+-nA$6YX!CkHJ!@@!{(a#n5X1wL6T4)KnoF2A8V_#T}jQd8Qk-$27BMcC)r-J!? zYM1&^>#0}K%Bo;a#D3H=_0{@CtBvy0N*ig`0n@F{q1B$?JzbGuua$zGlXNnwto(X8 z{i8asuZ5%A8!>vcRmGHgf-}X=)IVx4wk7qWW~eXV2B)^tcyB#0w`u;y5xA~^)(BKn z318pMSy44I9d=nyv`^YM3J;(y(0^vsV_7fH)`w^z))&N~|01OW>XPMFhg2RbSvz75 z0cRKRrhCD^!IlYF;%okgB7G2k#ktA&W?T_GevWRiWN>;4HwV(9* zbih8Xs#(wU0*tqk)?W8#40ZKN*l$a%mHJNor=2y{Ykl>9h_!oZ=k)q|9D6`F)CXnL zj}n9Bx4i0>I%fTgja9S~%^0h_zE1O38)4{fR-*P$O9M%Ht?_z>{?6LQO6d#z1RlAg zc20fNj_UI@4QAcUUTHD>LN8<+pmMVp+7QfF)LU5}%p=+(y#$%FAGIVkU;D)vrdQ)_ zt@R^XcYQ40dLGRCkM6Nbs5X{e|AuJrGwZxcq?5`Bl}9}#s^gBmxn3>S`s-IzO|7-{ zlNzo|wXu2l`5o-hAJy(@3EID=uhzskhwaQKv#+fxYc$bss}pLu+JLQ`CweWR3V_x5 zocl~vBUG$Oo|JV`yQ_6pp;mKshf)2c-?F|jXJ~Ep`T8MZ!?1^+HB5ZZ9RtbxV2h@^RID{lb=C2VioVsH(`SPN$(ehr&C{3af9orVaYh&=^>+Fh z&I336zmj#zEN9v93cVD$PiAE+ORr}&Q}u{Ek6Kss z^LR!J9-hGY!Ak9CT49zcd;V;9Dh_=e+yQdgHvktTZgg8LzV_s zv(#N{vC05}7hv%a?XsdCq%OOhk=lIYgmy=Ht=#$stDt^Ee+3=`^+&{04Y84yO1Fv` z4fMVEJ@E_|tUJ0L#xG%YQeBm=)>ZeYL0Vbtd9kAUyM9_{H&UglacY?1i-#GCZy13$ zY^a@wky@)Q#Q%md(5R?ARlTtBtHhf}^~stK-Z>9!Ruf+?yC893w3nKWx6^X=Y$TTT zT2ZW!23dLZV)_fcm+_5OjjWDl-pRxMRg>aoeWy467aLe|1Dv!GQH`JGnJtO|NFeSp44uLTF6)7|=heX2fAPa{T{ zgQt?ZP#syJv?A)-qS~tNte2;gp;E^BQIVmpYAd;!)))SfI%1oNkycvax(_x}0NobX zk85SDi|RC9zCT$Mx2-s3ureQK?c>R-RYR2zKhd0+e60$E7q1Y%PA9gqS;dKDM(Z)0 zroL9Ad1E_$6Im1=iTUPIH{~qR^ZUwtfVEtHR-DbX)RTTY?((CA9MqcARQGp^xDWLo7 zHhmjeu^s5#CN}_sS*6fZ&Z?;TsBLPu8i2iRQ+}$qs;f$??^QYCM9DCqqK>`*8NJs| z=uh?Y`cHZ<{f>4{+o|U<{?xZ&RZTgAx`FhmO-{yLKD=L3)k;-R2h2cojoD2-GMAa( zn!C({W=Xz#QY}=inbR@#6Zxdg*}0iT9C(@dQR=Myu9eWI>7NmCMCw^+BS=36ra$OE z=%ab}7X73C%COLgzwwM2KIaU4yS`h04^RJ&l|6?eFA_~Phm+^)HJR}MeX@R0zo#c^ zQAC`riEZ*|8RWa<(%+H|QBij?mjQZ|{zMNqw&^Cbn+YS=(}(KM(2wMj%&^MwXC~`| z9z@T-t2t(AGsWv~KJ>ZUnZ1$9V{?T!)*D9L*i&_8_v9Diw|Ckb zeW+31h%Esg41T zt&U=jK*tD2ZRdGsP3Ly!apy~CJy#P~LsxIt7FUpKxa)?iimRO~uWPVtpDWXK&2`*) z*Rjjq!9K}W&p4si#ww>$0HufLes;O+CRzD19T^YOrl+N(_Dpr8&Pf@WaxUd%O5c<| zDfLrgQ+(2%rfKPC(;H=O&a9ACJ^QeGzGs`~z4tq_q?zqqWo|S(n4Qf#<~sAXH^IBc z+tT~OGszR}Y3JSG+3r^EB)7|b!u{CuyZ1BmvDrqwR4*;1eQDIQFLAta7|vgvU0t<( zj`^1Iujcoq-%P(YekJ{H`!5Y#9Jo5LLGb;MZlRY$28B)yJsf&H^n6I3&?mv)23-i8 zA28g%hu0hQ-=f9ZrQkm1Uk}@A< z{+eCh?eI+T9x(q>HX@6jtU>1L{f#oV=f-bFCu5%Rm)@Oy{WjKMvy6AW=WzCynVZu8 zNjsL>BBgusgHMl>@+aL-Y?rhz=}=NaQh0J~^2_A7l&xu}(`RSw%}mcaKpDr9=47I9 z&H?oXwzIZJwzu{m=Mu*$N3^q+>#_46=Vj-8=RD`n&Oy$Tj^%cbZ5XW@l+n*N(r!3+ zIDheR`)=@i?f)t;G9)h4o~uOoknpA9W5T;d{1>r5qC!NK@Qkpgp}T@V4=NsT*DsH6 zbys&snn8_u^IOlV>@PAaWjs#{Pwkt$_|wEs<37z#PD!(8T+7^+)h+XSR(;PE?>OtR zvEJ6-h_E{yFCFz)2Ks)3omDgIV5tAj_L}I{C+>cL_hlr^fyo z(>NyeWAhJlKXm@s=wrd?PO(1?@ig87Mr=$t$V*$J6SiqFp4g)EY?eos{*eBiRnd?920p|ec9LFSkoNcFViS31P8B0G&hDK|nlzp$$<7(#< zynYsFe{}kRJ;%!8w+@~TYM(mDQAMtIjzM&0*3kHtzFXy+(XQFeF z?W&eyZtyhA4$N$pK0d8W>YvG@KK+yQEOA%Tm&sdFN~E4neU#QZ<3Q%0+5J6xypK)p zi0c=PJa)U|jAMplfOD9}vJVr*qMs*d{LIg&Ll<8WH1l;xjZC9X(V5&wJK z;n;DpuGqUVf5bM8s~o=|p?Tt#q<+aOQm&+J%karMoNahVnT3dr0*tw~CiY>DADly- zTbxnOYOZpw{?2yJFxM&P&yIDD4~|lf1NPaD#f};F^R{`mlD4x(CEGvtiOw0WIzBF6 zhkw0*xPYC(J;N@B^~|*>ym!Q#@L~~%BQ{3749_3_SFTH8R>=IIE&*fxZuordI_wx} z>p>K`!E-3vCu>B;{xnzWjpUb~YJA$8l$y9R>B*V@slxHzolxM_08U%^;ugoYNQ=WF7`=Fnvxil&@ldf zT!pyg*stOS#i_XS@jeOPCKmlvG5On+#i`$<-A*5!*(1BLrcP5+1}|iyaetCbm`VmY8`l%VHop3PwwPfsafeyGY@13 zdAF)8?VZuizRt1P`PB8B?^(ar{&W0S_&@VM;orhP)PI0qDc@gw`udjeJ>weT+~f#z z6to|*B^k-wbm+y&$!}U6y)t_-k@l008?H#d7XBLph6LXYeHQj@__Ew*^DNGr6`3pl zqM= z_nph@Xm58J>{_Y?p5s|nGiIg+C+|rrl=yGl{TN5gf#@3_Cwy!Xy)D`nQzmvxTt@uU z#GgM6PU)StJflvw?rqGfvas>WUdR>cbJI5jOJ5jREvQyd>!6WAgMy5pJb@zvO#f?s zYkXJx{N^g?Ty39di!%Bcx%7wRoUK!5%!OuS*7xbw&w2~nDSL6}J)d6wg#w!gCx;FU zpA)e#cagj$B6mf;i8LcmM}8iem}hV9LJ{l3N{93cTJAsA$L?%y5+ zX2PAgvoXI%5Bs?O!@H<&qK174i~bNjAhupYRFa;uBu&d~k{#&HZ(TK(Ic_>@`CRcG z>R&S8tH3frjRJ!LGW-ks&+_p)w%G1!GgM*ow0mFX-n4GXHxuLI567j(G>rb@W1){D zK3@MA99=j%HhO*R=6L_4T*=?1Y)Jb$^KSN0?^o6#{iE%e^PTSw|91i2z^lP+Lf41R z4J{j1F)S-2HMmpo^T3<_P5kQnrntH~KjNQm>(rODCaS(>3-2sXb&u)3>-M-$x_f(U zroZ(Va@S=mi<2c>y!(LPvT-?=0|G~ftLBoQlh5QwKKd5$4o4~L9|MA)7IA?JC)J%83 z&w7u=J$r@ciMp$o zu+MfXpWA+sfp>$-1h;|#_l6t}=@_~p8 zK$KF&G1q8fJ@MA`+{j8yUz&P0xnokjgbndlT(P*XW2?rlk6j)2OZ=A!9}%o39u4pWlnROt2n}c!kl>f!H`evSdCKvJ zEst?SyQO^0eBKEjANLnofm!9V{jy7Et;o8N?ae;pF5n$v)>1Xd$C#)eHtySoI5M5v zUGY8@{geE22RsYd7SuU7DyT~Es^E>mX+e#Ht_D5`u>5BEHt{*`d}=Ra%VGsyPu=yl z^i<2fow+^3onAS;RoeB`)v2>n&!kpKJCimgeN)D>tmE!eo>J^qI#`jcHX7Ii9p@Zv zor|3@&i|ahJ9{{rJ2yBk*~9D~jh6Z^R)3|umpljE*;(5%>t^&#FPXLv&VHVpC*^8N zWJ-k;d+LIiHy5u{K$s zX7sYT?04*6It=GyXAjmAH(b+vUbt4f*0?O!0M~w}?rP;c?0DgDId0lAjGjgb`anDs7%I&!{fyt+_{)unMq_UBi0ZkNt@?tjW6TBUrE1G&&ov^>wVu zGC5Ii!tT~c_^r0;Xx{WzF)w*rdjq^No+{p@o}b+f+%4T7v*u@?bVs|Bvg^33dqUjf zJZbLEtho-G^}LfkwXKKVdmewYg$m&hw{le`JM{mtcTAS4(OWNJ7)G$(+L&fs*9Wj? zP@eVjX-*T5vS&C$D`JfV6)~*lpPJvXj`5gRI5q##3{@vM-<)q5`fTzfKhu>ySWmXy zvG1~tG^#n~*-P6#bG)@h+Sl5v+xyz~8cmFD`e>~&@$4i{a}7;b#mp4*rnz4!R)JU5 z2X+NKsvElvy|}xY+qTM>VFcKh+Be!(+PXPj*ss`@+V|O;+T)1}3mF}Z()L|OK6d1P z=0uW8NouCIgW1C@Y*zB@@Rn6~Jh{EUdiQvnnN!TC-ifSLsZpmMuzR!9(#)ksL6DWM zHPE-~WOnJRRZZPTJE8t%=OaX|wPvu>x6U+GBW;j(wtAr|ux2@+_IdJ|9jsz%HY+4$ z`k3v#EmeDO3zO_zbAkCtwN%C6-a6J+y@qBer}mW*r@hcWXN(S817iWJ@zOSrdTw}- zX^eJ({Y3}+nya+^`j_k_t>HwJ8VV-$@U$k@AF8p+_R7h29d?TEvRigr+hdF1rb1qW z-X);xmT^oUq%Sj;>(`7o)>wNjb_813dr(d7onAs6)DIeU)nk>X5%r@qRlZuHeg8!wF27IhKy=~fC)=!*ATuNN?vYHz&UD^kkySd}nGY1h1) zyu;LX^-7H~Z(8+KDfPMfg)@%ERvvG#9;$BZYfSQq&9*wXg7pt(3GY&)5PbowYTeAA zs40`|ouKNX>q*)=)tAfYh1e(h&pXgtgDk2v)zp1P?`gTsc#}>}oWgk2c59X~oT`mW z^jYX6&A!iAtev%$vpv&)Gs+n^jVHDv>XWh5_KUGib+$PE9S5^`qul_9(WS zRmePesXg+RA%i`i?)E%nUu~@Y4Cm34sBYWW)=)RhD@Gez5%t&>YbEM$Y>&)t`efT% zeXUX1Sfk(7`WZFAb-K!r4l1j`+Gy3mO>HwX(3@_SbC*!7wGCjdqt(;Eb*X)2FvetNi)|cqh%@=x#s^!&eWPEzB!U(I)P5N)D zC3~6`%==awZPvNKr`M0qQ!mEM}1dJb24%mG#jW_w95sKsgvl*_hG z*Q}N7$YmK{>)VW-MhCsEUPs$t`_-&s>#2t7GmJH6J}cR~oRjAP<^?0st-&>$%`@&6 zS`BXG}dbt_0Y*{>O{sDfqVR;T?qImkooQ|!N3FN_nm3R($UqS4zp zz{$!iTZqnWX(LRFw5IDLy>aYpl~s`@cyjmB%b7FHbaR#a2h~z9;PqDn*@-XY-GT0A z>95UnEKh0w+7GJ9?2S#aS2EUVpNuj3O7`Lw8jr0&_0o1md9;DH3EmFM?QNl-@VxXE zGEZy$+{fK5y)Crz-dWxe+4PH4i_~dPh?T9z8p*~ht%|y6576G)i)(ppll9WtKt0Z0 zSCL6-%<~*}xES>$ZHbx0?yjBWx42#liCC9 ze&*4ddAr&gxM%9k;m-BeM9&lNeohIGTR)qdw0Y)9E!{lKN%2~pUP{&lTY{RX+ic&f z%J#a}GP|LbwM{YRI$WO5jVso1Jz1Zms%V4NZ`xSTIW5yewPa;i$5mJFW;4=EQKvlB ztr}*Cx0!aFebM#gMC|oUwZ1o7v*zrjhS(xhYrTa&UYlo+vh`6Jwj}#A-QRXzw}I=S z+9JE%+V6E6CDZ}^q$kB_=l17}+igm1pdeM%d)r%*baFHud|_si`4nsK zY(6yd+y1mR>1ld@yQM91ywiK@rS+;lbJ%nK(SFhFXl&vvh<+EIJjMxcZ|jX`np))P z;Qrj|r{*YrIiStno%g zt2k#u-il{8#!Bw zvmWZBjaSN{f6oabH=N+RJ6LHW{<@vB+L)>~_=&TG-O zSz0c2Sv&2Wrnl7I8f83PtaJJ*t&7^Ar`bH&E#PE>Isn70ht8~w_qLtv-fQMX&Zcj` z8%@olhC}tVd)Qy8$=-P;*w(DNY6DOH$f?CkJZWR^3tM^53VTznzqv*2H?lnQI7y~T zjaq3oG?K{LD$P035YE~9b31Ufy_=Ua8e^)uY2`KUnQzUNdWc@wETeDa6OB0YolewZ z>6h@79L#O=C|zs*}&r52kx_RF{T zq2t9=VI(0+-=rgQC-i%1ocnjVZ0aXDlW#&VmKMng^jWDV_yVJR0i0N@REW1YN8U+J z6`WFlw2MQD+tLPd6HyHvsw3zps!-3W!9SL^QY61iZbE(%n#f0_&7=d}yBumI#zsYs zVgBW+D<0Erh|=5~rW?baZtL5inA~_emwT|*B;Q`fG+APi>n~Sr= zT~s5n6#RNdlLm1t!LeoOwnQp50Mtey8I-Oo?Cfc}IW>idNJer3eN~!B#|rO=EusnZ z!x~UGi-}5zxn5zED$CDN@oFV*p=K(s^9QK%WG<>rr4?1^Ao$@pdL5A?#Lz9_(9(;x zqMw^X{-NkDXOcE)9`&DG1AX#}#60nc940nP8gioe09nTZDDR7j{irjDHGd{Ii^Igf z$cMx<=@@DUH>C3*j%JE>sy(=cG-(6fm0yKSz>Mx~uKb$3jd{3*cr30WcYuzvp^L0X zmhe%m41XIp{Iwc$4Ei?X&}DA|3ShHzMUp`y&5#F4vk4h1`5}3Y`i>@HC-C_DFrJmk zm&8Kphkw##a<^25IY{=9hcT@XzpRvsNEQUiKln)nVj@=iH)$j?hCij}(rsdav|EY_ zUb!<_TP{u?l%G*32GX7A`Eo<@8o8W4Dc@lh5Esb=auR0COTx*l1a}JnZe9q_8hXm%ktmCILwC2!gMl~pGr4FzY^YUVl|LS{bWDbgEFEIvG+icmoDOG z{(FrO5i`)St0=D`15|J9(etS>h;5gU%f!*- z8FaqG#57S!jF%>Xb1RFk=w{G=Wx+f4Bnm|EhM<@d#Xab1zm+H`#>!*;&IC;;gIHQa zvBXYtA8kcM=8*rS(Tyi=(dWc64=GgDz?z^(1S_rKKElw=h?`aI#SWKpJ_@+n}QyrPqO2rI3!xIC%+3UY`DfXpO z$yrh%xt2UD2~q-8h)jf&TT)-d^&BtAiEs41MUZqy{5b18l=*@tf37+==z% zC2aCo$&Sds193!(qw0cS`All41>lF0$m-HJ_yZ`Y_3}!ohTMw0AxuElcv^Z!?iNL4 z9plLV1ets#e#8_0xYP0%5Dw`$AyvX{qObqu&4E4qvc)Q2b`YfI5I7DwklE|8mS>X1$)CYz?FREP7z}v;b^ANw zv0}ZdkNT-bt(&9G)D1QCGnF!xF+0p!(<4(&(|M!LILdHVCuyf@1L|LtAE>qDG*Dyl zQk>9-OJF?_GV(06DaZxVgO@^YLz~0ZBU2-nA`bQtA1}TVf0E9~7sr?b*AcOg+*%_Xr@gU44Vwux?UQy zs(|Umyr&doRN5f);)X^SM4E=zhq42G137^}ph7Sj7=hlXKb#qrxQ#q1)&R%8hulil zWSS}}sj6v2O>0fA`l|XqKDL0QsHQx?te{mCMP^Gkgk^kfZa6zDx+#1!_`>h=d;Jys z1AXOvw7G_|y^b^8r5mX6jg*3(v>wTFGM-Di`nYHI~+ zX=@pCwxO*)U(-)zQCy?9Qt$^6%JT2n_~_%%;L!WPZNEOyDbP9akAI7w^M49%5A_P? zqc?Y(|0_-pW1dB#l!0RQpNyUO&b7%9LhS zTZUMgS%+I|Sxn}CO?6FejHeA}^-s0m)TLCvDT>j3Nw54#>LTXzv$#g=rU)1M9%>T$ zH&{EkCzu&@gbbl&p=se-kwwwr+-#vUDxa%~kDviJFe8-qTs>cyWn5Jmx0{C+hDWstMIVM)5zdx z9INN7yhZQ`?*zX%7kqU~@)CKITuFWa5DIYO4NM-A-Mgy07}KI-%OEih>6krP#)7W$H6;=`!?2 zsycOn+(k}69{3$>eXRi#Q`zP?ELh$qKMn@};e zKq>JPIN2=8FHM)~qf*~UIw#f>2aDT9TI?l}sseh@#MKg_qlJ~n}G!khUi{5162 zG^n{(5x(*Lcn_Z{+!m6A$--XYlyF&CgmrvPEF~TiD@zx}tD+!Ymd=5X+at|DeD(zX zJRa=Lb;wrKMXDdDnAHr=%UPnGjjN$MWzBPvNXM%_W3uj-H9_yN^w6|JhJ zJOlP=mf|Dxp6*Z2ryJ2@sRYUi%Iz+A{q;~ayp`5TFHpI)NPEF;b-@Z-B{r8#(mwI7 z=t0Fb9Tj~`3%`g>#r?tvVU+M*a0(5@&SGi&cb{-Te2%Z^EA5pY zBG0M<%6U8#FD}s6jZjHDj=D@u`cHZ|^DlFq8LoJvXb&!AmGXr0cjZmxJmmmoRpoDr z_KE?DW{Mof&YVFPd^pvbI*!x25Y@cr$U{PsQ`(Qyy}y(q)sjx&Jx`QINpaEz^esLh zhV_F_tPWnVH?%lxehf?FJuvO;qP+`ik2U@WIO|zTo&1Eyu3>K4cdj5;z@BF zIw7UdKZy#@giXSJ)YfhaZG<^Oc~KNz30h>2Rb<(582wbTJ_sT7>FbM7oW!y)Mnfy!VNs_(Z&fHCaWvBOVmXNgbr2l2?2$ z*24OqDV>DYO)drX)@kX)&IYv`{G)$CFc1Mu~6^|?a*^7F6!}S zR*A<&pV;e1eu0_U0q?aDVu2sd7#w;d?@$5z8LUxv@-X7ubEsF0L?m+sZ=oZo*dIEo zY-Bc%kX3I&6r4po1HpWg=uIxgJE%cjrS4N1)F1R^d>o}^x)meRPW(BU>BhXIThoK+ zrl9uPP^+*P{OCXY0Uh~0)I$U4;oJh_%AoR>2l6r~-Vpy4WAMx&WU3XVV$w8Z?bV=0 ztAV*NADX4f$m`P4Wvc?M6Q=G=u+rpw<1HRgR$OBe8)41&;aBUiC|9efMlKtcJ(9n zgj|eWC8`b;M0CEEYCwCblN3)`=_sY8w_x1s(xvHk^k$6zN9sI2W?{TD$xL!CNn%gf zgW1MIf&BsRd^niJ*~pHwrAAo&=;DD^9t6$hM6m3`p!lkQ=kZAdSnX3_;8$bRCrOEj zXJe%IVxbts6VcLJu@~5{)7bHT?3-_JB6Jitqw4;XG)Vdt%>FaXsDGpz_%6l4n6E+B zH4Q&`2x9%`*iTmAr;bGxV+4MOA6~FOG=l}`P1V3!YzvQ_bkrxl6Lm4;yOG1e$*b|y zt*AxR1oV-cp?f-(I*u7XkZOTFVh+^}f|xxdjXz)FEIo#=`T%7`Mex9V@zjH{x+a0k zZiMdIFE|1Fpr(@vwcr$Vzy84(DzOe`LRs-c>0AlVK2o;IM?u)X1%KNOXTdL+_jzKf z*i`BbUU{4}AG5tSM!F9o_$gQkd!@tZLVdV zv&k*wQS6Iv$!v6|+k@xWfH;35c@~}K5u^wDrAc72KVe_9V{X%^9F)U~`3v2Q_fjI> z^Bn9vxzO_caPv|@2{;njNOyFfwHR+BRf$}U5t#)|Pba8@8bLXE0@Ql~2yVADj@Uq! zLrqcz4JAA@h)L*Cjg;z%?XjjuN$rul{VedDg)htd`49Xp{sLc77>o|-Q|ygqaS`%@ zp-?#1B4-eLC8NYj8<1^J2EjIpyo}glFp)=&z*-$c1&LJRXE5a=PJmaW7qRtQ?BoH| zHfvD*$qb?tnSe2`PQAhV8coQgnjT0$gi>cHa?^FxE$R>SfPcX(xK1sgg5ac8L}_ISr9t&oxkgc3IaPTaJmh=2D*X#xl39eemya`VvwRjk zwV$Pr!fSp7znh=IU*V3kO`=`cd+awZi=Dy#$F^hNfkjVaKSxinTF%AY=Ie3e*dQC? z?(k!U(IPKc`Bd(*;1=c!Cc()a;yfExtH3{Bq|0g z_cT2*?9+R+XVs;_uD=4a)kVH5)Z(wRi=wN;?}8@-hy5pf^L&?l>E12gKfUFBEB!|T z8-k<5TcR>|U05nI(hzwI6;Lcu?Ny1OMdQH||E7JesjXh4?4`KEm>3rG)gv;(QtnUI z9f>015BZ1roBP-KZ}{AvSWgY_aG&Js=r{QTzSaH-!Ox*8(J|~tHo$h_3b@h2MN|y3 zQ4g$)m35Q6$#hnXXHGEl73qqSs;?@W`lEVTKJ{pIbQ27;C>8|8* z&$rpv*mv94G2jSW*fm^r#Esq22OX-otIpMpGyH5=VLWVXYng8w;s{$=(+k5ILqvaA z|C6?rYAc;W{4Dn8e_~&Tmj?gvtG%(VN=2^<1{O>z7*;s7Fp^(3e@VWou*hll`g~4b zH{WOfpzt|Xv29~l#I}tSVu!?L*n3*lmJ8;5W05XZrBaNiBhc==6`HUo zLIZ*~1E2h{zL4ANG&@z!!LAnWKJFOzB2Q=EZvWdrt#C(nwJ=7iKq?rU@}w%xP}?%W z+7NRmWYOE}#deP!Wp`NW7@z1~X>V%wC~uNe#3$^uNGSN-$GN5y9V=Lu|2>z>9-Sp; zw##0TyE$)59-r5vz*E%L)82nISO?78+9<(Sk*X4(uy0JIMCfGifjVubIK-sT9iWFC zk6O(y^hai?B99T6I?6p-zhS0nnt6xCX#c~}IxZppYJ6VYj)Vq@LPDMR!Lea`fBQY# z25Xvej&`Q9H^WmrSzf-wZ3<5gG{gnqCT|z_2e=VZ>-oC8@)GKPPbzWyyHy)0&r7hI2%~6G#hn=tz)05eva4F~L4;coU2AT=GKc;-*=%m`k zQsdvpk4+j}d~ES&#YV-~ab(&W*a|E<;{xqDY=iA4v%A@^$nSbNyC0I{#jt zJzrDMs~|srM}ADf@}g#*3;xQX#7G_1#eb1a%pLV$-BH5;^Kr+Q_-cvY6V}BYjBAk4 zHEBztHg>eRt!|vUr+S|96nTtW99-#{?fRw2o4-GMV@5&x`Sj%Uztcvg329R^o@M8N zw`@_^!&%4sEX1-}VT^D@xC?G(BfUZ~M^TRPlbw+D_QbQo2VShlKa4(%Uga-I3vtr6 zpjs(9YPE)_A;Yx5UOpi&xqXRc$p;dvCuNt&FY{lSaV7sq^u_$)u*Q6}+s&P|Cz%4& zh}ZLdqeFvly&+e1XHh|;ybd|#a}MQR%*)H~n*TP>pFhlrFA9B%6tX`H&E=JpQI)AX zZ#LL69qVEz$2N#RmzbP9DEV4a*ZAg+kJhW^9)>a6^~&1BP;N^|^saVwFOu_{=Cse` z(?_N?N}HVCH{-v|ZrK;Jr{;$9r#kO?H--GsO59N116pPwIg&9e^A-1*4Rn3VLQVt) z(pZ`;wiiCKTOx-7v;3m}Rj4WZCwG(2A-f`R3mC-EpN8HA!EKZ!5u+SYF(nG&13P933;= zy3ANXTatM$&SqDICi;%JY876{;WFg(vuW$nlG3-NANxKnvupOf+#3a1&dJ_;fmM+! zTx0R5ynwXP9TaL+Rh2>ck|{+WqwLf-bevytipbkwYG4uw{u;hMp7YMtMHc5c-=MI> z|0nxtud0J#j-^NJwxk=Sb1P(~G^_fkN=)SoRosvqC9W0sBppkv7T+PpYq!`Q82f43&_hI;9S53xuBUua)x3*Y?=y#H zjmT=7RW)mM)}0(}!8E7fF6sL-@GSg+{YO|SU6PxVc~m?zh#5!clek+@E&)wg22Ze; zLJ5AKcdECZcd#eZwYKQbqDIbcu9NP5UUSgJ-jaD{rPga2=h#~;zU1t(%PQ8b`nme7 zT4ic}sa83qTjeelqvalznqI7#-KoE(Tu+AiSK-dSr$v)eFP)g3_)o(A*yXn0%-al8 z^*gj)RU=v}v+Sf$hJTsAneUGKh;wKmkv}CbGe5hql=GzPzB|!t@p=9KgyyjXYF{_O zcrC-NkzdJVWUaHPmP7}!1fR*?kH)ZdA`OEtd_K=LXJ=;<*Bq!vE_ge8Had3~ZFP`~=gRd2QBHF{UyQ*~YC$K~&pjw?PQ{=2QM z;fC@Nxmai)?&3`?s+AwfUX#UU#C@NT)-+A`-JIpkX_DWgXotH(plb9pSQ$T~RTKJL z(*mp8w$NdUIU3tLzJ1)^4$@x2{?xX^I?!}M)14_n$#78mAkJfz!JoVu?=H_Xx8M%D z8aOkG#=5S!`n%tIZu({i=Z7CesA%12ceaqC{H7IO;=f0GjDfqC(m!*gTB9fRf2zqzlX9TMxvSeh2gg4z3q~1Ov2F8Z!6WW z+OcYSl^T^NR=Juozsk|_FG^=8w~L?RSY) z|3)apBi-n-TGrUtO4{qjrWS8iK2kZH@<+<9%70b)FJ))S;L4-QUnu#g*r2#tcGfUR zX(Hw$rocn~`_u5$dr`0=raVqQ9Y)>)>8hEtl-$}&txa;9)H+B3oj69RSoExjY%xvopD z_O9!QS$4WxdIoxb^F8pd3|Y9K(hacw~4of|7>t=_;X|ddyi<3T=nNT^s z+S;m9QmUr>Qn|2FY~{Wcx0G6w^eHyWnx)&O%p!O2)x&pvXI&Ta#$@l!?3>~KUOD4Q zMvIIRnQgLr=kImi@XZKmqUl^$DTZFBYN)5odn~1G|2Ya{FT^d5k54ET&&M8*O>{Ie zXBgTVE~?Kd#?rmzbL_{++i=}ry04kHy1Rn2qO+iAM$yKi^rFVjJm*9A29Mr|)ot4%E}1Fenitz)|;4lEWb)}ojyJ_s$tYDbZ+n`MyUvicfbpSUFc&1XbC!AHK| zJ>Q&~qGN^Q3TqdZE({d#`A_rzDqQUv;2q|_5=akh4c-d7*jnPhs85%M54jVS;Qx>z z{wo#}W^#|Cs)!3KS?RmvUFu!s{ooC|FFXG$TI4L@O7^x3t>jzFd2}aL1;aT@$v7^# zUfC-ZwpK1m>6o&;%AP9IQ}$NgUr}AYM5&Dl?`#iE19a1r{m4@MjezVD3XFNhb53RU z{yr&fPwI%Y?DTyZmh6{#%L@m)BHl`&Shl@1l0K)ps=aGiXMSee6x$|oVp3XCO!B9s zdByH0h7)Y@w;b!O$BcEg9~D)oh0?#=?Qpd~H%}So-Gci0ro1~jBeM@=RnD%Eb1yfN zzr2Wct#EJh{t|c{e$LhuZ=goC1NEp%rVCg!~fyz_(0E5D|H<$DRETNiIT(16BXSR_EtPqsZ-?vl}Ar^Y6xl+NjkyywKeR<+eoj1?^rZNw;*F9si!CTty;!9LPwakMw!xx#tsG33kk4{o zL-)J`U6YIc$e)z^B3qqxBSV|HDO1e+EqiqC$o%0&%iS%#C;chmO!jxNBykq%?@Cm2 zx}9Q%a=xN2Lr@LmICR|nJjd>iID=RHcfC73J>5}POLxRqArupN7`@3?CI>1%>w8#z z4r^SX*n^S_%hV}fzv7jO=PHCNFF?DziaiYXkOSCk!-<;pmmaUdfrV`5gl z9B1z1{L6)FT}i$M!Bdf=+<2kB^uw)2#hg}jQuJ4}Q1oCFbQbv&$)ex!O0Wp=Z0X4H zfId(nFfEeJK4K}B<%Ub0$O`IgL$cXx?&UDXy^JrNw6$cD(z;TcOZ6zVyLh!Eq1emB zm2qVqQS(||X{C!A0ygVLG&#t6HWbY$IGKMuZ(GiRY+H8ItgiU2uIHUB*yRj)9t6UO zS8s}I={BnWba%}ESqiOd9di8S#9xw9i~XLUjBOH=;TUdTXmRRms1MWo5jBX2u>SJ9 z-1mxXg`M-}=k(29ko_rpYEJ8%xSX8aKMH)#MV@B9R{kl$J7GWDTJ%c$;bH~S6}`4S zsFAOLFG6Q{Ts)S?id*;y_X~HCt;R1xx2izs0f(S|^cv-A&3WBE183>)*zZV+Z5^*l zR3s)Qtxp|lJ&_|0*vVw|?}mQu!mrj9C~5y*;SQ}$dqBQVZ4#dF2Q74|Ji%b$?H zGOtD6l6+0!*`nnx*|W``0-Mh|(h+h9vsGo)cGCq+l6`*614oINg)z4s$79OG7TE*l zzl>}2D>b*3UugJ5^Bto*gL?l4&l~5n!ifd_@+;=e%-xWalQSu=QNfkMmqk`rBagv< zIQSy`Cc22T2~Yvb?}(G+SX50@C<*n{JYoeZiqqvJ)bQGX@;MHY<|5gUuE&&99n@6T zrx@y+80$t`cl&IIC9Wv0X?#}v)c75-4Pws3=wdn|`#xkWsVk-4p-fe9RE*^3W=4;N zRt9ePXZX_G>zx~l{wv&BaJOJ(;mV@j&erZLo)llu|2)j|>C!IpIz3v^Rn=X8-Tc5h z)_TJF)%wU<+g{$W*|x*H!|+afLmg0_0pI*tjOSK{lY<9+Z9G4_yhW{w5(@9;=j7@0 zix+e$++S4a?CrYjTH_h-PYSILZ;afGz5@-B1Xr}x@C-{pKXnDzCLh@nE*kIAUrL~= zp&JsULUb491?3%eC0(JutKo=goMoxSYBk%bm^26Hc;Fx$t!(eC+iY{JL(H!X3w4*( zrB#Pf@wrDn2a$4`{WH=gd_8n5n1|@)oyYE3=icoe@7d*z^VRo0^o|W|iX?Jl_@lxC zK_hQxQZ#Ke_cS{-ZM7}*?@X!YL{nqKF#Si}L|v+OvD%@yMy(|tNLj)+c6Qi~{(GKp zj(3^6w5y6s;bz=@T;H72or_#Px6U`o@A9+$^?`pvWuiN{IeZcSj^8Qx#Q8D_Cz&d! z{ar$p^$7VJQ%x~d(Nv*@!s{p9FhfIAqWQ4-h!y4|_O*^NF+s;i$Do*`n3wib);X4u z=8~rKhJCu{>RHg3FQku>-%;uO3dNct(mdQCbT;tFzs)zv%XmL|MC=x6*l{oR8j zBJ0@MTo--oWDf>PBkwHGcIOXu_y9fWPim1ft)pg8oKtVA2(%RDSh8nu(gf)Q8o{nx|^L+Nw%ZBr`Lq zPH-9;CC&h^G88f2yWpt6SKk(|!rR(A8ChGdC+HdK^&-+;6(|f`5B3i?jogf6M@8-) z_8Kd?DI?J%%9pxA1y@0emln#U=!MK|^sjshO1(>KH&!qoG>aF{jSVl zI#BSlm)ZzBxES_KczN)a|Duoaxjgyqw(inyjeCl_t|!6U!Mn{X`ECcaAv%0BQk`{h zI{r3jig;vudi1-B5nV|obXtv|0Xk1Cq01_wjDkr}j8NUs+}AHMwlwmFRPz~I)PBYB zEM|1fLC2YxQgPAPp^j3vSnG3hs&THNo^F_`7t@oEz6K%B0LVYQJk4%B^9?@&+B zI5b{mBc=rDhoglP3d3t;A`%0AIJ$Qq6#*H>mu%wCsMyFmMQ;Hc2`Z;4AqU$lZNH` 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ΞsW-;0v_Ih^Kj%`=1C9Pp=0jt?E*_3Lmuiu~z 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 diff --git a/asr-monitor-test/app/tts_service.py b/asr-monitor-test/app/tts_service.py index af367aa5..9566ffe2 100644 --- a/asr-monitor-test/app/tts_service.py +++ b/asr-monitor-test/app/tts_service.py @@ -7,6 +7,8 @@ from datetime import timedelta import threading, time, queue, uuid, time, array from threading import Lock, Thread from concurrent.futures import ThreadPoolExecutor +from contextlib import asynccontextmanager +from multiprocessing import Manager import base64, gzip import os, io, re, json from io import BytesIO @@ -29,7 +31,20 @@ SAMPLE_WIDTH = 2 # 16-bit = 2字节 tts_router = APIRouter() +# 路由器专属的生命周期管理器 +@asynccontextmanager +async def tts_lifespan(app: FastAPI): + """tts_service路由模块的生命周期管理器""" + print("tts_service路由器正在启动...") + + try: + yield + finally: + print("tts_service路由器正在关闭...") + # logger = logging.getLogger(__name__) + + class MillisecondsFormatter(logging.Formatter): """自定义日志格式器,添加毫秒时间戳""" @@ -66,50 +81,61 @@ configure_logging() class StreamSessionManager: - def __init__(self): - self.sessions = {} # {session_id: {'tts_model': obj, 'buffer': queue, 'task_queue': Queue}} - self.lock = threading.Lock() + def __init__(self,manager = None): + #self.sessions = {} # {session_id: {'tts_model': obj, 'buffer': queue, 'task_queue': Queue}} + #self.lock = threading.Lock() + + self.sessions = {} + self.lock = threading.Lock() + self.executor = ThreadPoolExecutor(max_workers=30) # 固定大小线程池 self.gc_interval = 300 # 5分钟清理一次 - self.streaming_call_timeout = 15 # 20s + self.streaming_call_timeout = 10 # 10s self.gc_tts = 3 # 3s - self.sentence_timeout = 1.5 # 1500ms句子超时 + self.sentence_timeout = 2 # 2000ms句子超时 self.sentence_endings = set('。?!;.?!;') # 中英文结束符 # 增强版正则表达式:匹配中英文句子结束符(包含全角) self.sentence_pattern = re.compile( - r'([,,。?!;.?!;?!;…]+["\'”’]?)(?=\s|$|[^,,。?!;.?!;?!;…])' + #r'([,,。?!;.?!;?!;…]+["\'”’]?)(?=\s|$|[^,,。?!;.?!;?!;…])' + + r'((?:(? self.sentence_timeout: - with self.lock: - if session['text_buffer']: - # 直接处理剩余文本 - gen_tts_audio_func(session_id, session['text_buffer']) - session['text_buffer'] = "" - - if current_time - session['last_active'] > self.streaming_call_timeout: - if session.get('streaming_call'): - session['tts_model'].end_streaming_call() - session['streaming_call'] = False - - # 会话超时检查 - if current_time - session['last_active'] > self.gc_interval: - with self.lock: - if session['text_buffer']: - gen_tts_audio_func(session_id, session['text_buffer']) - session['text_buffer'] = "" - self.close_session(session_id) - break - - # 休眠避免CPU空转 - time.sleep(0.05) # 50ms检查间隔 def _process_tasks(self, session_id): # 20250718 新更新 """任务处理线程(每个会话独立)- 保留原有处理逻辑""" @@ -229,11 +211,11 @@ class StreamSessionManager: # 根据引擎类型选择处理函数 if session.get('streaming_call'): - gen_tts_audio_func = self._stream_audio + gen_tts_audio_func = self._generate_audio #self._stream_audio else: gen_tts_audio_func = self._generate_audio - while session['active']: + while session['active'] and session.get('should_stop', False) is False: current_time = time.time() text_to_process = "" @@ -244,6 +226,7 @@ class StreamSessionManager: # 2. 处理文本 + # 在Python中,空字符串在布尔上下文中被视为 False if text_to_process and not session['current_processing'] : session['text_buffer'] = "" # 分割完整句子 @@ -294,109 +277,96 @@ class StreamSessionManager: # 处理剩余的缓冲文本 if buffer: combined_text = "".join(buffer) - - # 重置完成事件状态 - session['sentence_complete_event'].clear() session['current_processing'] = True # 生成音频 - gen_tts_audio_func(session_id, combined_text) + gen_tts_audio_func(session_id, combined_text) #如果调用_stream_audio,则是同步调用,会阻塞,直到音频生成完成 - # 等待完成 - 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: + text_to_process = "" 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 + text_to_process = session['text_buffer'] + if text_to_process: + # 直接处理剩余文本 + session['current_processing'] = True + gen_tts_audio_func(session_id, session['text_buffer']) + session['text_buffer'] = "" + # 重置处理状态 + session['current_processing'] = False + """ # 4. 会话超时检查 - if current_time - session['last_active'] > self.gc_interval: + if current_time - session['last_active'] > session['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 # 关闭会话 + logging.info(f"--_process_tasks-- timeout {current_time} {session['last_active']} {session['gc_interval']}") 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 - logging.info(f"_generate_audio:{text}") - first_chunk = True - # logging.info(f"转换开始!!! {text}") - try: - """ - for chunk in session['tts_model'].tts(text, session['sample_rate'], session['stream_format']): - 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['tts_model'].text_tts_call(text) - 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后台已经返回,可以通知前端了 - # logging.info(f"转换结束!!! {session['audio_chunk_count']}") - 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: + if not session or session.get('should_stop', False): return try: - logging.info(f"StreamSessionManager _generate_audio--0 {text}") + #logging.info(f"StreamSessionManager _generate_audio--0 {text}") + + def on_data_whole(data: bytes): + if data: + try: + session['last_active'] = time.time() + session['buffer'].put({'type':'arraybuffer','data':data}) + #session['buffer'].put(data) + session['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}") + + # 重置完成事件 + session['sentence_complete_event'].clear() + session['tts_model'].setup_tts(on_data = on_data_whole,completion_event=session['sentence_complete_event']) # 调用 TTS session['tts_model'].text_tts_call(text) session['last_active'] = time.time() session['audio_chunk_count'] += 1 + # 等待句子完成,但会检查停止标志 + start_time = time.time() + timeout_or_stopped = True + while not session['sentence_complete_event'].wait(timeout=0.5): # 每0.5秒检查一次 + # 检查是否超时或收到停止信号 + if time.time() - start_time > 30 : + timeout_or_stopped = True + break + if session.get('should_stop',False): + timeout_or_stopped = False + break + logging.info(f"StreamSessionManager _generate_audio 转换结束!!!" + f"{session['audio_chunk_size']} {session_id} " + f"收到停止信号: {not timeout_or_stopped}") + session['buffer'].put({'type': 'sentence_end', 'data': ""}) if not session['tts_chunk_data_valid']: session['tts_chunk_data_valid'] = True @@ -412,6 +382,8 @@ class StreamSessionManager: # logging.info(f"Streaming text to TTS: {text}") try: + # 重置完成事件状态 + session['sentence_complete_event'].clear() # 使用流式调用发送文本 session['tts_model'].streaming_call(text) session['last_active'] = time.time() @@ -430,20 +402,60 @@ class StreamSessionManager: buffer = session['buffer'] # 这里是 queue.Queue last_data_time = time.time() # 记录最后一次获取数据的时间 - + get_tts_audio_size = 0 + get_tts_audio_return = 0 while session['active']: try: + # 检查会话是否被标记停止 + if session.get('should_stop', False): + logging.info(f"会话被标记停止: {session_id}") + break + # 使用 run_in_executor + wait_for 设置 10 秒超时 data = await asyncio.wait_for( - asyncio.get_event_loop().run_in_executor(None, buffer.get), + asyncio.get_event_loop().run_in_executor(self.executor, buffer.get), timeout=10.0 # 10 秒超时 ) + get_tts_audio_return += 1 + # 检查停止信号 + if isinstance(data, dict) and data.get('type') == 'stop_signal': + logging.info(f"StreamSessionManager get_tts_buffer_data收到停止信号: {session_id}") + break + if isinstance(data, dict) and data.get('data'): + get_tts_audio_size += len(data['data']) + #logging.info(f"get_tts_buffer_data {data}") last_data_time = time.time() # 更新最后数据时间 yield data except asyncio.TimeoutError: # 10 秒内没有新数据,检查是否超时 if time.time() - last_data_time >= 10.0: + logging.info(f"get_tts_buffer_data {session_id} Timeout after 10 seconds " + f"data_size={get_tts_audio_size} qsize={buffer.qsize()} {get_tts_audio_return}") + if buffer.qsize() >= 10: + # 获取线程池状态 - 使用自定义的 executor + active_threads = len(threading.enumerate()) # 当前系统线程数 + + # 获取线程池特定信息 + pool_threads = [ + t for t in threading.enumerate() + if t.name.startswith("ThreadPoolExecutor") + ] + + # 安全地获取等待任务数 + pending_tasks = 0 + if hasattr(self.executor, '_work_queue'): + pending_tasks = self.executor._work_queue.qsize() + + logging.warning( + f"[{threading.current_thread().name}] Timeout: " + f"System threads={active_threads}, " + f"ThreadPool threads={len(pool_threads)}, " + f"Pending tasks={pending_tasks}" + ) + # 202507 调试发现,偶尔存在队列中已经生成了TTS音频数据,但是上述从队列中获取数据时,不能成功 + # 所以做如下的复位关键资源的操作 dale_yxc + self.reset_manager() # 出现取不到队列数据的异常,重置关键资源 break else: continue # 未超时,继续等待 @@ -456,33 +468,68 @@ class StreamSessionManager: logging.error(f"Error in get_tts_buffer_data: {e}") break + def close_session(self, session_id): with self.lock: if session_id in self.sessions: - # 结束流式传输 - try: - # if self.sessions[session_id].get('streaming_call'): - # self.sessions[session_id]['tts_model'].end_streaming_call() - logging.info(f"Ended streaming for session {session_id}") - except Exception as e: - logging.error(f"Error ending streaming call: {str(e)}") + session = self.sessions[session_id] + session['active'] = False - # 标记会话为不活跃 - self.sessions[session_id]['active'] = False - # 设置完成事件(确保任何等待的线程被唤醒) - self.sessions[session_id]['sentence_complete_event'].set() - # 延迟2秒后清理资源 + # 设置完成事件 + session['sentence_complete_event'].set() + + # 清理TTS资源 + try: + if session.get('streaming_call'): + session['tts_model'].end_streaming_call() + except: + pass + + # 延迟清理会话 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 _cleanup_expired(self): + """优化后的清理方法""" + while True: + time.sleep(30) + now = time.time() + to_remove = [] + + # 快速收集需要清理的会话ID(减少锁持有时间) + with self.lock: + for sid, session in list(self.sessions.items()): + if now - session['last_active'] > self.gc_interval: + to_remove.append(sid) + + # 在锁外执行实际清理 + for sid in to_remove: + self._clean_session(sid) + + logging.info(f"清理资源: {len(to_remove)}会话") + + def stop_session(self, session_id: str): + """停止指定会话的音频生成""" + if session_id in self.sessions: + session = self.sessions[session_id] + + # 设置停止标志 + session['should_stop'] = True + + # 如果使用队列,放入停止标记 + if 'buffer' in session: try: - self.sessions[session_id]['tts_model'].end_streaming_call() + # 放入特殊值通知生成循环退出 + session['buffer'].put({"type": "stop_signal"}) except: pass - del self.sessions[session_id] + # 设置完成事件,确保任务处理线程能退出 + session['sentence_complete_event'].set() + logging.info(f"StreamSessionManager stop_session: {session_id}") def get_session(self, session_id): return self.sessions.get(session_id) @@ -506,6 +553,7 @@ class StreamSessionManager: """ 增强型句子分割器 返回: (完整句子列表, 剩余文本) + 限定返回长度 """ # 特殊处理:如果文本以逗号开头,先处理前面的部分 if text.startswith((",", ",")): @@ -531,7 +579,7 @@ class StreamSessionManager: continue # 检查是否为有效句子(最小长度或包含结束符) - if len(sentence) > 6 or any(char in "。.?!?!" for char in sentence): + if (len(sentence) > 6 or any(char in "。.?!?!" for char in sentence)) and (last_end<24): complete_sentences.append(sentence) last_end = end_pos else: @@ -542,34 +590,98 @@ class StreamSessionManager: # 3. 提取剩余文本 remaining_text = text[last_end:].strip() - return complete_sentences, remaining_text + def reset_manager(self): + """完全重置管理器 - 极简版本""" + logging.critical("Resetting StreamSessionManager...") + + # 步骤1: 关闭所有会话 + + for session_id in list(self.sessions.keys()): + try: + # 直接清理会话而不调用close_session + if session_id in self.sessions: + # 尝试释放TTS资源 + try: + if self.sessions[session_id].get('tts_model'): + self.sessions[session_id]['tts_model'].cleanup() + except Exception: + pass + del self.sessions[session_id] + except Exception: + pass + + # 步骤2: 重置关键资源 + # 重建线程池 + try: + self.executor.shutdown(wait=False) + except Exception: + pass + self.executor = ThreadPoolExecutor(max_workers=30) + + # 清空会话字典 + self.sessions = {} + + # 重建锁对象 + self.lock = threading.Lock() + + logging.critical("Reset completed") + + def get_self_thread_pool_status(self): + # 获取线程池状态 - 使用自定义的 executor + active_threads = len(threading.enumerate()) # 当前系统线程数 + + # 获取线程池特定信息 + pool_threads = [ + t for t in threading.enumerate() + if t.name.startswith("ThreadPoolExecutor") + ] + + # 安全地获取等待任务数 + pending_tasks = 0 + if hasattr(self.executor, '_work_queue'): + pending_tasks = self.executor._work_queue.qsize() + return ( + f"[{threading.current_thread().name}] Timeout: " + f"System threads={active_threads}, " + f"ThreadPool threads={len(pool_threads)}, " + f"Pending tasks={pending_tasks}" + ) + stream_manager = StreamSessionManager() + def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in {'png', 'jpg', 'jpeg', 'gif'} -audio_text_cache = {} -cache_lock = Lock() -CACHE_EXPIRE_SECONDS = 600 # 10分钟过期 - # WebSocket 连接管理 class ConnectionManager: def __init__(self): self.active_connections = {} + self.aichat_audio_sessions = {} # 用于存储aichat音频会话,关联StreamSessionManager的session_id async def connect(self, websocket: WebSocket, connection_id: str): await websocket.accept() self.active_connections[connection_id] = websocket logging.info(f"新连接建立: {connection_id}") + # 注册音频会话,关联StreamSessionManager的session_id + def register_audio_session(self, connection_id: str, audio_session_id: str): + self.aichat_audio_sessions[connection_id] = audio_session_id + async def disconnect(self, connection_id: str, code=1000, reason: str = ""): + # 通知StreamSessionManager管理器停止生音频 + if connection_id in self.aichat_audio_sessions: + audio_session_id = self.aichat_audio_sessions[connection_id] + stream_manager.stop_session(audio_session_id) + del self.aichat_audio_sessions[connection_id] + if connection_id in self.active_connections: try: # 尝试正常关闭连接(非阻塞) @@ -587,7 +699,7 @@ class ConnectionManager: """安全发送的通用方法(核心修改)""" # 1. 检查连接是否存在 if connection_id not in self.active_connections: - logging.warning(f"尝试向不存在的连接发送数据: {connection_id}") + #logging.warning(f"尝试向不存在的连接发送数据: {connection_id}") return False websocket = self.active_connections[connection_id] @@ -853,11 +965,6 @@ def parse_markdown_json(json_string): return {'success': False, 'data': 'not a valid markdown json string'} -audio_text_cache = {} -cache_lock = Lock() -CACHE_EXPIRE_SECONDS = 600 # 10分钟过期 - - # 全角字符到半角字符的映射 def fullwidth_to_halfwidth(s): full_to_half_map = { @@ -936,32 +1043,6 @@ def encode_gzip_base64(original_data: bytes) -> str: return base64.b64encode(compressed_bytes).decode('utf-8') # 默认不带换行符(等同于Android的Base64.NO_WRAP) -def clean_audio_cache(): - """定时清理过期缓存""" - with cache_lock: - now = time.time() - expired_keys = [ - k for k, v in audio_text_cache.items() - if now - v['created_at'] > CACHE_EXPIRE_SECONDS - ] - for k in expired_keys: - entry = audio_text_cache.pop(k, None) - if entry and entry.get('audio_stream'): - entry['audio_stream'].close() - - -def start_background_cleaner(): - """启动后台清理线程""" - - def cleaner_loop(): - while True: - time.sleep(180) # 每3分钟清理一次 - clean_audio_cache() - - cleaner_thread = Thread(target=cleaner_loop, daemon=True) - cleaner_thread.start() - - def test_qwen_chat(): messages = [ {'role': 'system', 'content': 'You are a helpful assistant.'}, @@ -1004,13 +1085,13 @@ class QwenTTS: 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 self.model_name = model_name.split('@')[0] dashscope.api_key = key ssl._create_default_https_context = ssl._create_unverified_context # 禁用验证 self.synthesizer = None self.callback = None self.is_cosyvoice = False + self.cosyvoice = "" self.voice = "" self.format = format self.sample_rate = sample_rate @@ -1020,7 +1101,9 @@ class QwenTTS: # 返回分离后的两个字符串parts[0], parts[1] if parts[0] == 'cosyvoice-v1' or parts[0] == 'cosyvoice-v2': self.is_cosyvoice = True + self.cosyvoice = parts[0] self.voice = parts[1] + logging.info(f"---begin--init QwenTTS-- {format} {sample_rate} {model_name} {self.cosyvoice} {self.voice}") # cyx self.completion_event = None # 新增:用于通知任务完成 # 特殊字符及其拼音映射 self.special_characters = special_characters or { @@ -1049,7 +1132,6 @@ 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) # 发送结束信号 @@ -1094,7 +1176,7 @@ class QwenTTS: break def on_open(self): - logging.info("Qwen CosyVoice tts open ") + #logging.info("Qwen CosyVoice tts open ") pass def on_complete(self): @@ -1113,7 +1195,7 @@ class QwenTTS: def on_close(self): # print("---Qwen call back close") # cyx - logging.info("Qwen CosyVoice tts close") + #logging.info("Qwen CosyVoice tts close") pass """ canceled for test 语音大模型CosyVoice @@ -1192,12 +1274,14 @@ class QwenTTS: 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"Qwen setup_tts {self.voice} {format_val}") + + if self.is_cosyvoice: + format_val = self.get_audio_format(self.format, self.sample_rate) + # logging.info(f"Qwen setup_tts {self.voice} {format_val}") self.synthesizer = CosySpeechSynthesizer( - model='cosyvoice-v1', - voice=self.voice, # voice="longyuan", #"longfei", + model=self.cosyvoice, #'cosyvoice-v1', + voice=self.voice, # voice="longyuan", #"longfei", "longyuan_2" callback=self.callback, format=format_val ) @@ -1227,11 +1311,21 @@ class QwenTTS: return f"{text}" def text_tts_call(self, text): - if self.special_characters and self.is_cosyvoice is False: + if self.special_characters : text = self.apply_phoneme_tags(text) #logging.info(f"Applied SSML phoneme tags to text: {text}") - + volume = 50 + if self.sample_rate < 10000: + volume = 70 if self.synthesizer and self.is_cosyvoice: + #logging.info(f"Qwen text_tts_call {text} {self.cosyvoice} {self.voice}") + format_val = self.get_audio_format(self.format, self.sample_rate) + self.synthesizer = CosySpeechSynthesizer( + model = self.cosyvoice, #'cosyvoice-v1', + voice = self.voice, # voice="longyuan", #"longfei", + callback=self.callback, + format=format_val + ) self.synthesizer.call(text) if self.is_cosyvoice is False: logging.info(f"Qwen text_tts_call {text}") @@ -1249,6 +1343,9 @@ class QwenTTS: # logging.info(f"---dale end_streaming_call") self.synthesizer.streaming_complete() + def cleanup(self): + pass + def get_audio_format(self, format: str, sample_rate: int): """动态获取音频格式""" from dashscope.audio.tts_v2 import AudioFormat @@ -1721,31 +1818,71 @@ def replace_domain(url: str) -> str: return f"http://localhost:9380/{url}" -async def proxy_aichat_audio_stream(client_id: str, audio_url: str): - """代理外部音频流请求""" + +async def proxy_aichat_audio_stream( + client_id: str, + audio_stream_id: str, + combined_state: dict = None # 新增组合状态参数 + ): try: - # 替换域名为本地地址 - local_url = audio_url - logging.info(f"代理音频流: {audio_url} -> {local_url}") + stream_session = stream_manager.get_session(audio_stream_id) + if not stream_session: + logging.warning(f"Audio session not found: {audio_stream_id}") + return + + # 注册当前连接的音频会话 + manager.register_audio_session(client_id, audio_stream_id) + + sample_rate = stream_session.get('sample_rate') + audio_data_size = 0 + + # 发送采样率 + await manager.send_json(client_id, {"command": "sample_rate", "params": sample_rate}) + + # 处理音频流 + async for data in stream_manager.get_tts_buffer_data(audio_stream_id): + # 检查websocket 连接是否仍然活跃 + if not manager.is_connected(client_id): + logging.info(f"audio websocket 连接已断开,停止音频生成: {client_id}") + # 通知会话管理器停止生成 + stream_manager.stop_session(audio_stream_id) + break + if isinstance(data, dict): + if data.get('type') == 'sentence_end': + await manager.send_json(client_id, {"command": "sentence_end"}) + + elif data.get('type') == 'arraybuffer': + audio_data = data.get('data') + audio_data_size += len(audio_data) + + if not await manager.send_bytes(client_id, audio_data): + break + + logging.info(f"--- proxy AiChatTts audio_data_size={audio_data_size}") + + # 组合模式通知音频流结束 + if combined_state: + combined_state["audio_completed"].set() - async with httpx.AsyncClient(timeout=60.0) as client: - async with client.stream("GET", local_url) as response: - # 流式转发音频数据 - async for chunk in response.aiter_bytes(): - if not await manager.send_bytes(client_id, chunk): - logging.warning(f"Audio proxy interrupted for {client_id}") - return except Exception as e: - logging.error(f"Audio proxy failed: {str(e)}") - await manager.send_text(client_id, json.dumps({ - "type": "error", - "message": f"音频流获取失败: {str(e)}" - })) - + logging.error(f"音频流处理失败: {str(e)}") + # 仅在连接活跃时发送错误 + if manager.is_connected(client_id): + await manager.send_text(client_id, json.dumps({ + "type": "error", + "message": f"音频流错误: {str(e)}" + })) + finally: + # 确保取消注册 + if client_id in manager.aichat_audio_sessions: + del manager.aichat_audio_sessions[client_id] # 代理函数 - 文本流 # 在微信小程序中,原来APK使用的SSE机制不能正常工作,需要使用WebSocket -async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload: dict): +async def proxy_aichat_text_stream(client_id: str, + completions_url: str, + payload: dict, + combined_state: dict = None): """代理大模型文本流请求 - 兼容现有Flask实现""" try: logging.info(f"代理文本流: completions_url={completions_url} {payload}") @@ -1755,32 +1892,15 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload "Content-Type": "application/json", 'Authorization': 'Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm' } + tts_model = None 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=tts_model_name - ) - streaming_call = False - if tts_model.is_cosyvoice: - streaming_call = True - - # 创建流会话 - tts_stream_session_id = stream_manager.create_session( - tts_model=tts_model, - sample_rate=payload.get('tts_sample_rate', 48000), - stream_format=payload.get('tts_stream_format', 'mp3'), - session_id=None, - streaming_call= streaming_call - ) - # logging.info(f"---tts_stream_session_id = {tts_stream_session_id}") + #logging.info(f"---create tts_stream_session_id = {tts_stream_session_id}") tts_stream_session_id_sent = False + # 使用更长的超时时间 (5分钟) - timeout = httpx.Timeout(300.0, connect=60.0) + timeout = httpx.Timeout(30.0, connect=20.0,read=20, write=20) async with httpx.AsyncClient(timeout=timeout) as client: # 关键修改:使用流式请求模式 async with client.stream( # <-- 使用stream方法 @@ -1789,8 +1909,8 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload json=payload, headers=headers ) as response: - logging.info(f"响应状态: HTTP {response.status_code}") + logging.info(f"响应状态: HTTP {response.status_code}") if response.status_code != 200: # 读取错误信息(非流式) error_content = await response.aread() @@ -1810,7 +1930,32 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload })) return - logging.info("开始处理SSE流") + if tts_model is None: + # 创建TTS实例 + tts_model = QwenTTS( + key=ALI_KEY, + format=payload.get('tts_stream_format', 'mp3'), + sample_rate=payload.get('tts_sample_rate', 48000), + model_name=tts_model_name + ) + streaming_call = False + if tts_model.is_cosyvoice: + streaming_call = True + + # 创建流会话 + tts_stream_session_id = stream_manager.create_session( + tts_model=tts_model, + sample_rate=payload.get('tts_sample_rate', 48000), + stream_format=payload.get('tts_stream_format', 'mp3'), + session_id=None, + streaming_call=streaming_call + ) + # 关键修改:设置TTS会话ID并触发就绪事件 + if combined_state is not None and tts_stream_session_id: + combined_state["tts_session_id"] = tts_stream_session_id + combined_state["tts_ready_event"].set() # 触发事件通知主流程 + + logging.info(f"开始处理SSE流 {tts_stream_session_id}") event_count = 0 # 使用异步迭代器逐行处理 async for line in response.aiter_lines(): @@ -1829,8 +1974,10 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload if isinstance(data_obj, dict) and isinstance(data_obj.get('data', None), dict): delta_text = data_obj.get('data', None).get('delta_ans', "") if tts_stream_session_id_sent is False: - data_obj.get('data')['audio_stream_url'] = f"/tts_stream/{tts_stream_session_id}" - data_str = json.dumps(data_obj) + if tts_stream_session_id and combined_state is None: + logging.info(f"--proxy_aichat_text_stream 发送audio_stream_url") + 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({ @@ -1838,7 +1985,8 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload "data": data_str })) # 这里构建{"type":"text",'data':"data_str"}) 是为了前端websocket进行数据解析 - if delta_text: + if delta_text and tts_stream_session_id: + # 追加到会话管理器 stream_manager.append_text(tts_stream_session_id, delta_text) # logging.info(f"文本代理转发: {data_str}") @@ -1849,13 +1997,16 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload # 保持连接活性 await asyncio.sleep(0.001) # 避免CPU空转 - logging.info(f"SSE流处理完成,事件数: {event_count}") + #logging.info(f"SSE流处理完成,事件数: {event_count}") - # 发送结束信号 - await manager.send_text(client_id, json.dumps({"type": "end"})) + # 发送文本流结束信号 + await manager.send_text(client_id, json.dumps({"type": "AiChatTextEnd"})) + # 标记文本输入结束 + if tts_stream_session_id and stream_manager.finish_text_input: + stream_manager.finish_text_input(tts_stream_session_id) - except httpx.ReadTimeout: - logging.error("读取后端服务超时") + except httpx.ConnectTimeout: + logging.error("后端服务超时") await manager.send_text(client_id, json.dumps({ "type": "error", "message": "后端服务响应超时" @@ -1872,7 +2023,11 @@ async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload "type": "error", "message": f"文本流获取失败: {str(e)}" })) - + finally: + pass + # 记录连接池状态 + #pool_status = await HTTPXConnectionPool.get_pool_status() + #logging.debug(f"连接池状态: {json.dumps(pool_status)}") @tts_router.get("/audio/pcm_mp3") async def stream_mp3(): @@ -1917,6 +2072,7 @@ def generate_silence_header(duration_ms: int = 500) -> bytes: # ------------------------ API路由 ------------------------ + @tts_router.post("/chats/{chat_id}/tts") async def create_tts_request(chat_id: str, request: Request): try: @@ -1964,9 +2120,6 @@ async def create_tts_request(chat_id: str, request: Request): raise HTTPException(500, detail="Internal server error") -executor = ThreadPoolExecutor() - - @tts_router.get("/chats/{chat_id}/tts/{audio_stream_id}") async def get_tts_audio( chat_id: str, @@ -2117,6 +2270,10 @@ async def websocket_tts_endpoint( # 接收 header 参数 headers = websocket.headers service_type = headers.get("x-tts-type") # 注意:header 名称转为小写 + #给H5代码特殊处理,H5代码中,x-tts-type的header不能工作 + # 浏览器内置WebSocket 的连接时不能附加额外的header传递参数 + if audio_stream_id == 'x-tts-type-is-TextToTts': + service_type = 'TextToTts' # audio_url = headers.get("x-audio-url") """ 前端示例 @@ -2146,31 +2303,131 @@ async def websocket_tts_endpoint( # 根据tts_type路由到不同的音频源 if service_type == "AiChatTts": # 音频代理服务 - 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 + await proxy_aichat_audio_stream(connection_id, audio_stream_id, combined_state = None) completed_successfully = True - logging.info(f"--- proxy AiChatTts audio_data_size={audio_data_size}") + elif service_type == "AiChatText": # 文本代理服务 # 等待客户端发送初始请求数据 进行大模型对话代理时,需要前端连接后发送payload payload = await websocket.receive_json() - completions_url = f"http://localhost:9380/api/v1/chats/{chat_id}/completions" - await proxy_aichat_text_stream(connection_id, completions_url, payload) + # 在代理前检查连接池状态 + completions_url = f"http://127.0.0.1:9380/api/v1/chats/{chat_id}/completions" + await proxy_aichat_text_stream(connection_id, completions_url, payload, combined_state = None) completed_successfully = True + elif service_type == "AiChatCombined": + # 接收初始请求数据 + payload = await websocket.receive_json() + + # 创建共享状态和同步事件 + combined_state = { + "tts_session_id": None, + "tts_ready_event": asyncio.Event(), # TTS准备就绪事件 + "audio_task": None, + "text_completed": asyncio.Event(), + "audio_completed": asyncio.Event() + } + + # 启动文本流任务 + text_task = asyncio.create_task( + proxy_aichat_text_stream( + client_id=connection_id, + completions_url=f"http://127.0.0.1:9380/api/v1/chats/{chat_id}/completions", + payload=payload, + combined_state=combined_state + ) + ) + + try: + # 等待TTS会话ID准备就绪(最多等待8秒) + await asyncio.wait_for(combined_state["tts_ready_event"].wait(), timeout=8.0) + + if combined_state["tts_session_id"]: + # 启动音频流任务 + combined_state["audio_task"] = asyncio.create_task( + proxy_aichat_audio_stream( + client_id=connection_id, + audio_stream_id=combined_state["tts_session_id"], + combined_state=combined_state + ) + ) + else: + logging.warning("TTS会话ID未生成,跳过音频流任务") + except asyncio.TimeoutError: + logging.warning("等待TTS会话ID超时,跳过音频流任务") + + # 等待两个任务完成(如果音频任务未启动,text_task会正常完成) + tasks = [text_task] + if combined_state["audio_task"]: + tasks.append(combined_state["audio_task"]) + + done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) + + # 检查任务状态并处理异常 + for task in done: + if task.exception(): + logging.error(f"任务异常: {task.exception()}") + # 发送错误消息给客户端 + await manager.send_text(connection_id, json.dumps({ + "type": "error", + "message": str(task.exception()) + })) + + # 取消任何未完成的任务 + for task in pending: + task.cancel() + + # 发送完成信号 + if manager.is_connected(connection_id): + await manager.send_text(connection_id, json.dumps({"type": "end"})) + logging.info(" websocket_tts_endpoint AiChatCombined completed successfully") + elif service_type == "TextToTts": + # 前端将文本发送到后端,后端调用TTS引擎生成音频流 ,并且将生成音频的文本、生成音频的参数 + # 返回音频,在1个websocket调用中完成 + params_valid = True + payload = await websocket.receive_json() + # 参数校验 + text = payload.get("text", "").strip() + if not text: + params_valid = False + data = payload.get("params", {}) + logging.info(f"websocket_tts_endpoint TextToTts:{text} {data}") + format = data.get("tts_stream_format", "mp3") + if format not in ["mp3", "wav", "pcm"]: + params_valid = False + + sample_rate = data.get("tts_sample_rate", 48000) + if sample_rate not in [8000, 16000, 22050, 44100, 48000]: + params_valid = False + + model_name = data.get("model_name", "cosyvoice-v1/longxiaochun") + delay_gen_audio = data.get('delay_gen_audio', False) + + if params_valid: + # 创建TTS任务 + audio_stream_id = tts_engine.create_tts_task( + text=text, + format=format, + sample_rate=sample_rate, + model_name=model_name, + key=ALI_KEY, + delay_gen_audio=delay_gen_audio + ) + # 使用引擎的生成器直接获取音频流 + audio_data_size = 0 + async for data in tts_engine.get_audio_stream(audio_stream_id): + audio_data_size += len(data) + if not await manager.send_bytes(connection_id, data): + logging.warning(f"Send failed, connection closed: {connection_id}") + break + await manager.send_json(connection_id, {"command": "sentence_end"}) + logging.info(f"websocket_tts_endpoint TextToTts completed successfully {audio_data_size} bytes") else: # 使用引擎的生成器直接获取音频流 async for data in tts_engine.get_audio_stream(audio_stream_id): if not await manager.send_bytes(connection_id, data): logging.warning(f"Send failed, connection closed: {connection_id}") break - + await manager.send_json(connection_id, {"command": "sentence_end"}) completed_successfully = True # 发送完成信号前检查连接状态 @@ -2184,9 +2441,9 @@ async def websocket_tts_endpoint( # 主动关闭WebSocket连接 await manager.disconnect(connection_id, code=1000, reason="Audio stream completed") except WebSocketDisconnect: - logging.info(f"WebSocket disconnected: {connection_id}") + logging.info(f"websocket_tts_endpoint WebSocket disconnected: {connection_id}") except Exception as e: - logging.error(f"WebSocket TTS error: {str(e)}") + logging.error(f"websocket_tts_endpoint WebSocket TTS error: {str(e)}") if manager.is_connected(connection_id): await manager.send_json(connection_id, {"error": str(e)}) finally: @@ -2194,15 +2451,17 @@ async def websocket_tts_endpoint( # await manager.disconnect(connection_id) -def cleanup_cache(): - """清理过期缓存""" - with cache_lock: - now = datetime.datetime.now() - expired = [k for k, v in audio_text_cache.items() - if (now - v["created_at"]).total_seconds() > CACHE_EXPIRE_SECONDS] - for key in expired: - logging.info(f"del audio_text_cache= {audio_text_cache[key]}") - del audio_text_cache[key] +@tts_router.get("/debug/get_threadpool") +async def get_threadpool(request: Request): + params = dict(request.query_params) + if params.get('reset'): + stream_manager.reset_manager() + + return JSONResponse( + status_code=200, + content={ + "status":stream_manager.get_self_thread_pool_status() + } + ) + -# 应用启动时启动清理线程 -# start_background_cleaner() diff --git a/asr-monitor-test/bk/tts_service.py b/asr-monitor-test/bk/tts_service.py new file mode 100644 index 00000000..e2531863 --- /dev/null +++ b/asr-monitor-test/bk/tts_service.py @@ -0,0 +1,2328 @@ +import logging +import binascii +from copy import deepcopy +from timeit import default_timer as timer +import datetime +from datetime import timedelta +import threading, time, queue, uuid, time, array +from threading import Lock, Thread +from concurrent.futures import ThreadPoolExecutor +import base64, gzip +import os, io, re, json +from io import BytesIO +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 + +TTS_SAMPLERATE = 44100 # 22050 # 16000 +FORMAT = "mp3" +CHANNELS = 1 # 单声道 +SAMPLE_WIDTH = 2 # 16-bit = 2字节 + +tts_router = APIRouter() + + +# logger = logging.getLogger(__name__) +class MillisecondsFormatter(logging.Formatter): + """自定义日志格式器,添加毫秒时间戳""" + + def formatTime(self, record, datefmt=None): + # 将时间戳转换为本地时间元组 + ct = self.converter(record.created) + # 格式化为 "小时:分钟:秒" + t = time.strftime("%H:%M:%S", ct) + # 添加毫秒(3位) + return f"{t}.{int(record.msecs):03d}" + + +# 配置全局日志格式 +def configure_logging(): + # 创建 Formatter + log_format = "%(asctime)s - %(levelname)s - %(message)s" + formatter = MillisecondsFormatter(log_format) + + # 获取根 Logger 并清除已有配置 + root_logger = logging.getLogger() + root_logger.handlers = [] + + # 创建并配置 Handler(输出到控制台) + console_handler = logging.StreamHandler() + console_handler.setFormatter(formatter) + + # 设置日志级别并添加 Handler + root_logger.setLevel(logging.INFO) + root_logger.addHandler(console_handler) + + +# 调用配置函数(程序启动时运行一次) +configure_logging() + + +class StreamSessionManager: + 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分钟清理一次 + self.streaming_call_timeout = 10 # 10s + self.gc_tts = 3 # 3s + self.sentence_timeout = 2 # 2000ms句子超时 + self.sentence_endings = set('。?!;.?!;') # 中英文结束符 + # 增强版正则表达式:匹配中英文句子结束符(包含全角) + self.sentence_pattern = re.compile( + r'([,,。?!;.?!;?!;…]+["\'”’]?)(?=\s|$|[^,,。?!;.?!;?!;…])' + ) + self.sentence_audio_store = {} # {sentence_id: {'data': bytes, 'text': str, 'created_at': float}} + self.sentence_lock = threading.Lock() + + threading.Thread(target=self._cleanup_expired, daemon=True).start() + + def create_session(self, tts_model, sample_rate=8000, stream_format='mp3', session_id=None, streaming_call=False): + if not session_id: + session_id = str(uuid.uuid4()) + with self.lock: + # 创建TTS实例并设置流式回调 + tts_instance = tts_model + + # 定义音频数据回调函数 + def on_data(data: bytes): + if data: + 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,completion_event) + # 创建会话 + 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, + 'audio_chunk_size': 0, + 'finished': threading.Event(), # 添加事件对象 + 'sample_rate': sample_rate, + 'stream_format': stream_format, + "tts_chunk_data_valid": False, + "text_buffer": "", # 新增文本缓冲区 + "last_text_time": time.time(), # 最后文本到达时间 + "streaming_call": streaming_call, + "tts_stream_started": False, # 标记是否已启动流 + "current_processing": False, # 标记是否正在处理句子 + "sentence_complete_event": completion_event, #threading.Event(), + 'sentences': [], # 存储句子ID列表 + 'current_sentence_index': 0, + 'gc_interval':300, # 5分钟清理一次 + } + # 启动任务处理线程 + 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 + # 更新文本缓冲区和时间戳 + session['text_buffer'] += text + session['last_text_time'] = time.time() + # 将文本放入任务队列(非阻塞) + try: + session['task_queue'].put(text, block=False) + except queue.Full: + logging.warning(f"Session {session_id} task queue full") + + def finish_text_input(self, session_id): + """标记文本输入结束,通知任务处理线程""" + with self.lock: + session = self.sessions.get(session_id) + if not session: + return + session['gc_interval'] = 100 # 所有的文本输入已经结束,可以将超时检查时间缩短 + + + 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._generate_audio #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['current_processing'] = True + + # 生成音频 + gen_tts_audio_func(session_id, combined_text) #如果调用_stream_audio,则是同步调用,会阻塞,直到音频生成完成 + + # 重置处理状态 + time.sleep(1.0) + session['current_processing'] = False + + + # 3. 检查超时未处理的文本 + if current_time - session['last_text_time'] > self.sentence_timeout: + with self.lock: + if session['text_buffer']: + # 直接处理剩余文本 + session['current_processing'] = True + gen_tts_audio_func(session_id, session['text_buffer']) + session['text_buffer'] = "" + # 重置处理状态 + session['current_processing'] = False + + # 4. 会话超时检查 + if current_time - session['last_active'] > session['gc_interval']: + # 处理剩余文本 + with self.lock: + if session['text_buffer']: + session['current_processing'] = True + + # 处理最后一段文本 + gen_tts_audio_func(session_id, session['text_buffer']) + session['text_buffer'] = "" + # 重置处理状态 + session['current_processing'] = False + + # 关闭会话 + logging.info(f"--_process_tasks-- timeout {session['last_active']} {session['gc_interval']}") + self.close_session(session_id) + break + + # 5. 休眠避免CPU空转 + time.sleep(0.05) # 50ms检查间隔 + + + 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}") + # 创建内存流 + audio_stream = io.BytesIO() + + # 定义回调函数:直接写入流 + def on_data_sentence(data: bytes): + if data: + audio_stream.write(data) + + def on_data_whole(data: bytes): + if data: + try: + session['last_active'] = time.time() + session['buffer'].put({'type':'arraybuffer','data':data}) + #session['buffer'].put(data) + session['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}") + + # 重置完成事件 + session['sentence_complete_event'].clear() + session['tts_model'].setup_tts(on_data = on_data_whole,completion_event=session['sentence_complete_event']) + # 调用 TTS + session['tts_model'].text_tts_call(text) + session['last_active'] = time.time() + session['audio_chunk_count'] += 1 + # 等待句子完成 + if not session['sentence_complete_event'].wait(timeout=30): # 30秒超时 + logging.warning(f"Timeout generating audio for: {text[:20]}...") + logging.info(f"StreamSessionManager _generate_audio 转换结束!!!") + session['buffer'].put({'type': 'sentence_end', 'data': ""}) + + # 获取音频数据 + audio_data = audio_stream.getvalue() + audio_stream.close() + + # 保存到句子存储 + self.add_sentence_audio(session_id, text, audio_data) + + 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) + if not session: + return + # logging.info(f"Streaming text to TTS: {text}") + + try: + # 重置完成事件状态 + session['sentence_complete_event'].clear() + # 使用流式调用发送文本 + 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 秒超时)""" + session = self.sessions.get(session_id) + if not session: + raise ValueError(f"Session {session_id} not found") + + buffer = session['buffer'] # 这里是 queue.Queue + last_data_time = time.time() # 记录最后一次获取数据的时间 + + while session['active']: + try: + # 使用 run_in_executor + wait_for 设置 10 秒超时 + data = await asyncio.wait_for( + asyncio.get_event_loop().run_in_executor(None, buffer.get), + timeout=10.0 # 10 秒超时 + ) + #logging.info(f"get_tts_buffer_data {data}") + last_data_time = time.time() # 更新最后数据时间 + yield data + + except asyncio.TimeoutError: + # 10 秒内没有新数据,检查是否超时 + if time.time() - last_data_time >= 10.0: + break + else: + continue # 未超时,继续等待 + + except asyncio.CancelledError: + logging.info(f"Session {session_id} stream cancelled") + break + + except Exception as e: + logging.error(f"Error in get_tts_buffer_data: {e}") + break + + def close_session(self, session_id): + with self.lock: + if session_id in self.sessions: + session = self.sessions[session_id] + session['active'] = False + + # 清理关联的音频数据 + with self.sentence_lock: + # 标记会话相关的句子为过期 + expired_sentences = [ + sid for sid, data in self.sentence_audio_store.items() + if data.get('session_id') == session_id + ] + + # 设置完成事件 + session['sentence_complete_event'].set() + + # 清理TTS资源 + try: + if session.get('streaming_call'): + session['tts_model'].end_streaming_call() + except: + pass + + # 延迟清理会话 + 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 _cleanup_expired(self): + """定时清理过期资源""" + while True: + time.sleep(30) + now = time.time() + + # 清理过期会话 + with self.lock: + expired_sessions = [ + sid for sid, session in self.sessions.items() + if now - session['last_active'] > self.gc_interval + ] + for sid in expired_sessions: + self._clean_session(sid) + + # 清理过期句子音频 + with self.sentence_lock: + expired_sentences = [ + sid for sid, data in self.sentence_audio_store.items() + if now - data['created_at'] > self.gc_interval + ] + for sid in expired_sentences: + del self.sentence_audio_store[sid] + + logging.info(f"清理资源: {len(expired_sessions)}会话, {len(expired_sentences)}句子") + + def get_session(self, session_id): + return self.sessions.get(session_id) + + def _has_sentence_ending(self, text): + """检测文本是否包含句子结束符""" + if not text: + return False + + # 检查常见结束符(包含全角字符) + if any(char in self.sentence_endings for char in text[-3:]): + return True + + # 检查中文段落结束(换行符前有结束符) + if '\n' in text and any(char in self.sentence_endings for char in text.split('\n')[-2:-1]): + return True + + return False + + def _split_and_extract(self, text): + """ + 增强型句子分割器 + 返回: (完整句子列表, 剩余文本) + """ + # 特殊处理:如果文本以逗号开头,先处理前面的部分 + if text.startswith((",", ",")): + return [text[0]], text[1:] + + # 1. 查找所有可能的句子结束位置 + matches = list(self.sentence_pattern.finditer(text)) + + if not matches: + return [], text # 没有找到结束符 + + # 2. 确定最后一个完整句子的结束位置 + last_end = 0 + complete_sentences = [] + + for match in matches: + end_pos = match.end() + sentence = text[last_end:end_pos].strip() + + # 跳过空句子 + if not sentence: + last_end = end_pos + continue + + # 检查是否为有效句子(最小长度或包含结束符) + if (len(sentence) > 6 or any(char in "。.?!?!" for char in sentence)) and (last_end<24): + complete_sentences.append(sentence) + last_end = end_pos + else: + # 短文本但包含结束符,可能是特殊符号 + if any(char in "。.?!?!" for char in sentence): + complete_sentences.append(sentence) + last_end = end_pos + + # 3. 提取剩余文本 + remaining_text = text[last_end:].strip() + return complete_sentences, remaining_text + + def add_sentence_audio(self, session_id, sentence_text, audio_data: bytes): + """添加句子音频到存储""" + with self.lock: + if session_id not in self.sessions: + return None + + # 生成唯一句子ID + sentence_id = str(uuid.uuid4()) + + # 存储音频数据 + with self.sentence_lock: + self.sentence_audio_store[sentence_id] = { + 'data': audio_data, + 'text': sentence_text, + 'created_at': time.time(), + 'session_id': session_id, + 'format': self.sessions[session_id]['stream_format'] + } + logging.info(f" StreamSessionManager add_sentence_audio") + # 添加到会话的句子列表 + self.sessions[session_id]['sentences'].append(sentence_id) + + return sentence_id + + def get_sentence_audio(self, sentence_id): + """获取句子音频数据""" + with self.sentence_lock: + if sentence_id not in self.sentence_audio_store: + return None + return self.sentence_audio_store[sentence_id]['data'] + + def get_sentence_info(self, sentence_id): + """获取句子信息""" + with self.sentence_lock: + if sentence_id not in self.sentence_audio_store: + return None + return self.sentence_audio_store[sentence_id] + + def get_next_sentence(self, session_id): + """获取下一个句子的信息""" + with self.lock: + session = self.sessions.get(session_id) + if not session or not session['active']: + return None + + if session['current_sentence_index'] < len(session['sentences']): + sentence_id = session['sentences'][session['current_sentence_index']] + session['current_sentence_index'] += 1 + return { + 'id': sentence_id, + 'url': f"/tts_sentence/{sentence_id}" # 虚拟URL + } + return None + def get_sentence_audio_data(self, session_id): + with self.lock: + session = self.sessions.get(session_id) + if not session or not session['active']: + return None + return self.sentence_audio_store + +stream_manager = StreamSessionManager() + + +def allowed_file(filename): + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in {'png', 'jpg', 'jpeg', 'gif'} + + +audio_text_cache = {} +cache_lock = Lock() +CACHE_EXPIRE_SECONDS = 600 # 10分钟过期 + + +# WebSocket 连接管理 +class ConnectionManager: + def __init__(self): + self.active_connections = {} + + async def connect(self, websocket: WebSocket, connection_id: str): + await websocket.accept() + self.active_connections[connection_id] = websocket + logging.info(f"新连接建立: {connection_id}") + + async def disconnect(self, connection_id: str, code=1000, reason: str = ""): + if connection_id in self.active_connections: + try: + # 尝试正常关闭连接(非阻塞) + await self.active_connections[connection_id].close(code=code, reason=reason) + except: + pass # 忽略关闭错误 + finally: + del self.active_connections[connection_id] + + def is_connected(self, connection_id: str) -> bool: + """检查连接是否仍然活跃""" + return connection_id in self.active_connections + + async def _safe_send(self, connection_id: str, send_func, *args): + """安全发送的通用方法(核心修改)""" + # 1. 检查连接是否存在 + if connection_id not in self.active_connections: + logging.warning(f"尝试向不存在的连接发送数据: {connection_id}") + return False + + websocket = self.active_connections[connection_id] + + try: + # 2. 检查连接状态(关键修改) + if websocket.client_state.name != "CONNECTED": + logging.warning(f"连接 {connection_id} 状态为 {websocket.client_state.name}") + await self.disconnect(connection_id) + return False + + # 3. 执行发送操作 + await send_func(websocket, *args) + return True + + except (WebSocketDisconnect, RuntimeError) as e: + # 4. 处理连接断开异常 + logging.info(f"发送时检测到断开连接: {connection_id}, {str(e)}") + await self.disconnect(connection_id) + return False + except Exception as e: + # 5. 处理其他异常 + logging.error(f"发送数据出错: {connection_id}, {str(e)}") + await self.disconnect(connection_id) + return False + + async def send_bytes(self, connection_id: str, data: bytes): + """安全发送字节数据""" + return await self._safe_send( + connection_id, + lambda ws, d: ws.send_bytes(d), + data + ) + + async def send_text(self, connection_id: str, message: str): + """安全发送文本数据""" + return await self._safe_send( + connection_id, + lambda ws, m: ws.send_text(m), + message + ) + + async def send_json(self, connection_id: str, data: dict): + """安全发送JSON数据""" + return await self._safe_send( + connection_id, + lambda ws, d: ws.send_json(d), + data + ) + + +manager = ConnectionManager() + + +def generate_mp3_header( + sample_rate: int, + bitrate_kbps: int, + channels: int = 1, + layer: str = "III" # 新增参数,支持 "I"/"II"/"III" +) -> bytes: + """ + 动态生成 MP3 帧头(4字节),支持 Layer I/II/III + + :param sample_rate: 采样率 (8000, 16000, 22050, 44100) + :param bitrate_kbps: 比特率(单位 kbps) + :param channels: 声道数 (1: 单声道, 2: 立体声) + :param layer: 编码层 ("I", "II", "III") + :return: 4字节的帧头数据 + """ + # ---------------------------------- + # 参数校验 + # ---------------------------------- + valid_sample_rates = {8000, 16000, 22050, 44100, 48000} + if sample_rate not in valid_sample_rates: + raise ValueError(f"不支持的采样率,可选:{valid_sample_rates}") + + valid_layers = {"I", "II", "III"} + if layer not in valid_layers: + raise ValueError(f"不支持的层,可选:{valid_layers}") + + # ---------------------------------- + # 确定 MPEG 版本和采样率索引 + # ---------------------------------- + if sample_rate == 44100: + mpeg_version = 0b11 # MPEG-1 + sample_rate_index = 0b00 + elif sample_rate == 22050: + mpeg_version = 0b10 # MPEG-2 + sample_rate_index = 0b00 + elif sample_rate == 16000: + mpeg_version = 0b10 # MPEG-2 + sample_rate_index = 0b10 + elif sample_rate == 8000: + mpeg_version = 0b00 # MPEG-2.5 + sample_rate_index = 0b10 + else: + raise ValueError("采样率与版本不匹配") + + # ---------------------------------- + # 动态选择比特率表(关键扩展) + # ---------------------------------- + # Layer 编码映射(I:0b11, II:0b10, III:0b01) + layer_code = { + "I": 0b11, + "II": 0b10, + "III": 0b01 + }[layer] + + # 比特率表(覆盖所有 Layer) + bitrate_tables = { + # ------------------------------- + # MPEG-1 (0b11) + # ------------------------------- + # Layer I + (0b11, 0b11): { + 32: 0b0000, 64: 0b0001, 96: 0b0010, 128: 0b0011, + 160: 0b0100, 192: 0b0101, 224: 0b0110, 256: 0b0111, + 288: 0b1000, 320: 0b1001, 352: 0b1010, 384: 0b1011, + 416: 0b1100, 448: 0b1101 + }, + # Layer II + (0b11, 0b10): { + 32: 0b0000, 48: 0b0001, 56: 0b0010, 64: 0b0011, + 80: 0b0100, 96: 0b0101, 112: 0b0110, 128: 0b0111, + 160: 0b1000, 192: 0b1001, 224: 0b1010, 256: 0b1011, + 320: 0b1100, 384: 0b1101 + }, + # Layer III + (0b11, 0b01): { + 32: 0b1000, 40: 0b1001, 48: 0b1010, 56: 0b1011, + 64: 0b1100, 80: 0b1101, 96: 0b1110, 112: 0b1111, + 128: 0b0000, 160: 0b0001, 192: 0b0010, 224: 0b0011, + 256: 0b0100, 320: 0b0101 + }, + + # ------------------------------- + # MPEG-2 (0b10) / MPEG-2.5 (0b00) + # ------------------------------- + # Layer I + (0b10, 0b11): { + 32: 0b0000, 48: 0b0001, 56: 0b0010, 64: 0b0011, + 80: 0b0100, 96: 0b0101, 112: 0b0110, 128: 0b0111, + 144: 0b1000, 160: 0b1001, 176: 0b1010, 192: 0b1011, + 224: 0b1100, 256: 0b1101 + }, + (0b00, 0b11): { + 32: 0b0000, 48: 0b0001, 56: 0b0010, 64: 0b0011, + 80: 0b0100, 96: 0b0101, 112: 0b0110, 128: 0b0111, + 144: 0b1000, 160: 0b1001, 176: 0b1010, 192: 0b1011, + 224: 0b1100, 256: 0b1101 + }, + + # Layer II + (0b10, 0b10): { + 8: 0b0000, 16: 0b0001, 24: 0b0010, 32: 0b0011, + 40: 0b0100, 48: 0b0101, 56: 0b0110, 64: 0b0111, + 80: 0b1000, 96: 0b1001, 112: 0b1010, 128: 0b1011, + 144: 0b1100, 160: 0b1101 + }, + (0b00, 0b10): { + 8: 0b0000, 16: 0b0001, 24: 0b0010, 32: 0b0011, + 40: 0b0100, 48: 0b0101, 56: 0b0110, 64: 0b0111, + 80: 0b1000, 96: 0b1001, 112: 0b1010, 128: 0b1011, + 144: 0b1100, 160: 0b1101 + }, + + # Layer III + (0b10, 0b01): { + 8: 0b1000, 16: 0b1001, 24: 0b1010, 32: 0b1011, + 40: 0b1100, 48: 0b1101, 56: 0b1110, 64: 0b1111, + 80: 0b0000, 96: 0b0001, 112: 0b0010, 128: 0b0011, + 144: 0b0100, 160: 0b0101 + }, + (0b00, 0b01): { + 8: 0b1000, 16: 0b1001, 24: 0b1010, 32: 0b1011, + 40: 0b1100, 48: 0b1101, 56: 0b1110, 64: 0b1111 + } + } + + # 获取当前版本的比特率表 + key = (mpeg_version, layer_code) + if key not in bitrate_tables: + raise ValueError(f"不支持的版本和层组合: MPEG={mpeg_version}, Layer={layer}") + bitrate_table = bitrate_tables[key] + + if bitrate_kbps not in bitrate_table: + raise ValueError(f"不支持的比特率,可选:{list(bitrate_table.keys())}") + bitrate_index = bitrate_table[bitrate_kbps] + + # ---------------------------------- + # 确定声道模式 + # ---------------------------------- + if channels == 1: + channel_mode = 0b11 # 单声道 + elif channels == 2: + channel_mode = 0b00 # 立体声 + else: + raise ValueError("声道数必须为1或2") + + # ---------------------------------- + # 组合帧头字段(修正层编码) + # ---------------------------------- + sync = 0x7FF << 21 # 同步字 11位 (0x7FF = 0b11111111111) + version = mpeg_version << 19 # MPEG 版本 2位 + layer_bits = layer_code << 17 # Layer 编码(I:0b11, II:0b10, III:0b01) + protection = 0 << 16 # 无 CRC + bitrate_bits = bitrate_index << 12 + sample_rate_bits = sample_rate_index << 10 + padding = 0 << 9 # 无填充 + private = 0 << 8 + mode = channel_mode << 6 + mode_ext = 0 << 4 # 扩展模式(单声道无需设置) + copyright = 0 << 3 + original = 0 << 2 + emphasis = 0b00 # 无强调 + + frame_header = ( + sync | + version | + layer_bits | + protection | + bitrate_bits | + sample_rate_bits | + padding | + private | + mode | + mode_ext | + copyright | + original | + emphasis + ) + + return frame_header.to_bytes(4, byteorder='big') + + +# ------------------------------------------------ +def audio_fade_in(audio_data, fade_length): + # 假设音频数据是16位单声道PCM + # 将二进制数据转换为整数数组 + samples = array.array('h', audio_data) + + # 对前fade_length个样本进行淡入处理 + for i in range(fade_length): + fade_factor = i / fade_length + samples[i] = int(samples[i] * fade_factor) + + # 将整数数组转换回二进制数据 + return samples.tobytes() + + +def parse_markdown_json(json_string): + # 使用正则表达式匹配Markdown中的JSON代码块 + match = re.search(r'```json\n(.*?)\n```', json_string, re.DOTALL) + if match: + try: + # 尝试解析JSON字符串 + data = json.loads(match[1]) + return {'success': True, 'data': data} + except json.JSONDecodeError as e: + # 如果解析失败,返回错误信息 + return {'success': False, 'data': str(e)} + else: + return {'success': False, 'data': 'not a valid markdown json string'} + + +audio_text_cache = {} +cache_lock = Lock() +CACHE_EXPIRE_SECONDS = 600 # 10分钟过期 + + +# 全角字符到半角字符的映射 +def fullwidth_to_halfwidth(s): + full_to_half_map = { + '!': '!', '"': '"', '#': '#', '$': '$', '%': '%', '&': '&', ''': "'", + '(': '(', ')': ')', '*': '*', '+': '+', ',': ',', '-': '-', '.': '.', + '/': '/', ':': ':', ';': ';', '<': '<', '=': '=', '>': '>', '?': '?', + '@': '@', '[': '[', '\': '\\', ']': ']', '^': '^', '_': '_', '`': '`', + '{': '{', '|': '|', '}': '}', '~': '~', '⦅': '⦅', '⦆': '⦆', '「': '「', + '」': '」', '、': ',', '・': '.', 'ー': '-', '。': '.', '「': '「', '」': '」', + '、': '、', '・': '・', ':': ':' + } + return ''.join(full_to_half_map.get(char, char) for char in s) + + +def split_text_at_punctuation(text, chunk_size=100): + # 使用正则表达式找到所有的标点符号和特殊字符 + punctuation_pattern = r'[\s,.!?;:\-\—\(\)\[\]{}"\'\\\/]+' + tokens = re.split(punctuation_pattern, text) + + # 移除空字符串 + tokens = [token for token in tokens if token] + + # 存储最终的文本块 + chunks = [] + current_chunk = '' + + for token in tokens: + if len(current_chunk) + len(token) <= chunk_size: + # 如果添加当前token后长度不超过chunk_size,则添加到当前块 + current_chunk += (token + ' ') + else: + # 如果长度超过chunk_size,则将当前块添加到chunks列表,并开始新块 + chunks.append(current_chunk.strip()) + current_chunk = token + ' ' + + # 添加最后一个块(如果有剩余) + if current_chunk: + chunks.append(current_chunk.strip()) + + return chunks + + +def extract_text_from_markdown(markdown_text): + # 移除Markdown标题 + text = re.sub(r'#\s*[^#]+', '', markdown_text) + # 移除内联代码块 + text = re.sub(r'`[^`]+`', '', text) + # 移除代码块 + text = re.sub(r'```[\s\S]*?```', '', text) + # 移除加粗和斜体 + text = re.sub(r'[*_]{1,3}(?=\S)(.*?\S[*_]{1,3})', '', text) + # 移除链接 + text = re.sub(r'\[.*?\]\(.*?\)', '', text) + # 移除图片 + text = re.sub(r'!\[.*?\]\(.*?\)', '', text) + # 移除HTML标签 + text = re.sub(r'<[^>]+>', '', text) + # 转换标点符号 + # text = re.sub(r'[^\w\s]', '', text) + text = fullwidth_to_halfwidth(text) + # 移除多余的空格 + text = re.sub(r'\s+', ' ', text).strip() + + return text + + +def encode_gzip_base64(original_data: bytes) -> str: + """核心编码过程:二进制数据 → Gzip压缩 → Base64编码""" + # Step 1: Gzip 压缩 + with BytesIO() as buf: + with gzip.GzipFile(fileobj=buf, mode='wb') as gz_file: + gz_file.write(original_data) + compressed_bytes = buf.getvalue() + + # Step 2: Base64 编码(配置与Android端匹配) + return base64.b64encode(compressed_bytes).decode('utf-8') # 默认不带换行符(等同于Android的Base64.NO_WRAP) + + +def clean_audio_cache(): + """定时清理过期缓存""" + with cache_lock: + now = time.time() + expired_keys = [ + k for k, v in audio_text_cache.items() + if now - v['created_at'] > CACHE_EXPIRE_SECONDS + ] + for k in expired_keys: + entry = audio_text_cache.pop(k, None) + if entry and entry.get('audio_stream'): + entry['audio_stream'].close() + + +def start_background_cleaner(): + """启动后台清理线程""" + + def cleaner_loop(): + while True: + time.sleep(180) # 每3分钟清理一次 + clean_audio_cache() + + cleaner_thread = Thread(target=cleaner_loop, daemon=True) + cleaner_thread.start() + + +def test_qwen_chat(): + messages = [ + {'role': 'system', 'content': 'You are a helpful assistant.'}, + {'role': 'user', 'content': '你是谁?'} + ] + response = Generation.call( + # 若没有配置环境变量,请用百炼API Key将下行替换为:api_key = "sk-xxx", + api_key=ALI_KEY, + model="qwen-plus", # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models + messages=messages, + result_format="message" + ) + + if response.status_code == 200: + print(response.output.choices[0].message.content) + else: + print(f"HTTP返回码:{response.status_code}") + print(f"错误码:{response.code}") + print(f"错误信息:{response.message}") + print("请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code") + + +ALI_KEY = "sk-a47a3fb5f4a94f66bbaf713779101c75" +from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse +from dashscope.audio.tts import ( + ResultCallback as TTSResultCallback, + SpeechSynthesizer as TTSSpeechSynthesizer, + SpeechSynthesisResult as TTSSpeechSynthesisResult, +) +# cyx 2025 01 19 测试cosyvoice 使用tts_v2 版本 +from dashscope.audio.tts_v2 import ( + ResultCallback as CosyResultCallback, + SpeechSynthesizer as CosySpeechSynthesizer, + AudioFormat, +) + + +class QwenTTS: + 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 + self.model_name = model_name.split('@')[0] + dashscope.api_key = key + ssl._create_default_https_context = ssl._create_unverified_context # 禁用验证 + self.synthesizer = None + self.callback = None + self.is_cosyvoice = False + self.voice = "" + self.format = format + self.sample_rate = sample_rate + self.first_chunk = True + if '/' in self.model_name: + parts = self.model_name.split('/', 1) + # 返回分离后的两个字符串parts[0], parts[1] + 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,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: + time.sleep(0) + continue + val = self.dque.popleft() + if val: + yield val + else: + break + + def on_open(self): + pass + + def on_complete(self): + 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)) + raise RuntimeError(str(response)) + + def on_close(self): + pass + + def on_event(self, result: TTSSpeechSynthesisResult): + 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,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: + time.sleep(0) + continue + val = self.dque.popleft() + if val: + yield val + else: + break + + def on_open(self): + logging.info("Qwen CosyVoice tts open ") + pass + + def on_complete(self): + 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)) + if self.data_callback: + self.data_callback(f"ERROR:{str(response)}".encode()) + raise RuntimeError(str(response)) + + def on_close(self): + # print("---Qwen call back close") # cyx + logging.info("Qwen CosyVoice 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): + # logging.info(f"recv speech synthsis message {message}") + pass + + # 以下适合语音大模型CosyVoice + def on_data(self, data: bytes) -> None: + if len(data) > 0: + if self.data_callback: + self.data_callback(data) + else: + self.dque.append(data) + + # -------------------------- + + 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( + data_callback=on_data, + completion_event=completion_event + ) + TTSSpeechSynthesizer.call(model=self.model_name, + text=text, + callback=self.callback, + 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-v2', + # 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 + # ----------------------------------- + try: + for data in self.callback._run(): + # logging.info(f"dashcope return data {len(data)}") + yield data + # 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 setup_tts(self, on_data,completion_event=None): + + """设置 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) + + + if self.is_cosyvoice: + format_val = self.get_audio_format(self.format, self.sample_rate) + # logging.info(f"Qwen setup_tts {self.voice} {format_val}") + self.synthesizer = CosySpeechSynthesizer( + model='cosyvoice-v1', + voice=self.voice, # voice="longyuan", #"longfei", + callback=self.callback, + format=format_val + ) + + return self.synthesizer + + def apply_phoneme_tags(self, text: str) -> str: + """ + 在文本中查找特殊字符并用标签包裹它们 + """ + # 如果文本已经是SSML格式,直接返回 + if text.strip().startswith("") and text.strip().endswith(""): + return text + + # 为特殊字符添加SSML标签 + for char, pinyin in self.special_characters.items(): + # 使用正则表达式确保只替换整个字符(避免部分匹配) + pattern = r'([^<]|^)' + re.escape(char) + r'([^>]|$)' + replacement = r'\1' + char + r'\2' + text = re.sub(pattern, replacement, text) + + # 如果文本中已有SSML标签,直接返回 + if "" in text: + return text + + # 否则包裹在标签中 + return f"{text}" + + def text_tts_call(self, text): + if self.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: + logging.info(f"Qwen text_tts_call {text} {self.is_cosyvoice}") + format_val = self.get_audio_format(self.format, self.sample_rate) + self.synthesizer = CosySpeechSynthesizer( + model='cosyvoice-v1', + voice=self.voice, # voice="longyuan", #"longfei", + callback=self.callback, + format=format_val + ) + 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: + self.synthesizer.streaming_call(text) + + def end_streaming_call(self): + if self.synthesizer: + # logging.info(f"---dale end_streaming_call") + self.synthesizer.streaming_complete() + + 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, + (48000, 'mp3'): AudioFormat.MP3_48000HZ_MONO_256KBPS, + (48000, 'pcm'): AudioFormat.PCM_48000HZ_MONO_16BIT, + (48000, 'wav'): AudioFormat.WAV_48000HZ_MONO_16BIT + + } + return format_map.get((sample_rate, format), AudioFormat.MP3_16000HZ_MONO_128KBPS) + + +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)}") + + 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: + def __init__(self): + self.lock = threading.Lock() + self.tasks = {} + self.executor = ThreadPoolExecutor(max_workers=10) + self.cache_expire = 300 # 5分钟缓存 + # 启动清理过期任务的定时器 + self.cleanup_timer = None + self.start_cleanup_timer() + + def _cleanup_old_tasks(self): + """清理过期任务""" + now = time.time() + with self.lock: + expired_ids = [task_id for task_id, task in self.tasks.items() + if now - task['created_at'] > self.cache_expire] + for task_id in expired_ids: + self._remove_task(task_id) + + def _remove_task(self, task_id): + """移除任务""" + if task_id in self.tasks: + task = self.tasks.pop(task_id) + # 取消可能的后台任务 + if 'future' in task and not task['future'].done(): + task['future'].cancel() + # 其他资源在任务被移除后会被垃圾回收 + # 资源释放机制总结: + # 移除任务引用:self.tasks.pop() 解除任务对象引用,触发垃圾回收。 + # 取消后台线程:future.cancel() 终止未完成线程,释放线程资源。 + # 自动内存回收:Python GC 回收任务对象及其队列、缓冲区占用的内存。 + # 线程池管理:执行器自动回收线程至池中,避免资源泄漏。 + + def create_tts_task(self, text, format, sample_rate, model_name, key, delay_gen_audio=False): + """创建TTS任务(同步方法)""" + self._cleanup_old_tasks() + audio_stream_id = str(uuid.uuid4()) + + # 创建任务数据结构 + task_data = { + 'id': audio_stream_id, + 'text': text, + 'format': format, + 'sample_rate': sample_rate, + 'model_name': model_name, + 'key': key, + 'delay_gen_audio': delay_gen_audio, + 'created_at': time.time(), + 'status': 'pending', + 'data_queue': deque(), + 'event': threading.Event(), + 'completed': False, + 'error': None + } + with self.lock: + self.tasks[audio_stream_id] = task_data + + # 如果不是延迟模式,立即启动任务 + if not delay_gen_audio: + self._start_tts_task(audio_stream_id) + + return audio_stream_id + + def _start_tts_task(self, audio_stream_id): + # 启动TTS任务(后台线程) + + task = self.tasks.get(audio_stream_id) + if not task or task['status'] != 'pending': + return + logging.info("已经启动 start tts task {audio_stream_id}") + task['status'] = 'processing' + + # 在后台线程中执行TTS + future = self.executor.submit(self._run_tts_sync, audio_stream_id) + task['future'] = future + + # 如果需要等待任务完成 + if not task.get('delay_gen_audio', True): + try: + # 等待任务完成(最多5分钟) + future.result(timeout=300) + logging.info(f"TTS任务 {audio_stream_id} 已完成") + self._merge_audio_data(audio_stream_id) + except concurrent.futures.TimeoutError: + task['error'] = "TTS生成超时" + task['completed'] = True + logging.error(f"TTS任务 {audio_stream_id} 超时") + except Exception as e: + task['error'] = f"ERROR:{str(e)}" + task['completed'] = True + logging.exception(f"TTS任务执行异常: {str(e)}") + + def _run_tts_sync(self, audio_stream_id): + # 同步执行TTS生成 在后台线程中执行 + task = self.tasks.get(audio_stream_id) + if not task: + return + + try: + # 创建完成事件 + completion_event = threading.Event() + # 创建TTS实例 + # 根据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): + if data is None: # 结束信号 + task['completed'] = True + task['event'].set() + logging.info(f"--data_handler on_complete") + elif data.startswith(b"ERROR"): # 错误信号 + task['error'] = data.decode() + task['completed'] = True + task['event'].set() + else: # 音频数据 + task['data_queue'].append(data) + + + # 设置并执行TTS + synthesizer = tts.setup_tts(data_handler,completion_event) + #synthesizer.call(task['text']) + tts.text_tts_call(task['text']) + # 等待完成或超时 + # 等待完成或超时 + 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缓冲区""" + task = self.tasks.get(audio_stream_id) + if not task or not task.get('completed'): + return + + try: + logging.info(f"开始合并音频数据: {audio_stream_id}") + + # 创建内存缓冲区 + buffer = io.BytesIO() + + # 合并所有数据块 + for data_chunk in task['data_queue']: + buffer.write(data_chunk) + + # 重置指针位置以便读取 + buffer.seek(0) + + # 保存到任务对象 + task['buffer'] = buffer + logging.info(f"音频数据合并完成,总大小: {buffer.getbuffer().nbytes} 字节") + + # 可选:清理原始数据队列以节省内存 + task['data_queue'].clear() + + except Exception as e: + logging.error(f"合并音频数据失败: {str(e)}") + task['error'] = f"合并错误: {str(e)}" + + async def get_audio_stream(self, audio_stream_id): + """获取音频流(异步生成器)""" + task = self.tasks.get(audio_stream_id) + if not task: + raise RuntimeError("Audio stream not found") + + # 如果是延迟任务且未启动,现在启动 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) + + # 流式返回数据 + while not task['completed'] or task['data_queue']: + while task['data_queue']: + data = task['data_queue'].popleft() + total_audio_data_size += len(data) + #logging.info(f"yield audio data {len(data)} {total_audio_data_size}") + yield data + + # 短暂等待新数据 + await asyncio.sleep(0.05) + + # 检查错误 + if task['error']: + raise RuntimeError(task['error']) + + def start_cleanup_timer(self): + """启动定时清理任务""" + if self.cleanup_timer: + self.cleanup_timer.cancel() + + self.cleanup_timer = threading.Timer(30.0, self.cleanup_task) # 每30秒清理一次 + self.cleanup_timer.daemon = True # 设置为守护线程 + self.cleanup_timer.start() + + def cleanup_task(self): + """执行清理任务""" + try: + self._cleanup_old_tasks() + except Exception as e: + logging.error(f"清理任务时出错: {str(e)}") + finally: + self.start_cleanup_timer() # 重新启动定时器 + + +# 全局 TTS 引擎实例 +tts_engine = UnifiedTTSEngine() + + +def replace_domain(url: str) -> str: + """替换URL中的域名为本地地址,不使用urllib.parse""" + # 定义需要替换的域名列表 + domains_to_replace = [ + "http://1.13.185.116:9380", + "https://ragflow.szzysztech.com", + "1.13.185.116:9380", + "ragflow.szzysztech.com" + ] + + # 尝试替换每个可能的域名 + for domain in domains_to_replace: + if domain in url: + # 直接替换域名部分 + return url.replace(domain, "http://localhost:9380", 1) + + # 如果未匹配到特定域名,尝试智能替换 + if "://" in url: + # 分割协议和路径 + protocol, path = url.split("://", 1) + + # 查找第一个斜杠位置来确定域名结束位置 + slash_pos = path.find("/") + if slash_pos > 0: + # 替换域名部分 + return f"http://localhost:9380{path[slash_pos:]}" + else: + # 没有路径部分,直接返回本地地址 + return "http://localhost:9380" + else: + # 没有协议部分,直接添加本地地址 + return f"http://localhost:9380/{url}" + + +async def proxy_aichat_audio_stream(client_id: str, audio_url: str): + """代理外部音频流请求""" + try: + # 替换域名为本地地址 + local_url = audio_url + logging.info(f"代理音频流: {audio_url} -> {local_url}") + + async with httpx.AsyncClient(timeout=60.0) as client: + async with client.stream("GET", local_url) as response: + # 流式转发音频数据 + async for chunk in response.aiter_bytes(): + if not await manager.send_bytes(client_id, chunk): + logging.warning(f"Audio proxy interrupted for {client_id}") + return + except Exception as e: + logging.error(f"Audio proxy failed: {str(e)}") + await manager.send_text(client_id, json.dumps({ + "type": "error", + "message": f"音频流获取失败: {str(e)}" + })) + + +# 代理函数 - 文本流 +# 在微信小程序中,原来APK使用的SSE机制不能正常工作,需要使用WebSocket +async def proxy_aichat_text_stream(client_id: str, completions_url: str, payload: dict): + """代理大模型文本流请求 - 兼容现有Flask实现""" + try: + logging.info(f"代理文本流: completions_url={completions_url} {payload}") + logging.debug(f"请求负载: {json.dumps(payload, ensure_ascii=False)}") + + headers = { + "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=tts_model_name + ) + streaming_call = False + if tts_model.is_cosyvoice: + streaming_call = True + + # 创建流会话 + tts_stream_session_id = stream_manager.create_session( + tts_model=tts_model, + sample_rate=payload.get('tts_sample_rate', 48000), + stream_format=payload.get('tts_stream_format', 'mp3'), + session_id=None, + streaming_call= streaming_call + ) + # logging.info(f"---tts_stream_session_id = {tts_stream_session_id}") + tts_stream_session_id_sent = False + send_sentence_tts_url = False + # 添加一个事件来标记所有句子已发送 + all_sentences_sent = asyncio.Event() + + # 任务:监听并发送新生成的句子 + async def send_new_sentences(): + """监听并发送新生成的句子""" + try: + while True: + # 获取下一个句子 + sentence_info = stream_manager.get_next_sentence(tts_stream_session_id) + + if sentence_info: + logging.info(f"--proxy_aichat_text_stream 发送sentence_info\r\n") + # 发送句子信息 + await manager.send_json(client_id, { + "type": "tts_sentence", + "id": sentence_info['id'], + "text": stream_manager.get_sentence_info(sentence_info['id'])['text'], + "url": sentence_info['url'] + }) + else: + # 检查会话是否结束且没有更多句子 + session = stream_manager.get_session(tts_stream_session_id) + if not session or (not session['active']): + #and session['current_sentence_index'] >= len(session['sentences'])): + # 标记所有句子已发送 + all_sentences_sent.set() + break + + # 等待新句子生成 + await asyncio.sleep(0.1) + except asyncio.CancelledError: + logging.info("句子监听任务被取消") + except Exception as e: + logging.error(f"句子监听任务出错: {str(e)}") + all_sentences_sent.set() + + + if send_sentence_tts_url: + # 启动句子监听任务 + sentence_task = asyncio.create_task(send_new_sentences()) + # 使用更长的超时时间 (5分钟) + timeout = httpx.Timeout(300.0, connect=60.0) + async with httpx.AsyncClient(timeout=timeout) as client: + # 关键修改:使用流式请求模式 + async with client.stream( # <-- 使用stream方法 + "POST", + completions_url, + json=payload, + headers=headers + ) as response: + logging.info(f"响应状态: HTTP {response.status_code}") + + if response.status_code != 200: + # 读取错误信息(非流式) + error_content = await response.aread() + error_msg = f"后端错误: HTTP {response.status_code}" + error_msg += f" - {error_content[:200].decode()}" if error_content else "" + await manager.send_text(client_id, json.dumps({"type": "error", "message": error_msg})) + return + + # 验证SSE流 + content_type = response.headers.get("content-type", "").lower() + if "text/event-stream" not in content_type: + logging.warning("非流式响应,转发完整内容") + full_content = await response.aread() + await manager.send_text(client_id, json.dumps({ + "type": "text", + "data": full_content.decode('utf-8') + })) + return + + logging.info("开始处理SSE流") + event_count = 0 + # 使用异步迭代器逐行处理 + async for line in response.aiter_lines(): + # 跳过空行和注释行 + if not line or line.startswith(':'): + continue + + # 处理SSE事件 + if line.startswith("data:"): + data_str = line[5:].strip() + if data_str: # 过滤空数据 + try: + # 解析并提取增量文本 + data_obj = json.loads(data_str) + delta_text = None + if isinstance(data_obj, dict) and isinstance(data_obj.get('data', None), dict): + delta_text = data_obj.get('data', None).get('delta_ans', "") + if tts_stream_session_id_sent is False: + logging.info(f"--proxy_aichat_text_stream 发送audio_stream_url") + 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", + "data": data_str + })) + # 这里构建{"type":"text",'data':"data_str"}) 是为了前端websocket进行数据解析 + if delta_text: + # 追加到会话管理器 + stream_manager.append_text(tts_stream_session_id, delta_text) + # logging.info(f"文本代理转发: {data_str}") + event_count += 1 + except Exception as e: + logging.error(f"事件发送失败: {str(e)}") + + # 保持连接活性 + await asyncio.sleep(0.001) # 避免CPU空转 + + logging.info(f"SSE流处理完成,事件数: {event_count}") + + # 发送文本流结束信号 + await manager.send_text(client_id, json.dumps({"type": "end"})) + # 标记文本输入结束 + if stream_manager.finish_text_input: + stream_manager.finish_text_input(tts_stream_session_id) + + if send_sentence_tts_url: + # 等待所有句子生成并发送(最多等待300秒) + try: + await asyncio.wait_for(all_sentences_sent.wait(), timeout=300.0) + logging.info(f"所有TTS句子已发送") + except asyncio.TimeoutError: + logging.warning("等待TTS句子发送超时") + + # 取消句子监听任务(如果仍在运行) + if not sentence_task.done(): + sentence_task.cancel() + try: + await sentence_task + except asyncio.CancelledError: + pass + + except httpx.ReadTimeout: + logging.error("读取后端服务超时") + await manager.send_text(client_id, json.dumps({ + "type": "error", + "message": "后端服务响应超时" + })) + except httpx.ConnectError as e: + logging.error(f"连接后端服务失败: {str(e)}") + await manager.send_text(client_id, json.dumps({ + "type": "error", + "message": f"无法连接到后端服务: {str(e)}" + })) + except Exception as e: + logging.exception(f"文本代理失败: {str(e)}") + await manager.send_text(client_id, json.dumps({ + "type": "error", + "message": f"文本流获取失败: {str(e)}" + })) + + +@tts_router.get("/audio/pcm_mp3") +async def stream_mp3(): + def audio_generator(): + path = './test.mp3' + try: + with open(path, 'rb') as f: + while True: + chunk = f.read(1024) + if not chunk: + break + yield chunk + except Exception as e: + logging.error(f"MP3 streaming error: {str(e)}") + + return StreamingResponse( + audio_generator(), + media_type="audio/mpeg", + headers={ + "Cache-Control": "no-store", + "Accept-Ranges": "bytes" + } + ) + + +def add_wav_header(pcm_data: bytes, sample_rate: int) -> bytes: + """动态生成WAV头(严格保持原有逻辑结构)""" + with BytesIO() as wav_buffer: + with wave.open(wav_buffer, 'wb') as wav_file: + wav_file.setnchannels(1) # 保持原单声道设置 + wav_file.setsampwidth(2) # 保持原16-bit设置 + wav_file.setframerate(sample_rate) + wav_file.writeframes(pcm_data) + wav_buffer.seek(0) + return wav_buffer.read() + + +def generate_silence_header(duration_ms: int = 500) -> bytes: + """生成静音数据(用于MP3流式传输预缓冲)""" + num_samples = int(TTS_SAMPLERATE * duration_ms / 1000) + return b'\x00' * num_samples * SAMPLE_WIDTH * CHANNELS + + +# ------------------------ API路由 ------------------------ +@tts_router.get("/tts_sentence/{sentence_id}") +async def get_sentence_audio(sentence_id: str): + # 获取音频数据 + audio_data = stream_manager.get_sentence_audio(sentence_id) + if not audio_data: + raise HTTPException(status_code=404, detail="Audio not found") + + # 获取音频格式 + sentence_info = stream_manager.get_sentence_info(sentence_id) + if not sentence_info: + raise HTTPException(status_code=404, detail="Sentence info not found") + + # 确定MIME类型 + format = sentence_info['format'] + media_type = "audio/mpeg" if format == "mp3" else "audio/wav" + logging.info(f"--http get sentence tts audio stream {sentence_id}") + # 返回流式响应 + return StreamingResponse( + io.BytesIO(audio_data), + media_type=media_type, + headers={ + "Content-Disposition": f"attachment; filename=audio.{format}", + "Cache-Control": "max-age=3600" # 缓存1小时 + } + ) + +@tts_router.post("/chats/{chat_id}/tts") +async def create_tts_request(chat_id: str, request: Request): + try: + data = await request.json() + logging.info(f"Creating TTS request: {data}") + + # 参数校验 + text = data.get("text", "").strip() + if not text: + raise HTTPException(400, detail="Text cannot be empty") + + format = data.get("tts_stream_format", "mp3") + if format not in ["mp3", "wav", "pcm"]: + raise HTTPException(400, detail="Unsupported audio format") + + sample_rate = data.get("tts_sample_rate", 48000) + if sample_rate not in [8000, 16000, 22050, 44100, 48000]: + raise HTTPException(400, detail="Unsupported sample rate") + + model_name = data.get("model_name", "cosyvoice-v1/longxiaochun") + delay_gen_audio = data.get('delay_gen_audio', False) + + # 创建TTS任务 + audio_stream_id = tts_engine.create_tts_task( + text=text, + format=format, + sample_rate=sample_rate, + model_name=model_name, + key=ALI_KEY, + delay_gen_audio=delay_gen_audio + ) + + return JSONResponse( + status_code=200, + content={ + "tts_url": f"/chats/{chat_id}/tts/{audio_stream_id}", + "url": f"/chats/{chat_id}/tts/{audio_stream_id}", + "ws_url": f"/chats/{chat_id}/tts/{audio_stream_id}", # WebSocket URL 2025 0622新增 + "expires_at": (datetime.datetime.now() + datetime.timedelta(seconds=300)).isoformat() + } + ) + + except Exception as e: + logging.error(f"Request failed: {str(e)}") + raise HTTPException(500, detail="Internal server error") + + +executor = ThreadPoolExecutor() + + +@tts_router.get("/chats/{chat_id}/tts/{audio_stream_id}") +async def get_tts_audio( + chat_id: str, + audio_stream_id: str, + range: str = Header(None) +): + try: + # 获取任务信息 + task = tts_engine.tasks.get(audio_stream_id) + if not task: + # 返回友好的错误信息而不是抛出异常 + return JSONResponse( + status_code=404, + content={ + "error": "Audio stream not found", + "message": f"The requested audio stream ID '{audio_stream_id}' does not exist or has expired", + "suggestion": "Please create a new TTS request and try again" + } + ) + + # 获取媒体类型 + format = task['format'] + media_type = { + "mp3": "audio/mpeg", + "wav": "audio/wav", + "pcm": f"audio/L16; rate={task['sample_rate']}; channels=1" + }[format] + + # 如果任务已完成且有完整缓冲区,处理Range请求 + logging.info(f"get_tts_audio task = {task.get('completed', 'None')} {task.get('buffer', 'None')}") + + # 创建响应内容生成器 + def buffer_read(buffer): + content_length = buffer.getbuffer().nbytes + remaining = content_length + chunk_size = 4096 + buffer.seek(0) + while remaining > 0: + read_size = min(remaining, chunk_size) + data = buffer.read(read_size) + if not data: + break + yield data + remaining -= len(data) + + if task.get('completed') and task.get('buffer') is not None: + buffer = task['buffer'] + total_size = buffer.getbuffer().nbytes + # 强制小文件使用流式传输(避免206响应问题) + + if total_size < 1024 * 120: # 小于300KB + range = None + + if range: + # 处理范围请求 + return handle_range_request(range, buffer, total_size, media_type) + else: + return StreamingResponse( + buffer_read(buffer), + media_type=media_type, + headers={ + "Accept-Ranges": "bytes", + "Cache-Control": "no-store", + "Transfer-Encoding": "chunked" + }) + + # 创建流式响应 + logging.info("tts_engine.get_audio_stream--0") + return StreamingResponse( + tts_engine.get_audio_stream(audio_stream_id), + media_type=media_type, + headers={ + "Accept-Ranges": "bytes", + "Cache-Control": "no-store", + "Transfer-Encoding": "chunked" + } + ) + + except Exception as e: + logging.error(f"Audio streaming failed: {str(e)}") + raise HTTPException(500, detail="Audio generation error") + + +def handle_range_request(range_header: str, buffer: BytesIO, total_size: int, media_type: str): + """处理 HTTP Range 请求""" + try: + # 解析 Range 头部 (示例: "bytes=0-1023") + range_type, range_spec = range_header.split('=') + if range_type != 'bytes': + raise ValueError("Unsupported range type") + + start_str, end_str = range_spec.split('-') + start = int(start_str) + end = int(end_str) if end_str else total_size - 1 + logging.info(f"handle_range_request--1 {start_str}-{end_str} {end}") + # 验证范围有效性 + if start >= total_size or end >= total_size: + raise HTTPException(status_code=416, headers={ + "Content-Range": f"bytes */{total_size}" + }) + + # 计算内容长度 + content_length = end - start + 1 + + # 设置状态码 + status_code = 206 # Partial Content + if start == 0 and end == total_size - 1: + status_code = 200 # Full Content + + # 设置流读取位置 + buffer.seek(start) + + # 创建响应内容生成器 + def content_generator(): + remaining = content_length + chunk_size = 4096 + while remaining > 0: + read_size = min(remaining, chunk_size) + data = buffer.read(read_size) + if not data: + break + yield data + remaining -= len(data) + + # 返回分块响应 + return StreamingResponse( + content_generator(), + status_code=status_code, + media_type=media_type, + headers={ + "Content-Range": f"bytes {start}-{end}/{total_size}", + "Content-Length": str(content_length), + "Accept-Ranges": "bytes", + "Cache-Control": "public, max-age=3600" + } + ) + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +@tts_router.websocket("/chats/{chat_id}/tts/{audio_stream_id}") +async def websocket_tts_endpoint( + websocket: WebSocket, + chat_id: str, + audio_stream_id: str +): + # 接收 header 参数 + headers = websocket.headers + service_type = headers.get("x-tts-type") # 注意:header 名称转为小写 + # audio_url = headers.get("x-audio-url") + """ + 前端示例 + websocketConnection = uni.connectSocket({ + url: url, + header: { + 'Authorization': token, + 'X-Tts-Type': 'AiChat', //'Ask' // 自定义参数1 + 'X-Device-Type': 'mobile', // 自定义参数2 + 'X-User-ID': '12345' // 自定义参数3 + }, + success: () => { + console.log('WebSocket connected'); + }, + fail: (err) => { + console.error('WebSocket connection failed:', err); + } + }); + """ + # 创建唯一连接 ID + connection_id = str(uuid.uuid4()) + # logging.info(f"---dale-- websocket connection_id = {connection_id} chat_id={chat_id}") + await manager.connect(websocket, connection_id) + + completed_successfully = False + try: + # 根据tts_type路由到不同的音频源 + if service_type == "AiChatTts": + # 音频代理服务 + 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): + if data.get('type') == 'sentence_end': + await manager.send_json(connection_id, {"command": "sentence_end"}) + + if data.get('type') == 'arraybuffer': + audio_data_size += len(data.get('data')) + if not await manager.send_bytes(connection_id, data.get('data')): + break + completed_successfully = True + logging.info(f"--- proxy AiChatTts audio_data_size={audio_data_size}") + elif service_type == "AiChatText": + # 文本代理服务 + # 等待客户端发送初始请求数据 进行大模型对话代理时,需要前端连接后发送payload + payload = await websocket.receive_json() + completions_url = f"http://localhost:9380/api/v1/chats/{chat_id}/completions" + await proxy_aichat_text_stream(connection_id, completions_url, payload) + completed_successfully = True + else: + # 使用引擎的生成器直接获取音频流 + async for data in tts_engine.get_audio_stream(audio_stream_id): + if not await manager.send_bytes(connection_id, data): + logging.warning(f"Send failed, connection closed: {connection_id}") + break + await manager.send_json(connection_id, {"command": "sentence_end"}) + completed_successfully = True + + # 发送完成信号前检查连接状态 + if manager.is_connected(connection_id): + # 发送完成信号 + await manager.send_json(connection_id, {"status": "completed"}) + + # 添加短暂延迟确保消息送达 + await asyncio.sleep(0.1) + + # 主动关闭WebSocket连接 + await manager.disconnect(connection_id, code=1000, reason="Audio stream completed") + except WebSocketDisconnect: + logging.info(f"WebSocket disconnected: {connection_id}") + except Exception as e: + logging.error(f"WebSocket TTS error: {str(e)}") + if manager.is_connected(connection_id): + await manager.send_json(connection_id, {"error": str(e)}) + finally: + pass + # await manager.disconnect(connection_id) + + +def cleanup_cache(): + """清理过期缓存""" + with cache_lock: + now = datetime.datetime.now() + expired = [k for k, v in audio_text_cache.items() + if (now - v["created_at"]).total_seconds() > CACHE_EXPIRE_SECONDS] + for key in expired: + logging.info(f"del audio_text_cache= {audio_text_cache[key]}") + del audio_text_cache[key] + +# 应用启动时启动清理线程 +# start_background_cleaner() diff --git a/asr-monitor-test/docker-compose.yml b/asr-monitor-test/docker-compose.yml index 599dcea5..713e26b2 100644 --- a/asr-monitor-test/docker-compose.yml +++ b/asr-monitor-test/docker-compose.yml @@ -3,8 +3,8 @@ # 需要准备 docker compose .yml 和 Dockerfile 文件 networks: - docker_ragflow: - external: true # 声明使用外部网络(需提前创建) + docker_ragflow: + external: true # 声明使用外部网络(需提前创建) services: asr-monitor-test: build: diff --git a/asr-monitor-test/requirements.txt b/asr-monitor-test/requirements.txt index cd6adae4..9ba1650f 100644 --- a/asr-monitor-test/requirements.txt +++ b/asr-monitor-test/requirements.txt @@ -3,6 +3,7 @@ uvicorn>=0.15.0 websockets==12.0 python-multipart==0.0.20 +dashscope>=1.23.8 # JWT 相关 python-jose[cryptography]==3.3.0 # 兼容 Python3 的 JOSE 实现 @@ -15,6 +16,7 @@ httpx # MySQL 驱动 pymysql==1.1.0 +tzdata==2025.2 # 连接池管理 dbutils==3.1.1 diff --git a/asr-monitor-test/run_app.sh b/asr-monitor-test/run_app.sh index eae35d57..d2766efb 100644 --- a/asr-monitor-test/run_app.sh +++ b/asr-monitor-test/run_app.sh @@ -20,8 +20,10 @@ export PYTHONPATH=.:$PYTHONPATH # 3. 使用nohup运行并防止终端退出影响 echo "➜ 启动应用进程..." -nohup python app/main.py > app.log 2>&1 & +#nohup python app/main.py > app.log 2>&1 & +#只能使用1个worker,共享全局变量使用会有问题 +nohup uvicorn app.main:app --host 0.0.0.0 --port 9580 --workers 4 > app.log 2>&1 & # 4. 验证新进程 sleep 3 # 等待进程启动 NEW_PID=$(lsof -ti :${PORT}) diff --git a/asr-monitor-test/start.sh b/asr-monitor-test/start.sh index 12eeb3b7..ce44b1a0 100755 --- a/asr-monitor-test/start.sh +++ b/asr-monitor-test/start.sh @@ -13,4 +13,13 @@ else fi source venv/bin/activate -export PYTHONPATH=.:$PYTHONPATH && python app/main.py +export PYTHONPATH=.:$PYTHONPATH +#python app/main.py + +# 高性能启动 FastAPI +uvicorn app.main:app \ + --host 0.0.0.0 \ + --port $PORT \ + --workers 4 \ + --timeout-keep-alive 65 \ + --no-access-log \ No newline at end of file