""" 小学数学苏格拉底导师 — 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 ) app = Flask(__name__) app.secret_key = "math-tutor-socratic-2026" def get_or_create_wiki() -> StudentWiki: """为当前会话获取/创建学生 Wiki""" 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(): """核心接口:学生提问 → Hermes 苏格拉底引导 + 可视化""" 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 prompt = build_socratic_prompt(question, student_profile, topic) socratic_reply = call_hermes(prompt) visual_hint = build_visual_hint(topic, question) # 生成可视化 SVG svg = _generate_svg_for_topic(topic, question) # 摄入 Wiki 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(): """学生请求可视化 → 生成 SVG""" data = request.json or {} viz_type = data.get("type", "pie") params = data.get("params", {}) svg = "" if viz_type == "pie": fractions = params.get("fractions", [1, 1]) title = params.get("title", "") svg = pie_chart(fractions, 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("description", "")) return jsonify({"status": "ok"}) def _generate_svg_for_topic(topic: str, question: str) -> str: """根据主题和问题自动生成 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 "" if __name__ == "__main__": app.run(host="0.0.0.0", port=8765, debug=True)