mistpe commited on
Commit
1d45c93
·
verified ·
1 Parent(s): c2c436e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +452 -159
app.py CHANGED
@@ -1,3 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from flask import Flask, request, make_response
2
  import hashlib
3
  import time
@@ -247,22 +292,75 @@ def verify_signature(signature, timestamp, nonce, token):
247
  return hash_sha1 == signature
248
 
249
  def verify_msg_signature(msg_signature, timestamp, nonce, token, encrypt_msg):
 
 
 
 
 
 
 
 
 
 
 
250
  items = [token, timestamp, nonce, encrypt_msg]
251
  items.sort()
252
  temp_str = ''.join(items)
253
  hash_sha1 = hashlib.sha1(temp_str.encode('utf-8')).hexdigest()
254
  return hash_sha1 == msg_signature
255
 
 
256
  def parse_xml_message(xml_content):
 
 
 
257
  root = ET.fromstring(xml_content)
258
- return {
259
- 'content': root.find('Content').text if root.find('Content') is not None else '',
260
  'from_user': root.find('FromUserName').text,
261
  'to_user': root.find('ToUserName').text,
262
- 'msg_id': root.find('MsgId').text if root.find('MsgId') is not None else '',
263
  'create_time': root.find('CreateTime').text,
264
- 'msg_type': root.find('MsgType').text
 
 
 
265
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  def generate_response_xml(to_user, from_user, content, response_type='text', media_id=None, encrypt_type='aes'):
268
  timestamp = str(int(time.time()))
@@ -350,96 +448,213 @@ def upload_image_to_wechat(image_data):
350
  logging.error(error_msg)
351
  raise
352
 
353
- def process_long_running_task(messages):
 
 
 
 
 
 
 
 
 
354
  try:
355
- logging.info("开始调用AI服务")
356
- response = client.chat.completions.create(
357
- model="o3-mini",
358
- messages=messages,
359
- tools=TOOLS,
360
- tool_choice="auto",
361
- timeout=60
362
- )
363
- logging.info("AI服务响应成功")
364
-
365
- if response.choices[0].message.tool_calls:
366
- logging.info("检测到tool调用")
367
- tool_call = response.choices[0].message.tool_calls[0]
368
- if tool_call.function.name == "generate_image":
369
- logging.info("开始处理图片生成请求")
370
- args = json.loads(tool_call.function.arguments)
371
- image_response = requests.post(
372
- IMAGE_MODEL_URL,
373
- headers={
374
- 'Content-Type': 'application/json',
375
- 'Authorization': f'Bearer {IMAGE_MODEL_KEY}'
376
- },
377
- json={
378
- "model": "grok-latest-image",
379
- "messages": [{
380
- "role": "user",
381
- "content": args['prompt']
382
- }]
383
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  )
385
- image_response.raise_for_status()
386
- result = image_response.json()
387
- logging.info("图片生成成功,准备下载图片")
388
-
389
- # 从markdown格式中提取URL
390
- markdown_content = result['choices'][0]['message']['content']
391
- image_url = re.search(r'\!\[image\]\((.*?)\)', markdown_content).group(1)
392
- logging.info(f"提取到图片URL: {image_url}")
393
 
394
- img_response = requests.get(image_url)
395
- img_response.raise_for_status()
396
- media_id = upload_image_to_wechat(img_response.content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
 
398
  return {
399
- "type": "image",
400
- "media_id": media_id
401
  }
402
-
403
- logging.info("返回文本响应")
404
- return {
405
- "type": "text",
406
- "content": response.choices[0].message.content
407
- }
 
 
408
  except Exception as e:
409
  logging.error(f"API调用错误: {str(e)}")
410
  raise
411
 
412
- def handle_async_task(session, task_id, messages):
 
 
 
 
413
  try:
414
- logging.info(f"开始处理异步任务: {task_id}")
 
415
  if task_id not in session.response_queue:
416
  return
417
 
418
- result = process_long_running_task(messages)
419
-
 
 
 
420
  if task_id in session.response_queue and not session.response_queue[task_id].is_expired():
421
  session.response_queue[task_id].status = "completed"
422
  session.response_queue[task_id].response_type = result.get("type", "text")
 
423
  if result["type"] == "image":
424
  session.response_queue[task_id].media_id = result["media_id"]
425
  session.response_queue[task_id].result = None
426
- messages.append({"role": "assistant", "content": "图片已生成"})
427
  else:
428
  session.response_queue[task_id].result = result["content"]
 
 
429
  messages.append({"role": "assistant", "content": result["content"]})
 
430
  except Exception as e:
431
  logging.error(f"异步任务处理失败: {str(e)}")
432
  if task_id in session.response_queue:
433
  session.response_queue[task_id].status = "failed"
434
  session.response_queue[task_id].error = str(e)
435
 
 
436
  def generate_initial_response():
437
  return "您的请求正在处理中,请回复'查询'获取结果(生图需要时间)"
438
 
439
  def split_message(message, max_length=500):
 
 
 
 
 
 
 
 
440
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
441
 
442
  def append_status_message(content, has_pending_parts=False, is_processing=False):
 
 
 
 
 
 
 
 
 
443
  if "您的请求正在处理中" in content:
444
  return content + "\n\n-------------------\n发送'新对话'开始新的对话"
445
 
@@ -455,6 +670,9 @@ session_manager = SessionManager()
455
 
456
  @app.route('/api/wx', methods=['GET', 'POST'])
457
  def wechatai():
 
 
 
458
  if request.method == 'GET':
459
  signature = request.args.get('signature')
460
  timestamp = request.args.get('timestamp')
@@ -467,153 +685,228 @@ def wechatai():
467
 
468
  try:
469
  encrypt_type = request.args.get('encrypt_type', '')
 
470
 
471
  if encrypt_type == 'aes':
472
  msg_signature = request.args.get('msg_signature')
473
  timestamp = request.args.get('timestamp')
474
  nonce = request.args.get('nonce')
475
 
 
476
  xml_tree = ET.fromstring(request.data)
477
  encrypted_text = xml_tree.find('Encrypt').text
478
 
 
479
  if not verify_msg_signature(msg_signature, timestamp, nonce, TOKEN, encrypted_text):
 
480
  return 'Invalid signature', 403
481
 
482
- decrypted_xml = session_manager.crypto.decrypt(encrypted_text)
483
- message_data = parse_xml_message(decrypted_xml)
 
 
 
 
 
484
  else:
485
- message_data = parse_xml_message(request.data)
 
 
 
 
 
486
 
487
- user_content = message_data['content'].strip()
488
  from_user = message_data['from_user']
489
  to_user = message_data['to_user']
 
490
 
491
- logging.info(f"收到用户({from_user})消息: {user_content}")
492
- session = session_manager.get_session(from_user)
493
-
494
- if user_content == '新对话':
495
- session_manager.clear_session(from_user)
 
 
496
  return generate_response_xml(
497
  from_user,
498
  to_user,
499
- append_status_message('已开始新的对话。请描述您的问题。'),
500
  encrypt_type=encrypt_type
501
  )
502
 
503
- if user_content == '继续':
504
- if session.pending_parts:
505
- next_part = session.pending_parts.pop(0)
506
- has_more = bool(session.pending_parts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
507
  return generate_response_xml(
508
  from_user,
509
  to_user,
510
- append_status_message(next_part, has_more),
511
  encrypt_type=encrypt_type
512
  )
513
- return generate_response_xml(
514
- from_user,
515
- to_user,
516
- append_status_message('没有更多内容了。请继续您的问题。'),
517
- encrypt_type=encrypt_type
518
- )
519
-
520
- if user_content == '查询':
521
- if session.current_task:
522
- task_response = session.response_queue.get(session.current_task)
523
- if task_response:
524
- if task_response.is_expired():
525
- del session.response_queue[session.current_task]
526
- session.current_task = None
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  return generate_response_xml(
528
  from_user,
529
  to_user,
530
- append_status_message('请求已过期,请重新提问。'),
531
  encrypt_type=encrypt_type
532
  )
533
-
534
- if task_response.status == "completed":
535
- if task_response.response_type == "image":
536
- logging.info("返回图片响应")
537
- del session.response_queue[session.current_task]
538
- session.current_task = None
539
- return generate_response_xml(
540
- from_user,
541
- to_user,
542
- "",
543
- response_type="image",
544
- media_id=task_response.media_id,
545
- encrypt_type=encrypt_type
546
- )
547
- else:
548
- response = task_response.result
549
- del session.response_queue[session.current_task]
550
- session.current_task = None
 
 
551
 
552
- if len(response) > 500:
553
- parts = split_message(response)
554
- first_part = parts.pop(0)
555
- session.pending_parts = parts
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  return generate_response_xml(
557
  from_user,
558
  to_user,
559
- append_status_message(first_part, True),
560
  encrypt_type=encrypt_type
561
  )
562
- return generate_response_xml(
563
- from_user,
564
- to_user,
565
- append_status_message(response),
566
- encrypt_type=encrypt_type
567
- )
568
- elif task_response.status == "failed":
569
- error_message = '处理过程中出现错误,请重新提问。'
570
- del session.response_queue[session.current_task]
571
- session.current_task = None
572
- return generate_response_xml(
573
- from_user,
574
- to_user,
575
- append_status_message(error_message),
576
- encrypt_type=encrypt_type
577
- )
578
- else:
579
- return generate_response_xml(
580
- from_user,
581
- to_user,
582
- append_status_message('正在处理中,请稍后再次查询。(生图需要时间)', is_processing=True),
583
- encrypt_type=encrypt_type
584
- )
585
- return generate_response_xml(
586
- from_user,
587
- to_user,
588
- append_status_message('没有正在处理的请求。'),
589
- encrypt_type=encrypt_type
590
- )
591
-
592
- session.messages.append({"role": "user", "content": user_content})
593
-
594
- task_id = str(uuid.uuid4())
595
- session.current_task = task_id
596
- session.response_queue[task_id] = AsyncResponse()
597
-
598
- executor.submit(handle_async_task, session, task_id, session.messages.copy())
599
-
600
- logging.info("返回初始响应")
601
- return generate_response_xml(
602
- from_user,
603
- to_user,
604
- append_status_message(generate_initial_response(), is_processing=True),
605
- encrypt_type=encrypt_type
606
- )
607
 
608
  except Exception as e:
609
  logging.error(f"处理请求时出错: {str(e)}")
610
  return generate_response_xml(
611
- message_data['from_user'],
612
- message_data['to_user'],
613
  append_status_message('抱歉,系统暂时出现问题,请稍后重试。'),
614
  encrypt_type if 'encrypt_type' in locals() else ''
615
  )
616
-
617
  def cleanup_sessions():
618
  while True:
619
  time.sleep(3600) # 每小时清理一次
@@ -626,4 +919,4 @@ if __name__ == '__main__':
626
  cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
627
  cleanup_thread.start()
628
 
629
- app.run(host='0.0.0.0', port=7860, debug=True)
 
1
+ Hugging Face's logo
2
+ Hugging Face
3
+ Models
4
+ Datasets
5
+ Spaces
6
+ Posts
7
+ Docs
8
+ Enterprise
9
+ Pricing
10
+
11
+
12
+
13
+ Spaces:
14
+
15
+ mistpe
16
+ /
17
+ wewe
18
+
19
+
20
+ like
21
+ 1
22
+
23
+ App
24
+ Files
25
+ Community
26
+ Settings
27
+ wewe
28
+ /
29
+ app.py
30
+
31
+ mistpe's picture
32
+ mistpe
33
+ Update app.py
34
+ c2c436e
35
+ verified
36
+ 5 days ago
37
+ raw
38
+
39
+ Copy download link
40
+ history
41
+ blame
42
+ edit
43
+ delete
44
+
45
+ 25 kB
46
  from flask import Flask, request, make_response
47
  import hashlib
48
  import time
 
292
  return hash_sha1 == signature
293
 
294
  def verify_msg_signature(msg_signature, timestamp, nonce, token, encrypt_msg):
295
+ """
296
+ 验证消息签名
297
+ Args:
298
+ msg_signature: 消息签名
299
+ timestamp: 时间戳
300
+ nonce: 随机数
301
+ token: 验证令牌
302
+ encrypt_msg: 加密的消息内容
303
+ Returns:
304
+ bool: 签名是否有效
305
+ """
306
  items = [token, timestamp, nonce, encrypt_msg]
307
  items.sort()
308
  temp_str = ''.join(items)
309
  hash_sha1 = hashlib.sha1(temp_str.encode('utf-8')).hexdigest()
310
  return hash_sha1 == msg_signature
311
 
312
+
313
  def parse_xml_message(xml_content):
314
+ """
315
+ 解析微信XML消息,支持文本和图片消息类型
316
+ """
317
  root = ET.fromstring(xml_content)
318
+ message = {
 
319
  'from_user': root.find('FromUserName').text,
320
  'to_user': root.find('ToUserName').text,
 
321
  'create_time': root.find('CreateTime').text,
322
+ 'msg_type': root.find('MsgType').text,
323
+ 'msg_id': root.find('MsgId').text if root.find('MsgId') is not None else '',
324
+ 'msg_data_id': root.find('MsgDataId').text if root.find('MsgDataId') is not None else '',
325
+ 'idx': root.find('Idx').text if root.find('Idx') is not None else ''
326
  }
327
+
328
+ if message['msg_type'] == 'text':
329
+ message['content'] = root.find('Content').text if root.find('Content') is not None else ''
330
+ elif message['msg_type'] == 'image':
331
+ message['pic_url'] = root.find('PicUrl').text
332
+ message['media_id'] = root.find('MediaId').text
333
+
334
+ return message
335
+
336
+ def get_image_content(media_id):
337
+ """
338
+ 通过微信接口获取图片内容
339
+ """
340
+ try:
341
+ access_token = token_manager.get_token()
342
+ url = f'https://api.weixin.qq.com/cgi-bin/media/get?access_token={access_token}&media_id={media_id}'
343
+
344
+ logging.info(f"开始下载图片,media_id: {media_id}")
345
+ response = requests.get(url)
346
+
347
+ if response.headers.get('Content-Type') == 'text/plain':
348
+ # 如果返回JSON错误信息
349
+ error_info = response.json()
350
+ if error_info.get('errcode') == 40001:
351
+ # access_token过期,刷新后重试
352
+ logging.info("access_token已过期,正在刷新并重试")
353
+ access_token = token_manager.refresh_token()
354
+ url = f'https://api.weixin.qq.com/cgi-bin/media/get?access_token={access_token}&media_id={media_id}'
355
+ response = requests.get(url)
356
+
357
+ response.raise_for_status()
358
+ return response.content
359
+
360
+ except Exception as e:
361
+ logging.error(f"获取图片内容失败: {str(e)}")
362
+ raise
363
+
364
 
365
  def generate_response_xml(to_user, from_user, content, response_type='text', media_id=None, encrypt_type='aes'):
366
  timestamp = str(int(time.time()))
 
448
  logging.error(error_msg)
449
  raise
450
 
451
+ def process_long_running_task(messages, message_type='text', image_data=None):
452
+ """
453
+ 处理长时间运行的任务,支持文本对话和图片识别
454
+ Args:
455
+ messages: 消息历史记录列表
456
+ message_type: 消息类型,'text'或'image'
457
+ image_data: 图片相关数据,包含media_id等信息
458
+ Returns:
459
+ dict: 包含处理结果的字典
460
+ """
461
  try:
462
+ logging.info(f"开始调用AI服务,消息类型: {message_type}")
463
+
464
+ if message_type == 'image':
465
+ try:
466
+ # 获取图片内容
467
+ image_content = get_image_content(image_data['media_id'])
468
+ # 将图片内容转换为base64
469
+ image_base64 = base64.b64encode(image_content).decode('utf-8')
470
+
471
+ # 构建图像识别请求
472
+ image_messages = [
473
+ {
474
+ "role": "user",
475
+ "content": [
476
+ {"type": "text", "text": "请详细描述这张图片中的内容,包括主要对象、场景、活动等关键信息"},
477
+ {
478
+ "type": "image_url",
479
+ "image_url": {
480
+ "url": f"data:image/jpeg;base64,{image_base64}"
481
+ }
482
+ }
483
+ ]
 
 
 
 
 
 
484
  }
485
+ ]
486
+
487
+ logging.info("开始调用图像识别模型")
488
+ image_response = client.chat.completions.create(
489
+ model="gpt-4o-mini",
490
+ messages=image_messages,
491
+ max_tokens=300,
492
+ timeout=60
493
+ )
494
+ logging.info("图像识别完成")
495
+
496
+ # 检查响应是否成功
497
+ if not image_response.choices:
498
+ raise Exception("图像识别服务未返回有效结果")
499
+
500
+ return {
501
+ "type": "text",
502
+ "content": image_response.choices[0].message.content
503
+ }
504
+
505
+ except requests.exceptions.RequestException as e:
506
+ logging.error(f"获取或处理图片时发生网络错误: {str(e)}")
507
+ raise
508
+ except Exception as e:
509
+ logging.error(f"图像识别过程中发生错误: {str(e)}")
510
+ raise
511
+
512
+ else:
513
+ # 处理文本消息
514
+ try:
515
+ logging.info("开始处理文本消息")
516
+ response = client.chat.completions.create(
517
+ model="o3-mini",
518
+ messages=messages,
519
+ tools=TOOLS,
520
+ tool_choice="auto",
521
+ timeout=60
522
  )
 
 
 
 
 
 
 
 
523
 
524
+ # 检查是否需要生成图片
525
+ if response.choices[0].message.tool_calls:
526
+ tool_call = response.choices[0].message.tool_calls[0]
527
+ if tool_call.function.name == "generate_image":
528
+ try:
529
+ logging.info("检测到图片生成请求")
530
+ args = json.loads(tool_call.function.arguments)
531
+
532
+ # 调用图片生成服务
533
+ image_generation_response = requests.post(
534
+ IMAGE_MODEL_URL,
535
+ headers={
536
+ 'Content-Type': 'application/json',
537
+ 'Authorization': f'Bearer {IMAGE_MODEL_KEY}'
538
+ },
539
+ json={
540
+ "model": "grok-latest-image",
541
+ "messages": [{
542
+ "role": "user",
543
+ "content": args['prompt']
544
+ }]
545
+ },
546
+ timeout=60
547
+ )
548
+ image_generation_response.raise_for_status()
549
+ generation_result = image_generation_response.json()
550
+
551
+ if 'choices' not in generation_result or not generation_result['choices']:
552
+ raise Exception("图片生成服务未返回有效结果")
553
+
554
+ # 从markdown格式中提取URL
555
+ markdown_content = generation_result['choices'][0]['message']['content']
556
+ image_url_match = re.search(r'\!\[image\]\((.*?)\)', markdown_content)
557
+ if not image_url_match:
558
+ raise Exception("无法从响应中提取图片URL")
559
+
560
+ image_url = image_url_match.group(1)
561
+
562
+ # 下载生成的图片
563
+ img_response = requests.get(image_url, timeout=30)
564
+ img_response.raise_for_status()
565
+
566
+ # 上传图片到微信服务器
567
+ media_id = upload_image_to_wechat(img_response.content)
568
+
569
+ return {
570
+ "type": "image",
571
+ "media_id": media_id
572
+ }
573
+
574
+ except requests.exceptions.RequestException as e:
575
+ logging.error(f"图片生成过程中发生网络错误: {str(e)}")
576
+ raise
577
+ except Exception as e:
578
+ logging.error(f"图片生成过程中发生错误: {str(e)}")
579
+ raise
580
 
581
+ # 返回文本响应
582
  return {
583
+ "type": "text",
584
+ "content": response.choices[0].message.content
585
  }
586
+
587
+ except requests.exceptions.RequestException as e:
588
+ logging.error(f"处理文本消息时发生网络错误: {str(e)}")
589
+ raise
590
+ except Exception as e:
591
+ logging.error(f"处理文本消息时发生错误: {str(e)}")
592
+ raise
593
+
594
  except Exception as e:
595
  logging.error(f"API调用错误: {str(e)}")
596
  raise
597
 
598
+
599
+ def handle_async_task(session, task_id, messages=None, message_type='text', message_data=None):
600
+ """
601
+ 处理异步任务,支持文本对话和图片识别
602
+ """
603
  try:
604
+ logging.info(f"开始处理异步任务: {task_id}, 类型: {message_type}")
605
+
606
  if task_id not in session.response_queue:
607
  return
608
 
609
+ if message_type == 'image':
610
+ result = process_long_running_task(None, 'image', message_data)
611
+ else:
612
+ result = process_long_running_task(messages)
613
+
614
  if task_id in session.response_queue and not session.response_queue[task_id].is_expired():
615
  session.response_queue[task_id].status = "completed"
616
  session.response_queue[task_id].response_type = result.get("type", "text")
617
+
618
  if result["type"] == "image":
619
  session.response_queue[task_id].media_id = result["media_id"]
620
  session.response_queue[task_id].result = None
 
621
  else:
622
  session.response_queue[task_id].result = result["content"]
623
+
624
+ if messages and result["type"] == "text":
625
  messages.append({"role": "assistant", "content": result["content"]})
626
+
627
  except Exception as e:
628
  logging.error(f"异步任务处理失败: {str(e)}")
629
  if task_id in session.response_queue:
630
  session.response_queue[task_id].status = "failed"
631
  session.response_queue[task_id].error = str(e)
632
 
633
+
634
  def generate_initial_response():
635
  return "您的请求正在处理中,请回复'查询'获取结果(生图需要时间)"
636
 
637
  def split_message(message, max_length=500):
638
+ """
639
+ 将长消息分割成多个部分
640
+ Args:
641
+ message: 需要分割的消息
642
+ max_length: 每部分的最大长度
643
+ Returns:
644
+ list: 分割后的消息部分列表
645
+ """
646
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
647
 
648
  def append_status_message(content, has_pending_parts=False, is_processing=False):
649
+ """
650
+ 添加状态消息到响应内容
651
+ Args:
652
+ content: 原始内容
653
+ has_pending_parts: 是否有待发送的部分
654
+ is_processing: 是否正在处理中
655
+ Returns:
656
+ str: 添加了状态信息的内容
657
+ """
658
  if "您的请求正在处理中" in content:
659
  return content + "\n\n-------------------\n发送'新对话'开始新的对话"
660
 
 
670
 
671
  @app.route('/api/wx', methods=['GET', 'POST'])
672
  def wechatai():
673
+ """
674
+ 处理微信公众号请求的主要路由函数
675
+ """
676
  if request.method == 'GET':
677
  signature = request.args.get('signature')
678
  timestamp = request.args.get('timestamp')
 
685
 
686
  try:
687
  encrypt_type = request.args.get('encrypt_type', '')
688
+ current_time = int(time.time())
689
 
690
  if encrypt_type == 'aes':
691
  msg_signature = request.args.get('msg_signature')
692
  timestamp = request.args.get('timestamp')
693
  nonce = request.args.get('nonce')
694
 
695
+ # 解析加密消息
696
  xml_tree = ET.fromstring(request.data)
697
  encrypted_text = xml_tree.find('Encrypt').text
698
 
699
+ # 验证消息签名
700
  if not verify_msg_signature(msg_signature, timestamp, nonce, TOKEN, encrypted_text):
701
+ logging.error("消息签名验证失败")
702
  return 'Invalid signature', 403
703
 
704
+ try:
705
+ # 解密消息
706
+ decrypted_xml = session_manager.crypto.decrypt(encrypted_text)
707
+ message_data = parse_xml_message(decrypted_xml)
708
+ except Exception as e:
709
+ logging.error(f"消息解密失败: {str(e)}")
710
+ return 'Decryption failed', 403
711
  else:
712
+ # 处理未加密的消息
713
+ try:
714
+ message_data = parse_xml_message(request.data)
715
+ except Exception as e:
716
+ logging.error(f"解析XML消息失败: {str(e)}")
717
+ return 'Invalid XML', 400
718
 
 
719
  from_user = message_data['from_user']
720
  to_user = message_data['to_user']
721
+ msg_type = message_data['msg_type']
722
 
723
+ logging.info(f"收到用户({from_user})消息类型: {msg_type}")
724
+
725
+ # 获取或创建用户会话
726
+ try:
727
+ session = session_manager.get_session(from_user)
728
+ except Exception as e:
729
+ logging.error(f"获取用户会话失败: {str(e)}")
730
  return generate_response_xml(
731
  from_user,
732
  to_user,
733
+ append_status_message('系统错误,请稍后重试。'),
734
  encrypt_type=encrypt_type
735
  )
736
 
737
+ if msg_type == 'image':
738
+ try:
739
+ logging.info(f"收到图片消息: MediaId={message_data.get('media_id')}")
740
+
741
+ # 创建新的异步任务
742
+ task_id = str(uuid.uuid4())
743
+ session.current_task = task_id
744
+ session.response_queue[task_id] = AsyncResponse()
745
+
746
+ # 启动异步图片识别任务
747
+ executor.submit(
748
+ handle_async_task,
749
+ session,
750
+ task_id,
751
+ None,
752
+ 'image',
753
+ message_data
754
+ )
755
+
756
  return generate_response_xml(
757
  from_user,
758
  to_user,
759
+ append_status_message("正在分析图片,请稍候...\n回复'查询'获取分析结果", is_processing=True),
760
  encrypt_type=encrypt_type
761
  )
762
+ except Exception as e:
763
+ logging.error(f"处理图片消息时发生错误: {str(e)}")
764
+ return generate_response_xml(
765
+ from_user,
766
+ to_user,
767
+ append_status_message('处理图片时出现错误,请稍后重试。'),
768
+ encrypt_type=encrypt_type
769
+ )
770
+ else:
771
+ # 处理文本消息
772
+ try:
773
+ user_content = message_data['content'].strip()
774
+
775
+ # 处理特殊命令
776
+ if user_content == '新对话':
777
+ session_manager.clear_session(from_user)
778
+ return generate_response_xml(
779
+ from_user,
780
+ to_user,
781
+ append_status_message('已开始新的对话。请描述您的问题。'),
782
+ encrypt_type=encrypt_type
783
+ )
784
+
785
+ if user_content == '继续':
786
+ if session.pending_parts:
787
+ next_part = session.pending_parts.pop(0)
788
+ has_more = bool(session.pending_parts)
789
  return generate_response_xml(
790
  from_user,
791
  to_user,
792
+ append_status_message(next_part, has_more),
793
  encrypt_type=encrypt_type
794
  )
795
+ return generate_response_xml(
796
+ from_user,
797
+ to_user,
798
+ append_status_message('没有更多内容了。请继续您的问题。'),
799
+ encrypt_type=encrypt_type
800
+ )
801
+
802
+ if user_content == '查询':
803
+ if session.current_task:
804
+ task_response = session.response_queue.get(session.current_task)
805
+ if task_response:
806
+ if task_response.is_expired():
807
+ del session.response_queue[session.current_task]
808
+ session.current_task = None
809
+ return generate_response_xml(
810
+ from_user,
811
+ to_user,
812
+ append_status_message('请求已过期,请重新提问。'),
813
+ encrypt_type=encrypt_type
814
+ )
815
 
816
+ if task_response.status == "completed":
817
+ if task_response.response_type == "image":
818
+ logging.info("返回图片响应")
819
+ del session.response_queue[session.current_task]
820
+ session.current_task = None
821
+ return generate_response_xml(
822
+ from_user,
823
+ to_user,
824
+ "",
825
+ response_type="image",
826
+ media_id=task_response.media_id,
827
+ encrypt_type=encrypt_type
828
+ )
829
+ else:
830
+ response = task_response.result
831
+ del session.response_queue[session.current_task]
832
+ session.current_task = None
833
+
834
+ if len(response) > 500:
835
+ parts = split_message(response)
836
+ first_part = parts.pop(0)
837
+ session.pending_parts = parts
838
+ return generate_response_xml(
839
+ from_user,
840
+ to_user,
841
+ append_status_message(first_part, True),
842
+ encrypt_type=encrypt_type
843
+ )
844
+ return generate_response_xml(
845
+ from_user,
846
+ to_user,
847
+ append_status_message(response),
848
+ encrypt_type=encrypt_type
849
+ )
850
+ elif task_response.status == "failed":
851
+ error_message = '处理过程中出现错误,请重新提问。'
852
+ del session.response_queue[session.current_task]
853
+ session.current_task = None
854
  return generate_response_xml(
855
  from_user,
856
  to_user,
857
+ append_status_message(error_message),
858
  encrypt_type=encrypt_type
859
  )
860
+ else:
861
+ return generate_response_xml(
862
+ from_user,
863
+ to_user,
864
+ append_status_message('正在处理中,请稍后再次查询。', is_processing=True),
865
+ encrypt_type=encrypt_type
866
+ )
867
+ return generate_response_xml(
868
+ from_user,
869
+ to_user,
870
+ append_status_message('没有正在处理的请求。'),
871
+ encrypt_type=encrypt_type
872
+ )
873
+
874
+ # 处理普通文本消息
875
+ session.messages.append({"role": "user", "content": user_content})
876
+
877
+ # 创建新的异步任务
878
+ task_id = str(uuid.uuid4())
879
+ session.current_task = task_id
880
+ session.response_queue[task_id] = AsyncResponse()
881
+
882
+ # 启动异步处理
883
+ executor.submit(handle_async_task, session, task_id, session.messages.copy())
884
+
885
+ return generate_response_xml(
886
+ from_user,
887
+ to_user,
888
+ append_status_message(generate_initial_response(), is_processing=True),
889
+ encrypt_type=encrypt_type
890
+ )
891
+
892
+ except Exception as e:
893
+ logging.error(f"处理文本消息时发生错误: {str(e)}")
894
+ return generate_response_xml(
895
+ from_user,
896
+ to_user,
897
+ append_status_message('处理消息时出现错误,请稍后重试。'),
898
+ encrypt_type=encrypt_type
899
+ )
 
 
 
 
 
900
 
901
  except Exception as e:
902
  logging.error(f"处理请求时出错: {str(e)}")
903
  return generate_response_xml(
904
+ message_data['from_user'] if 'message_data' in locals() else 'unknown',
905
+ message_data['to_user'] if 'message_data' in locals() else 'unknown',
906
  append_status_message('抱歉,系统暂时出现问题,请稍后重试。'),
907
  encrypt_type if 'encrypt_type' in locals() else ''
908
  )
909
+
910
  def cleanup_sessions():
911
  while True:
912
  time.sleep(3600) # 每小时清理一次
 
919
  cleanup_thread = threading.Thread(target=cleanup_sessions, daemon=True)
920
  cleanup_thread.start()
921
 
922
+ app.run(host='0.0.0.0', port=7860, debug=True)