mistpe commited on
Commit
184c9da
·
verified ·
1 Parent(s): b40cb3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -1000
app.py CHANGED
@@ -1,913 +1,3 @@
1
- # #!/usr/bin/env python
2
- # # -*- coding: utf-8 -*-
3
- # from flask import Flask, request, make_response
4
- # import hashlib
5
- # import time
6
- # import xml.etree.ElementTree as ET
7
- # import os
8
- # import json
9
- # from openai import OpenAI
10
- # from dotenv import load_dotenv
11
- # from markdown import markdown
12
- # import re
13
- # import threading
14
- # import logging
15
- # from datetime import datetime
16
-
17
- # # 配置日志记录
18
- # logging.basicConfig(
19
- # level=logging.INFO,
20
- # format='%(asctime)s - %(levelname)s - %(message)s',
21
- # handlers=[
22
- # logging.FileHandler('wechat_service.log'),
23
- # logging.StreamHandler()
24
- # ]
25
- # )
26
-
27
- # # 加载环境变量
28
- # load_dotenv()
29
-
30
- # app = Flask(__name__)
31
-
32
- # # 基础配置
33
- # TOKEN = os.getenv('TOKEN')
34
- # API_KEY = os.getenv("API_KEY")
35
- # BASE_URL = os.getenv("OPENAI_BASE_URL")
36
- # client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
37
-
38
- # class UserSession:
39
- # def __init__(self):
40
- # self.messages = [{"role": "system", "content": "You are a helpful assistant."}]
41
- # self.pending_parts = []
42
- # self.last_active = time.time()
43
-
44
- # class SessionManager:
45
- # def __init__(self):
46
- # self.sessions = {}
47
- # self.session_timeout = 3600 # 1小时会话超时
48
- # self._lock = threading.Lock()
49
-
50
- # def get_session(self, user_id):
51
- # with self._lock:
52
- # if user_id not in self.sessions:
53
- # self.sessions[user_id] = UserSession()
54
- # session = self.sessions[user_id]
55
- # session.last_active = time.time()
56
- # return session
57
-
58
- # def clear_session(self, user_id):
59
- # with self._lock:
60
- # if user_id in self.sessions:
61
- # self.sessions[user_id] = UserSession()
62
-
63
- # def cleanup_expired_sessions(self):
64
- # with self._lock:
65
- # current_time = time.time()
66
- # expired_users = [
67
- # user_id for user_id, session in self.sessions.items()
68
- # if current_time - session.last_active > self.session_timeout
69
- # ]
70
- # for user_id in expired_users:
71
- # del self.sessions[user_id]
72
- # logging.info(f"已清理过期会话: {user_id}")
73
-
74
- # session_manager = SessionManager()
75
-
76
- # def convert_markdown_to_wechat(md_text):
77
- # """将Markdown转换为微信友好的文本格式"""
78
- # md_text = re.sub(r'^# (.*?)$', r'【标题】\1', md_text, flags=re.MULTILINE)
79
- # md_text = re.sub(r'^## (.*?)$', r'【子标题】\1', md_text, flags=re.MULTILINE)
80
- # md_text = re.sub(r'\*\*(.*?)\*\*', r'『\1』', md_text)
81
- # md_text = re.sub(r'\*(.*?)\*', r'「\1」', md_text)
82
- # md_text = re.sub(r'^\- ', '• ', md_text, flags=re.MULTILINE)
83
- # md_text = re.sub(r'^\d\. ', '○ ', md_text, flags=re.MULTILINE)
84
- # md_text = re.sub(r'```(.*?)```', r'【代码】\n\1\n【代码结束】', md_text, flags=re.DOTALL)
85
- # md_text = re.sub(r'^> (.*?)$', r'▎\1', md_text, flags=re.MULTILINE)
86
- # return md_text
87
-
88
- # def verify_wechat(request):
89
- # """验证微信服务器请求"""
90
- # data = request.args
91
- # signature = data.get('signature')
92
- # timestamp = data.get('timestamp')
93
- # nonce = data.get('nonce')
94
- # echostr = data.get('echostr')
95
-
96
- # temp = [timestamp, nonce, TOKEN]
97
- # temp.sort()
98
- # temp = ''.join(temp)
99
-
100
- # if hashlib.sha1(temp.encode('utf8')).hexdigest() == signature:
101
- # return echostr
102
- # return 'error', 403
103
-
104
- # def parse_xml_message(xml_content):
105
- # """解析微信XML消息"""
106
- # root = ET.fromstring(xml_content)
107
- # return {
108
- # 'content': root.find('Content').text,
109
- # 'from_user': root.find('FromUserName').text,
110
- # 'to_user': root.find('ToUserName').text,
111
- # 'msg_id': root.find('MsgId').text,
112
- # 'create_time': root.find('CreateTime').text
113
- # }
114
-
115
- # def generate_response_xml(to_user, from_user, content):
116
- # """生成回复的XML消息"""
117
- # response_content = convert_markdown_to_wechat(content)
118
- # xml_template = '''
119
- # <xml>
120
- # <ToUserName><![CDATA[%s]]></ToUserName>
121
- # <FromUserName><![CDATA[%s]]></FromUserName>
122
- # <CreateTime>%s</CreateTime>
123
- # <MsgType><![CDATA[text]]></MsgType>
124
- # <Content><![CDATA[%s]]></Content>
125
- # </xml>
126
- # '''
127
- # response = make_response(
128
- # xml_template % (to_user, from_user, str(int(time.time())), response_content)
129
- # )
130
- # response.content_type = 'application/xml'
131
- # return response
132
-
133
- # def get_openai_response(messages, timeout=30):
134
- # """获取OpenAI API响应"""
135
- # try:
136
- # response = client.chat.completions.create(
137
- # model="gpt-4o-mini",
138
- # messages=messages,
139
- # timeout=timeout
140
- # )
141
- # return response.choices[0].message.content
142
- # except Exception as e:
143
- # logging.error(f"OpenAI API错误: {str(e)}")
144
- # return "抱歉,我暂时无法回答,请稍后再试。"
145
-
146
- # def split_message(message, max_length=500):
147
- # """将长消息分段"""
148
- # return [message[i:i+max_length] for i in range(0, len(message), max_length)]
149
-
150
- # def append_status_message(content, has_pending_parts=False):
151
- # """添加状态提示信息"""
152
- # status_message = "\n\n-------------------\n"
153
- # if has_pending_parts:
154
- # status_message += "当前消息已截断,发送’继续‘查看后续内容\n"
155
- # status_message += "发送’新对话‘开始新的对话"
156
- # return content + status_message
157
-
158
- # @app.route('/api/wx', methods=['GET', 'POST'])
159
- # def wechatai():
160
- # if request.method == 'GET':
161
- # return verify_wechat(request)
162
-
163
- # try:
164
- # message_data = parse_xml_message(request.data)
165
- # user_content = message_data['content']
166
- # from_user = message_data['from_user']
167
- # to_user = message_data['to_user']
168
-
169
- # logging.info(f"收到用户({from_user})消息: {user_content}")
170
-
171
- # session = session_manager.get_session(from_user)
172
-
173
- # if user_content.strip() == '新对话':
174
- # session_manager.clear_session(from_user)
175
- # return generate_response_xml(
176
- # from_user,
177
- # to_user,
178
- # append_status_message("已开始新的对话。请描述您的问题。")
179
- # )
180
-
181
- # if user_content.strip() == '继续':
182
- # if session.pending_parts:
183
- # next_part = session.pending_parts.pop(0)
184
- # has_more = bool(session.pending_parts)
185
- # return generate_response_xml(
186
- # from_user,
187
- # to_user,
188
- # append_status_message(next_part, has_more)
189
- # )
190
- # return generate_response_xml(
191
- # from_user,
192
- # to_user,
193
- # append_status_message("没有更多内容了。请继续您的问题。")
194
- # )
195
-
196
- # session.messages.append({"role": "user", "content": user_content})
197
- # response = get_openai_response(session.messages)
198
- # session.messages.append({"role": "assistant", "content": response})
199
-
200
- # if len(response) > 500:
201
- # parts = split_message(response)
202
- # first_part = parts.pop(0)
203
- # session.pending_parts = parts
204
- # return generate_response_xml(
205
- # from_user,
206
- # to_user,
207
- # append_status_message(first_part, True)
208
- # )
209
-
210
- # return generate_response_xml(
211
- # from_user,
212
- # to_user,
213
- # append_status_message(response)
214
- # )
215
-
216
- # except Exception as e:
217
- # logging.error(f"处理请求时出错: {str(e)}")
218
- # return generate_response_xml(
219
- # message_data['from_user'],
220
- # message_data['to_user'],
221
- # append_status_message("抱歉,系统暂时出现问题,请稍后重试。")
222
- # )
223
-
224
- # def cleanup_sessions():
225
- # """定期清理过期会话"""
226
- # while True:
227
- # time.sleep(3600)
228
- # session_manager.cleanup_expired_sessions()
229
-
230
- # if __name__ == '__main__':
231
- # # 启动清理线程
232
- # cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
233
- # cleanup_thread.start()
234
-
235
- # app.run(host='0.0.0.0', port=7860, debug=True)
236
- #!/usr/bin/env python
237
- # -*- coding: utf-8 -*-
238
- # from flask import Flask, request, make_response
239
- # import hashlib
240
- # import time
241
- # import xml.etree.ElementTree as ET
242
- # import os
243
- # import json
244
- # from openai import OpenAI
245
- # from dotenv import load_dotenv
246
- # from markdown import markdown
247
- # import re
248
- # import threading
249
- # import logging
250
- # from datetime import datetime
251
- # import asyncio
252
- # from concurrent.futures import ThreadPoolExecutor
253
- # import queue
254
- # import uuid
255
-
256
- # # 配置日志记录
257
- # logging.basicConfig(
258
- # level=logging.INFO,
259
- # format='%(asctime)s - %(levelname)s - %(message)s',
260
- # handlers=[
261
- # logging.FileHandler('wechat_service.log'),
262
- # logging.StreamHandler()
263
- # ]
264
- # )
265
-
266
- # # 加载环境变量
267
- # load_dotenv()
268
-
269
- # app = Flask(__name__)
270
-
271
- # # 基础配置
272
- # TOKEN = os.getenv('TOKEN')
273
- # API_KEY = os.getenv("API_KEY")
274
- # BASE_URL = os.getenv("OPENAI_BASE_URL")
275
- # client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
276
-
277
- # # 创建线程池
278
- # executor = ThreadPoolExecutor(max_workers=10)
279
-
280
- # def convert_markdown_to_wechat(md_text):
281
- # """将Markdown转换为微信友好的文本格式"""
282
- # if not md_text:
283
- # return md_text
284
-
285
- # # 处理标题
286
- # md_text = re.sub(r'^# (.*?)$', r'【标题】\1', md_text, flags=re.MULTILINE)
287
- # md_text = re.sub(r'^## (.*?)$', r'【子标题】\1', md_text, flags=re.MULTILINE)
288
- # md_text = re.sub(r'^### (.*?)$', r'【小标题】\1', md_text, flags=re.MULTILINE)
289
-
290
- # # 处理强调语法
291
- # md_text = re.sub(r'\*\*(.*?)\*\*', r'『\1』', md_text) # 粗体
292
- # md_text = re.sub(r'\*(.*?)\*', r'「\1」', md_text) # 斜体
293
- # md_text = re.sub(r'`(.*?)`', r'「\1」', md_text) # 行内代码
294
-
295
- # # 处理列表
296
- # md_text = re.sub(r'^\- ', '• ', md_text, flags=re.MULTILINE) # 无序列表
297
- # md_text = re.sub(r'^\d\. ', '○ ', md_text, flags=re.MULTILINE) # 有序列表
298
-
299
- # # 处理代码块
300
- # md_text = re.sub(r'```[\w]*\n(.*?)```', r'【代码开始】\n\1\n【代码结束】', md_text, flags=re.DOTALL)
301
-
302
- # # 处理引用
303
- # md_text = re.sub(r'^> (.*?)$', r'▎\1', md_text, flags=re.MULTILINE)
304
-
305
- # # 处理分隔线
306
- # md_text = re.sub(r'^-{3,}$', r'—————————', md_text, flags=re.MULTILINE)
307
-
308
- # # 处理链接
309
- # md_text = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1(\2)', md_text)
310
-
311
- # # 净化处理:去除多余的空行
312
- # md_text = re.sub(r'\n{3,}', '\n\n', md_text)
313
-
314
- # return md_text
315
-
316
- # class AsyncResponse:
317
- # def __init__(self):
318
- # self.status = "processing" # processing, completed, failed
319
- # self.result = None
320
- # self.error = None
321
-
322
- # class UserSession:
323
- # def __init__(self):
324
- # self.messages = [{"role": "system", "content": "You are a helpful assistant."}]
325
- # self.pending_parts = []
326
- # self.last_active = time.time()
327
- # self.current_task = None # 存储当前正在处理的任务ID
328
- # self.response_queue = {} # 存储异步响应
329
-
330
- # class SessionManager:
331
- # def __init__(self):
332
- # self.sessions = {}
333
- # self.session_timeout = 3600 # 1小时会话超时
334
- # self._lock = threading.Lock()
335
-
336
- # def get_session(self, user_id):
337
- # with self._lock:
338
- # if user_id not in self.sessions:
339
- # self.sessions[user_id] = UserSession()
340
- # session = self.sessions[user_id]
341
- # session.last_active = time.time()
342
- # return session
343
-
344
- # def clear_session(self, user_id):
345
- # with self._lock:
346
- # if user_id in self.sessions:
347
- # self.sessions[user_id] = UserSession()
348
-
349
- # def cleanup_expired_sessions(self):
350
- # with self._lock:
351
- # current_time = time.time()
352
- # expired_users = [
353
- # user_id for user_id, session in self.sessions.items()
354
- # if current_time - session.last_active > self.session_timeout
355
- # ]
356
- # for user_id in expired_users:
357
- # del self.sessions[user_id]
358
- # logging.info(f"已清理过期会话: {user_id}")
359
-
360
- # session_manager = SessionManager()
361
-
362
- # def verify_wechat(request):
363
- # """验证微信服务器请求"""
364
- # data = request.args
365
- # signature = data.get('signature')
366
- # timestamp = data.get('timestamp')
367
- # nonce = data.get('nonce')
368
- # echostr = data.get('echostr')
369
-
370
- # temp = [timestamp, nonce, TOKEN]
371
- # temp.sort()
372
- # temp = ''.join(temp)
373
-
374
- # if hashlib.sha1(temp.encode('utf8')).hexdigest() == signature:
375
- # return echostr
376
- # return 'error', 403
377
-
378
- # def parse_xml_message(xml_content):
379
- # """解析微信XML消息"""
380
- # root = ET.fromstring(xml_content)
381
- # return {
382
- # 'content': root.find('Content').text,
383
- # 'from_user': root.find('FromUserName').text,
384
- # 'to_user': root.find('ToUserName').text,
385
- # 'msg_id': root.find('MsgId').text,
386
- # 'create_time': root.find('CreateTime').text
387
- # }
388
-
389
- # def generate_response_xml(to_user, from_user, content):
390
- # """生成回复的XML消息"""
391
- # formatted_content = convert_markdown_to_wechat(content)
392
- # xml_template = '''
393
- # <xml>
394
- # <ToUserName><![CDATA[%s]]></ToUserName>
395
- # <FromUserName><![CDATA[%s]]></FromUserName>
396
- # <CreateTime>%s</CreateTime>
397
- # <MsgType><![CDATA[text]]></MsgType>
398
- # <Content><![CDATA[%s]]></Content>
399
- # </xml>
400
- # '''
401
- # response = make_response(
402
- # xml_template % (to_user, from_user, str(int(time.time())), formatted_content)
403
- # )
404
- # response.content_type = 'application/xml'
405
- # return response
406
-
407
- # def process_long_running_task(messages):
408
- # """处理耗时任务"""
409
- # try:
410
- # response = client.chat.completions.create(
411
- # model="gpt-4o-mini",
412
- # messages=messages,
413
- # timeout=60
414
- # )
415
- # return response.choices[0].message.content
416
- # except Exception as e:
417
- # logging.error(f"API调用错误: {str(e)}")
418
- # raise
419
-
420
- # def handle_async_task(session, task_id, messages):
421
- # """异步任务处理函数"""
422
- # try:
423
- # result = process_long_running_task(messages)
424
- # session.response_queue[task_id].status = "completed"
425
- # session.response_queue[task_id].result = result
426
- # except Exception as e:
427
- # session.response_queue[task_id].status = "failed"
428
- # session.response_queue[task_id].error = str(e)
429
-
430
- # def generate_initial_response():
431
- # """生成初始响应消息"""
432
- # return "您的��求正在处理中,请稍后回复’查询‘获取结果。"
433
-
434
- # def split_message(message, max_length=500):
435
- # """将长消息分段"""
436
- # return [message[i:i+max_length] for i in range(0, len(message), max_length)]
437
-
438
- # def append_status_message(content, has_pending_parts=False, is_processing=False):
439
- # """添加状态提示信息"""
440
- # status_message = "\n\n-------------------\n"
441
- # if is_processing:
442
- # status_message += "您的请求正在处理中,请回复’查询‘获取结果\n"
443
- # elif has_pending_parts:
444
- # status_message += "当前消息已截断,发送’继续‘查看后续内容\n"
445
- # status_message += "发送‘新对话’开始新的对话"
446
- # return content + status_message
447
-
448
- # @app.route('/api/wx', methods=['GET', 'POST'])
449
- # def wechatai():
450
- # if request.method == 'GET':
451
- # return verify_wechat(request)
452
-
453
- # try:
454
- # message_data = parse_xml_message(request.data)
455
- # user_content = message_data['content'].strip()
456
- # from_user = message_data['from_user']
457
- # to_user = message_data['to_user']
458
-
459
- # logging.info(f"收到用户({from_user})消息: {user_content}")
460
- # session = session_manager.get_session(from_user)
461
-
462
- # # 处理特殊命令
463
- # if user_content == '新对话':
464
- # session_manager.clear_session(from_user)
465
- # return generate_response_xml(
466
- # from_user,
467
- # to_user,
468
- # append_status_message("已开始新的对话。请描述您的问题。")
469
- # )
470
-
471
- # if user_content == '继续':
472
- # if session.pending_parts:
473
- # next_part = session.pending_parts.pop(0)
474
- # has_more = bool(session.pending_parts)
475
- # return generate_response_xml(
476
- # from_user,
477
- # to_user,
478
- # append_status_message(next_part, has_more)
479
- # )
480
- # return generate_response_xml(
481
- # from_user,
482
- # to_user,
483
- # append_status_message("没有更多内容了。请继续您的问题。")
484
- # )
485
-
486
- # if user_content == '查询':
487
- # if session.current_task:
488
- # task_response = session.response_queue.get(session.current_task)
489
- # if task_response:
490
- # if task_response.status == "completed":
491
- # response = task_response.result
492
- # # 清理完成的任务
493
- # del session.response_queue[session.current_task]
494
- # session.current_task = None
495
-
496
- # # 处理长消息
497
- # if len(response) > 500:
498
- # parts = split_message(response)
499
- # first_part = parts.pop(0)
500
- # session.pending_parts = parts
501
- # return generate_response_xml(
502
- # from_user,
503
- # to_user,
504
- # append_status_message(first_part, True)
505
- # )
506
- # return generate_response_xml(
507
- # from_user,
508
- # to_user,
509
- # append_status_message(response)
510
- # )
511
- # elif task_response.status == "failed":
512
- # error_message = "处理过程中出现错误,请重新提问。"
513
- # # 清理失败的任务
514
- # del session.response_queue[session.current_task]
515
- # session.current_task = None
516
- # return generate_response_xml(
517
- # from_user,
518
- # to_user,
519
- # append_status_message(error_message)
520
- # )
521
- # else:
522
- # return generate_response_xml(
523
- # from_user,
524
- # to_user,
525
- # append_status_message("正在处理中,请稍后再次查询。", is_processing=True)
526
- # )
527
- # return generate_response_xml(
528
- # from_user,
529
- # to_user,
530
- # append_status_message("没有正在处理的请求。")
531
- # )
532
-
533
- # # 处理新的用户消息
534
- # session.messages.append({"role": "user", "content": user_content})
535
-
536
- # # 创建新的异步任务
537
- # task_id = str(uuid.uuid4())
538
- # session.current_task = task_id
539
- # session.response_queue[task_id] = AsyncResponse()
540
-
541
- # # 启动异步处理
542
- # executor.submit(handle_async_task, session, task_id, session.messages.copy())
543
-
544
- # # 返回初始响应
545
- # return generate_response_xml(
546
- # from_user,
547
- # to_user,
548
- # append_status_message(generate_initial_response(), is_processing=True)
549
- # )
550
-
551
- # except Exception as e:
552
- # logging.error(f"处理请求时出错: {str(e)}")
553
- # return generate_response_xml(
554
- # message_data['from_user'],
555
- # message_data['to_user'],
556
- # append_status_message("抱歉,系统暂时出现问题,请稍后重试。")
557
- # )
558
-
559
- # def cleanup_sessions():
560
- # """定期清理过期会话"""
561
- # while True:
562
- # time.sleep(3600) # 每小时清理一次
563
- # try:
564
- # session_manager.cleanup_expired_sessions()
565
- # except Exception as e:
566
- # logging.error(f"清理会话时出错: {str(e)}")
567
-
568
- # if __name__ == '__main__':
569
- # # 启动清理线程
570
- # cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
571
- # cleanup_thread.start()
572
-
573
- # # 启动Flask应用
574
- # app.run(host='0.0.0.0', port=7860, debug=True)
575
- # #!/usr/bin/env python
576
- # # -*- coding: utf-8 -*-
577
- # from flask import Flask, request, make_response
578
- # import hashlib
579
- # import time
580
- # import xml.etree.ElementTree as ET
581
- # import os
582
- # import json
583
- # from openai import OpenAI
584
- # from dotenv import load_dotenv
585
- # from markdown import markdown
586
- # import re
587
- # import threading
588
- # import logging
589
- # from datetime import datetime
590
- # import asyncio
591
- # from concurrent.futures import ThreadPoolExecutor
592
- # import queue
593
- # import uuid
594
-
595
- # # 配置日志记录
596
- # logging.basicConfig(
597
- # level=logging.INFO,
598
- # format='%(asctime)s - %(levelname)s - %(message)s',
599
- # handlers=[
600
- # logging.FileHandler('wechat_service.log'),
601
- # logging.StreamHandler()
602
- # ]
603
- # )
604
-
605
- # # 加载环境变量
606
- # load_dotenv()
607
-
608
- # app = Flask(__name__)
609
-
610
- # # 基础配置
611
- # TOKEN = os.getenv('TOKEN')
612
- # API_KEY = os.getenv("API_KEY")
613
- # BASE_URL = os.getenv("OPENAI_BASE_URL")
614
- # client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
615
-
616
- # # 创建线程池
617
- # executor = ThreadPoolExecutor(max_workers=10)
618
-
619
- # def convert_markdown_to_wechat(md_text):
620
- # """将Markdown转换为微信友好的文本格式"""
621
- # if not md_text:
622
- # return md_text
623
-
624
- # # 处理标题
625
- # md_text = re.sub(r'^# (.*?)$', r'【标题】\1', md_text, flags=re.MULTILINE)
626
- # md_text = re.sub(r'^## (.*?)$', r'【子标题】\1', md_text, flags=re.MULTILINE)
627
- # md_text = re.sub(r'^### (.*?)$', r'【小标题】\1', md_text, flags=re.MULTILINE)
628
-
629
- # # 处理强调语法
630
- # md_text = re.sub(r'\*\*(.*?)\*\*', r'『\1』', md_text) # 粗体
631
- # md_text = re.sub(r'\*(.*?)\*', r'「\1」', md_text) # 斜体
632
- # md_text = re.sub(r'`(.*?)`', r'「\1」', md_text) # 行内代码
633
-
634
- # # 处理列表
635
- # md_text = re.sub(r'^\- ', '• ', md_text, flags=re.MULTILINE) # 无序列表
636
- # md_text = re.sub(r'^\d\. ', '○ ', md_text, flags=re.MULTILINE) # 有序列表
637
-
638
- # # 处理代码块
639
- # md_text = re.sub(r'```[\w]*\n(.*?)```', r'【代码开始】\n\1\n【代码结束】', md_text, flags=re.DOTALL)
640
-
641
- # # 处理引用
642
- # md_text = re.sub(r'^> (.*?)$', r'▎\1', md_text, flags=re.MULTILINE)
643
-
644
- # # 处理分隔线
645
- # md_text = re.sub(r'^-{3,}$', r'—————————', md_text, flags=re.MULTILINE)
646
-
647
- # # 处理链接
648
- # md_text = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1(\2)', md_text)
649
-
650
- # # 净化处理:去除多余的空行
651
- # md_text = re.sub(r'\n{3,}', '\n\n', md_text)
652
-
653
- # return md_text
654
-
655
- # class AsyncResponse:
656
- # def __init__(self):
657
- # self.status = "processing" # processing, completed, failed
658
- # self.result = None
659
- # self.error = None
660
-
661
- # class UserSession:
662
- # def __init__(self):
663
- # self.messages = [{"role": "system", "content": "You are a helpful assistant."}]
664
- # self.pending_parts = []
665
- # self.last_active = time.time()
666
- # self.current_task = None
667
- # self.response_queue = {}
668
-
669
- # class SessionManager:
670
- # def __init__(self):
671
- # self.sessions = {}
672
- # self.session_timeout = 3600
673
- # self._lock = threading.Lock()
674
-
675
- # def get_session(self, user_id):
676
- # with self._lock:
677
- # if user_id not in self.sessions:
678
- # self.sessions[user_id] = UserSession()
679
- # session = self.sessions[user_id]
680
- # session.last_active = time.time()
681
- # return session
682
-
683
- # def clear_session(self, user_id):
684
- # with self._lock:
685
- # if user_id in self.sessions:
686
- # self.sessions[user_id] = UserSession()
687
-
688
- # def cleanup_expired_sessions(self):
689
- # with self._lock:
690
- # current_time = time.time()
691
- # expired_users = [
692
- # user_id for user_id, session in self.sessions.items()
693
- # if current_time - session.last_active > self.session_timeout
694
- # ]
695
- # for user_id in expired_users:
696
- # del self.sessions[user_id]
697
- # logging.info(f"已清理过期会话: {user_id}")
698
-
699
- # session_manager = SessionManager()
700
-
701
- # def verify_wechat(request):
702
- # """验证微信服务器请求"""
703
- # data = request.args
704
- # signature = data.get('signature')
705
- # timestamp = data.get('timestamp')
706
- # nonce = data.get('nonce')
707
- # echostr = data.get('echostr')
708
-
709
- # temp = [timestamp, nonce, TOKEN]
710
- # temp.sort()
711
- # temp = ''.join(temp)
712
-
713
- # if hashlib.sha1(temp.encode('utf8')).hexdigest() == signature:
714
- # return echostr
715
- # return 'error', 403
716
-
717
- # def parse_xml_message(xml_content):
718
- # """解析微信XML消息"""
719
- # root = ET.fromstring(xml_content)
720
- # return {
721
- # 'content': root.find('Content').text,
722
- # 'from_user': root.find('FromUserName').text,
723
- # 'to_user': root.find('ToUserName').text,
724
- # 'msg_id': root.find('MsgId').text,
725
- # 'create_time': root.find('CreateTime').text
726
- # }
727
-
728
- # def generate_response_xml(to_user, from_user, content):
729
- # """生成回复的XML消息"""
730
- # formatted_content = convert_markdown_to_wechat(content)
731
- # xml_template = '''
732
- # <xml>
733
- # <ToUserName><![CDATA[%s]]></ToUserName>
734
- # <FromUserName><![CDATA[%s]]></FromUserName>
735
- # <CreateTime>%s</CreateTime>
736
- # <MsgType><![CDATA[text]]></MsgType>
737
- # <Content><![CDATA[%s]]></Content>
738
- # </xml>
739
- # '''
740
- # response = make_response(
741
- # xml_template % (to_user, from_user, str(int(time.time())), formatted_content)
742
- # )
743
- # response.content_type = 'application/xml'
744
- # return response
745
-
746
- # def process_long_running_task(messages):
747
- # """处理耗时任务"""
748
- # try:
749
- # response = client.chat.completions.create(
750
- # model="gpt-4o-mini",
751
- # messages=messages,
752
- # timeout=60
753
- # )
754
- # return response.choices[0].message.content
755
- # except Exception as e:
756
- # logging.error(f"API调用错误: {str(e)}")
757
- # raise
758
-
759
- # def handle_async_task(session, task_id, messages):
760
- # """异步任务处理函数"""
761
- # try:
762
- # result = process_long_running_task(messages)
763
- # session.response_queue[task_id].status = "completed"
764
- # session.response_queue[task_id].result = result
765
- # except Exception as e:
766
- # session.response_queue[task_id].status = "failed"
767
- # session.response_queue[task_id].error = str(e)
768
-
769
- # def generate_initial_response():
770
- # """生成初始响应消息"""
771
- # return "您的请求正在处理中"
772
-
773
- # def split_message(message, max_length=500):
774
- # """将长消息分段"""
775
- # return [message[i:i+max_length] for i in range(0, len(message), max_length)]
776
-
777
- # def append_status_message(content, has_pending_parts=False, is_processing=False):
778
- # """添加状态提示信息"""
779
- # status_message = "\n\n-------------------"
780
- # if is_processing:
781
- # status_message += "\n请回复'查询'获取结果"
782
- # elif has_pending_parts:
783
- # status_message += "\n当前消息已截断,发送'继续'查看后续内容"
784
- # status_message += "\n发送'新对话'开始新的对话"
785
- # return content + status_message
786
-
787
- # @app.route('/api/wx', methods=['GET', 'POST'])
788
- # def wechatai():
789
- # if request.method == 'GET':
790
- # return verify_wechat(request)
791
-
792
- # try:
793
- # message_data = parse_xml_message(request.data)
794
- # user_content = message_data['content'].strip()
795
- # from_user = message_data['from_user']
796
- # to_user = message_data['to_user']
797
-
798
- # logging.info(f"收到用户({from_user})消息: {user_content}")
799
- # session = session_manager.get_session(from_user)
800
-
801
- # if user_content == '新对话':
802
- # session_manager.clear_session(from_user)
803
- # return generate_response_xml(
804
- # from_user,
805
- # to_user,
806
- # append_status_message('已开始新的对话。请描述您的问题。')
807
- # )
808
-
809
- # if user_content == '继续':
810
- # if session.pending_parts:
811
- # next_part = session.pending_parts.pop(0)
812
- # has_more = bool(session.pending_parts)
813
- # return generate_response_xml(
814
- # from_user,
815
- # to_user,
816
- # append_status_message(next_part, has_more)
817
- # )
818
- # return generate_response_xml(
819
- # from_user,
820
- # to_user,
821
- # append_status_message('没有更多内容了。请继续您的问题。')
822
- # )
823
-
824
- # if user_content == '查询':
825
- # if session.current_task:
826
- # task_response = session.response_queue.get(session.current_task)
827
- # if task_response:
828
- # if task_response.status == "completed":
829
- # response = task_response.result
830
- # del session.response_queue[session.current_task]
831
- # session.current_task = None
832
-
833
- # if len(response) > 500:
834
- # parts = split_message(response)
835
- # first_part = parts.pop(0)
836
- # session.pending_parts = parts
837
- # return generate_response_xml(
838
- # from_user,
839
- # to_user,
840
- # append_status_message(first_part, True)
841
- # )
842
- # return generate_response_xml(
843
- # from_user,
844
- # to_user,
845
- # append_status_message(response)
846
- # )
847
- # elif task_response.status == "failed":
848
- # error_message = '处理过程中出现错误,请重新提问。'
849
- # del session.response_queue[session.current_task]
850
- # session.current_task = None
851
- # return generate_response_xml(
852
- # from_user,
853
- # to_user,
854
- # append_status_message(error_message)
855
- # )
856
- # else:
857
- # return generate_response_xml(
858
- # from_user,
859
- # to_user,
860
- # append_status_message('正在处理中,请稍后再次查询。', is_processing=True)
861
- # )
862
- # return generate_response_xml(
863
- # from_user,
864
- # to_user,
865
- # append_status_message('没有正在处理的请求。')
866
- # )
867
-
868
- # session.messages.append({"role": "user", "content": user_content})
869
-
870
- # task_id = str(uuid.uuid4())
871
- # session.current_task = task_id
872
- # session.response_queue[task_id] = AsyncResponse()
873
-
874
- # executor.submit(handle_async_task, session, task_id, session.messages.copy())
875
-
876
- # return generate_response_xml(
877
- # from_user,
878
- # to_user,
879
- # append_status_message(generate_initial_response(), is_processing=True)
880
- # )
881
-
882
- # except Exception as e:
883
- # logging.error(f"处理请求时出错: {str(e)}")
884
- # return generate_response_xml(
885
- # message_data['from_user'],
886
- # message_data['to_user'],
887
- # append_status_message('抱歉,系统暂时出现问题,请稍后重试。')
888
- # )
889
-
890
- # def cleanup_sessions():
891
- # """定期清理过期会话"""
892
- # while True:
893
- # time.sleep(3600)
894
- # try:
895
- # session_manager.cleanup_expired_sessions()
896
- # except Exception as e:
897
- # logging.error(f"清理会话时出错: {str(e)}")
898
-
899
- # if __name__ == '__main__':
900
- # cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
901
- # cleanup_thread.start()
902
-
903
- # app.run(host='0.0.0.0', port=7860, debug=True)
904
- #下面这个代码解决的是响应查询时重复回应的情况
905
- #!/usr/bin/env python
906
- # -*- coding: utf-8 -*-
907
- #
908
- #下面这个代码是告诉用户超时后就需要重新回答了
909
- #!/usr/bin/env python
910
- # -*- coding: utf-8 -*-
911
  from flask import Flask, request, make_response
912
  import hashlib
913
  import time
@@ -925,8 +15,12 @@ import asyncio
925
  from concurrent.futures import ThreadPoolExecutor
926
  import queue
927
  import uuid
 
 
 
 
 
928
 
929
- # 配置日志记录
930
  logging.basicConfig(
931
  level=logging.INFO,
932
  format='%(asctime)s - %(levelname)s - %(message)s',
@@ -936,30 +30,75 @@ logging.basicConfig(
936
  ]
937
  )
938
 
939
- # 加载环境变量
940
  load_dotenv()
941
 
942
  app = Flask(__name__)
943
 
944
- # 基础配置
945
  TOKEN = os.getenv('TOKEN')
 
 
946
  API_KEY = os.getenv("API_KEY")
947
  BASE_URL = os.getenv("OPENAI_BASE_URL")
948
- client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
949
 
950
- # 创建线程池
951
  executor = ThreadPoolExecutor(max_workers=10)
952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
953
  class AsyncResponse:
954
  def __init__(self):
955
- self.status = "processing" # processing, completed, failed
956
  self.result = None
957
  self.error = None
958
- self.create_time = time.time() # 任务创建时间
959
- self.timeout = 3600 # 任务超时时间(1小时)
960
 
961
  def is_expired(self):
962
- """检查任务是否过期"""
963
  return time.time() - self.create_time > self.timeout
964
 
965
  class UserSession:
@@ -969,14 +108,12 @@ class UserSession:
969
  self.last_active = time.time()
970
  self.current_task = None
971
  self.response_queue = {}
972
- self.session_timeout = 3600 # 会话超时时间(1小时)
973
 
974
  def is_expired(self):
975
- """检查会话是否过期"""
976
  return time.time() - self.last_active > self.session_timeout
977
 
978
  def cleanup_expired_tasks(self):
979
- """清理过期的任务"""
980
  expired_tasks = [
981
  task_id for task_id, response in self.response_queue.items()
982
  if response.is_expired()
@@ -990,6 +127,7 @@ class SessionManager:
990
  def __init__(self):
991
  self.sessions = {}
992
  self._lock = threading.Lock()
 
993
 
994
  def get_session(self, user_id):
995
  with self._lock:
@@ -997,9 +135,9 @@ class SessionManager:
997
  if user_id in self.sessions:
998
  session = self.sessions[user_id]
999
  if session.is_expired():
1000
- session = UserSession() # 创建新会话
1001
  else:
1002
- session.cleanup_expired_tasks() # 清理过期任务
1003
  else:
1004
  session = UserSession()
1005
  session.last_active = current_time
@@ -1025,88 +163,98 @@ class SessionManager:
1025
  session_manager = SessionManager()
1026
 
1027
  def convert_markdown_to_wechat(md_text):
1028
- """将Markdown转换为微信友好的文本格式"""
1029
  if not md_text:
1030
  return md_text
1031
 
1032
- # 处理标题
1033
  md_text = re.sub(r'^# (.*?)$', r'【标题】\1', md_text, flags=re.MULTILINE)
1034
  md_text = re.sub(r'^## (.*?)$', r'【子标题】\1', md_text, flags=re.MULTILINE)
1035
  md_text = re.sub(r'^### (.*?)$', r'【小标题】\1', md_text, flags=re.MULTILINE)
1036
-
1037
- # 处理强调语法
1038
- md_text = re.sub(r'\*\*(.*?)\*\*', r'『\1', md_text) # 粗体
1039
- md_text = re.sub(r'\*(.*?)\*', r'「\1」', md_text) # 斜体
1040
- md_text = re.sub(r'`(.*?)`', r'「\1」', md_text) # 行内代码
1041
-
1042
- # 处理列表
1043
- md_text = re.sub(r'^\- ', '• ', md_text, flags=re.MULTILINE) # 无序列表
1044
- md_text = re.sub(r'^\d\. ', '○ ', md_text, flags=re.MULTILINE) # 有序列表
1045
-
1046
- # 处理代码块
1047
  md_text = re.sub(r'```[\w]*\n(.*?)```', r'【代码开始】\n\1\n【代码结束】', md_text, flags=re.DOTALL)
1048
-
1049
- # 处理引用
1050
  md_text = re.sub(r'^> (.*?)$', r'▎\1', md_text, flags=re.MULTILINE)
1051
-
1052
- # 处理分隔线
1053
  md_text = re.sub(r'^-{3,}$', r'—————————', md_text, flags=re.MULTILINE)
1054
-
1055
- # 处理链接
1056
  md_text = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1(\2)', md_text)
1057
-
1058
- # 净化处理:去除多余的空行
1059
  md_text = re.sub(r'\n{3,}', '\n\n', md_text)
1060
 
1061
  return md_text
1062
 
1063
- def verify_wechat(request):
1064
- """验证微信服务器请求"""
1065
- data = request.args
1066
- signature = data.get('signature')
1067
- timestamp = data.get('timestamp')
1068
- nonce = data.get('nonce')
1069
- echostr = data.get('echostr')
1070
-
1071
- temp = [timestamp, nonce, TOKEN]
1072
- temp.sort()
1073
- temp = ''.join(temp)
1074
-
1075
- if hashlib.sha1(temp.encode('utf8')).hexdigest() == signature:
1076
- return echostr
1077
- return 'error', 403
1078
 
1079
  def parse_xml_message(xml_content):
1080
- """解析微信XML消息"""
1081
  root = ET.fromstring(xml_content)
1082
  return {
1083
- 'content': root.find('Content').text,
1084
  'from_user': root.find('FromUserName').text,
1085
  'to_user': root.find('ToUserName').text,
1086
- 'msg_id': root.find('MsgId').text,
1087
- 'create_time': root.find('CreateTime').text
 
1088
  }
1089
 
1090
- def generate_response_xml(to_user, from_user, content):
1091
- """生成回复的XML消息"""
1092
  formatted_content = convert_markdown_to_wechat(content)
1093
- xml_template = '''
1094
- <xml>
1095
- <ToUserName><![CDATA[%s]]></ToUserName>
1096
- <FromUserName><![CDATA[%s]]></FromUserName>
1097
- <CreateTime>%s</CreateTime>
1098
- <MsgType><![CDATA[text]]></MsgType>
1099
- <Content><![CDATA[%s]]></Content>
1100
- </xml>
1101
- '''
1102
- response = make_response(
1103
- xml_template % (to_user, from_user, str(int(time.time())), formatted_content)
1104
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
  response.content_type = 'application/xml'
1106
  return response
1107
 
1108
  def process_long_running_task(messages):
1109
- """处理耗时任务"""
1110
  try:
1111
  response = client.chat.completions.create(
1112
  model="gpt-4o-mini",
@@ -1119,7 +267,6 @@ def process_long_running_task(messages):
1119
  raise
1120
 
1121
  def handle_async_task(session, task_id, messages):
1122
- """异步任务处理函数"""
1123
  try:
1124
  if task_id not in session.response_queue:
1125
  return
@@ -1135,15 +282,12 @@ def handle_async_task(session, task_id, messages):
1135
  session.response_queue[task_id].error = str(e)
1136
 
1137
  def generate_initial_response():
1138
- """生成初始响应消息"""
1139
  return "您的请求正在处理中,请回复'查询'获取结果"
1140
 
1141
  def split_message(message, max_length=500):
1142
- """将长消息分段"""
1143
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
1144
 
1145
  def append_status_message(content, has_pending_parts=False, is_processing=False):
1146
- """添加状态提示信息"""
1147
  if "您的请求正在处理中" in content:
1148
  return content + "\n\n-------------------\n发送'新对话'开始新的对话"
1149
 
@@ -1158,10 +302,37 @@ def append_status_message(content, has_pending_parts=False, is_processing=False)
1158
  @app.route('/api/wx', methods=['GET', 'POST'])
1159
  def wechatai():
1160
  if request.method == 'GET':
1161
- return verify_wechat(request)
 
 
 
 
 
 
 
1162
 
1163
  try:
1164
- message_data = parse_xml_message(request.data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1165
  user_content = message_data['content'].strip()
1166
  from_user = message_data['from_user']
1167
  to_user = message_data['to_user']
@@ -1174,7 +345,8 @@ def wechatai():
1174
  return generate_response_xml(
1175
  from_user,
1176
  to_user,
1177
- append_status_message('已开始新的对话。请描述您的问题。')
 
1178
  )
1179
 
1180
  if user_content == '继续':
@@ -1184,12 +356,14 @@ def wechatai():
1184
  return generate_response_xml(
1185
  from_user,
1186
  to_user,
1187
- append_status_message(next_part, has_more)
 
1188
  )
1189
  return generate_response_xml(
1190
  from_user,
1191
  to_user,
1192
- append_status_message('没有更多内容了。请继续您的问题。')
 
1193
  )
1194
 
1195
  if user_content == '查询':
@@ -1197,13 +371,13 @@ def wechatai():
1197
  task_response = session.response_queue.get(session.current_task)
1198
  if task_response:
1199
  if task_response.is_expired():
1200
- # 处理过期任务
1201
  del session.response_queue[session.current_task]
1202
  session.current_task = None
1203
  return generate_response_xml(
1204
  from_user,
1205
  to_user,
1206
- append_status_message('请求已过期,请重新提问。')
 
1207
  )
1208
 
1209
  if task_response.status == "completed":
@@ -1219,12 +393,14 @@ def wechatai():
1219
  return generate_response_xml(
1220
  from_user,
1221
  to_user,
1222
- append_status_message(first_part, True)
 
1223
  )
1224
  return generate_response_xml(
1225
  from_user,
1226
  to_user,
1227
- append_status_message(response)
 
1228
  )
1229
  elif task_response.status == "failed":
1230
  error_message = '处理过程中出现错误,请重新提问。'
@@ -1233,18 +409,21 @@ def wechatai():
1233
  return generate_response_xml(
1234
  from_user,
1235
  to_user,
1236
- append_status_message(error_message)
 
1237
  )
1238
  else:
1239
  return generate_response_xml(
1240
  from_user,
1241
  to_user,
1242
- append_status_message('正在处理中,请稍后再次查询。', is_processing=True)
 
1243
  )
1244
  return generate_response_xml(
1245
  from_user,
1246
  to_user,
1247
- append_status_message('没有正���处理的请求。')
 
1248
  )
1249
 
1250
  session.messages.append({"role": "user", "content": user_content})
@@ -1258,7 +437,8 @@ def wechatai():
1258
  return generate_response_xml(
1259
  from_user,
1260
  to_user,
1261
- append_status_message(generate_initial_response(), is_processing=True)
 
1262
  )
1263
 
1264
  except Exception as e:
@@ -1266,11 +446,11 @@ def wechatai():
1266
  return generate_response_xml(
1267
  message_data['from_user'],
1268
  message_data['to_user'],
1269
- append_status_message('抱歉,系统暂时出现问题,请稍后重试。')
 
1270
  )
1271
 
1272
  def cleanup_sessions():
1273
- """定期清理过期会话"""
1274
  while True:
1275
  time.sleep(3600) # 每小时清理一次
1276
  try:
@@ -1279,9 +459,7 @@ def cleanup_sessions():
1279
  logging.error(f"清理会话时出错: {str(e)}")
1280
 
1281
  if __name__ == '__main__':
1282
- # 启动清理线程
1283
  cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
1284
  cleanup_thread.start()
1285
 
1286
- # 启动Flask应用
1287
  app.run(host='0.0.0.0', port=7860, debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from flask import Flask, request, make_response
2
  import hashlib
3
  import time
 
15
  from concurrent.futures import ThreadPoolExecutor
16
  import queue
17
  import uuid
18
+ import base64
19
+ from Crypto.Cipher import AES
20
+ import struct
21
+ import random
22
+ import string
23
 
 
24
  logging.basicConfig(
25
  level=logging.INFO,
26
  format='%(asctime)s - %(levelname)s - %(message)s',
 
30
  ]
31
  )
32
 
 
33
  load_dotenv()
34
 
35
  app = Flask(__name__)
36
 
 
37
  TOKEN = os.getenv('TOKEN')
38
+ ENCODING_AES_KEY = os.getenv('ENCODING_AES_KEY')
39
+ APPID = os.getenv('APPID')
40
  API_KEY = os.getenv("API_KEY")
41
  BASE_URL = os.getenv("OPENAI_BASE_URL")
 
42
 
43
+ client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
44
  executor = ThreadPoolExecutor(max_workers=10)
45
 
46
+ class WeChatCrypto:
47
+ def __init__(self, key, app_id):
48
+ self.key = base64.b64decode(key + '=')
49
+ self.app_id = app_id
50
+
51
+ def encrypt(self, text):
52
+ # 生成随机16字节字符串
53
+ random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
54
+ text_bytes = text.encode('utf-8')
55
+
56
+ # 构造明文字符串
57
+ msg_len = struct.pack('>I', len(text_bytes))
58
+ message = random_str.encode('utf-8') + msg_len + text_bytes + self.app_id.encode('utf-8')
59
+
60
+ # 补位
61
+ pad_len = 32 - (len(message) % 32)
62
+ message += chr(pad_len).encode('utf-8') * pad_len
63
+
64
+ # 加密
65
+ cipher = AES.new(self.key, AES.MODE_CBC, self.key[:16])
66
+ encrypted = cipher.encrypt(message)
67
+ return base64.b64encode(encrypted).decode('utf-8')
68
+
69
+ def decrypt(self, encrypted_text):
70
+ # Base64解码
71
+ encrypted_data = base64.b64decode(encrypted_text)
72
+
73
+ # 解密
74
+ cipher = AES.new(self.key, AES.MODE_CBC, self.key[:16])
75
+ decrypted = cipher.decrypt(encrypted_data)
76
+
77
+ # 获取填充长度
78
+ pad_len = decrypted[-1]
79
+ if not isinstance(pad_len, int):
80
+ pad_len = ord(pad_len)
81
+ content = decrypted[16:-pad_len]
82
+
83
+ # 获取消息长度
84
+ msg_len = struct.unpack('>I', content[:4])[0]
85
+ xml_content = content[4:msg_len + 4].decode('utf-8')
86
+ app_id = content[msg_len + 4:].decode('utf-8')
87
+
88
+ if app_id != self.app_id:
89
+ raise ValueError('Invalid AppID')
90
+
91
+ return xml_content
92
+
93
  class AsyncResponse:
94
  def __init__(self):
95
+ self.status = "processing"
96
  self.result = None
97
  self.error = None
98
+ self.create_time = time.time()
99
+ self.timeout = 3600
100
 
101
  def is_expired(self):
 
102
  return time.time() - self.create_time > self.timeout
103
 
104
  class UserSession:
 
108
  self.last_active = time.time()
109
  self.current_task = None
110
  self.response_queue = {}
111
+ self.session_timeout = 3600
112
 
113
  def is_expired(self):
 
114
  return time.time() - self.last_active > self.session_timeout
115
 
116
  def cleanup_expired_tasks(self):
 
117
  expired_tasks = [
118
  task_id for task_id, response in self.response_queue.items()
119
  if response.is_expired()
 
127
  def __init__(self):
128
  self.sessions = {}
129
  self._lock = threading.Lock()
130
+ self.crypto = WeChatCrypto(ENCODING_AES_KEY, APPID)
131
 
132
  def get_session(self, user_id):
133
  with self._lock:
 
135
  if user_id in self.sessions:
136
  session = self.sessions[user_id]
137
  if session.is_expired():
138
+ session = UserSession()
139
  else:
140
+ session.cleanup_expired_tasks()
141
  else:
142
  session = UserSession()
143
  session.last_active = current_time
 
163
  session_manager = SessionManager()
164
 
165
  def convert_markdown_to_wechat(md_text):
 
166
  if not md_text:
167
  return md_text
168
 
 
169
  md_text = re.sub(r'^# (.*?)$', r'【标题】\1', md_text, flags=re.MULTILINE)
170
  md_text = re.sub(r'^## (.*?)$', r'【子标题】\1', md_text, flags=re.MULTILINE)
171
  md_text = re.sub(r'^### (.*?)$', r'【小标题】\1', md_text, flags=re.MULTILINE)
172
+ md_text = re.sub(r'\*\*(.*?)\*\*', r'『\1』', md_text)
173
+ md_text = re.sub(r'\*(.*?)\*', r'「\1」', md_text)
174
+ md_text = re.sub(r'`(.*?)`', r'「\1', md_text)
175
+ md_text = re.sub(r'^\- ', '', md_text, flags=re.MULTILINE)
176
+ md_text = re.sub(r'^\d\. ', '', md_text, flags=re.MULTILINE)
 
 
 
 
 
 
177
  md_text = re.sub(r'```[\w]*\n(.*?)```', r'【代码开始】\n\1\n【代码结束】', md_text, flags=re.DOTALL)
 
 
178
  md_text = re.sub(r'^> (.*?)$', r'▎\1', md_text, flags=re.MULTILINE)
 
 
179
  md_text = re.sub(r'^-{3,}$', r'—————————', md_text, flags=re.MULTILINE)
 
 
180
  md_text = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1(\2)', md_text)
 
 
181
  md_text = re.sub(r'\n{3,}', '\n\n', md_text)
182
 
183
  return md_text
184
 
185
+ def verify_signature(signature, timestamp, nonce, token):
186
+ items = [token, timestamp, nonce]
187
+ items.sort()
188
+ temp_str = ''.join(items)
189
+ hash_sha1 = hashlib.sha1(temp_str.encode('utf-8')).hexdigest()
190
+ return hash_sha1 == signature
191
+
192
+ def verify_msg_signature(msg_signature, timestamp, nonce, token, encrypt_msg):
193
+ items = [token, timestamp, nonce, encrypt_msg]
194
+ items.sort()
195
+ temp_str = ''.join(items)
196
+ hash_sha1 = hashlib.sha1(temp_str.encode('utf-8')).hexdigest()
197
+ return hash_sha1 == msg_signature
 
 
198
 
199
  def parse_xml_message(xml_content):
 
200
  root = ET.fromstring(xml_content)
201
  return {
202
+ 'content': root.find('Content').text if root.find('Content') is not None else '',
203
  'from_user': root.find('FromUserName').text,
204
  'to_user': root.find('ToUserName').text,
205
+ 'msg_id': root.find('MsgId').text if root.find('MsgId') is not None else '',
206
+ 'create_time': root.find('CreateTime').text,
207
+ 'msg_type': root.find('MsgType').text
208
  }
209
 
210
+ def generate_response_xml(to_user, from_user, content, encrypt_type='aes'):
 
211
  formatted_content = convert_markdown_to_wechat(content)
212
+ timestamp = str(int(time.time()))
213
+ nonce = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
214
+
215
+ if encrypt_type == 'aes':
216
+ xml_content = f'''
217
+ <xml>
218
+ <ToUserName><![CDATA[{to_user}]]></ToUserName>
219
+ <FromUserName><![CDATA[{from_user}]]></FromUserName>
220
+ <CreateTime>{timestamp}</CreateTime>
221
+ <MsgType><![CDATA[text]]></MsgType>
222
+ <Content><![CDATA[{formatted_content}]]></Content>
223
+ </xml>
224
+ '''
225
+
226
+ # 加密消息内容
227
+ encrypted = session_manager.crypto.encrypt(xml_content)
228
+
229
+ # 生成签名
230
+ signature_list = [TOKEN, timestamp, nonce, encrypted]
231
+ signature_list.sort()
232
+ msg_signature = hashlib.sha1(''.join(signature_list).encode('utf-8')).hexdigest()
233
+
234
+ response_xml = f'''
235
+ <xml>
236
+ <Encrypt><![CDATA[{encrypted}]]></Encrypt>
237
+ <MsgSignature><![CDATA[{msg_signature}]]></MsgSignature>
238
+ <TimeStamp>{timestamp}</TimeStamp>
239
+ <Nonce><![CDATA[{nonce}]]></Nonce>
240
+ </xml>
241
+ '''
242
+ else:
243
+ response_xml = f'''
244
+ <xml>
245
+ <ToUserName><![CDATA[{to_user}]]></ToUserName>
246
+ <FromUserName><![CDATA[{from_user}]]></FromUserName>
247
+ <CreateTime>{timestamp}</CreateTime>
248
+ <MsgType><![CDATA[text]]></MsgType>
249
+ <Content><![CDATA[{formatted_content}]]></Content>
250
+ </xml>
251
+ '''
252
+
253
+ response = make_response(response_xml)
254
  response.content_type = 'application/xml'
255
  return response
256
 
257
  def process_long_running_task(messages):
 
258
  try:
259
  response = client.chat.completions.create(
260
  model="gpt-4o-mini",
 
267
  raise
268
 
269
  def handle_async_task(session, task_id, messages):
 
270
  try:
271
  if task_id not in session.response_queue:
272
  return
 
282
  session.response_queue[task_id].error = str(e)
283
 
284
  def generate_initial_response():
 
285
  return "您的请求正在处理中,请回复'查询'获取结果"
286
 
287
  def split_message(message, max_length=500):
 
288
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
289
 
290
  def append_status_message(content, has_pending_parts=False, is_processing=False):
 
291
  if "您的请求正在处理中" in content:
292
  return content + "\n\n-------------------\n发送'新对话'开始新的对话"
293
 
 
302
  @app.route('/api/wx', methods=['GET', 'POST'])
303
  def wechatai():
304
  if request.method == 'GET':
305
+ signature = request.args.get('signature')
306
+ timestamp = request.args.get('timestamp')
307
+ nonce = request.args.get('nonce')
308
+ echostr = request.args.get('echostr')
309
+
310
+ if verify_signature(signature, timestamp, nonce, TOKEN):
311
+ return echostr
312
+ return 'error', 403
313
 
314
  try:
315
+ encrypt_type = request.args.get('encrypt_type', '')
316
+
317
+ if encrypt_type == 'aes':
318
+ msg_signature = request.args.get('msg_signature')
319
+ timestamp = request.args.get('timestamp')
320
+ nonce = request.args.get('nonce')
321
+
322
+ # 解析加密的XML
323
+ xml_tree = ET.fromstring(request.data)
324
+ encrypted_text = xml_tree.find('Encrypt').text
325
+
326
+ # 验证消息签名
327
+ if not verify_msg_signature(msg_signature, timestamp, nonce, TOKEN, encrypted_text):
328
+ return 'Invalid signature', 403
329
+
330
+ # 解密消息
331
+ decrypted_xml = session_manager.crypto.decrypt(encrypted_text)
332
+ message_data = parse_xml_message(decrypted_xml)
333
+ else:
334
+ message_data = parse_xml_message(request.data)
335
+
336
  user_content = message_data['content'].strip()
337
  from_user = message_data['from_user']
338
  to_user = message_data['to_user']
 
345
  return generate_response_xml(
346
  from_user,
347
  to_user,
348
+ append_status_message('已开始新的对话。请描述您的问题。'),
349
+ encrypt_type
350
  )
351
 
352
  if user_content == '继续':
 
356
  return generate_response_xml(
357
  from_user,
358
  to_user,
359
+ append_status_message(next_part, has_more),
360
+ encrypt_type
361
  )
362
  return generate_response_xml(
363
  from_user,
364
  to_user,
365
+ append_status_message('没有更多内容了。请继续您的问题。'),
366
+ encrypt_type
367
  )
368
 
369
  if user_content == '查询':
 
371
  task_response = session.response_queue.get(session.current_task)
372
  if task_response:
373
  if task_response.is_expired():
 
374
  del session.response_queue[session.current_task]
375
  session.current_task = None
376
  return generate_response_xml(
377
  from_user,
378
  to_user,
379
+ append_status_message('请求已过期,请重新提问。'),
380
+ encrypt_type
381
  )
382
 
383
  if task_response.status == "completed":
 
393
  return generate_response_xml(
394
  from_user,
395
  to_user,
396
+ append_status_message(first_part, True),
397
+ encrypt_type
398
  )
399
  return generate_response_xml(
400
  from_user,
401
  to_user,
402
+ append_status_message(response),
403
+ encrypt_type
404
  )
405
  elif task_response.status == "failed":
406
  error_message = '处理过程中出现错误,请重新提问。'
 
409
  return generate_response_xml(
410
  from_user,
411
  to_user,
412
+ append_status_message(error_message),
413
+ encrypt_type
414
  )
415
  else:
416
  return generate_response_xml(
417
  from_user,
418
  to_user,
419
+ append_status_message('正在处理中,请稍后再次查询。', is_processing=True),
420
+ encrypt_type
421
  )
422
  return generate_response_xml(
423
  from_user,
424
  to_user,
425
+ append_status_message('没有正在处理的请求。'),
426
+ encrypt_type
427
  )
428
 
429
  session.messages.append({"role": "user", "content": user_content})
 
437
  return generate_response_xml(
438
  from_user,
439
  to_user,
440
+ append_status_message(generate_initial_response(), is_processing=True),
441
+ encrypt_type
442
  )
443
 
444
  except Exception as e:
 
446
  return generate_response_xml(
447
  message_data['from_user'],
448
  message_data['to_user'],
449
+ append_status_message('抱歉,系统暂时出现问题,请稍后重试。'),
450
+ encrypt_type if 'encrypt_type' in locals() else ''
451
  )
452
 
453
  def cleanup_sessions():
 
454
  while True:
455
  time.sleep(3600) # 每小时清理一次
456
  try:
 
459
  logging.error(f"清理会话时出错: {str(e)}")
460
 
461
  if __name__ == '__main__':
 
462
  cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
463
  cleanup_thread.start()
464
 
 
465
  app.run(host='0.0.0.0', port=7860, debug=True)