File size: 8,892 Bytes
6cb4362
 
094c29b
8cca692
6cb4362
094c29b
6cb4362
094c29b
 
8cca692
 
 
6cb4362
 
094c29b
 
 
 
 
 
 
 
ba5349b
094c29b
6191204
 
 
 
094c29b
f4b05fc
 
094c29b
 
 
 
 
 
 
 
 
 
 
 
4d75bf0
 
 
 
 
 
 
 
 
094c29b
25cac28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48ddd4e
 
 
ba5349b
48ddd4e
 
 
a17f2c4
6cb4362
 
 
 
f4b05fc
6cb4362
 
 
48ddd4e
094c29b
48ddd4e
 
 
 
6cb4362
48ddd4e
6cb4362
094c29b
 
6cb4362
 
48ddd4e
6cb4362
48ddd4e
6cb4362
094c29b
6eb80b8
4d75bf0
 
0f95080
ab7e393
 
 
 
 
 
0f95080
ab7e393
0f95080
 
 
 
 
 
 
4d75bf0
ab7e393
6eb80b8
42e22cc
a426fe8
6cb4362
a426fe8
48ddd4e
 
f4b05fc
6cb4362
 
 
48ddd4e
 
 
094c29b
4d75bf0
54819ca
4b798ad
4d75bf0
4b798ad
48ddd4e
 
8cca692
48ddd4e
4d75bf0
8cca692
f4b05fc
4d75bf0
6cb4362
 
 
4d75bf0
6cb4362
 
 
4d75bf0
a426fe8
 
8cca692
4d75bf0
6cb4362
 
 
a426fe8
48ddd4e
 
6cb4362
 
a426fe8
6cb4362
48ddd4e
6cb4362
 
 
 
 
0f95080
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72fb9b6
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
187
188
189
190
191
192
193
194
195
196
import gradio as gr
import uuid
import os
import matplotlib.pyplot as plt
from gtts import gTTS
from openai import OpenAI
from app_utils import (
    LANG_CODES, save_to_db, fetch_user_sessions,
    convert_to_wav, transcribe_audio,
    parse_scores_from_feedback, generate_progress_summary,
    build_score_comparison_data, render_score_chart,
    build_trend_data, render_trend_chart
)

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def generate_feedback(transcript, language, goal="general improvement", focus_areas=None, previous_transcript=None):
    focus_str = ", ".join(focus_areas) if focus_areas else "Clarity, Structure, Fluency, Content Relevance, and Tone"
    history_section = f"\n\nFor reference, their previous transcript was:\n{previous_transcript}" if previous_transcript else ""

    prompt = f"""
You are a supportive communication coach helping a learner whose goal is: **{goal}**.
First, return a JSON object of scores (0–10) for these areas:
{focus_str}
Then provide a clear and friendly evaluation:
For each area:
- Repeat the score (0–10)
- Explain why the user got that score
Then provide:
- A detailed summary of strengths and improvement areas.
- One motivational line to end with. Do not specifically add motivational keyword, just add the line.
Transcript:
{history_section}
""".strip()

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"You are a warm and constructive communication coach responding in {language}."},
            {"role": "user", "content": prompt}
        ],
        temperature=0.7
    )
    feedback = response.choices[0].message.content

    try:
        split_idx = feedback.index('}') + 1
        feedback_clean = feedback[split_idx:].strip()
    except:
        feedback_clean = feedback

    return feedback, feedback_clean

def generate_example_response(transcript, language):
    prompt = f"""Rewrite this speech to make it more polished, fluent, and confident.
Keep the meaning and tone the same, but improve clarity and structure.
Transcript:
{transcript}
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"Reply in {language}. Provide only the improved version of the speech."},
            {"role": "user", "content": prompt}
        ]
    )
    return response.choices[0].message.content

def render_empty_chart(title):
    fig, ax = plt.subplots()
    ax.set_title(title)
    ax.text(0.5, 0.5, "No scores yet.\nSpeak again to generate progress!", ha='center', va='center', fontsize=12)
    ax.axis('off')
    return fig

def spoken_dashboard(nickname_input):
    with gr.Column() as spoken_panel:
        gr.Markdown("""
        <div id="header" style="text-align: center;">
            <h2>πŸ¦‰ Meet <strong>Chatter the Owl</strong></h2>
            <p>Speak in your chosen language and get personalized feedback and progress tracking.</p>
        </div>
        """)

        with gr.Row():
            language_dropdown = gr.Dropdown(label="🌍 Language", choices=list(LANG_CODES.keys()), value="English")
            goal_dropdown = gr.Dropdown(label="🎯 Goal", choices=["Interview preparation", "Public speaking", "Class presentation", "General improvement"], value="General improvement")
            focus_checkboxes = gr.CheckboxGroup(label="🧠 Focus Areas", choices=["Clarity", "Structure", "Fluency", "Tone", "Content Relevance"], value=["Clarity", "Structure", "Fluency", "Tone", "Content Relevance"])

        with gr.Row():
            audio_input = gr.Audio(type="filepath", label="πŸŽ™ Speak or Upload Audio")
            audio_output = gr.Audio(label="πŸ”Š Chatter's Response", type="filepath")

        transcript_box = gr.Textbox(label="πŸ“– Transcript", interactive=False)
        feedback_box = gr.Textbox(label="πŸ’‘ Feedback", interactive=False)
        hidden_transcript = gr.Textbox(visible=False)

        with gr.Row():
            try_again = gr.Button("πŸ” Try Again")
            show_example = gr.Button("🎯 Show Me an Example")

        example_box = gr.Textbox(label="πŸ—£ Suggested Improvement", visible=True)
        history_table = gr.Dataframe(headers=["πŸ•’ Timestamp", "🌐 Language", "πŸ“„ Transcript", "πŸ’¬ Feedback"])

        with gr.Row():
            with gr.Column(scale=1):
                gr.Dropdown(
                    choices=[""],
                    label="πŸ“Š Score Comparison",
                    interactive=False,
                    show_label=True
                )
                score_chart = gr.Plot()
        
            with gr.Column(scale=1):
                trend_category_dropdown = gr.Dropdown(
                    label="πŸ“ˆ Track Progress In",
                    choices=["Clarity", "Structure", "Fluency", "Tone", "Content Relevance"],
                    value="Tone"
                )
                trend_chart = gr.Plot(label="Progress Over Time")


        milestone_box = gr.Markdown(visible=False)

        def tutor_feedback(audio_file, language, goal, focus_areas, trend_category, nickname):
            if not audio_file:
                return "", "No audio received.", None, "", [], render_empty_chart("πŸ“Š Score Comparison"), render_empty_chart("πŸ“ˆ Progress Over Time"), gr.update(visible=False)

            if hasattr(nickname, "value"):
                nickname = nickname.value

            wav_path = convert_to_wav(audio_file)
            transcript = transcribe_audio(wav_path)
            previous_sessions = fetch_user_sessions(nickname)
            previous_transcript = previous_sessions[-1].transcript if previous_sessions else None
            previous_feedback = previous_sessions[-1].feedback if previous_sessions else None

            full_feedback, feedback_clean = generate_feedback(transcript, language, goal, focus_areas, previous_transcript)

            if previous_feedback:
                feedback_clean += generate_progress_summary(full_feedback, previous_feedback)

            milestone = ""
            session_count = len(previous_sessions) + 1
            if session_count in [3, 5, 10]:
                milestone = f"πŸŽ‰ Congrats on completing **{session_count} sessions**!"
                feedback_clean += f"\n\n{milestone}"

            lang_code = LANG_CODES.get(language, "en")
            tts = gTTS(feedback_clean, lang=lang_code)
            mp3_path = f"/tmp/{uuid.uuid4()}.mp3"
            tts.save(mp3_path)

            save_to_db(nickname, transcript, full_feedback, language)
            sessions = fetch_user_sessions(nickname)
            session_table = [[s.timestamp, s.language, s.transcript[:40], s.feedback[:40]] for s in sessions]

            score_plot = render_score_chart(build_score_comparison_data(full_feedback, previous_feedback)) if previous_feedback else render_empty_chart("πŸ“Š Score Comparison")
            dates, trend_scores = build_trend_data(sessions, trend_category)
            trend_plot = render_trend_chart(dates, trend_scores, trend_category) if trend_scores else render_empty_chart(f"πŸ“ˆ {trend_category} Progress")

            return transcript, feedback_clean, mp3_path, transcript, session_table, score_plot, trend_plot, gr.update(visible=bool(milestone), value=milestone)

        audio_input.change(
            fn=tutor_feedback,
            inputs=[audio_input, language_dropdown, goal_dropdown, focus_checkboxes, trend_category_dropdown, nickname_input],
            outputs=[transcript_box, feedback_box, audio_output, hidden_transcript, history_table, score_chart, trend_chart, milestone_box],
            show_progress="minimal"
        )

        try_again.click(fn=lambda: ("", "", None, "", "", render_empty_chart("πŸ“Š Score Comparison"), render_empty_chart("πŸ“ˆ Progress Over Time"), gr.update(visible=False)),
                        inputs=None,
                        outputs=[transcript_box, feedback_box, audio_output, hidden_transcript, example_box, score_chart, trend_chart, milestone_box])

        show_example.click(fn=generate_example_response,
                           inputs=[hidden_transcript, language_dropdown],
                           outputs=example_box)

        def update_trend_chart(trend_category, nickname):
            if hasattr(nickname, "value"):
                nickname = nickname.value
            sessions = fetch_user_sessions(nickname)
            dates, trend_scores = build_trend_data(sessions, trend_category)
            if trend_scores:
                return render_trend_chart(dates, trend_scores, trend_category)
            return render_empty_chart(f"πŸ“ˆ {trend_category} Progress")

        trend_category_dropdown.change(
            fn=update_trend_chart,
            inputs=[trend_category_dropdown, nickname_input],
            outputs=[trend_chart]
        )

    return spoken_panel