更新:models/routes/services/templates/docs
This commit is contained in:
@@ -3,11 +3,12 @@
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from app.config import load_api_config
|
||||
|
||||
|
||||
def generate_practice_plan(
|
||||
student_name, problems, practice_time="30-60分钟"
|
||||
student_name, problems, practice_time="30-60分钟", goals=None
|
||||
):
|
||||
"""
|
||||
根据学员问题和练习时间生成针对性练习方案
|
||||
@@ -16,6 +17,7 @@ def generate_practice_plan(
|
||||
student_name: 学员姓名
|
||||
problems: 问题列表 [{problem_id, problem_name, severity, level, content}]
|
||||
practice_time: 练习时间描述
|
||||
goals: 目标列表 [{goal_id, goal_name, goal_content, status, mastery_level}],默认为空列表
|
||||
|
||||
Returns:
|
||||
dict: 包含方案内容的字典
|
||||
@@ -41,6 +43,7 @@ def generate_practice_plan(
|
||||
{
|
||||
"name": p["problem_name"],
|
||||
"severity": p["severity"],
|
||||
"level": p.get("level", ""),
|
||||
"content": _extract_key_sections(content) if content else {"problem": f"针对{p['problem_name']}的练习"},
|
||||
"time_allocation": _calculate_time_allocation(
|
||||
p["severity"], time_config
|
||||
@@ -48,9 +51,6 @@ def generate_practice_plan(
|
||||
}
|
||||
)
|
||||
|
||||
# 生成每日练习计划
|
||||
daily_plan = _generate_daily_schedule(time_config, problem_contents)
|
||||
|
||||
# 生成方案
|
||||
plan = {
|
||||
"student_name": student_name,
|
||||
@@ -60,12 +60,12 @@ def generate_practice_plan(
|
||||
{
|
||||
"name": p["name"],
|
||||
"severity": p["severity"],
|
||||
"level": p.get("level", ""),
|
||||
"focus": p["time_allocation"],
|
||||
}
|
||||
for p in problem_contents
|
||||
],
|
||||
"daily_schedule": daily_plan,
|
||||
"generated_at": "2026-04-17",
|
||||
"generated_at": datetime.now().strftime("%Y-%m-%d"),
|
||||
}
|
||||
|
||||
return plan
|
||||
@@ -143,85 +143,6 @@ def _calculate_time_allocation(severity, time_config):
|
||||
}
|
||||
|
||||
|
||||
def _generate_daily_schedule(time_config, problem_contents):
|
||||
"""生成每日练习计划"""
|
||||
total = time_config["total"]
|
||||
|
||||
# 基础练习(哈农+音阶)
|
||||
basic_time = time_config["basic"]
|
||||
|
||||
# 技术练习(针对问题)
|
||||
tech_time = time_config["tech"]
|
||||
|
||||
# 曲目练习
|
||||
piece_time = time_config["piece"]
|
||||
|
||||
schedule = []
|
||||
|
||||
# 1. 热身
|
||||
schedule.append(
|
||||
{
|
||||
"phase": "热身",
|
||||
"duration": "3分钟",
|
||||
"content": "手部放松操 + 呼吸调节",
|
||||
"purpose": "放松肌肉,进入状态",
|
||||
}
|
||||
)
|
||||
|
||||
# 2. 基础练习
|
||||
if basic_time > 0:
|
||||
schedule.append(
|
||||
{
|
||||
"phase": "基础练习",
|
||||
"duration": f"{basic_time}分钟",
|
||||
"content": "哈农练习曲 + 音阶练习",
|
||||
"purpose": "建立基本功",
|
||||
}
|
||||
)
|
||||
|
||||
# 3. 技术练习(针对问题)
|
||||
if tech_time > 0 and problem_contents:
|
||||
tech_items = []
|
||||
for p in problem_contents:
|
||||
practices = p.get("content", {}).get("practices", [])
|
||||
if practices:
|
||||
# 取前2个练习
|
||||
for practice in practices[:2]:
|
||||
tech_items.append(practice["name"])
|
||||
|
||||
schedule.append(
|
||||
{
|
||||
"phase": "技术练习",
|
||||
"duration": f"{tech_time}分钟",
|
||||
"content": "、".join(tech_items[:3]) if tech_items else "针对性练习",
|
||||
"purpose": "解决具体问题",
|
||||
}
|
||||
)
|
||||
|
||||
# 4. 曲目练习
|
||||
if piece_time > 0:
|
||||
schedule.append(
|
||||
{
|
||||
"phase": "曲目练习",
|
||||
"duration": f"{piece_time}分钟",
|
||||
"content": "复习所学曲目 + 预习新曲目",
|
||||
"purpose": "提升演奏能力",
|
||||
}
|
||||
)
|
||||
|
||||
# 5. 总结
|
||||
schedule.append(
|
||||
{
|
||||
"phase": "总结",
|
||||
"duration": "3分钟",
|
||||
"content": "练习记录 + 问题检查 + 明日计划",
|
||||
"purpose": "巩固学习成果",
|
||||
}
|
||||
)
|
||||
|
||||
return schedule
|
||||
|
||||
|
||||
def _get_severity_advice(severity):
|
||||
"""根据严重程度给出建议"""
|
||||
advice = {
|
||||
@@ -236,7 +157,7 @@ def _get_severity_advice(severity):
|
||||
|
||||
|
||||
def generate_ai_report(
|
||||
student_name, wechat_nickname, problems, practice_time, time_config, template_id=None, dry_run=False
|
||||
student_name, wechat_nickname, problems, practice_time, time_config, template_id=None, dry_run=False, goals=None
|
||||
):
|
||||
"""
|
||||
使用AI生成个性化的练习报告
|
||||
@@ -249,6 +170,11 @@ def generate_ai_report(
|
||||
time_config: 时间配置 {total, basic, tech, piece}
|
||||
template_id: 可选的AI提示词模板ID
|
||||
dry_run: 如果为True,只返回提示词不调用API
|
||||
goals: 目标列表 [{goal_id, goal_name, goal_content, status, mastery_level}]
|
||||
practice_time: 练习时间描述
|
||||
time_config: 时间配置 {total, basic, tech, piece}
|
||||
template_id: 可选的AI提示词模板ID
|
||||
dry_run: 如果为True,只返回提示词不调用API
|
||||
|
||||
Returns:
|
||||
tuple: (prompt, ai_report, error) - 提示词、AI报告内容、错误信息
|
||||
@@ -324,14 +250,25 @@ def generate_ai_report(
|
||||
f"**详细内容和练习方法**:\n{content}"
|
||||
)
|
||||
|
||||
# 构建学员未达成目标列表(只包含未完成的目标)
|
||||
student_goals = []
|
||||
if goals:
|
||||
for g in goals:
|
||||
# 只处理未完成的目标
|
||||
if g.get("status") != "已完成":
|
||||
student_goals.append(
|
||||
f"- **{g['goal_name']}**\n 内容:{g.get('goal_content', '未提供具体内容')}"
|
||||
)
|
||||
|
||||
# 使用配置的模板,如果为空则使用默认模板
|
||||
if prompt_template:
|
||||
prompt = prompt_template.format(
|
||||
student_name=student_name,
|
||||
wechat_nickname=wechat_nickname or "未设置",
|
||||
practice_time=practice_time,
|
||||
student_problems="\n".join(student_problems),
|
||||
problems="\n\n".join(problems_full),
|
||||
student_problems="\n".join(student_problems) if student_problems else "无",
|
||||
problems="\n\n".join(problems_full) if problems_full else "无",
|
||||
student_goals="\n".join(student_goals) if student_goals else "无",
|
||||
)
|
||||
else:
|
||||
# 默认模板(向后兼容)
|
||||
@@ -363,7 +300,15 @@ def generate_ai_report(
|
||||
|
||||
# 如果是 dry_run(预览模式),直接返回提示词不调用API
|
||||
if dry_run:
|
||||
return prompt, None, None
|
||||
# 计算各部分字数
|
||||
student_problems_text = "\n".join(student_problems) if student_problems else "无"
|
||||
problems_text = "\n\n".join(problems_full) if problems_full else "无"
|
||||
student_goals_text = "\n".join(student_goals) if student_goals else "无"
|
||||
return prompt, None, None, {
|
||||
"student_problems_length": len(student_problems_text),
|
||||
"problems_length": len(problems_text),
|
||||
"student_goals_length": len(student_goals_text),
|
||||
}
|
||||
|
||||
# 调用API
|
||||
headers = {
|
||||
@@ -407,7 +352,7 @@ def generate_ai_report(
|
||||
content = (
|
||||
result.get("choices", [{}])[0].get("message", {}).get("content", "")
|
||||
)
|
||||
return prompt, content, None
|
||||
return prompt, content, None, None
|
||||
else:
|
||||
error_msg = f"API错误: {response.status_code}"
|
||||
try:
|
||||
@@ -415,9 +360,9 @@ def generate_ai_report(
|
||||
error_msg = error_detail.get("error", {}).get("message", error_msg)
|
||||
except:
|
||||
pass
|
||||
return prompt, None, error_msg
|
||||
return prompt, None, error_msg, None
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return prompt, None, "API请求超时,请稍后重试"
|
||||
return prompt, None, "API请求超时,请稍后重试", None
|
||||
except Exception as e:
|
||||
return prompt, None, f"调用API失败: {str(e)}"
|
||||
return prompt, None, f"调用API失败: {str(e)}", None
|
||||
|
||||
Reference in New Issue
Block a user