Oviya commited on
Commit
58309bf
Β·
1 Parent(s): 28880f0
Files changed (1) hide show
  1. Findingword.py +32 -33
Findingword.py CHANGED
@@ -1,9 +1,8 @@
1
  import openai
2
  from flask import Flask, jsonify, request, send_from_directory, send_file, Blueprint, current_app
3
  import os
4
- from google.cloud import texttospeech
5
  from flask_cors import CORS
6
- import io # NEW: for streaming S3 bytes in HF/AWS mode
7
 
8
  # Optional (only used in AWS mode)
9
  try:
@@ -17,17 +16,15 @@ except Exception:
17
  app = Flask(__name__)
18
  CORS(app)
19
 
20
- # --- NEW: Blueprint ---
21
  finding_bp = Blueprint("findingword", __name__)
22
 
23
  # Directories for video, audio, and transcripts
24
  VIDEO_FOLDER = 'static/videos'
25
  AUDIO_FOLDER = 'static/audio' # Ensure this folder exists
26
  TRANSCRIPT_FOLDER = 'static/transcripts'
 
27
 
28
- # Set your OpenAI API key (left as-is per your request)
29
- # openai.api_key = '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'
30
- # openai.api_key = os.getenv("OPENAI_API_KEY", "")
31
  # --- OpenAI key handling (same as vocab builder) ---
32
  _OPENAI_API_KEY_FALLBACK = os.getenv("OPENAI_API_KEY", "")
33
 
@@ -36,13 +33,8 @@ def _ensure_openai_key():
36
  api_key = (current_app.config.get("OPENAI_API_KEY") if current_app else None) or _OPENAI_API_KEY_FALLBACK
37
  if api_key:
38
  openai.api_key = api_key
39
- # Initialize Google Cloud TTS client (local mode)
40
- client = texttospeech.TextToSpeechClient()
41
-
42
- # Ensure required folders exist (used in local mode)
43
- os.makedirs(AUDIO_FOLDER, exist_ok=True)
44
 
45
- # ---------------------- audio-mode helpers (UNCHANGED) ----------------------
46
  def _is_aws_mode() -> bool:
47
  """
48
  Switch to AWS Polly + S3 on Hugging Face / prod.
@@ -64,8 +56,11 @@ def _sanitize_filename(word: str) -> str:
64
 
65
  @finding_bp.route('/generate-vocabulary', methods=['GET'])
66
  def get_vocabulary_word_from_openai():
67
- #prompt = "Pick a random vocabulary word suitable for children and provide its meaning. Do not repeat words from previous responses. Format: 'Word: [word]. Meaning: [meaning].'"
68
- prompt = "Pick a simple vocabulary word suitable for children (ages 6–8) and provide its meaning in very easy English. Do not repeat words from previous responses. Format: 'Word: [word]. Meaning: [meaning].'"
 
 
 
69
 
70
  try:
71
  _ensure_openai_key()
@@ -83,31 +78,30 @@ def get_vocabulary_word_from_openai():
83
  if "Word:" in result and "Meaning:" in result:
84
  parts = result.split("Meaning:")
85
  word = parts[0].replace("Word:", "").strip()
86
- # βœ… Ensure the extracted word does not contain trailing dots or special characters
87
- word = word.rstrip('.')
88
  meaning = parts[1].strip()
89
 
90
  # Generate the sentence
91
  sentence = generate_sentence(word, meaning)
92
 
93
  # Generate audio file for the vocabulary word
94
- audio_file_path_or_name = generate_audio(word) # may be local path or just filename in AWS mode
95
 
96
- # Convert for frontend exactly as before
97
  audio_url = f"/static/audio/{os.path.basename(audio_file_path_or_name)}"
98
 
99
  return jsonify({
100
  "word": word,
101
  "meaning": meaning,
102
  "sentence": sentence,
103
- "audio_file_path": audio_url # Returning the same field as before
104
  })
105
 
106
  else:
107
  return jsonify({"response": result, "message": "Meaning not provided in the expected format"})
108
 
109
  except Exception as e:
110
- return jsonify({"error": str(e)})
111
 
112
 
113
  def generate_sentence(word, meaning):
@@ -120,14 +114,13 @@ def generate_sentence(word, meaning):
120
  {"role": "user", "content": prompt},
121
  ]
122
  )
123
-
124
  sentence = response.choices[0].message.content.strip()
125
  return sentence
126
 
127
 
128
  def generate_audio(word):
129
  """
130
- Local (default): Google TTS β†’ write MP3 to ./static/audio/<word>.mp3 β†’ return full path (unchanged).
131
  Hugging Face / AWS mode: Polly β†’ upload to S3 (findingword/<word>.mp3) β†’ return just the filename,
132
  and let /static/audio/<filename> stream from S3 (see route below).
133
  """
@@ -171,18 +164,31 @@ def generate_audio(word):
171
  # Return only the filename; /static/audio/<filename> will proxy from S3
172
  return filename
173
 
174
- # ---- Local Google TTS path (unchanged) ----
175
  os.makedirs(AUDIO_FOLDER, exist_ok=True)
176
  audio_file_path = os.path.join(AUDIO_FOLDER, filename)
177
 
178
  if not os.path.exists(audio_file_path):
 
 
 
 
 
 
 
 
 
 
 
179
  synthesis_input = texttospeech.SynthesisInput(text=word)
180
  voice = texttospeech.VoiceSelectionParams(
181
  language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
182
  )
183
  audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
184
 
185
- response = client.synthesize_speech(input=synthesis_input, voice=voice, audio_config=audio_config)
 
 
186
 
187
  with open(audio_file_path, "wb") as out:
188
  out.write(response.audio_content)
@@ -196,33 +202,27 @@ def generate_audio(word):
196
  def validate_word():
197
  try:
198
  data = request.get_json()
199
- print("πŸ“₯ Received data for validation:", data) # Log input data
200
 
201
  if not data or 'user_input' not in data or 'correct_word' not in data:
202
- print("❌ Missing user_input or correct_word in request data.")
203
  return jsonify({"error": "Invalid request, missing fields"}), 400
204
 
205
  user_input = data.get('user_input', '').strip()
206
  correct_word = data.get('correct_word', '').strip()
207
 
208
- print(f"πŸ” Validating: User Input - '{user_input}' | Correct Word - '{correct_word}'")
209
-
210
  if user_input.lower() == correct_word.lower():
211
- print("βœ… Validation Success")
212
  return jsonify({"status": "success", "message": "Correct! You typed the word correctly."})
213
  else:
214
- print("❌ Validation Failed")
215
  return jsonify({"status": "failure", "message": f"Incorrect. The correct word was '{correct_word}'."})
216
 
217
  except Exception as e:
218
- print("❌ Exception in validate-word API:", str(e))
219
  return jsonify({"error": str(e)}), 500
220
 
221
 
222
  @finding_bp.route('/static/audio/<filename>')
223
  def serve_audio(filename):
224
  """
225
- Local: serve from disk (unchanged).
226
  AWS mode (HF): fetch the object from S3 and stream it (no local storage).
227
  """
228
  if _is_aws_mode():
@@ -240,7 +240,6 @@ def serve_audio(filename):
240
  try:
241
  obj = s3.get_object(Bucket=bucket, Key=key)
242
  data = obj["Body"].read()
243
- # Stream as an MP3 without saving locally
244
  return send_file(
245
  io.BytesIO(data),
246
  mimetype="audio/mpeg",
 
1
  import openai
2
  from flask import Flask, jsonify, request, send_from_directory, send_file, Blueprint, current_app
3
  import os
 
4
  from flask_cors import CORS
5
+ import io # for streaming S3 bytes in HF/AWS mode
6
 
7
  # Optional (only used in AWS mode)
8
  try:
 
16
  app = Flask(__name__)
17
  CORS(app)
18
 
19
+ # --- Blueprint ---
20
  finding_bp = Blueprint("findingword", __name__)
21
 
22
  # Directories for video, audio, and transcripts
23
  VIDEO_FOLDER = 'static/videos'
24
  AUDIO_FOLDER = 'static/audio' # Ensure this folder exists
25
  TRANSCRIPT_FOLDER = 'static/transcripts'
26
+ os.makedirs(AUDIO_FOLDER, exist_ok=True)
27
 
 
 
 
28
  # --- OpenAI key handling (same as vocab builder) ---
29
  _OPENAI_API_KEY_FALLBACK = os.getenv("OPENAI_API_KEY", "")
30
 
 
33
  api_key = (current_app.config.get("OPENAI_API_KEY") if current_app else None) or _OPENAI_API_KEY_FALLBACK
34
  if api_key:
35
  openai.api_key = api_key
 
 
 
 
 
36
 
37
+ # ---------------------- audio-mode helpers ----------------------
38
  def _is_aws_mode() -> bool:
39
  """
40
  Switch to AWS Polly + S3 on Hugging Face / prod.
 
56
 
57
  @finding_bp.route('/generate-vocabulary', methods=['GET'])
58
  def get_vocabulary_word_from_openai():
59
+ prompt = (
60
+ "Pick a simple vocabulary word suitable for children (ages 6–8) "
61
+ "and provide its meaning in very easy English. Do not repeat words from previous responses. "
62
+ "Format: 'Word: [word]. Meaning: [meaning].'"
63
+ )
64
 
65
  try:
66
  _ensure_openai_key()
 
78
  if "Word:" in result and "Meaning:" in result:
79
  parts = result.split("Meaning:")
80
  word = parts[0].replace("Word:", "").strip()
81
+ word = word.rstrip('.') # avoid trailing dot
 
82
  meaning = parts[1].strip()
83
 
84
  # Generate the sentence
85
  sentence = generate_sentence(word, meaning)
86
 
87
  # Generate audio file for the vocabulary word
88
+ audio_file_path_or_name = generate_audio(word) # local path or just filename in AWS mode
89
 
90
+ # URL for frontend remains identical
91
  audio_url = f"/static/audio/{os.path.basename(audio_file_path_or_name)}"
92
 
93
  return jsonify({
94
  "word": word,
95
  "meaning": meaning,
96
  "sentence": sentence,
97
+ "audio_file_path": audio_url
98
  })
99
 
100
  else:
101
  return jsonify({"response": result, "message": "Meaning not provided in the expected format"})
102
 
103
  except Exception as e:
104
+ return jsonify({"error": str(e)}), 500
105
 
106
 
107
  def generate_sentence(word, meaning):
 
114
  {"role": "user", "content": prompt},
115
  ]
116
  )
 
117
  sentence = response.choices[0].message.content.strip()
118
  return sentence
119
 
120
 
121
  def generate_audio(word):
122
  """
123
+ Local (default): Google TTS β†’ write MP3 to ./static/audio/<word>.mp3 β†’ return full path.
124
  Hugging Face / AWS mode: Polly β†’ upload to S3 (findingword/<word>.mp3) β†’ return just the filename,
125
  and let /static/audio/<filename> stream from S3 (see route below).
126
  """
 
164
  # Return only the filename; /static/audio/<filename> will proxy from S3
165
  return filename
166
 
167
+ # ---- Local Google TTS path (lazy import; no GCP on HF) ----
168
  os.makedirs(AUDIO_FOLDER, exist_ok=True)
169
  audio_file_path = os.path.join(AUDIO_FOLDER, filename)
170
 
171
  if not os.path.exists(audio_file_path):
172
+ try:
173
+ # Import only in local mode to avoid HF credential errors
174
+ from google.cloud import texttospeech
175
+ gcp_client = texttospeech.TextToSpeechClient()
176
+ except Exception as e:
177
+ raise RuntimeError(
178
+ "Google TTS is required in local mode but missing. "
179
+ "Install google-cloud-texttospeech and set GOOGLE_APPLICATION_CREDENTIALS. "
180
+ f"Details: {e}"
181
+ )
182
+
183
  synthesis_input = texttospeech.SynthesisInput(text=word)
184
  voice = texttospeech.VoiceSelectionParams(
185
  language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
186
  )
187
  audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
188
 
189
+ response = gcp_client.synthesize_speech(
190
+ input=synthesis_input, voice=voice, audio_config=audio_config
191
+ )
192
 
193
  with open(audio_file_path, "wb") as out:
194
  out.write(response.audio_content)
 
202
  def validate_word():
203
  try:
204
  data = request.get_json()
205
+ print("πŸ“₯ Received data for validation:", data)
206
 
207
  if not data or 'user_input' not in data or 'correct_word' not in data:
 
208
  return jsonify({"error": "Invalid request, missing fields"}), 400
209
 
210
  user_input = data.get('user_input', '').strip()
211
  correct_word = data.get('correct_word', '').strip()
212
 
 
 
213
  if user_input.lower() == correct_word.lower():
 
214
  return jsonify({"status": "success", "message": "Correct! You typed the word correctly."})
215
  else:
 
216
  return jsonify({"status": "failure", "message": f"Incorrect. The correct word was '{correct_word}'."})
217
 
218
  except Exception as e:
 
219
  return jsonify({"error": str(e)}), 500
220
 
221
 
222
  @finding_bp.route('/static/audio/<filename>')
223
  def serve_audio(filename):
224
  """
225
+ Local: serve from disk.
226
  AWS mode (HF): fetch the object from S3 and stream it (no local storage).
227
  """
228
  if _is_aws_mode():
 
240
  try:
241
  obj = s3.get_object(Bucket=bucket, Key=key)
242
  data = obj["Body"].read()
 
243
  return send_file(
244
  io.BytesIO(data),
245
  mimetype="audio/mpeg",