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
|