|
|
@@ -6,12 +6,16 @@ from voice.ali.ali_voice import AliVoice |
|
|
|
from common import utils,redis_helper,memory,kafka_helper |
|
|
|
from common.log import logger |
|
|
|
import xml.etree.ElementTree as ET |
|
|
|
import threading,time |
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
|
|
|
|
|
from voice import audio_convert |
|
|
|
|
|
|
|
|
|
|
|
timeout_duration = 4.0 |
|
|
|
|
|
|
|
class MessagesResource(Resource): |
|
|
|
def __init__(self): |
|
|
|
self.parser = reqparse.RequestParser() |
|
|
@@ -37,25 +41,33 @@ class MessagesResource(Resource): |
|
|
|
to_wxid = msg_data["ToUserName"]["string"] |
|
|
|
msg_push_content=msg_data.get("PushContent") #群发 |
|
|
|
|
|
|
|
handlers = { |
|
|
|
1: handle_text, |
|
|
|
3: handle_image, |
|
|
|
34: handle_voice, |
|
|
|
49: handle_xml, |
|
|
|
37: handle_add_friend_notice, |
|
|
|
10002: handle_10002_msg |
|
|
|
} |
|
|
|
# (扫码进群情况)判断受否是群聊,并添加到通信录, |
|
|
|
if check_chatroom(from_wxid) or check_chatroom(to_wxid): |
|
|
|
logger.info('群信息') |
|
|
|
chatroom_id=from_wxid |
|
|
|
ret,msg,data=gewe_chat.wxchat.save_contract_list(token_id,app_id,chatroom_id,3) |
|
|
|
logger.info(f'保存到通讯录 chatroom_id {chatroom_id} {msg}') |
|
|
|
gewe_chat.wxchat.update_groups_info_to_cache(token_id,app_id,wxid,chatroom_id) |
|
|
|
handlers[1]=handle_text_group |
|
|
|
handlers[3]=handle_image_group |
|
|
|
handlers[34]=handle_voice_group |
|
|
|
|
|
|
|
wx_config = gewe_chat.wxchat.get_wxchat_config_from_cache(wxid) |
|
|
|
if not bool(wx_config.get("agentEnabled",False)): |
|
|
|
logger.warning(f'{wxid} 智能体已关闭') |
|
|
|
handlers = { |
|
|
|
49: handle_xml, |
|
|
|
37: handle_add_friend_notice, |
|
|
|
10002: handle_10002_msg |
|
|
|
} |
|
|
|
else: |
|
|
|
handlers = { |
|
|
|
1: handle_text, |
|
|
|
3: handle_image, |
|
|
|
34: handle_voice, |
|
|
|
49: handle_xml, |
|
|
|
37: handle_add_friend_notice, |
|
|
|
10002: handle_10002_msg |
|
|
|
} |
|
|
|
# (扫码进群情况)判断受否是群聊,并添加到通信录 |
|
|
|
if check_chatroom(from_wxid) or check_chatroom(to_wxid): |
|
|
|
logger.info('群信息') |
|
|
|
chatroom_id=from_wxid |
|
|
|
ret,msg,data=gewe_chat.wxchat.save_contract_list(token_id,app_id,chatroom_id,3) |
|
|
|
logger.info(f'保存到通讯录 chatroom_id {chatroom_id} {msg}') |
|
|
|
gewe_chat.wxchat.update_groups_info_to_cache(token_id,app_id,wxid,chatroom_id) |
|
|
|
handlers[1]=handle_text_group |
|
|
|
handlers[3]=handle_image_group |
|
|
|
handlers[34]=handle_voice_group |
|
|
|
|
|
|
|
handler = handlers.get(msg_type) |
|
|
|
if handler: |
|
|
@@ -115,94 +127,216 @@ def handle_text(token_id,app_id, wxid,msg_data,from_wxid, to_wxid): |
|
|
|
logger.info("发送对话 %s",input_message) |
|
|
|
else: |
|
|
|
callback_to_user=msg_data["FromUserName"]["string"] |
|
|
|
hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}' |
|
|
|
|
|
|
|
prompt={"role": "user", "content": [{ |
|
|
|
"type": "text", |
|
|
|
"text": msg_content |
|
|
|
}]} |
|
|
|
messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
# 收到的对话 |
|
|
|
input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}] |
|
|
|
input_message=utils.dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message) |
|
|
|
kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
logger.info("发送对话 %s",input_message) |
|
|
|
# hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}' |
|
|
|
|
|
|
|
# prompt={"role": "user", "content": [{ |
|
|
|
# "type": "text", |
|
|
|
# "text": msg_content |
|
|
|
# }]} |
|
|
|
# messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
# # 收到的对话 |
|
|
|
# input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}] |
|
|
|
# input_message=utils.dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message) |
|
|
|
# kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
# logger.info("发送对话 %s",input_message) |
|
|
|
|
|
|
|
cache_data = memory.USER_INTERACTIVE_CACHE.get(wxid) |
|
|
|
if cache_data and cache_data.get('interactive') : |
|
|
|
o=get_first_char_if_digit(msg_content) |
|
|
|
if o is not None: |
|
|
|
userSelectOptions=cache_data.get('options') |
|
|
|
if o < len(userSelectOptions): |
|
|
|
o=o-1 |
|
|
|
msg_content=userSelectOptions[o].get("value") |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
else: |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
else: |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
# cache_data = memory.USER_INTERACTIVE_CACHE.get(wxid) |
|
|
|
# if cache_data and cache_data.get('interactive') : |
|
|
|
# o=get_first_char_if_digit(msg_content) |
|
|
|
# if o is not None: |
|
|
|
# userSelectOptions=cache_data.get('options') |
|
|
|
# if o < len(userSelectOptions): |
|
|
|
# o=o-1 |
|
|
|
# msg_content=userSelectOptions[o].get("value") |
|
|
|
# messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
# else: |
|
|
|
# messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
# else: |
|
|
|
# messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
|
|
|
|
res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
# res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
# reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
description = '' |
|
|
|
userSelectOptions = [] |
|
|
|
|
|
|
|
if isinstance(reply_content, list) and any(item.get("type") == "interactive" for item in reply_content): |
|
|
|
for item in reply_content: |
|
|
|
if item["type"] == "interactive" and item["interactive"]["type"] == "userSelect": |
|
|
|
params = item["interactive"]["params"] |
|
|
|
description = params.get("description") |
|
|
|
userSelectOptions = params.get("userSelectOptions", []) |
|
|
|
values_string = "\n".join(option["value"] for option in userSelectOptions) |
|
|
|
# description = '' |
|
|
|
# userSelectOptions = [] |
|
|
|
|
|
|
|
# if isinstance(reply_content, list) and any(item.get("type") == "interactive" for item in reply_content): |
|
|
|
# for item in reply_content: |
|
|
|
# if item["type"] == "interactive" and item["interactive"]["type"] == "userSelect": |
|
|
|
# params = item["interactive"]["params"] |
|
|
|
# description = params.get("description") |
|
|
|
# userSelectOptions = params.get("userSelectOptions", []) |
|
|
|
# values_string = "\n".join(option["value"] for option in userSelectOptions) |
|
|
|
|
|
|
|
if description is not None: |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":True, |
|
|
|
"options": userSelectOptions, |
|
|
|
} |
|
|
|
reply_content=description + '------------------------------\n'+values_string |
|
|
|
# if description is not None: |
|
|
|
# memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
# "interactive":True, |
|
|
|
# "options": userSelectOptions, |
|
|
|
# } |
|
|
|
# reply_content=description + '------------------------------\n'+values_string |
|
|
|
|
|
|
|
elif isinstance(reply_content, list) and any(item.get("type") == "text" for item in reply_content): |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":False |
|
|
|
} |
|
|
|
text='' |
|
|
|
for item in reply_content: |
|
|
|
if item["type"] == "text": |
|
|
|
text=item["text"]["content"] |
|
|
|
if text=='': |
|
|
|
# 去除上次上一轮对话再次请求 |
|
|
|
cache_messages_str=redis_helper.redis_helper.get_hash_field(hash_key,"data") |
|
|
|
cache_messages = json.loads(cache_messages_str) if cache_messages_str else [] |
|
|
|
# elif isinstance(reply_content, list) and any(item.get("type") == "text" for item in reply_content): |
|
|
|
# memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
# "interactive":False |
|
|
|
# } |
|
|
|
# text='' |
|
|
|
# for item in reply_content: |
|
|
|
# if item["type"] == "text": |
|
|
|
# text=item["text"]["content"] |
|
|
|
# if text=='': |
|
|
|
# # 去除上次上一轮对话再次请求 |
|
|
|
# cache_messages_str=redis_helper.redis_helper.get_hash_field(hash_key,"data") |
|
|
|
# cache_messages = json.loads(cache_messages_str) if cache_messages_str else [] |
|
|
|
|
|
|
|
if len(cache_messages) >= 3: |
|
|
|
cache_messages = cache_messages[:-3] |
|
|
|
# if len(cache_messages) >= 3: |
|
|
|
# cache_messages = cache_messages[:-3] |
|
|
|
|
|
|
|
# redis_helper.redis_helper.update_hash_field(hash_key,"data",json.dumps(cache_messages,ensure_ascii=False)) |
|
|
|
# messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
# res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
# reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
|
|
|
|
# if isinstance(reply_content, list) : |
|
|
|
# reply_content=reply_content[0].get('text').get("content") |
|
|
|
|
|
|
|
# else: |
|
|
|
# reply_content=text |
|
|
|
# else: |
|
|
|
# memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
# "interactive":False |
|
|
|
# } |
|
|
|
# reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
# gewe_chat.wxchat.post_text(token_id,app_id,callback_to_user,reply_content) |
|
|
|
# gewe_chat.wxchat.save_session_messages_to_cache(hash_key, {"role": "assistant", "content": reply_content}) |
|
|
|
# # 回复的对话 |
|
|
|
# input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}] |
|
|
|
# input_message=utils.dialogue_message(wxid,callback_to_user,input_wx_content_dialogue_message,True) |
|
|
|
# kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
# logger.info("发送对话 %s",input_message) |
|
|
|
|
|
|
|
# 创建并启动任务线程,将参数传递给 ai_chat_text 函数 |
|
|
|
task_thread = threading.Thread( |
|
|
|
target=ai_chat_text, |
|
|
|
args=(token_id,app_id,wxid,msg_data,msg_content) |
|
|
|
) |
|
|
|
task_thread.start() |
|
|
|
|
|
|
|
# 设置定时器,1秒后检查任务是否超时。这里需要使用 lambda 来传递参数 |
|
|
|
timeout_timer = threading.Timer( |
|
|
|
timeout_duration, |
|
|
|
lambda:check_timeout(task_thread, token_id, app_id, callback_to_user) |
|
|
|
) |
|
|
|
timeout_timer.start() |
|
|
|
|
|
|
|
# 等待任务线程完成 |
|
|
|
task_thread.join() |
|
|
|
# 取消定时器 |
|
|
|
timeout_timer.cancel() |
|
|
|
|
|
|
|
def check_timeout( task_thread:threading.Thread, token_id, app_id, callback_to_user): |
|
|
|
if task_thread.is_alive(): |
|
|
|
print(f"任务运行时间超过{timeout_duration}秒,token_id={token_id}, app_id={app_id}, callback_to_user={callback_to_user}") |
|
|
|
gewe_chat.wxchat.post_text(token_id,app_id,callback_to_user,"亲,我正在组织回复的信息,请稍等一会") |
|
|
|
|
|
|
|
def ai_chat_text(token_id,app_id,wxid,msg_data,msg_content): |
|
|
|
start_time = time.time() # 记录任务开始时间 |
|
|
|
|
|
|
|
callback_to_user=msg_data["FromUserName"]["string"] |
|
|
|
hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}' |
|
|
|
|
|
|
|
redis_helper.redis_helper.update_hash_field(hash_key,"data",json.dumps(cache_messages,ensure_ascii=False)) |
|
|
|
messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
prompt={"role": "user", "content": [{ |
|
|
|
"type": "text", |
|
|
|
"text": msg_content |
|
|
|
}]} |
|
|
|
messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
# 收到的对话 |
|
|
|
input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}] |
|
|
|
input_message=utils.dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message) |
|
|
|
kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
logger.info("发送对话 %s",input_message) |
|
|
|
|
|
|
|
cache_data = memory.USER_INTERACTIVE_CACHE.get(wxid) |
|
|
|
if cache_data and cache_data.get('interactive') : |
|
|
|
o=get_first_char_if_digit(msg_content) |
|
|
|
if o is not None: |
|
|
|
userSelectOptions=cache_data.get('options') |
|
|
|
if o < len(userSelectOptions): |
|
|
|
o=o-1 |
|
|
|
msg_content=userSelectOptions[o].get("value") |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
else: |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
else: |
|
|
|
messages_to_send=[{"role": "user", "content": msg_content}] |
|
|
|
res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
|
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
description = '' |
|
|
|
userSelectOptions = [] |
|
|
|
|
|
|
|
if isinstance(reply_content, list) and any(item.get("type") == "interactive" for item in reply_content): |
|
|
|
for item in reply_content: |
|
|
|
if item["type"] == "interactive" and item["interactive"]["type"] == "userSelect": |
|
|
|
params = item["interactive"]["params"] |
|
|
|
description = params.get("description") |
|
|
|
userSelectOptions = params.get("userSelectOptions", []) |
|
|
|
values_string = "\n".join(option["value"] for option in userSelectOptions) |
|
|
|
|
|
|
|
if description is not None: |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":True, |
|
|
|
"options": userSelectOptions, |
|
|
|
} |
|
|
|
reply_content=description + '------------------------------\n'+values_string |
|
|
|
|
|
|
|
elif isinstance(reply_content, list) and any(item.get("type") == "text" for item in reply_content): |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":False |
|
|
|
} |
|
|
|
text='' |
|
|
|
for item in reply_content: |
|
|
|
if item["type"] == "text": |
|
|
|
text=item["text"]["content"] |
|
|
|
if text=='': |
|
|
|
# 去除上次上一轮对话再次请求 |
|
|
|
cache_messages_str=redis_helper.redis_helper.get_hash_field(hash_key,"data") |
|
|
|
cache_messages = json.loads(cache_messages_str) if cache_messages_str else [] |
|
|
|
|
|
|
|
if len(cache_messages) >= 3: |
|
|
|
cache_messages = cache_messages[:-3] |
|
|
|
|
|
|
|
redis_helper.redis_helper.update_hash_field(hash_key,"data",json.dumps(cache_messages,ensure_ascii=False)) |
|
|
|
messages_to_send=gewe_chat.wxchat.save_session_messages_to_cache(hash_key, prompt) |
|
|
|
res=fast_gpt_api(messages_to_send,wxid,callback_to_user) |
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
if isinstance(reply_content, list) : |
|
|
|
reply_content=reply_content[0].get('text').get("content") |
|
|
|
|
|
|
|
else: |
|
|
|
reply_content=text |
|
|
|
if isinstance(reply_content, list) : |
|
|
|
reply_content=reply_content[0].get('text').get("content") |
|
|
|
|
|
|
|
else: |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":False |
|
|
|
} |
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
reply_content=text |
|
|
|
else: |
|
|
|
memory.USER_INTERACTIVE_CACHE[wxid] = { |
|
|
|
"interactive":False |
|
|
|
} |
|
|
|
reply_content=res["choices"][0]["message"]["content"] |
|
|
|
|
|
|
|
gewe_chat.wxchat.post_text(token_id,app_id,callback_to_user,reply_content) |
|
|
|
gewe_chat.wxchat.save_session_messages_to_cache(hash_key, {"role": "assistant", "content": reply_content}) |
|
|
|
# 回复的对话 |
|
|
|
input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}] |
|
|
|
input_message=utils.dialogue_message(wxid,callback_to_user,input_wx_content_dialogue_message,True) |
|
|
|
kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
logger.info("发送对话 %s",input_message) |
|
|
|
|
|
|
|
end_time = time.time() # 记录任务结束时间 |
|
|
|
execution_time = end_time - start_time # 计算执行时间 |
|
|
|
logger.info(f"AI回答任务完成,耗时 {execution_time:.2f} 秒") |
|
|
|
|
|
|
|
gewe_chat.wxchat.post_text(token_id,app_id,callback_to_user,reply_content) |
|
|
|
gewe_chat.wxchat.save_session_messages_to_cache(hash_key, {"role": "assistant", "content": reply_content}) |
|
|
|
# 回复的对话 |
|
|
|
input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}] |
|
|
|
input_message=utils.dialogue_message(wxid,callback_to_user,input_wx_content_dialogue_message,True) |
|
|
|
kafka_helper.kafka_client.produce_message(input_message) |
|
|
|
logger.info("发送对话 %s",input_message) |
|
|
|
|
|
|
|
def handle_text_group(token_id,app_id, wxid,msg_data,from_wxid, to_wxid): |
|
|
|
''' |
|
|
@@ -396,8 +530,13 @@ def handle_voice(token_id,app_id, wxid,msg_data,from_wxid, to_wxid): |
|
|
|
has_url=contains_url(ai_res_content) |
|
|
|
if not has_url: |
|
|
|
voice_during,voice_url=utils.wx_voice(ai_res_content) |
|
|
|
ret,ret_msg,res=gewe_chat.wxchat.post_voice(token_id,app_id,callback_to_user,voice_url,voice_during) |
|
|
|
|
|
|
|
|
|
|
|
if voice_during < 60 * 1000: |
|
|
|
ret,ret_msg,res=gewe_chat.wxchat.post_voice(token_id,app_id,callback_to_user,voice_url,voice_during) |
|
|
|
|
|
|
|
else: |
|
|
|
ret,ret_msg,res=gewe_chat.wxchat.post_text(token_id,app_id,callback_to_user,ai_res_content) |
|
|
|
logger.warning(f'回应语音消息长度 {voice_during/1000}秒,超过60秒,转为文本回复') |
|
|
|
if ret==200: |
|
|
|
logger.info((f'{wxid} 向 {callback_to_user} 发送语音文本【{ai_res_content}】{ret_msg}')) |
|
|
|
|
|
|
|