better 日程系统2.0
This commit is contained in:
@@ -130,7 +130,7 @@ MaiMBot是一个开源项目,我们非常欢迎你的参与。你的贡献,
|
|||||||
### 💬交流群
|
### 💬交流群
|
||||||
- [五群](https://qm.qq.com/q/JxvHZnxyec) 1022489779(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
- [五群](https://qm.qq.com/q/JxvHZnxyec) 1022489779(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
||||||
- [一群](https://qm.qq.com/q/VQ3XZrWgMs) 766798517 【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
- [一群](https://qm.qq.com/q/VQ3XZrWgMs) 766798517 【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
||||||
- [二群](https://qm.qq.com/q/RzmCiRtHEW) 571780722 【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
- [二群](https://qm.qq.com/q/RzmCiRtHEW) 571780722(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
||||||
- [三群](https://qm.qq.com/q/wlH5eT8OmQ) 1035228475【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
- [三群](https://qm.qq.com/q/wlH5eT8OmQ) 1035228475【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
||||||
- [四群](https://qm.qq.com/q/wlH5eT8OmQ) 729957033【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
- [四群](https://qm.qq.com/q/wlH5eT8OmQ) 729957033【已满】(开发和建议相关讨论)不一定有空回复,会优先写文档和代码
|
||||||
|
|
||||||
|
|||||||
@@ -22,57 +22,7 @@ class LLMModel:
|
|||||||
|
|
||||||
logger.info(f"API URL: {self.base_url}") # 使用 logger 记录 base_url
|
logger.info(f"API URL: {self.base_url}") # 使用 logger 记录 base_url
|
||||||
|
|
||||||
def generate_response(self, prompt: str) -> Union[str, Tuple[str, str]]:
|
async def generate_response_async(self, prompt: str) -> str:
|
||||||
"""根据输入的提示生成模型的响应"""
|
|
||||||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
|
|
||||||
|
|
||||||
# 构建请求体
|
|
||||||
data = {
|
|
||||||
"model": self.model_name,
|
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
|
||||||
"temperature": 0.5,
|
|
||||||
**self.params,
|
|
||||||
}
|
|
||||||
|
|
||||||
# 发送请求到完整的 chat/completions 端点
|
|
||||||
api_url = f"{self.base_url.rstrip('/')}/chat/completions"
|
|
||||||
logger.info(f"Request URL: {api_url}") # 记录请求的 URL
|
|
||||||
|
|
||||||
max_retries = 3
|
|
||||||
base_wait_time = 15 # 基础等待时间(秒)
|
|
||||||
|
|
||||||
for retry in range(max_retries):
|
|
||||||
try:
|
|
||||||
response = requests.post(api_url, headers=headers, json=data)
|
|
||||||
|
|
||||||
if response.status_code == 429:
|
|
||||||
wait_time = base_wait_time * (2**retry) # 指数退避
|
|
||||||
logger.warning(f"遇到请求限制(429),等待{wait_time}秒后重试...")
|
|
||||||
time.sleep(wait_time)
|
|
||||||
continue
|
|
||||||
|
|
||||||
response.raise_for_status() # 检查其他响应状态
|
|
||||||
|
|
||||||
result = response.json()
|
|
||||||
if "choices" in result and len(result["choices"]) > 0:
|
|
||||||
content = result["choices"][0]["message"]["content"]
|
|
||||||
reasoning_content = result["choices"][0]["message"].get("reasoning_content", "")
|
|
||||||
return content, reasoning_content
|
|
||||||
return "没有返回结果", ""
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
if retry < max_retries - 1: # 如果还有重试机会
|
|
||||||
wait_time = base_wait_time * (2**retry)
|
|
||||||
logger.error(f"[回复]请求失败,等待{wait_time}秒后重试... 错误: {str(e)}")
|
|
||||||
time.sleep(wait_time)
|
|
||||||
else:
|
|
||||||
logger.error(f"请求失败: {str(e)}")
|
|
||||||
return f"请求失败: {str(e)}", ""
|
|
||||||
|
|
||||||
logger.error("达到最大重试次数,请求仍然失败")
|
|
||||||
return "达到最大重试次数,请求仍然失败", ""
|
|
||||||
|
|
||||||
async def generate_response_async(self, prompt: str) -> Union[str, Tuple[str, str]]:
|
|
||||||
"""异步方式根据输入的提示生成模型的响应"""
|
"""异步方式根据输入的提示生成模型的响应"""
|
||||||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
|
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class ScheduleGenerator:
|
|||||||
|
|
||||||
def __init__(self, name: str = "bot_name", personality: str = "你是一个爱国爱党的新时代青年", behavior: str = "你非常外向,喜欢尝试新事物和人交流"):
|
def __init__(self, name: str = "bot_name", personality: str = "你是一个爱国爱党的新时代青年", behavior: str = "你非常外向,喜欢尝试新事物和人交流"):
|
||||||
# 使用离线LLM模型
|
# 使用离线LLM模型
|
||||||
self.llm_scheduler = LLMModel(model_name="Pro/deepseek-ai/DeepSeek-V3", temperature=0.9)
|
self.llm_scheduler = LLMModel(model_name="Qwen/Qwen2.5-32B-Instruct", temperature=0.9)
|
||||||
|
|
||||||
self.today_schedule_text = ""
|
self.today_schedule_text = ""
|
||||||
self.today_done_list = []
|
self.today_done_list = []
|
||||||
@@ -34,6 +34,8 @@ class ScheduleGenerator:
|
|||||||
|
|
||||||
self.start_time = datetime.datetime.now()
|
self.start_time = datetime.datetime.now()
|
||||||
|
|
||||||
|
self.schedule_doing_update_interval = 60 #最好大于60
|
||||||
|
|
||||||
async def mai_schedule_start(self):
|
async def mai_schedule_start(self):
|
||||||
"""启动日程系统,每5分钟执行一次move_doing,并在日期变化时重新检查日程"""
|
"""启动日程系统,每5分钟执行一次move_doing,并在日期变化时重新检查日程"""
|
||||||
try:
|
try:
|
||||||
@@ -43,6 +45,8 @@ class ScheduleGenerator:
|
|||||||
self.print_schedule()
|
self.print_schedule()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
print(self.get_current_num_task(1, True))
|
||||||
|
|
||||||
current_time = datetime.datetime.now()
|
current_time = datetime.datetime.now()
|
||||||
|
|
||||||
# 检查是否需要重新生成日程(日期变化)
|
# 检查是否需要重新生成日程(日期变化)
|
||||||
@@ -56,8 +60,7 @@ class ScheduleGenerator:
|
|||||||
current_activity = await self.move_doing()
|
current_activity = await self.move_doing()
|
||||||
logger.info(f"当前活动: {current_activity}")
|
logger.info(f"当前活动: {current_activity}")
|
||||||
|
|
||||||
# 等待5分钟
|
await asyncio.sleep(self.schedule_doing_update_interval)
|
||||||
await asyncio.sleep(300) # 300秒 = 5分钟
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"日程系统运行时出错: {str(e)}")
|
logger.error(f"日程系统运行时出错: {str(e)}")
|
||||||
@@ -79,6 +82,8 @@ class ScheduleGenerator:
|
|||||||
|
|
||||||
# 检查今天的日程
|
# 检查今天的日程
|
||||||
self.today_schedule_text, self.today_done_list = self.load_schedule_from_db(today)
|
self.today_schedule_text, self.today_done_list = self.load_schedule_from_db(today)
|
||||||
|
if not self.today_done_list:
|
||||||
|
self.today_done_list = []
|
||||||
if not self.today_schedule_text:
|
if not self.today_schedule_text:
|
||||||
logger.info(f"{today.strftime('%Y-%m-%d')}的日程不存在,准备生成新的日程")
|
logger.info(f"{today.strftime('%Y-%m-%d')}的日程不存在,准备生成新的日程")
|
||||||
self.today_schedule_text = await self.generate_daily_schedule(target_date=today)
|
self.today_schedule_text = await self.generate_daily_schedule(target_date=today)
|
||||||
@@ -98,10 +103,16 @@ class ScheduleGenerator:
|
|||||||
|
|
||||||
def construct_doing_prompt(self,time: datetime.datetime):
|
def construct_doing_prompt(self,time: datetime.datetime):
|
||||||
now_time = time.strftime("%H:%M")
|
now_time = time.strftime("%H:%M")
|
||||||
previous_doing = self.today_done_list[-20:] if len(self.today_done_list) > 20 else self.today_done_list
|
if self.today_done_list:
|
||||||
|
previous_doing = self.get_current_num_task(10, True)
|
||||||
|
print(previous_doing)
|
||||||
|
else:
|
||||||
|
previous_doing = "我没做什么事情"
|
||||||
|
|
||||||
|
|
||||||
prompt = f"我是{self.name},{self.personality},{self.behavior}"
|
prompt = f"我是{self.name},{self.personality},{self.behavior}"
|
||||||
prompt += f"我今天的日程是:{self.today_schedule_text}\n"
|
prompt += f"我今天的日程是:{self.today_schedule_text}\n"
|
||||||
prompt += f"我之前做了的事情是:{previous_doing}\n"
|
prompt += f"我之前做了的事情是:{previous_doing},从之前到现在已经过去了{self.schedule_doing_update_interval/60}分钟了\n"
|
||||||
prompt += f"现在是{now_time},结合我的个人特点和行为习惯,"
|
prompt += f"现在是{now_time},结合我的个人特点和行为习惯,"
|
||||||
prompt += "推测我现在做什么,具体一些,详细一些\n"
|
prompt += "推测我现在做什么,具体一些,详细一些\n"
|
||||||
prompt += "直接返回我在做的事情,不要输出其他内容:"
|
prompt += "直接返回我在做的事情,不要输出其他内容:"
|
||||||
@@ -110,7 +121,7 @@ class ScheduleGenerator:
|
|||||||
async def generate_daily_schedule(
|
async def generate_daily_schedule(
|
||||||
self, target_date: datetime.datetime = None,) -> Dict[str, str]:
|
self, target_date: datetime.datetime = None,) -> Dict[str, str]:
|
||||||
daytime_prompt = self.construct_daytime_prompt(target_date)
|
daytime_prompt = self.construct_daytime_prompt(target_date)
|
||||||
daytime_response, _ = await self.llm_scheduler.generate_response(daytime_prompt)
|
daytime_response,_ = await self.llm_scheduler.generate_response_async(daytime_prompt)
|
||||||
return daytime_response
|
return daytime_response
|
||||||
|
|
||||||
def _time_diff(self, time1: str, time2: str) -> int:
|
def _time_diff(self, time1: str, time2: str) -> int:
|
||||||
@@ -160,15 +171,54 @@ class ScheduleGenerator:
|
|||||||
current_time = datetime.datetime.now()
|
current_time = datetime.datetime.now()
|
||||||
time_str = current_time.strftime("%H:%M")
|
time_str = current_time.strftime("%H:%M")
|
||||||
doing_prompt = self.construct_doing_prompt(current_time)
|
doing_prompt = self.construct_doing_prompt(current_time)
|
||||||
doing_response, _ = await self.llm_scheduler.generate_response(doing_prompt)
|
doing_response,_ = await self.llm_scheduler.generate_response_async(doing_prompt)
|
||||||
self.today_done_list.append(current_time,time_str + "在" + doing_response)
|
self.today_done_list.append((current_time, time_str + "时," + doing_response))
|
||||||
|
|
||||||
await self.update_today_done_list()
|
await self.update_today_done_list()
|
||||||
|
|
||||||
return doing_response
|
return doing_response
|
||||||
|
|
||||||
|
async def get_task_from_time_to_time(self, start_time: str, end_time: str):
|
||||||
|
"""获取指定时间范围内的任务列表
|
||||||
|
|
||||||
|
Args:
|
||||||
|
start_time (str): 开始时间,格式为"HH:MM"
|
||||||
|
end_time (str): 结束时间,格式为"HH:MM"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 时间范围内的任务列表
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
for task in self.today_done_list:
|
||||||
|
task_time = task[0] # 获取任务的时间戳
|
||||||
|
task_time_str = task_time.strftime("%H:%M")
|
||||||
|
|
||||||
|
# 检查任务时间是否在指定范围内
|
||||||
|
if self._time_diff(start_time, task_time_str) >= 0 and self._time_diff(task_time_str, end_time) >= 0:
|
||||||
|
result.append(task)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_current_num_task(self, num=1, time_info = False):
|
||||||
|
"""获取最新加入的指定数量的日程
|
||||||
|
|
||||||
|
Args:
|
||||||
|
num (int): 需要获取的日程数量,默认为1
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 最新加入的日程列表
|
||||||
|
"""
|
||||||
|
if not self.today_done_list:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 确保num不超过列表长度
|
||||||
|
num = min(num, len(self.today_done_list))
|
||||||
|
pre_doing = ""
|
||||||
|
for doing in self.today_done_list[-num:]:
|
||||||
|
pre_doing += doing[1]
|
||||||
|
|
||||||
|
# 返回最新的num条日程
|
||||||
|
return pre_doing
|
||||||
|
|
||||||
def save_today_schedule_to_db(self):
|
def save_today_schedule_to_db(self):
|
||||||
"""保存日程到数据库,同时初始化 today_done_list"""
|
"""保存日程到数据库,同时初始化 today_done_list"""
|
||||||
@@ -200,18 +250,10 @@ class ScheduleGenerator:
|
|||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
# 使用示例
|
# 使用示例
|
||||||
scheduler = ScheduleGenerator(name="麦麦", personality="你叫麦麦,你19岁,是一个大二的女大学生,你有一头黑色短发,你会刷贴吧,你现在在学习心理学", behavior="你比较内向")
|
scheduler = ScheduleGenerator(name="麦麦", personality="你叫麦麦,你19岁,是一个大二的女大学生,你有一头黑色短发,你会刷贴吧,你现在在学习心理学", behavior="你比较内向,一般熬夜比较晚,然后第二天早上10点起床吃早午饭")
|
||||||
await scheduler.check_and_create_today_schedule()
|
await scheduler.mai_schedule_start()
|
||||||
scheduler.print_schedule()
|
|
||||||
print("\n当前任务:")
|
|
||||||
print(await scheduler.get_current_task())
|
|
||||||
|
|
||||||
print("昨天日程:")
|
|
||||||
print(scheduler.yesterday_schedule)
|
|
||||||
print("今天日程:")
|
|
||||||
print(scheduler.today_schedule)
|
|
||||||
print("明天日程:")
|
|
||||||
print(scheduler.tomorrow_schedule)
|
|
||||||
|
|
||||||
# 当作为组件导入时使用的实例
|
# 当作为组件导入时使用的实例
|
||||||
bot_schedule = ScheduleGenerator()
|
bot_schedule = ScheduleGenerator()
|
||||||
|
|||||||
Reference in New Issue
Block a user