Spaces:
Running
Running
| """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") | |
| def index(): | |
| return render_template("index.html") | |
| def health(): | |
| return jsonify({"status": "ok", "models": get_model_info()}) | |
| def curriculum(): | |
| return jsonify(get_curriculum_data()) | |
| def teachers(): | |
| return jsonify({"teachers": get_all_teachers()}) | |
| 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!")}) | |
| 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 | |
| }) | |
| 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", "") | |
| }) | |
| 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 | |
| }) | |
| 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) | |
| 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) | |