ankban commited on
Commit
b0d77d1
Β·
verified Β·
1 Parent(s): 5da2126

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -231
app.py CHANGED
@@ -1,238 +1,42 @@
1
- import gradio as gr
2
- import openai
3
- from openai import OpenAI
4
- import os
5
- import uuid
6
- from gtts import gTTS
7
- from faster_whisper import WhisperModel
8
- import subprocess
9
- import shutil
10
- from datetime import datetime
11
- from sqlmodel import SQLModel, Field, create_engine, Session, select
12
- from typing import Optional
13
- import glob
14
- import re
15
- import matplotlib.pyplot as plt
16
- import io
17
- import base64
18
- from PIL import Image
19
-
20
- # === Temp file cleanup ===
21
- for pattern in ["/tmp/*.wav", "/tmp/*.mp3"]:
22
- for filepath in glob.glob(pattern):
23
- try:
24
- os.remove(filepath)
25
- except Exception as e:
26
- print(f"Could not delete {filepath}: {e}")
27
-
28
- # === Environment setup ===
29
- os.environ["HF_HOME"] = "/tmp/hf"
30
- os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf"
31
- os.environ["XDG_CACHE_HOME"] = "/tmp/hf"
32
- os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
33
- db_path = "/tmp/chatter_sessions.db"
34
- openai.api_key = os.getenv("OPENAI_API_KEY")
35
- client = OpenAI(api_key=openai.api_key)
36
-
37
- # === Language codes ===
38
- LANG_CODES = {
39
- "English": "en", "Spanish": "es", "Hindi": "hi", "French": "fr", "German": "de",
40
- "Arabic": "ar", "Chinese": "zh", "Portuguese": "pt", "Japanese": "ja", "Korean": "ko"
41
- }
42
- CATEGORIES = ["Clarity", "Structure", "Fluency", "Content Relevance", "Tone & Expression", "Average"]
43
-
44
- # === SQLModel setup ===
45
- class SessionEntry(SQLModel, table=True):
46
- id: Optional[int] = Field(default=None, primary_key=True)
47
- user: str
48
- timestamp: str
49
- transcript: str
50
- feedback: str
51
- language: str
52
-
53
- engine = create_engine(f"sqlite:///{db_path}")
54
- SQLModel.metadata.create_all(engine)
55
-
56
- def save_to_db(user, transcript, feedback, language):
57
- session = Session(engine)
58
- entry = SessionEntry(
59
- user=user,
60
- timestamp=datetime.now().strftime("%Y-%m-%d %H:%M"),
61
- transcript=transcript,
62
- feedback=feedback,
63
- language=language
64
- )
65
- session.add(entry)
66
- session.commit()
67
- session.close()
68
-
69
- def fetch_user_sessions(user):
70
- session = Session(engine)
71
- statement = select(SessionEntry).where(SessionEntry.user == user)
72
- results = session.exec(statement).all()
73
- session.close()
74
- return results
75
-
76
- # === Whisper ===
77
- model = WhisperModel("base", compute_type="int8")
78
-
79
- def convert_to_wav(input_file):
80
- output_wav = f"/tmp/{uuid.uuid4()}.wav"
81
- command = ["ffmpeg", "-y", "-i", input_file, "-ar", "16000", "-ac", "1", output_wav]
82
- subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
83
- return output_wav
84
-
85
- def transcribe_audio(audio_path):
86
- segments, _ = model.transcribe(audio_path)
87
- return " ".join([segment.text for segment in segments])
88
-
89
- # === GPT-4 Feedback ===
90
- def generate_feedback(transcript, language):
91
- prompt = f"""You are a communication coach. Please respond in [language={language}].
92
- Evaluate the user's speech on:
93
- 1. Clarity
94
- 2. Structure
95
- 3. Fluency
96
- 4. Content Relevance
97
- 5. Tone & Expression
98
- Each category:
99
- - Score out of 10
100
- - Short explanation
101
- End with:
102
- - Overall feedback summary
103
- - One motivational line
104
- Transcript:
105
- {transcript}
106
- """
107
- response = client.chat.completions.create(
108
- model="gpt-4",
109
- messages=[
110
- {"role": "system", "content": f"You are a supportive communication coach responding in {language}."},
111
- {"role": "user", "content": prompt}
112
- ],
113
- temperature=0.7
114
- )
115
- return response.choices[0].message.content
116
-
117
- def generate_example_response(transcript, language):
118
- prompt = f"""You are a communication coach. Rewrite this speech to make it more polished, fluent, and confident.
119
- Keep the meaning and tone the same, but improve clarity and structure.
120
- Transcript:
121
- {transcript}
122
- """
123
- response = client.chat.completions.create(
124
- model="gpt-4",
125
- messages=[
126
- {"role": "system", "content": f"Reply in {language}. Provide only the improved version of the speech."},
127
- {"role": "user", "content": prompt}
128
- ]
129
- )
130
- return response.choices[0].message.content
131
-
132
- def parse_scores(feedback):
133
- scores = {}
134
- for cat in CATEGORIES[:-1]: # Skip "Average" for now
135
- match = re.search(fr"{cat}:\s*(\d+)/10", feedback)
136
- scores[cat] = int(match.group(1)) if match else None
137
- values = [s for s in scores.values() if s is not None]
138
- scores["Average"] = round(sum(values)/len(values), 2) if values else None
139
- return scores
140
-
141
- def generate_user_chart(user, metric):
142
- sessions = fetch_user_sessions(user)
143
- if not sessions or metric not in CATEGORIES:
144
- return None
145
-
146
- session_ids = list(range(1, len(sessions) + 1))
147
- scores = []
148
- for s in sessions:
149
- parsed = parse_scores(s.feedback)
150
- scores.append(parsed.get(metric, 0))
151
-
152
- fig, ax = plt.subplots()
153
- ax.plot(session_ids, scores, marker='o', label=metric)
154
- ax.set_title(f"{metric} Score Over Time for {user}")
155
- ax.set_xlabel("Session")
156
- ax.set_ylabel("Score (0–10)")
157
- ax.set_ylim(0, 10)
158
- ax.grid(True)
159
- ax.legend()
160
-
161
- buf = io.BytesIO()
162
- plt.savefig(buf, format="png")
163
- plt.close(fig)
164
- buf.seek(0)
165
- return Image.open(buf)
166
 
167
- def tutor_feedback(audio_file, language, nickname):
168
- if not audio_file or not os.path.exists(audio_file):
169
- return "", "No audio received.", None, "", []
170
-
171
- wav_path = convert_to_wav(audio_file)
172
- transcript = transcribe_audio(wav_path)
173
- feedback_text = generate_feedback(transcript, language)
174
-
175
- lang_code = LANG_CODES.get(language, "en")
176
- tts = gTTS(feedback_text, lang=lang_code)
177
- mp3_path = f"/tmp/{uuid.uuid4()}.mp3"
178
- tts.save(mp3_path)
179
-
180
- save_to_db(nickname, transcript, feedback_text, language)
181
- sessions = fetch_user_sessions(nickname)
182
-
183
- return transcript, feedback_text, mp3_path, transcript, [[s.timestamp, s.language, s.transcript[:40], s.feedback[:40]] for s in sessions]
184
 
185
- # === Gradio Interface ===
186
  with gr.Blocks(css="light_mode_chatter_owl.css") as app:
187
- gr.Markdown("""
188
- <div id="header" style="text-align: center;">
189
- <img src="file/images/chatter_owl.png" width="120">
190
- <h2>πŸ¦‰ Meet <strong>Chatter the Owl</strong></h2>
191
- <p>Enter your name, choose a language, and speak! I’ll help you grow as a communicator.</p>
192
- </div>
193
- """)
194
-
195
- nickname_box = gr.Textbox(label="πŸ‘€ Your Nickname", placeholder="Enter your name...")
196
- language_dropdown = gr.Dropdown(label="🌍 Select Your Language", choices=list(LANG_CODES.keys()), value="English")
197
-
198
- with gr.Row():
199
- audio_input = gr.Audio(type="filepath", label="πŸŽ™ Speak or Upload Audio")
200
-
201
- transcript_box = gr.Textbox(label="πŸ“– What You Said", interactive=False)
202
- feedback_box = gr.Textbox(label="πŸ’‘ Chatter’s Feedback", interactive=False)
203
- audio_output = gr.Audio(label="πŸ”Š Chatter Speaks", type="filepath")
204
- hidden_transcript = gr.Textbox(visible=False)
205
 
206
  with gr.Row():
207
- try_again = gr.Button("πŸ” Try Again")
208
- show_example = gr.Button("🎯 Show Me an Example")
209
-
210
- example_box = gr.Textbox(label="πŸ—£ Suggested Improvement", visible=True, placeholder="Click to generate improved speech...")
211
- history_table = gr.Dataframe(headers=["πŸ•’ Timestamp", "🌐 Language", "πŸ“ Transcript (Preview)", "πŸ“‹ Feedback (Preview)"])
212
-
213
- with gr.Row():
214
- chart_metric = gr.Dropdown(label="πŸ“ˆ Choose Metric to Visualize", choices=CATEGORIES, value="Average")
215
- view_chart = gr.Button("πŸ“Š Show Progress Chart")
216
-
217
- chart_output = gr.Image(label="πŸ“‰ Your Progress")
218
-
219
- audio_input.change(fn=tutor_feedback,
220
- inputs=[audio_input, language_dropdown, nickname_box],
221
- outputs=[transcript_box, feedback_box, audio_output, hidden_transcript, history_table])
222
-
223
- try_again.click(fn=lambda: ("", "", None, "", "", []),
224
- inputs=None,
225
- outputs=[transcript_box, feedback_box, audio_output, hidden_transcript, example_box, history_table])
226
-
227
- show_example.click(fn=generate_example_response,
228
- inputs=[hidden_transcript, language_dropdown],
229
- outputs=example_box)
230
-
231
- view_chart.click(fn=generate_user_chart,
232
- inputs=[nickname_box, chart_metric],
233
- outputs=chart_output)
 
 
 
 
234
 
235
- # === Launch ===
236
  if __name__ == "__main__":
237
- print("βœ… App is launching...")
238
- app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
+ import gradio as gr
3
+ from spoken_module import spoken_dashboard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
 
5
  with gr.Blocks(css="light_mode_chatter_owl.css") as app:
6
+ study_type = gr.State("spoken")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  with gr.Row():
9
+ with gr.Column(scale=1, min_width=200):
10
+ gr.Markdown("### πŸ“š Study Modes")
11
+ btn_spoken = gr.Button("πŸ—£ Spoken Communication")
12
+ btn_written = gr.Button("✍️ Written Communication")
13
+ btn_file = gr.Button("πŸ“„ File-based Learning")
14
+
15
+ with gr.Column(scale=4):
16
+ output_panel = gr.Column()
17
+
18
+ # Dynamic sections
19
+ spoken_panel = spoken_dashboard()
20
+ written_panel = gr.Column(visible=False)
21
+ file_panel = gr.Column(visible=False)
22
+
23
+ with written_panel:
24
+ gr.Markdown("## ✍️ Written Communication (Coming Soon)")
25
+
26
+ with file_panel:
27
+ gr.Markdown("## πŸ“„ File-Based Learning (Coming Soon)")
28
+
29
+ def switch_mode(mode):
30
+ return (
31
+ gr.update(visible=(mode == "spoken")),
32
+ gr.update(visible=(mode == "written")),
33
+ gr.update(visible=(mode == "file")),
34
+ mode
35
+ )
36
+
37
+ btn_spoken.click(fn=lambda: switch_mode("spoken"), inputs=[], outputs=[spoken_panel, written_panel, file_panel, study_type])
38
+ btn_written.click(fn=lambda: switch_mode("written"), inputs=[], outputs=[spoken_panel, written_panel, file_panel, study_type])
39
+ btn_file.click(fn=lambda: switch_mode("file"), inputs=[], outputs=[spoken_panel, written_panel, file_panel, study_type])
40
 
 
41
  if __name__ == "__main__":
42
+ app.launch(server_name="0.0.0.0", server_port=7860)