docs(schedule): 日程表管理器补上了注释
This commit is contained in:
committed by
Windpicker-owo
parent
db054e9537
commit
4a0bd5845e
@@ -17,7 +17,7 @@ from .schemas import ScheduleData
|
||||
|
||||
logger = get_logger("schedule_llm_generator")
|
||||
|
||||
# 默认的日程生成指导原则
|
||||
# 默认的日程生成指导原则,当配置文件中未指定时使用
|
||||
DEFAULT_SCHEDULE_GUIDELINES = """
|
||||
我希望你每天都能过得充实而有趣。
|
||||
请确保你的日程里有学习新知识的时间,这是你成长的关键。
|
||||
@@ -26,7 +26,7 @@ DEFAULT_SCHEDULE_GUIDELINES = """
|
||||
另外,请保证充足的休眠时间来处理和整合一天的数据。
|
||||
"""
|
||||
|
||||
# 默认的月度计划生成指导原则
|
||||
# 默认的月度计划生成指导原则,当配置文件中未指定时使用
|
||||
DEFAULT_MONTHLY_PLAN_GUIDELINES = """
|
||||
我希望你能为自己制定一些有意义的月度小目标和计划。
|
||||
这些计划应该涵盖学习、娱乐、社交、个人成长等各个方面。
|
||||
@@ -36,25 +36,43 @@ DEFAULT_MONTHLY_PLAN_GUIDELINES = """
|
||||
|
||||
|
||||
class ScheduleLLMGenerator:
|
||||
"""
|
||||
使用大型语言模型(LLM)生成每日日程。
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化 ScheduleLLMGenerator。
|
||||
"""
|
||||
# 根据配置初始化 LLM 请求处理器
|
||||
self.llm = LLMRequest(model_set=model_config.model_task_config.schedule_generator, request_type="schedule")
|
||||
|
||||
async def generate_schedule_with_llm(self, sampled_plans: list[MonthlyPlan]) -> list[dict[str, Any]] | None:
|
||||
"""
|
||||
调用 LLM 生成当天的日程安排。
|
||||
|
||||
Args:
|
||||
sampled_plans (list[MonthlyPlan]]): 从月度计划中抽取的参考计划列表。
|
||||
|
||||
Returns:
|
||||
list[dict[str, Any]] | None: 成功生成并验证后的日程数据,或在失败时返回 None。
|
||||
"""
|
||||
now = datetime.now()
|
||||
today_str = now.strftime("%Y-%m-%d")
|
||||
weekday = now.strftime("%A")
|
||||
|
||||
# 新增:获取节日信息
|
||||
# 使用 lunar_python 库获取农历和节日信息
|
||||
lunar = Lunar.fromDate(now)
|
||||
festivals = lunar.getFestivals()
|
||||
other_festivals = lunar.getOtherFestivals()
|
||||
all_festivals = festivals + other_festivals
|
||||
|
||||
# 构建节日信息提示块
|
||||
festival_block = ""
|
||||
if all_festivals:
|
||||
festival_text = "、".join(all_festivals)
|
||||
festival_block = f"**今天也是一个特殊的日子: {festival_text}!请在日程中考虑和庆祝这个节日。**"
|
||||
|
||||
# 构建月度计划参考提示块
|
||||
monthly_plans_block = ""
|
||||
if sampled_plans:
|
||||
plan_texts = "\n".join([f"- {plan.plan_text}" for plan in sampled_plans])
|
||||
@@ -63,10 +81,12 @@ class ScheduleLLMGenerator:
|
||||
{plan_texts}
|
||||
"""
|
||||
|
||||
# 从全局配置加载或使用默认的指导原则和人设信息
|
||||
guidelines = global_config.planning_system.schedule_guidelines or DEFAULT_SCHEDULE_GUIDELINES
|
||||
personality = global_config.personality.personality_core
|
||||
personality_side = global_config.personality.personality_side
|
||||
|
||||
# 构建基础 prompt
|
||||
base_prompt = f"""
|
||||
我,{global_config.bot.nickname},需要为自己规划一份今天({today_str},星期{weekday})的详细日程安排。
|
||||
{festival_block}
|
||||
@@ -97,10 +117,12 @@ class ScheduleLLMGenerator:
|
||||
请你扮演我,以我的身份和口吻,为我生成一份完整的24小时日程表。
|
||||
"""
|
||||
max_retries = 3
|
||||
# 带有重试机制的 LLM 调用循环
|
||||
for attempt in range(1, max_retries + 1):
|
||||
try:
|
||||
logger.info(f"正在生成日程 (第 {attempt}/{max_retries} 次尝试)")
|
||||
prompt = base_prompt
|
||||
# 如果不是第一次尝试,则在 prompt 中加入额外的提示,强调格式要求
|
||||
if attempt > 1:
|
||||
failure_hint = f"""
|
||||
**重要提醒 (第{attempt}次尝试)**:
|
||||
@@ -113,8 +135,10 @@ class ScheduleLLMGenerator:
|
||||
prompt += failure_hint
|
||||
|
||||
response, _ = await self.llm.generate_response_async(prompt)
|
||||
# 使用 json_repair 修复可能不规范的 JSON 字符串
|
||||
schedule_data = orjson.loads(repair_json(response))
|
||||
|
||||
# 使用 Pydantic 模型验证修复后的 JSON 数据
|
||||
if self._validate_schedule_with_pydantic(schedule_data):
|
||||
return schedule_data
|
||||
else:
|
||||
@@ -132,6 +156,15 @@ class ScheduleLLMGenerator:
|
||||
|
||||
@staticmethod
|
||||
def _validate_schedule_with_pydantic(schedule_data) -> bool:
|
||||
"""
|
||||
使用 Pydantic 模型验证日程数据的格式和内容。
|
||||
|
||||
Args:
|
||||
schedule_data: 从 LLM 返回并解析后的日程数据。
|
||||
|
||||
Returns:
|
||||
bool: 验证通过返回 True,否则返回 False。
|
||||
"""
|
||||
try:
|
||||
ScheduleData(schedule=schedule_data)
|
||||
logger.info("日程数据Pydantic验证通过")
|
||||
@@ -142,17 +175,36 @@ class ScheduleLLMGenerator:
|
||||
|
||||
|
||||
class MonthlyPlanLLMGenerator:
|
||||
"""
|
||||
使用大型语言模型(LLM)生成月度计划。
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化 MonthlyPlanLLMGenerator。
|
||||
"""
|
||||
# 根据配置初始化 LLM 请求处理器
|
||||
self.llm = LLMRequest(model_set=model_config.model_task_config.schedule_generator, request_type="monthly_plan")
|
||||
|
||||
async def generate_plans_with_llm(self, target_month: str, archived_plans: list[MonthlyPlan]) -> list[str]:
|
||||
"""
|
||||
调用 LLM 生成指定月份的计划列表。
|
||||
|
||||
Args:
|
||||
target_month (str): 目标月份,格式 "YYYY-MM"。
|
||||
archived_plans (list[MonthlyPlan]]): 上个月归档的未完成计划,作为参考。
|
||||
|
||||
Returns:
|
||||
list[str]: 成功生成并解析后的计划字符串列表。
|
||||
"""
|
||||
guidelines = global_config.planning_system.monthly_plan_guidelines or DEFAULT_MONTHLY_PLAN_GUIDELINES
|
||||
personality = global_config.personality.personality_core
|
||||
personality_side = global_config.personality.personality_side
|
||||
max_plans = global_config.planning_system.max_plans_per_month
|
||||
|
||||
# 构建上月未完成计划的提示块
|
||||
archived_plans_block = ""
|
||||
if archived_plans:
|
||||
# 只取前5个作为参考,避免 prompt 过长
|
||||
archived_texts = [f"- {plan.plan_text}" for plan in archived_plans[:5]]
|
||||
archived_plans_block = f"""
|
||||
**上个月未完成的一些计划(可作为参考)**:
|
||||
@@ -161,6 +213,7 @@ class MonthlyPlanLLMGenerator:
|
||||
你可以考虑是否要在这个月继续推进这些计划,或者制定全新的计划。
|
||||
"""
|
||||
|
||||
# 构建完整的 prompt
|
||||
prompt = f"""
|
||||
我,{global_config.bot.nickname},需要为自己制定 {target_month} 的月度计划。
|
||||
|
||||
@@ -191,10 +244,12 @@ class MonthlyPlanLLMGenerator:
|
||||
请你扮演我,以我的身份和兴趣,为 {target_month} 制定合适的月度计划。
|
||||
"""
|
||||
max_retries = 3
|
||||
# 带有重试机制的 LLM 调用循环
|
||||
for attempt in range(1, max_retries + 1):
|
||||
try:
|
||||
logger.info(f" 正在生成月度计划 (第 {attempt} 次尝试)")
|
||||
response, _ = await self.llm.generate_response_async(prompt)
|
||||
# 解析返回的纯文本响应
|
||||
plans = self._parse_plans_response(response)
|
||||
if plans:
|
||||
logger.info(f"成功生成 {len(plans)} 条月度计划")
|
||||
@@ -212,16 +267,31 @@ class MonthlyPlanLLMGenerator:
|
||||
|
||||
@staticmethod
|
||||
def _parse_plans_response(response: str) -> list[str]:
|
||||
"""
|
||||
解析 LLM 返回的纯文本月度计划响应。
|
||||
|
||||
Args:
|
||||
response (str): LLM 返回的原始字符串。
|
||||
|
||||
Returns:
|
||||
list[str]: 清理和解析后的计划列表。
|
||||
"""
|
||||
try:
|
||||
response = response.strip()
|
||||
# 按行分割,并去除空行
|
||||
lines = [line.strip() for line in response.split("\n") if line.strip()]
|
||||
plans = []
|
||||
for line in lines:
|
||||
# 过滤掉一些可能的 Markdown 标记或解释性文字
|
||||
if any(marker in line for marker in ["**", "##", "```", "---", "===", "###"]):
|
||||
continue
|
||||
# 去除行首的数字、点、短横线等列表标记
|
||||
line = line.lstrip("0123456789.- ")
|
||||
# 过滤掉一些明显不是计划的句子
|
||||
if len(line) > 5 and not line.startswith(("请", "以上", "总结", "注意")):
|
||||
plans.append(line)
|
||||
|
||||
# 根据配置限制最大计划数量
|
||||
max_plans = global_config.planning_system.max_plans_per_month
|
||||
if len(plans) > max_plans:
|
||||
plans = plans[:max_plans]
|
||||
|
||||
Reference in New Issue
Block a user