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)