Spaces:
Running
Running
File size: 5,750 Bytes
07bc9aa 7f9bc0e 07bc9aa 7f9bc0e 07bc9aa 7f9bc0e 07bc9aa 7f9bc0e 07bc9aa 7f9bc0e 07bc9aa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | """Flask entry point for Language Tutor HF Space."""
import os
import base64
import logging
from flask import Flask, request, jsonify, render_template
from backend.language_config import get_curriculum_data, LANGUAGES
from backend.teacher_profiles import get_all_teachers
from backend.session_manager import sessions
from backend.tutor_engine import build_system_prompt, build_greeting_prompt, evaluate_pronunciation
from backend.hf_client import chat_completion, speech_to_text, get_model_info
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__, static_folder="static", template_folder="templates")
@app.route("/")
def index():
return render_template("index.html")
@app.route("/api/health", methods=["GET"])
def health():
return jsonify({"status": "ok", "models": get_model_info()})
@app.route("/api/curriculum", methods=["GET"])
def curriculum():
return jsonify(get_curriculum_data())
@app.route("/api/teachers", methods=["GET"])
def teachers():
return jsonify({"teachers": get_all_teachers()})
@app.route("/api/teacher/voice-sample", methods=["POST"])
def teacher_voice_sample():
"""Return sample text for client-side TTS preview."""
data = request.json or {}
target_lang = data.get("target_lang", "hindi")
lang = LANGUAGES.get(target_lang)
if not lang:
return jsonify({"error": "Unknown language"}), 400
return jsonify({"text": lang.get("sample_text", "Hello!")})
@app.route("/api/session/start", methods=["POST"])
def session_start():
data = request.json or {}
target_lang = data.get("target_lang")
instruction_lang = data.get("instruction_lang", "english")
level = data.get("level", "A1")
topic = data.get("topic", "greetings")
teacher_id = data.get("teacher_id", "anaya")
if not target_lang or target_lang not in LANGUAGES:
return jsonify({"error": "Invalid target language"}), 400
if instruction_lang not in LANGUAGES:
return jsonify({"error": "Invalid instruction language"}), 400
session = sessions.create_session(target_lang, instruction_lang, level, topic, teacher_id)
system_prompt = build_system_prompt(target_lang, instruction_lang, level, topic, teacher_id)
session.add_message("system", system_prompt)
greeting_prompt = build_greeting_prompt(target_lang, instruction_lang, level, topic, teacher_id)
session.add_message("user", greeting_prompt)
result = chat_completion(session.get_messages())
greeting = result.get("content", "Hello! Let's begin our lesson.")
session.add_message("assistant", greeting)
return jsonify({
"session_id": session.session_id,
"greeting": greeting,
"teacher_id": teacher_id
})
@app.route("/api/chat", methods=["POST"])
def chat():
data = request.json or {}
session_id = data.get("session_id")
user_message = data.get("message", "").strip()
if not session_id or not user_message:
return jsonify({"error": "session_id and message required"}), 400
session = sessions.get_session(session_id)
if not session:
return jsonify({"error": "Session expired or not found"}), 404
session.add_message("user", user_message)
result = chat_completion(session.get_messages())
reply = result.get("content", "")
session.add_message("assistant", reply)
session.add_xp(5)
return jsonify({
"reply": reply,
"xp": session.xp,
"model": result.get("model", "")
})
@app.route("/api/voice", methods=["POST"])
def voice():
session_id = request.form.get("session_id")
if not session_id:
return jsonify({"error": "session_id required"}), 400
session = sessions.get_session(session_id)
if not session:
return jsonify({"error": "Session expired or not found"}), 404
audio_file = request.files.get("audio")
if not audio_file:
return jsonify({"error": "No audio file provided"}), 400
audio_bytes = audio_file.read()
transcribed = speech_to_text(audio_bytes)
if not transcribed:
return jsonify({"error": "Could not transcribe audio", "transcribed": ""}), 200
session.add_message("user", transcribed)
result = chat_completion(session.get_messages())
reply = result.get("content", "")
session.add_message("assistant", reply)
session.add_xp(10)
return jsonify({
"transcribed": transcribed,
"reply": reply,
"xp": session.xp
})
@app.route("/api/pronunciation/score", methods=["POST"])
def pronunciation_score():
data = request.json or {}
session_id = data.get("session_id")
expected = data.get("expected_text", "")
audio_b64 = data.get("audio")
if not expected:
return jsonify({"error": "expected_text required"}), 400
if audio_b64:
audio_bytes = base64.b64decode(audio_b64)
transcribed = speech_to_text(audio_bytes)
else:
transcribed = data.get("user_text", "")
result = evaluate_pronunciation(transcribed, expected)
if session_id:
session = sessions.get_session(session_id)
if session and result["score"] >= 70:
session.add_xp(15)
result["xp_earned"] = 15
return jsonify(result)
@app.route("/api/progress", methods=["GET"])
def get_progress():
session_id = request.args.get("session_id")
if not session_id:
return jsonify({"error": "session_id required"}), 400
session = sessions.get_session(session_id)
if not session:
return jsonify({"error": "Session not found"}), 404
return jsonify(session.to_dict())
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
app.run(host="0.0.0.0", port=port, debug=False)
|