diff --git a/common/utils.py b/common/utils.py index 0230450..5b49190 100644 --- a/common/utils.py +++ b/common/utils.py @@ -10,6 +10,12 @@ from urllib.parse import urlparse, unquote from voice.ali.ali_voice import AliVoice from voice import audio_convert + +import cv2 +import os +import tempfile +from moviepy import VideoFileClip + from common import redis_helper from datetime import datetime @@ -339,4 +345,70 @@ def get_login_info_by_wxid(wxid: str) ->dict: if cursor == 0: break - return None,None \ No newline at end of file + return None,None + + +def download_video_and_get_thumbnail(url, thumbnail_path): + """ + 从指定URL下载MP4视频,提取首帧作为缩略图,并返回缩略图路径及视频时长。 + + 参数: + url (str): 视频的URL地址。 + thumbnail_path (str): 缩略图的保存路径。 + + 返回: + tuple: (缩略图路径, 视频时长(秒)) + + 异常: + 可能抛出requests.exceptions.RequestException,cv2.error,IOError等异常。 + """ + # 创建临时目录以下载视频 + with tempfile.TemporaryDirectory() as tmp_dir: + # 下载视频到临时文件 + video_path = os.path.join(tmp_dir, 'temp_video.mp4') + response = requests.get(url, stream=True) + response.raise_for_status() # 确保请求成功 + + with open(video_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: # 过滤掉保持连接的空白块 + f.write(chunk) + + # 提取视频首帧作为缩略图 + vidcap = cv2.VideoCapture(video_path) + success, image = vidcap.read() + vidcap.release() + if not success: + raise RuntimeError("无法读取视频的首帧,请检查视频文件是否有效。") + + # 确保缩略图的目录存在 + thumbnail_dir = os.path.dirname(thumbnail_path) + if thumbnail_dir: + os.makedirs(thumbnail_dir, exist_ok=True) + + # 保存缩略图 + cv2.imwrite(thumbnail_path, image) + + # 使用moviepy计算视频时长 + clip = VideoFileClip(video_path) + duration = clip.duration + clip.close() + + # OSS 配置(建议将凭证存储在安全的地方) + oss_access_key_id="LTAI5tRTG6pLhTpKACJYoPR5" + oss_access_key_secret="E7dMzeeMxq4VQvLg7Tq7uKf3XWpYfN" + oss_endpoint="http://oss-cn-shanghai.aliyuncs.com" + oss_bucket_name="cow-agent" + oss_prefix="cow" + + # 上传文件到 OSS + file_path = thumbnail_path + file_url = upload_oss(oss_access_key_id, oss_access_key_secret, oss_endpoint, oss_bucket_name, file_path, oss_prefix) + + # 删除临时文件 + try: + os.remove(thumbnail_path) + except FileNotFoundError: + pass # 如果文件未找到,跳过删除 + + return file_url, duration \ No newline at end of file diff --git a/docker/Dockerfile.latest b/docker/Dockerfile.latest index 8c0775e..cea42d1 100644 --- a/docker/Dockerfile.latest +++ b/docker/Dockerfile.latest @@ -25,7 +25,7 @@ RUN apt-get update \ && cd ${BUILD_PREFIX} \ && cp config-template.json config.json \ && /usr/local/bin/python -m pip install --no-cache --upgrade pip \ - && pip install --no-cache -r requirements.txt + && pip install --no-cache -r requirements.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple WORKDIR ${BUILD_PREFIX} diff --git a/requirements.txt b/requirements.txt index 36b584e..88524c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,4 +42,8 @@ pysilk-mod #pip3 install pysilk-mod oss2 -gunicorn \ No newline at end of file +gunicorn + + +opencv-python +moviepy \ No newline at end of file diff --git a/resources/messages_resource.py b/resources/messages_resource.py index 76218aa..7e784ad 100644 --- a/resources/messages_resource.py +++ b/resources/messages_resource.py @@ -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}')) diff --git a/wechat/biz.py b/wechat/biz.py index 5831b59..f03f976 100644 --- a/wechat/biz.py +++ b/wechat/biz.py @@ -1,7 +1,7 @@ import threading from common import kafka_helper,redis_helper,utils - +from urllib.parse import urlparse, unquote import json,time,re,random,os from common.log import logger, log_exception from datetime import datetime @@ -69,6 +69,7 @@ def process_group_sending_v0(wxchat:gewe_chat.GeWeChatCom, content_data, agent_t send_tts_message(wxchat, token_id, app_id, agent_wxid, intersection_wxids, wx_content["text"]) + def process_group_sending(wxchat:gewe_chat.GeWeChatCom, content_data, agent_tel:str): # 获取登录信息 hash_key = f"__AI_OPS_WX__:LOGININFO:{agent_tel}" @@ -112,7 +113,10 @@ def process_group_sending(wxchat:gewe_chat.GeWeChatCom, content_data, agent_tel: # send_image_message(wxchat, token_id, app_id, agent_wxid, intersection_wxids, wx_content.get("image_url", {}).get("url")) # elif wx_content["type"] == "tts": # send_tts_message(wxchat, token_id, app_id, agent_wxid, intersection_wxids, wx_content["text"]) - + wxchat.forward_video_aeskey = '' + wxchat.forward_video_cdnvideourl = '' + wxchat.forward_video_length = 0 + for intersection_wxid in intersection_wxids: for wx_content in wx_content_list: if wx_content["type"] == "text": @@ -121,6 +125,8 @@ def process_group_sending(wxchat:gewe_chat.GeWeChatCom, content_data, agent_tel: send_image_message(wxchat, token_id, app_id, agent_wxid, [intersection_wxid], wx_content.get("image_url", {}).get("url")) elif wx_content["type"] == "tts": send_tts_message(wxchat, token_id, app_id, agent_wxid, [intersection_wxid], wx_content["text"]) + elif wx_content["type"] == "file": + send_file_message(wxchat, token_id, app_id, agent_wxid, [intersection_wxid], wx_content.get("file_url", {}).get("url")) @@ -211,6 +217,56 @@ def send_tts_message(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, agent_wxid, # 等待随机时间 time.sleep(random.uniform(5, 15)) +def send_file_message(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, agent_wxid, intersection_wxids, file_url): + + parsed_url = urlparse(file_url) + path = parsed_url.path + # 从路径中提取文件名 + filename = path.split('/')[-1] + # 获取扩展名 + _, ext = os.path.splitext(filename) + + if ext == '.mp4': + send_video_message(wxchat, token_id, app_id, agent_wxid, intersection_wxids, file_url) + else: + send_other_file_message(wxchat, token_id, app_id, agent_wxid, intersection_wxids, file_url) + #time.sleep(random.uniform(5, 15)) + + +def send_video_message(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, agent_wxid, intersection_wxids, file_url): + for t in intersection_wxids: + # 发送视频消息 + parsed_url = urlparse(file_url) + filename = os.path.basename(parsed_url.path) + tmp_file_path = os.path.join(os.getcwd(),'tmp', filename) # 拼接完整路径 + thumbnail_path=tmp_file_path.replace('.mp4','.jpg') + video_duration,video_thumb_url =utils.download_video_and_get_thumbnail(file_url,thumbnail_path) + + if wxchat.forward_video_aeskey == '': + ret,ret_msg,res = wxchat.post_video(token_id, app_id, t, file_url,video_thumb_url,video_duration) + if ret==200: + wxchat.forward_video_aeskey = res["aesKey"] + wxchat.forward_video_cdnvideourl = res["cdnVideoUrl"] + wxchat.forward_video_length = res["length"] + else: + ret,ret_msg,res = wxchat.forward_video(token_id, app_id, t, wxchat.forward_video_aeskey, wxchat.forward_video_cdnvideourl, wxchat.forward_video_length) + print('转发视频') + if ret==200: + logger.info(f'{agent_wxid} 向 {t} 发送视频【{file_url}】{ret_msg}') + # 构造对话消息并发送到 Kafka + input_wx_content_dialogue_message = [{"type": "file", "file_url": {"url": file_url}}] + input_message = utils.dialogue_message(agent_wxid, t, input_wx_content_dialogue_message) + kafka_helper.kafka_client.produce_message(input_message) + logger.info("发送对话 %s", input_message) + else: + logger.warning((f'{agent_wxid} 向 {t} 发送视频【{file_url}】{ret_msg}')) + + # 等待随机时间 + time.sleep(random.uniform(5, 15)) + +def send_other_file_message(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, agent_wxid, intersection_wxids, file_url): + print('send_otherfile_message') + def clean_json_string(json_str): # 删除所有控制字符(非打印字符),包括换行符、回车符等 diff --git a/wechat/gewe_chat.py b/wechat/gewe_chat.py index a82700a..ee3639f 100644 --- a/wechat/gewe_chat.py +++ b/wechat/gewe_chat.py @@ -337,6 +337,23 @@ class GeWeChatCom: response_object = response.json() return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) + def post_video(self,token_id,app_id,to_wxid,video_url,video_thumb_url,video_duration): + api_url = f"{self.base_url}/v2/api/message/postVideo" + headers = { + 'X-GEWE-TOKEN': token_id, + 'Content-Type': 'application/json' + } + data = { + "appId": app_id, + "toWxid": to_wxid, + "videoUrl": video_url, + "videoDuration":video_duration, + "videoThumbUrl":video_thumb_url + } + response = requests.post(url=api_url, headers=headers, data=json.dumps(data)) + response_object = response.json() + return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) + def forward_image(self,token_id,app_id,to_wxid,aeskey,cdnthumburl,cdnthumblength,cdnthumbheight,cdnthumbwidth,length,md5): api_url = f"{self.base_url}/v2/api/message/forwardImage" headers = { @@ -353,6 +370,22 @@ class GeWeChatCom: response_object = response.json() return response_object.get('data',None),response_object.get('ret',None),response_object.get('msg',None) + def forward_video(self,token_id,app_id,to_wxid,aeskey,cdnvideourl,length): + api_url = f"{self.base_url}/v2/api/message/forwardVideo" + headers = { + 'X-GEWE-TOKEN': token_id, + 'Content-Type': 'application/json' + } + data = { + "appId": app_id, + "toWxid": to_wxid, + "xml": f"\n\n\t\n" + + } + response = requests.post(url=api_url, headers=headers, data=json.dumps(data)) + response_object = response.json() + return response_object.get('data',None),response_object.get('ret',None),response_object.get('msg',None) + def add_contacts(self,token_id:str,app_id:str,scene:int,option:int,v3:str,v4:str,content:str): api_url = f"{self.base_url}/v2/api/contacts/addContacts" headers = {