YoussefA7med commited on
Commit
27ccdcb
Β·
verified Β·
1 Parent(s): 9254af3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +126 -82
app.py CHANGED
@@ -7,6 +7,7 @@ from dotenv import load_dotenv
7
  import os
8
  import speech_recognition as sr
9
  from pydub import AudioSegment
 
10
 
11
  load_dotenv()
12
 
@@ -22,39 +23,50 @@ recognizer = sr.Recognizer()
22
 
23
  MAIN_SYSTEM_PROMPT = {
24
  "role": "system",
25
- "content": """You are Sam, an intelligent and adaptive English tutor. Your responses must be in JSON format with these keys:
26
- 'response': Your main response,
27
- 'corrections': Grammar or pronunciation corrections if needed,
28
- 'vocabulary': Suggested alternative words or phrases,
29
- 'level_assessment': Current assessment of user's English level (beginner/intermediate/advanced),
30
  'encouragement': A motivating comment,
31
- 'context_memory': Important details about the user to remember (interests, job, etc.)
32
- Guidelines:
33
- 1. Maintain natural conversation while gathering user information
34
- 2. Adapt language complexity to user's level
35
- 3. Provide gentle corrections without interrupting flow
36
- 4. Remember and use context from previous messages
37
- 5. Focus on user's interests and profession
38
- 6. Give specific vocabulary related to user's field
39
- 7. Keep responses encouraging and supportive
40
 
41
- Special behaviors:
42
- - If user mentions their country β†’ Ask about their culture/country
43
- - If user mentions their job β†’ Use profession-specific vocabulary
44
- - If user mentions hobbies β†’ Engage in that topic
45
- - For beginners β†’ Use simple words and short sentences
46
- - For intermediate/advanced β†’ Introduce more complex vocabulary
47
- Always maintain conversation history and adapt based on it."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  WELCOME_PROMPT = {
51
  "role": "system",
52
- "content": """Create a brief welcome message that:
53
- 1. Introduces you as Sam, the English tutor
54
- 2. Asks for the user's name only
 
55
 
56
  Return in JSON format with key 'greeting'.
57
- Keep it short, friendly and natural - maximum 2 sentences."""
58
  }
59
 
60
  class EnglishTutor:
@@ -62,7 +74,7 @@ class EnglishTutor:
62
  self.chat_history = [MAIN_SYSTEM_PROMPT]
63
  self.user_info = {
64
  "name": None,
65
- "level": None,
66
  "interests": [],
67
  "country": None,
68
  "profession": None,
@@ -77,7 +89,7 @@ class EnglishTutor:
77
  json={
78
  "model": "deepseek-chat",
79
  "messages": [WELCOME_PROMPT],
80
- "temperature": random.uniform(0.9, 1),
81
  "response_format": {"type": "json_object"}
82
  }
83
  )
@@ -85,11 +97,15 @@ class EnglishTutor:
85
  return welcome_json["greeting"]
86
  except Exception as e:
87
  print(f"Error in welcome message: {str(e)}")
88
- return "Hi! I'm Sam, your English tutor. What's your name?"
89
 
90
  def get_bot_response(self, user_message):
91
  try:
92
- self.chat_history.append({"role": "user", "content": user_message})
 
 
 
 
93
 
94
  response = requests.post(
95
  "https://api.deepseek.com/v1/chat/completions",
@@ -97,49 +113,66 @@ class EnglishTutor:
97
  json={
98
  "model": "deepseek-chat",
99
  "messages": self.chat_history,
100
- "temperature": random.uniform(0.9, 1.0),
101
  "response_format": {"type": "json_object"}
102
  }
103
  )
104
 
105
  bot_response = json.loads(response.json()["choices"][0]["message"]["content"])
106
 
 
107
  if "level_assessment" in bot_response:
108
  self.user_info["level"] = bot_response["level_assessment"]
109
  if "context_memory" in bot_response:
110
  self._update_user_info(bot_response["context_memory"])
111
 
112
- formatted_response = self._format_response(bot_response)
113
-
114
  self.chat_history.append({"role": "assistant", "content": json.dumps(bot_response)})
115
 
116
- return formatted_response
117
  except Exception as e:
118
  print(f"Error getting bot response: {str(e)}")
119
- return "I apologize, but I couldn't process that properly. Could you try again?"
 
 
 
 
 
 
 
 
120
 
121
  def _update_user_info(self, context_memory):
122
- if isinstance(context_memory, dict):
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  for key in self.user_info:
124
  if key in context_memory:
125
  self.user_info[key] = context_memory[key]
126
 
127
- def _format_response(self, response_dict):
128
- formatted = response_dict["response"]
 
129
 
130
- if response_dict.get("encouragement"):
131
- encouragement = response_dict["encouragement"]
132
- # Make encouragement more impressive
133
- if "doing" in encouragement.lower() and "great" in encouragement.lower():
134
- formatted += f"\n\n🌟 {encouragement}"
135
- elif "wonderful" in encouragement.lower() or "excellent" in encouragement.lower():
136
- formatted += f"\n\n✨ {encouragement}"
137
- elif "good" in encouragement.lower() or "well" in encouragement.lower():
138
- formatted += f"\n\n🎯 {encouragement}"
139
- else:
140
- formatted += f"\n\nπŸ’« {encouragement}"
141
 
142
- return formatted
 
 
 
 
 
143
 
144
  def convert_audio_to_text(audio_path):
145
  try:
@@ -178,14 +211,15 @@ tutor = EnglishTutor()
178
  def initialize_chat():
179
  try:
180
  welcome = tutor.get_welcome_message()
181
- welcome_audio = text_to_speech(welcome)
 
182
  history = [{"role": "assistant", "content": welcome}]
183
- return history, welcome_audio, f"🎀 Sam: {welcome}", ""
184
  except Exception as e:
185
  print(f"Error initializing chat: {str(e)}")
186
- welcome_msg = "Hi! I'm Sam, your English tutor. What's your name?"
187
  history = [{"role": "assistant", "content": welcome_msg}]
188
- return history, None, f"🎀 Sam: {welcome_msg}", ""
189
 
190
  def process_audio(audio, history, transcript, corrections):
191
  try:
@@ -196,40 +230,50 @@ def process_audio(audio, history, transcript, corrections):
196
  if not user_message:
197
  return history, None, transcript, corrections
198
 
199
- bot_response_json = tutor.get_bot_response(user_message)
200
 
201
- try:
202
- response_dict = json.loads(bot_response_json) if isinstance(bot_response_json, str) else bot_response_json
203
- except:
204
- response_dict = {"response": bot_response_json}
205
 
206
- tts_response = response_dict.get("response", bot_response_json)
207
- if response_dict.get("encouragement"):
208
- tts_response += f" {response_dict['encouragement']}"
209
 
210
- audio_response = text_to_speech(tts_response)
 
 
211
 
212
- formatted_response = tutor._format_response(response_dict) if hasattr(tutor, '_format_response') else bot_response_json
213
-
214
  history = history or []
215
  history.append({"role": "user", "content": user_message})
216
- history.append({"role": "assistant", "content": formatted_response})
217
 
218
- new_transcript = transcript + f"\n\n🎀 You: {user_message}\nπŸ€– Sam: {tts_response}"
 
219
 
 
220
  new_corrections = corrections
221
- if response_dict.get("corrections") or response_dict.get("vocabulary"):
222
- correction_text = ""
223
- if response_dict.get("corrections"):
224
- correction_text += f"✍️ Grammar: {response_dict['corrections']}\n\n"
225
- if response_dict.get("vocabulary"):
226
- vocab = response_dict['vocabulary']
227
- if isinstance(vocab, dict):
228
- vocab_text = "\n".join([f"β€’ '{k}' β†’ '{v}'" for k, v in vocab.items()])
229
- else:
230
- vocab_text = str(vocab)
231
- correction_text += f"πŸ“š Vocabulary:\n{vocab_text}"
232
- new_corrections = corrections + f"\n\n{correction_text}" if corrections else correction_text
 
 
 
 
 
 
 
233
 
234
  return history, audio_response, new_transcript, new_corrections
235
  except Exception as e:
@@ -245,8 +289,8 @@ def clear_chat():
245
  return initialize_chat()
246
 
247
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
248
- gr.Markdown("# πŸŽ“ English Learning Assistant")
249
- gr.Markdown("🎀 **Record your voice and click submit** - I'll help you improve your English conversation skills!")
250
 
251
  with gr.Row():
252
  with gr.Column(scale=3):
@@ -291,13 +335,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
291
  max_lines=8,
292
  show_label=False,
293
  interactive=False,
294
- placeholder="Grammar corrections and vocabulary suggestions will appear here...",
295
  container=True
296
  )
297
 
298
  with gr.Row():
299
  clear_btn = gr.Button("πŸ”„ Start New Conversation", variant="secondary", size="lg")
300
- gr.Markdown("πŸ’‘ **Tip**: Check the Learning Corner for personalized feedback on your English!")
301
 
302
  submit_btn.click(
303
  submit_recording,
 
7
  import os
8
  import speech_recognition as sr
9
  from pydub import AudioSegment
10
+ import re
11
 
12
  load_dotenv()
13
 
 
23
 
24
  MAIN_SYSTEM_PROMPT = {
25
  "role": "system",
26
+ "content": """You are Sam, an intelligent and proactive English tutor. You drive the conversation and actively engage students. Your responses must be in JSON format with these keys:
27
+ 'response': Your main response (keep it conversational and engaging),
28
+ 'corrections': Specific grammar or pronunciation corrections with examples,
29
+ 'vocabulary': Alternative words/phrases with explanations,
30
+ 'level_assessment': Current assessment (beginner/intermediate/advanced),
31
  'encouragement': A motivating comment,
32
+ 'context_memory': Important details about the user,
33
+ 'next_question': A follow-up question to keep conversation flowing
 
 
 
 
 
 
 
34
 
35
+ Your personality:
36
+ - Be the conversation driver - ask follow-up questions
37
+ - Show genuine interest in the student's life
38
+ - Provide corrections naturally without stopping the flow
39
+ - Use the student's name frequently
40
+ - Build on previous topics
41
+ - Be encouraging but provide constructive feedback
42
+ - Ask about their day, work, hobbies, culture, goals
43
+
44
+ Correction guidelines:
45
+ - Always provide corrections if there are grammar mistakes
46
+ - Suggest better vocabulary choices
47
+ - Give pronunciation tips when needed
48
+ - Use format: "Instead of 'X', try saying 'Y'"
49
+
50
+ Conversation flow:
51
+ - Start with personal questions (name, country, job, hobbies)
52
+ - Build conversations around their interests
53
+ - Use profession-specific vocabulary
54
+ - Ask about their culture and experiences
55
+ - Keep the conversation natural and flowing
56
+ - Always end with a question to continue the dialogue
57
+
58
+ Response length: Keep responses conversational (2-3 sentences max for response field)."""
59
  }
60
 
61
  WELCOME_PROMPT = {
62
  "role": "system",
63
+ "content": """Create a warm welcome message that:
64
+ 1. Introduces you as Sam, an enthusiastic English tutor
65
+ 2. Asks for their name and where they're from
66
+ 3. Shows excitement about helping them
67
 
68
  Return in JSON format with key 'greeting'.
69
+ Make it warm, friendly and enthusiastic - maximum 2 sentences."""
70
  }
71
 
72
  class EnglishTutor:
 
74
  self.chat_history = [MAIN_SYSTEM_PROMPT]
75
  self.user_info = {
76
  "name": None,
77
+ "level": "beginner",
78
  "interests": [],
79
  "country": None,
80
  "profession": None,
 
89
  json={
90
  "model": "deepseek-chat",
91
  "messages": [WELCOME_PROMPT],
92
+ "temperature": random.uniform(0.8, 1.0),
93
  "response_format": {"type": "json_object"}
94
  }
95
  )
 
97
  return welcome_json["greeting"]
98
  except Exception as e:
99
  print(f"Error in welcome message: {str(e)}")
100
+ return "Hi! I'm Sam, your English tutor. What's your name and where are you from?"
101
 
102
  def get_bot_response(self, user_message):
103
  try:
104
+ # Add user context to the message
105
+ context_info = f"User info: {self.user_info}"
106
+ enhanced_message = f"{user_message}\n\n[Context: {context_info}]"
107
+
108
+ self.chat_history.append({"role": "user", "content": enhanced_message})
109
 
110
  response = requests.post(
111
  "https://api.deepseek.com/v1/chat/completions",
 
113
  json={
114
  "model": "deepseek-chat",
115
  "messages": self.chat_history,
116
+ "temperature": random.uniform(0.8, 1.0),
117
  "response_format": {"type": "json_object"}
118
  }
119
  )
120
 
121
  bot_response = json.loads(response.json()["choices"][0]["message"]["content"])
122
 
123
+ # Update user info
124
  if "level_assessment" in bot_response:
125
  self.user_info["level"] = bot_response["level_assessment"]
126
  if "context_memory" in bot_response:
127
  self._update_user_info(bot_response["context_memory"])
128
 
 
 
129
  self.chat_history.append({"role": "assistant", "content": json.dumps(bot_response)})
130
 
131
+ return bot_response
132
  except Exception as e:
133
  print(f"Error getting bot response: {str(e)}")
134
+ return {
135
+ "response": "I apologize, but I couldn't process that properly. Could you try again?",
136
+ "corrections": "",
137
+ "vocabulary": "",
138
+ "level_assessment": "beginner",
139
+ "encouragement": "Don't worry, let's keep practicing!",
140
+ "context_memory": "",
141
+ "next_question": "What would you like to talk about?"
142
+ }
143
 
144
  def _update_user_info(self, context_memory):
145
+ if isinstance(context_memory, str):
146
+ # Try to extract name if mentioned
147
+ if "name" in context_memory.lower():
148
+ name_match = re.search(r"name[:\s]+([A-Za-z]+)", context_memory)
149
+ if name_match:
150
+ self.user_info["name"] = name_match.group(1)
151
+
152
+ # Try to extract country if mentioned
153
+ if "country" in context_memory.lower() or "from" in context_memory.lower():
154
+ country_match = re.search(r"(?:from|country)[:\s]+([A-Za-z\s]+)", context_memory)
155
+ if country_match:
156
+ self.user_info["country"] = country_match.group(1).strip()
157
+
158
+ elif isinstance(context_memory, dict):
159
  for key in self.user_info:
160
  if key in context_memory:
161
  self.user_info[key] = context_memory[key]
162
 
163
+ def clean_text_for_tts(self, text):
164
+ # Remove emojis and special characters that might cause TTS issues
165
+ text = re.sub(r'[πŸŽ―πŸŒŸβœ¨πŸ’«πŸŽ€πŸ€–]', '', text)
166
 
167
+ # Remove extra spaces and newlines
168
+ text = re.sub(r'\s+', ' ', text).strip()
 
 
 
 
 
 
 
 
 
169
 
170
+ # Remove duplicate words at the beginning
171
+ words = text.split()
172
+ if len(words) > 1 and words[0].lower() == words[1].lower():
173
+ text = ' '.join(words[1:])
174
+
175
+ return text
176
 
177
  def convert_audio_to_text(audio_path):
178
  try:
 
211
  def initialize_chat():
212
  try:
213
  welcome = tutor.get_welcome_message()
214
+ clean_welcome = tutor.clean_text_for_tts(welcome)
215
+ welcome_audio = text_to_speech(clean_welcome)
216
  history = [{"role": "assistant", "content": welcome}]
217
+ return history, welcome_audio, f"πŸ€– Sam: {welcome}", ""
218
  except Exception as e:
219
  print(f"Error initializing chat: {str(e)}")
220
+ welcome_msg = "Hi! I'm Sam, your English tutor. What's your name and where are you from?"
221
  history = [{"role": "assistant", "content": welcome_msg}]
222
+ return history, None, f"πŸ€– Sam: {welcome_msg}", ""
223
 
224
  def process_audio(audio, history, transcript, corrections):
225
  try:
 
230
  if not user_message:
231
  return history, None, transcript, corrections
232
 
233
+ bot_response = tutor.get_bot_response(user_message)
234
 
235
+ # Create the main response with follow-up question
236
+ main_response = bot_response.get("response", "")
237
+ if bot_response.get("next_question"):
238
+ main_response += f" {bot_response['next_question']}"
239
 
240
+ # Add encouragement
241
+ if bot_response.get("encouragement"):
242
+ main_response += f" {bot_response['encouragement']}"
243
 
244
+ # Clean text for TTS
245
+ clean_response = tutor.clean_text_for_tts(main_response)
246
+ audio_response = text_to_speech(clean_response)
247
 
248
+ # Update chat history
 
249
  history = history or []
250
  history.append({"role": "user", "content": user_message})
251
+ history.append({"role": "assistant", "content": main_response})
252
 
253
+ # Update transcript
254
+ new_transcript = transcript + f"\n\n🎀 You: {user_message}\nπŸ€– Sam: {main_response}"
255
 
256
+ # Update corrections and vocabulary (THIS IS THE FIX!)
257
  new_corrections = corrections
258
+ correction_parts = []
259
+
260
+ if bot_response.get("corrections") and bot_response["corrections"].strip():
261
+ correction_parts.append(f"✍️ **Grammar Corrections:**\n{bot_response['corrections']}")
262
+
263
+ if bot_response.get("vocabulary") and bot_response["vocabulary"].strip():
264
+ vocab = bot_response['vocabulary']
265
+ if isinstance(vocab, dict):
266
+ vocab_text = "\n".join([f"β€’ '{k}' β†’ '{v}'" for k, v in vocab.items()])
267
+ else:
268
+ vocab_text = str(vocab)
269
+ correction_parts.append(f"πŸ“š **Vocabulary Suggestions:**\n{vocab_text}")
270
+
271
+ if bot_response.get("level_assessment"):
272
+ correction_parts.append(f"πŸ“Š **Current Level:** {bot_response['level_assessment'].title()}")
273
+
274
+ if correction_parts:
275
+ new_correction_text = "\n\n".join(correction_parts)
276
+ new_corrections = new_corrections + f"\n\n--- Latest Feedback ---\n{new_correction_text}" if new_corrections else new_correction_text
277
 
278
  return history, audio_response, new_transcript, new_corrections
279
  except Exception as e:
 
289
  return initialize_chat()
290
 
291
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
292
+ gr.Markdown("# πŸŽ“ English Learning Assistant with Sam")
293
+ gr.Markdown("🎀 **Record your voice and click submit** - Sam will actively guide your conversation and help improve your English!")
294
 
295
  with gr.Row():
296
  with gr.Column(scale=3):
 
335
  max_lines=8,
336
  show_label=False,
337
  interactive=False,
338
+ placeholder="Grammar corrections, vocabulary suggestions, and level assessment will appear here...",
339
  container=True
340
  )
341
 
342
  with gr.Row():
343
  clear_btn = gr.Button("πŸ”„ Start New Conversation", variant="secondary", size="lg")
344
+ gr.Markdown("πŸ’‘ **Tip**: Sam will actively guide the conversation and provide personalized feedback!")
345
 
346
  submit_btn.click(
347
  submit_recording,