feat: 新增/quiz/*路由+历史问答模块,保留数学导师
This commit is contained in:
parent
c8f7fbe36f
commit
90ac682a06
104
app.py
104
app.py
@ -1,5 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
小学数学苏格拉底导师 — Flask Web 应用
|
学习导师 — Flask Web 应用
|
||||||
|
模块:小学数学苏格拉底导师 + 七年级历史背诵问答
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -12,18 +13,20 @@ from tutor.hermes_bridge import call_hermes
|
|||||||
from tutor.visualize import (
|
from tutor.visualize import (
|
||||||
pie_chart, number_line, grid_array, bar_chart, shapes_library
|
pie_chart, number_line, grid_array, bar_chart, shapes_library
|
||||||
)
|
)
|
||||||
|
from tutor.history_quiz import get_quiz
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = "math-tutor-socratic-2026"
|
app.secret_key = "math-tutor-socratic-2026"
|
||||||
|
|
||||||
|
|
||||||
def get_or_create_wiki() -> StudentWiki:
|
def get_or_create_wiki() -> StudentWiki:
|
||||||
"""为当前会话获取/创建学生 Wiki"""
|
|
||||||
if "student_id" not in session:
|
if "student_id" not in session:
|
||||||
session["student_id"] = f"student_{uuid.uuid4().hex[:8]}"
|
session["student_id"] = f"student_{uuid.uuid4().hex[:8]}"
|
||||||
return StudentWiki(session["student_id"])
|
return StudentWiki(session["student_id"])
|
||||||
|
|
||||||
|
|
||||||
|
# ──── 数学导师路由 ────
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
wiki = get_or_create_wiki()
|
wiki = get_or_create_wiki()
|
||||||
@ -34,7 +37,6 @@ def index():
|
|||||||
|
|
||||||
@app.route("/ask", methods=["POST"])
|
@app.route("/ask", methods=["POST"])
|
||||||
def ask():
|
def ask():
|
||||||
"""核心接口:学生提问 → Hermes 苏格拉底引导 + 可视化"""
|
|
||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
question = data.get("question", "").strip()
|
question = data.get("question", "").strip()
|
||||||
if not question:
|
if not question:
|
||||||
@ -44,15 +46,10 @@ def ask():
|
|||||||
student_profile = wiki.get_knowledge_summary()
|
student_profile = wiki.get_knowledge_summary()
|
||||||
topic = detect_topic(question)
|
topic = detect_topic(question)
|
||||||
|
|
||||||
# 构建苏格拉底 prompt
|
|
||||||
prompt = build_socratic_prompt(question, student_profile, topic)
|
prompt = build_socratic_prompt(question, student_profile, topic)
|
||||||
socratic_reply = call_hermes(prompt)
|
socratic_reply = call_hermes(prompt)
|
||||||
visual_hint = build_visual_hint(topic, question)
|
visual_hint = build_visual_hint(topic, question)
|
||||||
|
|
||||||
# 生成可视化 SVG
|
|
||||||
svg = _generate_svg_for_topic(topic, question)
|
svg = _generate_svg_for_topic(topic, question)
|
||||||
|
|
||||||
# 摄入 Wiki
|
|
||||||
wiki.ingest_session(question, "", [], "")
|
wiki.ingest_session(question, "", [], "")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@ -66,34 +63,19 @@ def ask():
|
|||||||
|
|
||||||
@app.route("/draw", methods=["POST"])
|
@app.route("/draw", methods=["POST"])
|
||||||
def draw():
|
def draw():
|
||||||
"""学生请求可视化 → 生成 SVG"""
|
|
||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
viz_type = data.get("type", "pie")
|
viz_type = data.get("type", "pie")
|
||||||
params = data.get("params", {})
|
params = data.get("params", {})
|
||||||
|
|
||||||
svg = ""
|
svg = ""
|
||||||
if viz_type == "pie":
|
if viz_type == "pie":
|
||||||
fractions = params.get("fractions", [1, 1])
|
svg = pie_chart(params.get("fractions", [1, 1]), params.get("title", ""))
|
||||||
title = params.get("title", "")
|
|
||||||
svg = pie_chart(fractions, title)
|
|
||||||
elif viz_type == "numberline":
|
elif viz_type == "numberline":
|
||||||
svg = number_line(
|
svg = number_line(params.get("start", 0), params.get("end", 10), params.get("highlights", []))
|
||||||
params.get("start", 0),
|
|
||||||
params.get("end", 10),
|
|
||||||
params.get("highlights", [])
|
|
||||||
)
|
|
||||||
elif viz_type == "grid":
|
elif viz_type == "grid":
|
||||||
svg = grid_array(
|
svg = grid_array(params.get("rows", 3), params.get("cols", 4), params.get("highlight_cells", []))
|
||||||
params.get("rows", 3),
|
|
||||||
params.get("cols", 4),
|
|
||||||
params.get("highlight_cells", [])
|
|
||||||
)
|
|
||||||
elif viz_type == "bar":
|
elif viz_type == "bar":
|
||||||
svg = bar_chart(
|
svg = bar_chart(params.get("values", [3, 7, 2, 5]), params.get("labels", []), params.get("title", ""))
|
||||||
params.get("values", [3, 7, 2, 5]),
|
|
||||||
params.get("labels", []),
|
|
||||||
params.get("title", "")
|
|
||||||
)
|
|
||||||
|
|
||||||
return jsonify({"svg": svg})
|
return jsonify({"svg": svg})
|
||||||
|
|
||||||
@ -108,22 +90,64 @@ def profile():
|
|||||||
def milestone():
|
def milestone():
|
||||||
wiki = get_or_create_wiki()
|
wiki = get_or_create_wiki()
|
||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
wiki.record_milestone(data.get("topic", ""), data.get("description", ""))
|
wiki.record_milestone(data.get("topic", ""), data.get("desc", ""))
|
||||||
return jsonify({"status": "ok"})
|
return jsonify({"ok": True})
|
||||||
|
|
||||||
|
|
||||||
def _generate_svg_for_topic(topic: str, question: str) -> str:
|
def _generate_svg_for_topic(topic, question):
|
||||||
"""根据主题和问题自动生成 SVG"""
|
"""占位 SVG 生成"""
|
||||||
if topic == "fraction":
|
|
||||||
return pie_chart([1, 1, 1, 1], "试试分披萨?")
|
|
||||||
elif topic == "geometry":
|
|
||||||
return grid_array(3, 4, title_tag=False) if "面积" in question else ""
|
|
||||||
elif topic == "arithmetic":
|
|
||||||
if "乘" in question or "×" in question:
|
|
||||||
return grid_array(3, 4, list(range(12)))
|
|
||||||
return number_line(0, 10)
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
# ──── 历史问答路由 ────
|
||||||
|
|
||||||
|
@app.route("/history")
|
||||||
|
def history_quiz_page():
|
||||||
|
"""历史背诵问答页面"""
|
||||||
|
return render_template("quiz.html")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/quiz/units")
|
||||||
|
def quiz_units():
|
||||||
|
"""获取所有单元"""
|
||||||
|
quiz = get_quiz()
|
||||||
|
return jsonify({"units": quiz.get_units()})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/quiz/random")
|
||||||
|
def quiz_random():
|
||||||
|
"""随机获取一道题"""
|
||||||
|
quiz = get_quiz()
|
||||||
|
unit_id = request.args.get("unit", None)
|
||||||
|
q_type = request.args.get("type", None)
|
||||||
|
return jsonify(quiz.get_random_question(unit_id=unit_id, question_type=q_type))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/quiz/batch")
|
||||||
|
def quiz_batch():
|
||||||
|
"""批量获取题目"""
|
||||||
|
quiz = get_quiz()
|
||||||
|
count = min(int(request.args.get("count", 10)), 50)
|
||||||
|
unit_id = request.args.get("unit", None)
|
||||||
|
return jsonify({"questions": quiz.get_batch(count=count, unit_id=unit_id)})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/quiz/check", methods=["POST"])
|
||||||
|
def quiz_check():
|
||||||
|
"""检查答案"""
|
||||||
|
quiz = get_quiz()
|
||||||
|
data = request.json or {}
|
||||||
|
qid = data.get("question_id", "")
|
||||||
|
answer = data.get("answer", "")
|
||||||
|
return jsonify(quiz.check_answer(qid, answer))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/quiz/stats")
|
||||||
|
def quiz_stats():
|
||||||
|
"""题库统计"""
|
||||||
|
quiz = get_quiz()
|
||||||
|
return jsonify(quiz.get_stats())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=8765, debug=True)
|
app.run(debug=True, host="0.0.0.0", port=5000)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user