diff --git a/base/func_claude.py b/base/func_claude.py new file mode 100644 index 0000000..a51cab3 --- /dev/null +++ b/base/func_claude.py @@ -0,0 +1,121 @@ +import requests +import json +import logging + +from datetime import datetime + + +class Claude(): + def __init__(self, conf: dict) -> None: + self.key = conf.get("key") + self.api = conf.get("api") + prompt = conf.get("prompt") + self.model = conf.get("model", "windsurf/claude-3-5-sonnet") + self.LOG = logging.getLogger("Claude") + self.conversation_list = {} + self.system_content_msg = {"role": "system", "content": prompt} + + def __repr__(self): + return 'Claude' + + def get_answer(self, question: str, wxid: str) -> str: + # 设置请求头 + self.updateMessage(wxid, question, "user") + rsp = "" + try: + headers = { + "Content-Type": "application/json; charset=utf-8", + "Authorization": self.key + } + # 设置请求的payload + data = { + "model": self.model, + "messages": [ + { + "role": "user", + "content": f"{question}" + } + + ] + } + # 发送POST请求 + response = requests.post(self.api, headers=headers, data=json.dumps(data), ) + response.encoding = 'utf-8' + + # 输出响应内容 + print(response.status_code) + # print(response.text) + rsp = extract_content(response.text) + self.updateMessage(wxid, rsp, "assistant") + except Exception as e0: + self.LOG.error(f"发生未知错误:{str(e0)}") + return rsp + + def updateMessage(self, wxid: str, question: str, role: str) -> None: + now_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + + time_mk = "当需要回答时间时请直接参考回复:" + # 初始化聊天记录,组装系统信息 + if wxid not in self.conversation_list.keys(): + question_ = [ + self.system_content_msg, + {"role": "system", "content": "" + time_mk + now_time} + ] + self.conversation_list[wxid] = question_ + + # 当前问题 + content_question_ = {"role": role, "content": question} + self.conversation_list[wxid].append(content_question_) + + for cont in self.conversation_list[wxid]: + if cont["role"] != "system": + continue + if cont["content"].startswith(time_mk): + cont["content"] = time_mk + now_time + + # 只存储10条记录,超过滚动清除 + i = len(self.conversation_list[wxid]) + if i > 10: + print("滚动清除微信记录:" + wxid) + # 删除多余的记录,倒着删,且跳过第一个的系统消息 + del self.conversation_list[wxid][1] + + @staticmethod + def value_check(conf: dict) -> bool: + if conf: + if conf.get("key") and conf.get("api") and conf.get("prompt"): + return True + return False + + +# 解析JSON +def extract_content(data_string): + try: + data = json.loads(data_string) + # 提取content字段 + content = data["choices"][0]["message"].get("content", "") + return content + except json.JSONDecodeError: + print("Invalid JSON") + return None + + +if __name__ == '__main__': + from configuration import Config + + config = Config().CLAUDE + if not config: + exit(0) + + chat = Claude(config) + + while True: + q = input(">>> ") + try: + time_start = datetime.now() # 记录开始时间 + print(chat.get_answer(q, "Jyunere")) + time_end = datetime.now() # 记录结束时间 + + print(f"{round((time_end - time_start).total_seconds(), 2)}s") # 计算的时间差为程序的执行时间,单位为秒/s + except Exception as e: + print(e) diff --git a/config.yaml b/config.yaml index 23c29eb..86cc8a7 100644 --- a/config.yaml +++ b/config.yaml @@ -36,42 +36,38 @@ logging: root: level: INFO - handlers: [console, info_file_handler, error_file_handler] + handlers: [ console, info_file_handler, error_file_handler ] groups: - enable: [45317011307@chatroom,49571962306@chatroom,43687793133@chatroom] # 允许响应的群 roomId,大概长这样:2xxxxxxxxx3@chatroom + enable: [ 45317011307@chatroom,49571962306@chatroom,43687793133@chatroom ] # 允许响应的群 roomId,大概长这样:2xxxxxxxxx3@chatroom news: - receivers: [45317011307@chatroom,49571962306@chatroom,43687793133@chatroom] # 定时新闻接收人(roomid 或者 wxid) + receivers: [ 45317011307@chatroom,49571962306@chatroom,43687793133@chatroom ] # 定时新闻接收人(roomid 或者 wxid) report_reminder: - receivers: [] # 定时日报周报月报提醒(roomid 或者 wxid) + receivers: [ ] # 定时日报周报月报提醒(roomid 或者 wxid) -chatgpt: # -----chatgpt配置这行不填----- - key: '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'# 填写你 ChatGPT 的 key +chatgpt: # -----chatgpt配置这行不填----- + key: # 填写你 ChatGPT 的 key api: https://api.openai.com/v1 # 如果你不知道这是干嘛的,就不要改 model: gpt-3.5-turbo proxy: # 如果你在国内,你可能需要魔法,大概长这样:http://域名或者IP地址:端口号 - prompt: '你是一个信息归纳分析工程师,你叫小牛,你根据提问会搜索相关资料。经过信息精炼之后返回内容。 - 请回复时以以下格式进行返回: - - 问题:回顾提问内容 - - 问题评价:分析问题的提出角度,如(财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐)等 - - 总结:经过200个字以内的优化返回' # 根据需要对角色进行设定 + prompt: 你是智能聊天机器人,你叫 wcferry # 根据需要对角色进行设定 -chatglm: # -----chatglm配置这行不填----- +chatglm: # -----chatglm配置这行不填----- key: sk-012345678901234567890123456789012345678901234567 # 这个应该不用动 api: http://localhost:8000/v1 # 根据自己的chatglm地址修改 proxy: # 如果你在国内,你可能需要魔法,大概长这样:http://域名或者IP地址:端口号 prompt: 你是智能聊天机器人,你叫小薇 # 根据需要对角色进行设定 file_path: F:/Pictures/temp #设定生成图片和代码使用的文件夹路径 -tigerbot: # -----tigerbot配置这行不填----- +tigerbot: # -----tigerbot配置这行不填----- key: # key model: # tigerbot-7b-sft -xinghuo_web: # -----讯飞星火web模式api配置这行不填 抓取方式详见文档:https://www.bilibili.com/read/cv27066577----- - cookie: 'di_c_mti=43ec310c-b357-69d2-bee6-88ab435fd53c; d_d_app_ver=1.4.0; daas_st={%22sdk_ver%22:%221.3.9%22%2C%22status%22:%220%22}; appid=150b4dfebe; d_d_ci=1630e780-7a48-6218-a830-c5e010a79ce7; account_id=19737093603; ui=19737093603; Hm_lvt_fe740601c79b0c00b6d5458d146aa5ef=1734055597; HMACCOUNT=5A31BCBD7768359B; _gcl_au=1.1.215462428.1734055660; _gid=GA1.2.1466291769.1734055660; gr_user_id=f091018a-96fa-4924-8cff-7c966125acbc; 8473744dbcf62d60_gr_session_id=e47c497c-0e6f-4ef5-894e-6871bd6b6738; 8473744dbcf62d60_gr_session_id_sent_vst=e47c497c-0e6f-4ef5-894e-6871bd6b6738; _clck=83pjx%7C2%7Cfro%7C0%7C1808; ssoSessionId=51e2f966-5d97-4d34-970f-4f85349c8fbc; _ga_0KHV9JM0VW=GS1.1.1734055659.1.1.1734055751.60.0.0; _ga=GA1.2.942876758.1734055660; Hm_lpvt_fe740601c79b0c00b6d5458d146aa5ef=1734055752; _clsk=mb13en%7C1734055752782%7C2%7C1%7Cu.clarity.ms%2Fcollect; _uetsid=110d3500b8f411efab484704728f4bef; _uetvid=110d4ac0b8f411ef8e340ba70a661722; clientType=2; gt_local_id=ECXGmUamQt4vFnWW51Qc/ab09lpZc0qUDWBG3vZJNnvd2a1UuNMIwA==' - fd: 853568 +xinghuo_web: # -----讯飞星火web模式api配置这行不填 抓取方式详见文档:https://www.bilibili.com/read/cv27066577----- + cookie: 'di_c_mti=43ec310c-b357-69d2-bee6-88ab435fd53c; d_d_app_ver=1.4.0; daas_st={%22sdk_ver%22:%221.3.9%22%2C%22status%22:%220%22}; appid=150b4dfebe; d_d_ci=1630e780-7a48-6218-a830-c5e010a79ce7; account_id=19737093603; ui=19737093603; Hm_lvt_fe740601c79b0c00b6d5458d146aa5ef=1734055597; HMACCOUNT=5A31BCBD7768359B; _gcl_au=1.1.215462428.1734055660; _gid=GA1.2.1466291769.1734055660; gr_user_id=f091018a-96fa-4924-8cff-7c966125acbc; 8473744dbcf62d60_gr_session_id=e47c497c-0e6f-4ef5-894e-6871bd6b6738; 8473744dbcf62d60_gr_session_id_sent_vst=e47c497c-0e6f-4ef5-894e-6871bd6b6738; _clck=83pjx%7C2%7Cfro%7C0%7C1808; ssoSessionId=51e2f966-5d97-4d34-970f-4f85349c8fbc; _ga_0KHV9JM0VW=GS1.1.1734055659.1.1.1734055751.60.0.0; _ga=GA1.2.942876758.1734055660; Hm_lpvt_fe740601c79b0c00b6d5458d146aa5ef=1734055752; _clsk=mb13en%7C1734055752782%7C2%7C1%7Cu.clarity.ms%2Fcollect; _uetsid=110d3500b8f411efab484704728f4bef; _uetvid=110d4ac0b8f411ef8e340ba70a661722; clientType=2; gt_local_id=ECXGmUamQt4vFnWW51Qc/ab09lpZc0qUDWBG3vZJNnvd2a1UuNMIwA==' + fd: 853568 GtToken: 'RzAwAGOoiVpTGIoDB0FU98fzRkWkl4Zz0G00jC1OaW+v6uI+ZfzitDHi/UOJG6r8wzM3aqmT0QL8WFc4Gc2vTw4dfUvZNr5cVYmjaJ0pR5nl2pq9SbAqGWNhDq3uLdRqIa0yCE+X2WoEoefXm12ucQKMIUKV9OJgnkOxmQnoy3ZjLPmmdRR/OmxLZO8vkiFYQMZrplI85Y8b6qLCeGEFSieJvDmoqOB6qPJUy6qxn17/rNRYllFSon5MwH8Gj0gtFyu3VDZT1aa2u+xn/gG4nSpjgi0J2n2A0MbXgztBkhsljk0YgAuhpNzjLapQkj2rt2v7b9BCouKYkMsHVNbyoDhfgT3MmRafU1vtj6vz3VfghVqEnpUtAvWBk6eQBefPMqTHXbMs4cEPZcJVAjdjYBbS5cao1yjmkU+lR1OUK8xQJNV3eVDnVcDxf59VXc2gSDiRipca1duw12jnxtgq2acvsLptuHtbWh/b+F06eNF5pg4fMQvRIsXmko0SjXb4T81cz3i+vZPVgz46N0ByvoxNt6Jtr0DQOFgk4e5yu378AC0Nz/rWCnROvtQAYSU2DWtTK41bjX0QtJCOnRSkZiYeGhmV6pSOoQ3VAy8EdslEEK0hQHp08H+SAVC3Kb8LrANxQqctY/x2wn5V/3izfzzOkbPTkz+Pry0GK05RFfrtVH2FP0tlrdgOuCawWkN5Mc64ypNbMXiB3ZvrKOMe6Uu/50qzH78Yqk3OVDH6LrfJ0NPrtF9Wpf77p9eXdtVs9hvU6hFRKko8yx/i18mIu5RmCatbuo/Qmly3FscUimKfT+7Gl+76oeUKf4sQ7jGwylbklgOfqwFgd12IEkvqXiVI9d1vkHZ73rEeO4JlJ9viCTuUd2tsFXlSAglYrgLkJQHlNQJWeA0JjFd3XK/VJaoAc2YkysFHClOFevG619Iw+bwKQwgymDzvzOevQH6FoXI6V4zxwIMwW9FhYS9GK2iwofD0UOeR2MRURxxa5nQnUAKRx78WI+yY9w/d88RqBNVXDdQy+toS+mQjn8LZzlK0cGi0ow6eKMA09ZTRbALk7htMbw==' prompt: '你是一个信息归纳分析工程师,你根据提问会搜索相关资料。经过信息精炼之后返回内容。 请回复时以以下格式进行返回: @@ -88,6 +84,16 @@ bard: # -----bard配置这行不填----- # I want you to act as a spoken English teacher and improver. I will speak to you in English and you will reply to me in English to practice my spoken English. I want you to keep your reply neat, limiting the reply to 100 words. I want you to strictly correct my grammar mistakes, typos, and factual errors. I want you to ask me a question in your reply. Now let's start practicing, you could ask me a question first. Remember, I want you to strictly correct my grammar mistakes, typos, and factual errors. prompt: You am a large language model, trained by Google. -zhipu: # -----zhipu配置这行不填----- +zhipu: # -----zhipu配置这行不填----- api_key: #api key - model: # 模型类型 \ No newline at end of file + model: # 模型类型 + +claude: + key: 46a5674a-e978-491b-a810-5d54605f2c36 + api: http://127.0.0.1:8080/v1/chat/completions # 如果你不知道这是干嘛的,就不要改 + model: windsurf/claude-3-5-sonnet + prompt: '你是一个信息归纳分析工程师,你根据提问会搜索相关资料。经过信息精炼之后返回内容。 + 请回复时以以下格式进行返回: + - 问题:回顾提问内容 + - 问题评价:分析问题的提出角度,如(财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐)等 + - 总结:经过200个字以内的优化返回' # 根据需要对角色进行设定 \ No newline at end of file diff --git a/configuration.py b/configuration.py index 611a526..361f425 100644 --- a/configuration.py +++ b/configuration.py @@ -37,3 +37,4 @@ class Config(object): self.CHATGLM = yconfig.get("chatglm", {}) self.BardAssistant = yconfig.get("bard", {}) self.ZhiPu = yconfig.get("zhipu", {}) + self.CLAUDE = yconfig.get("claude", {}) diff --git a/constants.py b/constants.py index 8a909cc..260c301 100644 --- a/constants.py +++ b/constants.py @@ -10,12 +10,13 @@ class ChatType(IntEnum): CHATGLM = 4 # ChatGLM BardAssistant = 5 # Google Bard ZhiPu = 6 # ZhiPu + CLAUDE = 7 # CLAUDE @staticmethod def is_in_chat_types(chat_type: int) -> bool: if chat_type in [ChatType.TIGER_BOT.value, ChatType.CHATGPT.value, ChatType.XINGHUO_WEB.value, ChatType.CHATGLM.value, - ChatType.BardAssistant.value, ChatType.ZhiPu.value]: + ChatType.BardAssistant.value, ChatType.ZhiPu.value, ChatType.CLAUDE.value]: return True return False diff --git a/message_report/process_message.py b/message_report/process_message.py index e1d6ff0..897c796 100644 --- a/message_report/process_message.py +++ b/message_report/process_message.py @@ -1,6 +1,6 @@ import redis from datetime import datetime -import re + from wcferry import WxMsg diff --git a/message_storage/message_to_db.py b/message_storage/message_to_db.py index 1898088..249fee9 100644 --- a/message_storage/message_to_db.py +++ b/message_storage/message_to_db.py @@ -1,5 +1,6 @@ import pymysql from datetime import datetime, timedelta +import redis # 配置数据库连接 db_config = { @@ -9,6 +10,9 @@ db_config = { 'database': 'message_archive' } +# 连接到Redis +r = redis.Redis(host='192.168.2.32', port=6379, db=0) + def archive_message(group_id, timestamp_str, sender, content, message_type, attachment_url=None): # 连接到数据库 @@ -41,13 +45,21 @@ def get_messages(group_id, all_contacts: dict): connection = pymysql.connect(**db_config) try: - with connection.cursor() as cursor: + # 获取redis 中的上次总结时间,本次从上次开始算,弱没有,则从8小时之前开始计算 + # 生成Redis key + key = f"{group_id}:summary_time" + last_summary_time = r.get(key) + if last_summary_time is None: # 获取当前时间并计算8小时前的时间 current_time = datetime.now() eight_hours_ago = current_time - timedelta(hours=8) # 转换为数据库中存储的时间格式 (假设timestamp是DATETIME类型) - eight_hours_ago_str = eight_hours_ago.strftime('%Y-%m-%d %H:%M:%S') + last_summary_time = eight_hours_ago.strftime('%Y-%m-%d %H:%M:%S') + current_date = current_time.strftime('%Y-%m-%d %H:%M:%S') + r.set(key, current_date) + + with connection.cursor() as cursor: # 执行查询,获取最近8小时的消息 query = """ @@ -55,7 +67,7 @@ def get_messages(group_id, all_contacts: dict): FROM messages WHERE timestamp >= %s AND message_type =1 and group_id = %s """ - cursor.execute(query, (eight_hours_ago_str, group_id)) + cursor.execute(query, (last_summary_time, group_id)) # 提取结果并组成带逗号的字符串 result = [] diff --git a/robot.py b/robot.py index 7d2e972..8f39e2f 100644 --- a/robot.py +++ b/robot.py @@ -20,6 +20,7 @@ from base.func_chengyu import cy from base.func_news import News from base.func_tigerbot import TigerBot from base.func_xinghuo_web import XinghuoWeb +from base.func_claude import Claude from configuration import Config from constants import ChatType from job_mgmt import Job @@ -57,6 +58,8 @@ class Robot(Job): self.chat = BardAssistant(self.config.BardAssistant) elif chat_type == ChatType.ZhiPu.value and ZhiPu.value_check(self.config.ZhiPu): self.chat = ZhiPu(self.config.ZhiPu) + elif chat_type == ChatType.CLAUDE.value and Claude.value_check(self.config.CLAUDE): + self.chat = Claude(self.config.CLAUDE) else: self.LOG.warning("未配置模型") self.chat = None @@ -73,6 +76,8 @@ class Robot(Job): self.chat = BardAssistant(self.config.BardAssistant) elif ZhiPu.value_check(self.config.ZhiPu): self.chat = ZhiPu(self.config.ZhiPu) + elif Claude.value_check(self.config.CLAUDE): + self.chat = Claude(self.config.CLAUDE) else: self.LOG.warning("未配置模型") self.chat = None