math-tutor/app.py

154 lines
4.2 KiB
Python

"""
学习导师 — Flask Web 应用
模块:小学数学苏格拉底导师 + 七年级历史背诵问答
"""
import json
import uuid
from flask import Flask, request, jsonify, render_template, session
from tutor.wiki import StudentWiki
from tutor.socratic import build_socratic_prompt, detect_topic, build_visual_hint
from tutor.hermes_bridge import call_hermes
from tutor.visualize import (
pie_chart, number_line, grid_array, bar_chart, shapes_library
)
from tutor.history_quiz import get_quiz
app = Flask(__name__)
app.secret_key = "math-tutor-socratic-2026"
def get_or_create_wiki() -> StudentWiki:
if "student_id" not in session:
session["student_id"] = f"student_{uuid.uuid4().hex[:8]}"
return StudentWiki(session["student_id"])
# ──── 数学导师路由 ────
@app.route("/")
def index():
wiki = get_or_create_wiki()
return render_template("index.html",
student_id=wiki.student_id,
shapes=shapes_library())
@app.route("/ask", methods=["POST"])
def ask():
data = request.json or {}
question = data.get("question", "").strip()
if not question:
return jsonify({"error": "请输入你的问题哦~"}), 400
wiki = get_or_create_wiki()
student_profile = wiki.get_knowledge_summary()
topic = detect_topic(question)
prompt = build_socratic_prompt(question, student_profile, topic)
socratic_reply = call_hermes(prompt)
visual_hint = build_visual_hint(topic, question)
svg = _generate_svg_for_topic(topic, question)
wiki.ingest_session(question, "", [], "")
return jsonify({
"reply": socratic_reply,
"visual_hint": visual_hint,
"topic": topic,
"svg": svg,
"student_profile": student_profile
})
@app.route("/draw", methods=["POST"])
def draw():
data = request.json or {}
viz_type = data.get("type", "pie")
params = data.get("params", {})
svg = ""
if viz_type == "pie":
svg = pie_chart(params.get("fractions", [1, 1]), params.get("title", ""))
elif viz_type == "numberline":
svg = number_line(params.get("start", 0), params.get("end", 10), params.get("highlights", []))
elif viz_type == "grid":
svg = grid_array(params.get("rows", 3), params.get("cols", 4), params.get("highlight_cells", []))
elif viz_type == "bar":
svg = bar_chart(params.get("values", [3, 7, 2, 5]), params.get("labels", []), params.get("title", ""))
return jsonify({"svg": svg})
@app.route("/profile", methods=["GET"])
def profile():
wiki = get_or_create_wiki()
return jsonify(wiki.get_schema())
@app.route("/milestone", methods=["POST"])
def milestone():
wiki = get_or_create_wiki()
data = request.json or {}
wiki.record_milestone(data.get("topic", ""), data.get("desc", ""))
return jsonify({"ok": True})
def _generate_svg_for_topic(topic, question):
"""占位 SVG 生成"""
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__":
app.run(debug=True, host="0.0.0.0", port=5000)