mMonika commited on
Commit
fcc7565
·
verified ·
1 Parent(s): def4473

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +260 -275
app.py CHANGED
@@ -27,20 +27,218 @@ def fetch_sheet_data(sheet_url):
27
  return data
28
 
29
 
 
30
  data = fetch_sheet_data(SHEET_URL)
31
 
32
- # Load the project using the hardcoded project code
33
- current_project = [row for row in data if row["Project Code"] == PROJECT_CODE]
34
- if current_project:
35
- current_project = current_project[0]
36
- prompts = [current_project[f"Prompt{i+1}"] for i in range(4) if current_project.get(f"Prompt{i+1}")]
37
- recording_status = [False] * len(prompts) # Initialize recording status for each prompt
38
- responses = [None] * len(prompts)
39
- else:
40
- prompts = []
41
 
42
- custom_html="""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
 
 
 
 
 
 
 
 
 
 
 
44
  <style>
45
  /* Body Styles */
46
  .gr-container {
@@ -64,6 +262,7 @@ custom_html="""
64
  padding: 10px 10px;
65
  border-radius: 10px;
66
  font-size:20px;
 
67
  }
68
 
69
  .gr-audio button[title="Clear"] {
@@ -140,7 +339,7 @@ custom_html="""
140
  padding: 10px;
141
  background-color: #FF0000; /* Light red background for alert */
142
  }
143
- .sucess-alert {
144
  font-size: 16px;
145
  color: black;
146
  margin-top: 2px;
@@ -184,284 +383,70 @@ custom_html="""
184
  }
185
  </style>
186
  """
187
-
188
- def fetch_sheet_data(sheet_url):
189
- gc = gspread.service_account(filename="story_legacy_service_account.json")
190
- sh = gc.open_by_url(sheet_url)
191
- worksheet = sh.sheet1
192
- data = worksheet.get_all_records()
193
- return data
194
-
195
- # Load Google Sheet data
196
- data = fetch_sheet_data(SHEET_URL)
197
-
198
- # Global variables to track the state
199
- current_project = None
200
- current_prompt_index = 0
201
- prompts = []
202
- recording_status = []
203
- responses = []
204
-
205
- # Load the project using the hardcoded project code
206
- current_project = [row for row in data if row["Project Code"] == PROJECT_CODE]
207
- if current_project:
208
- current_project = current_project[0]
209
- prompts = [current_project[f"Prompt{i+1}"] for i in range(4) if current_project.get(f"Prompt{i+1}")]
210
- recording_status = [False] * len(prompts) # Initialize recording status for each prompt
211
- responses = [None] * len(prompts)
212
- else:
213
- prompts = []
214
-
215
- # Function to transcribe audio files and save them locally
216
- def transcribe_audio(local_file_path):
217
- """Transcribes audio data from a Google Cloud Storage bucket."""
218
-
219
- with open(local_file_path, "rb") as audio_file:
220
- content = audio_file.read()
221
-
222
- client = speech.SpeechClient()
223
- audio = speech.RecognitionAudio(content=content)
224
- config = speech.RecognitionConfig(
225
- encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
226
- sample_rate_hertz=44100, # Adjust if needed
227
- language_code="en-US",
228
- )
229
- response = client.recognize(config=config, audio=audio)
230
- return response.results[0].alternatives[0].transcript if response.results else "No transcription available."
231
-
232
- # function to upload responses and generate transcripts
233
- def upload_to_gcs_and_cleanup():
234
- try:
235
- # Initialize GCS client
236
- client = storage.Client(project="story-legacy-442314")
237
- bucket = client.bucket(GCS_BUCKET_NAME)
238
-
239
- # Walk through the responses directory
240
- for root, _, files in os.walk(f"responses/{PROJECT_CODE}"):
241
- for file in files:
242
- local_path = os.path.join(root, file)
243
-
244
- # Define the relative path for GCS
245
- relative_path = os.path.relpath(local_path, f"responses/{PROJECT_CODE}")
246
- gcs_path = f"{PROJECT_CODE}/responses/{relative_path}"
247
-
248
- # Upload the file to GCS
249
- blob = bucket.blob(gcs_path)
250
- blob.upload_from_filename(local_path)
251
- print(f"Uploaded {local_path} to {gcs_path}")
252
-
253
- # Generate the transcript
254
- transcript_text = transcribe_audio(local_path)
255
-
256
- # Save the transcript in GCS under the transcripts folder with the new structure
257
- transcript_relative_path = relative_path.replace("responses/", "") # Remove "responses/" from path
258
- transcript_gcs_path = f"{PROJECT_CODE}/transcripts/{transcript_relative_path.replace(os.path.splitext(file)[1], '.txt')}"
259
- transcript_blob = bucket.blob(transcript_gcs_path)
260
- transcript_blob.upload_from_string(transcript_text)
261
- print(f"Transcript uploaded to {transcript_gcs_path}")
262
-
263
- # Delete the local response file
264
- os.remove(local_path)
265
-
266
- # Remove the responses directory after successful upload
267
- response_dir = f"responses/{PROJECT_CODE}"
268
- if os.path.exists(response_dir):
269
- shutil.rmtree(response_dir)
270
- print(f"Local directory {response_dir} has been deleted.")
271
-
272
- return True, "All responses and transcripts have been uploaded to GCS, and local files deleted."
273
- except Exception as e:
274
- print(f"Error during GCS upload: {e}")
275
- return False, f"Error during GCS upload: {str(e)}"
276
-
277
- # Background task function
278
- def async_upload_to_gcs_and_cleanup():
279
- success, message = upload_to_gcs_and_cleanup()
280
- print(message)
281
-
282
-
283
-
284
- def submit_audio(audio_path):
285
- global current_prompt_index
286
- print(f"Received audio_path: {audio_path}") # Debugging line to check the value
287
-
288
- # Check if the response has already been submitted
289
- if recording_status[current_prompt_index]:
290
- return (
291
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div> <div class="prompt-text">{prompts[current_prompt_index]}</div>""",
292
- gr.update(value=f"""<div class="sucess-alert">⚠️ Response for Prompt {current_prompt_index + 1} has already been submitted.</div>""", visible=True),
293
- )
294
-
295
- # Check if no audio is recorded
296
- if audio_path is None:
297
- return (
298
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
299
- gr.update(value="", visible=True),
300
- )
301
-
302
- try:
303
- # Ensure the directory exists and move the file
304
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
305
- folder_path = f"responses/{PROJECT_CODE}/Prompt{current_prompt_index + 1}"
306
- os.makedirs(folder_path, exist_ok=True)
307
- file_path = f"{folder_path}/response_{timestamp}.wav"
308
- shutil.move(audio_path, file_path)
309
-
310
- # Update recording status and responses
311
- recording_status[current_prompt_index] = True
312
- responses[current_prompt_index] = file_path
313
-
314
- return (
315
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
316
- gr.update(value=f"""<div class = "sucess-alert">Response for Prompt {current_prompt_index + 1} has been submitted successfully!</div>""", visible=True),
317
- )
318
- except Exception as e:
319
- print(f"Error occurred during submission: {e}") # Debugging line for exception
320
- return (
321
- f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
322
- gr.update(value=f"""<div class= "fail-alert">⚠️ An error occurred during submission: {str(e)}</div>""", visible=True),
323
- )
324
-
325
- def save_and_next():
326
- global current_prompt_index
327
- if not recording_status[current_prompt_index]:
328
- return (
329
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1} of {len(prompts)}:</div><div class="prompt-text">{prompts[current_prompt_index]}</div>""",
330
- gr.update(value=f"""<div class="warning-alert">⚠️ Please record and submit your response before moving to the next prompt.</div>""", visible=True),
331
- gr.update(visible=True),
332
- gr.update(visible=True),
333
- gr.update(visible=True),
334
-
335
- )
336
-
337
- if current_prompt_index < len(prompts) - 1:
338
- current_prompt_index += 1
339
- is_last_prompt = current_prompt_index == len(prompts) - 1
340
- next_button_text = "Finish" if is_last_prompt else f"Next Prompt ({current_prompt_index + 2} of {len(prompts)})"
341
- return (
342
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1} of {len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
343
- gr.update(value="", visible=False), # Clear the alert message
344
- gr.update(value=None, visible=True),
345
- gr.update(value=next_button_text, visible=True),
346
- gr.update(visible=True),
347
-
348
- )
349
- else:
350
- # "Finish" button clicked
351
- threading.Thread(target=async_upload_to_gcs_and_cleanup, daemon=True).start()
352
-
353
- # print(upload_to_gcs_and_cleanup())
354
- # alert_class = "success-alert" if success else "fail-alert"
355
- return (
356
- "Thank you for your participation in this research, all of your stories have been submitted. We place great value on your stories and will treat them with the respect they deserve.",
357
- gr.update(value="", visible=True),
358
- gr.update(visible=False),
359
- gr.update(visible=False),
360
- gr.update(visible=False),
361
-
362
- )
363
-
364
- def erase_and_record():
365
- global current_prompt_index
366
- # Check if a response exists for the current prompt
367
- if responses[current_prompt_index]:
368
- # Delete the file
369
- try:
370
- os.remove(responses[current_prompt_index])
371
- except FileNotFoundError:
372
- pass # Ignore if the file doesn't exist
373
- responses[current_prompt_index] = None # Reset the response
374
- recording_status[current_prompt_index] = False # Reset recording status
375
-
376
- # Return updated prompt and alert message
377
- return (
378
- f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
379
- gr.update(value=None, visible=True), # Reset the audio input
380
- gr.update(value=f"""<div class= "sucess-alert">Your previous response has been erased. Please re-record your response.</div>""", visible=True), # Updated alert message
381
- )
382
- else:
383
- return (
384
- f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
385
- gr.update(visible=True), # Reset the audio input
386
- gr.update(value=f"""<div class= "warning-alert">⚠️ Please record and submit your response first.</div>""", visible=True), # Updated alert message
387
- )
388
- # Gradio Interface
389
  def gradio_app():
390
- # reset_state()
391
- with gr.Blocks(theme='allenai/gradio-theme',css = custom_html) as demo:
 
 
392
  with gr.Row():
393
- with gr.Blocks(theme='allenai/gradio-theme',css = custom_html):
394
- gr.Markdown("""# StoryLegacy""",elem_classes=['gr-story_legacy_heading'])
395
- gr.Markdown(f"""# Project: {PROJECT_CODE}""",elem_classes=['gr-project_code'])
 
 
 
 
 
396
  with gr.Row():
397
  alert_box = gr.Markdown("", elem_id="alert-box", visible=False)
 
398
  with gr.Row():
399
  prompt_display = gr.Markdown(
400
- f"""<div class ="prompt-class">Prompt {current_prompt_index + 1} of {len(prompts)}:</div> <div class="prompt-text">{prompts[0] if prompts else 'No prompts available.'}</div>",
401
- """,elem_classes=["gr-prompt"]
 
402
  )
 
403
  with gr.Row():
404
  # Create a hidden label to dynamically update microphone status
405
  record_audio = gr.Audio(
406
- sources="microphone",
407
- type="filepath",
408
  label="Record your response",
409
- elem_classes=["gr-audio"]
410
- )
411
- with gr.Row():
412
- erase_button = gr.Button("Erase & Re - Record Current Prompt", elem_classes=["gr-erase_button"])
413
- save_next_button = gr.Button(f"Next Prompt (2 of {len(prompts)})", elem_classes=["gr-next_button"])
414
 
415
- record_audio.change(submit_audio, inputs=record_audio, outputs=[prompt_display,alert_box])
 
 
416
 
417
- save_next_button.click(
418
- save_and_next,
419
- inputs=[],
420
- outputs=[
421
- prompt_display,
422
- alert_box,
423
- record_audio,
424
- save_next_button,
425
- erase_button,
426
-
427
- ],
428
  )
429
  erase_button.click(
430
- erase_and_record,
431
- inputs=[],
432
- outputs=[
433
- prompt_display,
434
- record_audio,
435
- alert_box,
436
-
437
- ],
438
  )
439
-
440
- @demo.load
441
- def initialize_state():
442
- """Initialize or reset the app's state when reloaded."""
443
- global current_project, current_prompt_index, prompts, recording_status, responses
444
-
445
- # Load the Google Sheet data
446
- data = fetch_sheet_data(SHEET_URL)
447
-
448
- # Load the project using the hardcoded project code
449
- current_project = [row for row in data if row["Project Code"] == PROJECT_CODE]
450
- if current_project:
451
- current_project = current_project[0]
452
- prompts = [current_project[f"Prompt{i+1}"] for i in range(4) if current_project.get(f"Prompt{i+1}")]
453
- recording_status = [False] * len(prompts)
454
- responses = [None] * len(prompts)
455
- else:
456
- prompts = []
457
-
458
- # Reset the current prompt index
459
- current_prompt_index = 0
460
- print("State has been initialized.")
461
-
462
- return demo
463
-
464
- # Run the app
465
- # reset_state()
466
  app = gradio_app()
467
- app.launch()
 
27
  return data
28
 
29
 
30
+ # Load Google Sheet data
31
  data = fetch_sheet_data(SHEET_URL)
32
 
 
 
 
 
 
 
 
 
 
33
 
34
+ # Helper function to initialize a new session state
35
+ def initialize_session_state():
36
+ current_project = [row for row in data if row["Project Code"] == PROJECT_CODE]
37
+ if current_project:
38
+ current_project = current_project[0]
39
+ prompts = [
40
+ current_project[f"Prompt{i+1}"] for i in range(4) if current_project.get(f"Prompt{i+1}")
41
+ ]
42
+ recording_status = [False] * len(prompts)
43
+ responses = [None] * len(prompts)
44
+ else:
45
+ prompts = []
46
+ recording_status = []
47
+ responses = []
48
+
49
+ return {
50
+ "current_prompt_index": 0,
51
+ "prompts": prompts,
52
+ "recording_status": recording_status,
53
+ "responses": responses,
54
+ }
55
+
56
+
57
+ def submit_audio(audio_path, state):
58
+ current_prompt_index = state["current_prompt_index"]
59
+ prompts = state["prompts"]
60
+ recording_status = state["recording_status"]
61
+ responses = state["responses"]
62
+
63
+ # Check if response for current prompt is already recorded
64
+ if recording_status[current_prompt_index]:
65
+
66
+ return (
67
+ f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
68
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
69
+ gr.update(value=responses[current_prompt_index]), # Show already recorded response
70
+ gr.update(value=f"""<div class="success-alert"> Response for Prompt {current_prompt_index + 1} has been recorded.</div>""", visible=True),
71
+ state,
72
+ )
73
+
74
+ # Ensure audio is available before saving
75
+ if audio_path is None:
76
+ return (
77
+ f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
78
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
79
+ gr.update(value=None), # Reset the audio input
80
+ gr.update(value="", visible=True),
81
+ state,
82
+ )
83
+
84
+ try:
85
+ # Ensure the directory exists and move the file
86
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
87
+ folder_path = f"responses/{PROJECT_CODE}/Prompt{current_prompt_index + 1}"
88
+ os.makedirs(folder_path, exist_ok=True)
89
+ file_path = f"{folder_path}/response_{timestamp}.wav"
90
+ shutil.move(audio_path, file_path)
91
+
92
+ # Update recording status and responses
93
+ recording_status[current_prompt_index] = True
94
+ responses[current_prompt_index] = file_path
95
+
96
+ # Update state
97
+ state["recording_status"] = recording_status
98
+ state["responses"] = responses
99
+
100
+ return (
101
+ f"""<div class ="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
102
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
103
+ gr.update(value=file_path), # Show the saved response for playback
104
+ gr.update(value=f"""<div class="success-alert">Response for Prompt {current_prompt_index + 1} has been submitted successfully!</div>""", visible=True),
105
+ state,
106
+ )
107
+ except Exception as e:
108
+ print(f"Error occurred during submission: {e}")
109
+ return (
110
+ f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
111
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
112
+ gr.update(value=None), # Reset the audio input
113
+ gr.update(value=f"""<div class="fail-alert">⚠️ An error occurred during submission: {str(e)}</div>""", visible=True),
114
+ state,
115
+ )
116
+
117
+ def erase_and_record(state):
118
+ current_prompt_index = state["current_prompt_index"]
119
+ prompts = state["prompts"]
120
+ recording_status = state["recording_status"]
121
+ responses = state["responses"]
122
+
123
+ # Check if a response exists for the current prompt
124
+ if responses[current_prompt_index]:
125
+ try:
126
+ # Delete the recorded file
127
+ os.remove(responses[current_prompt_index])
128
+ except FileNotFoundError:
129
+ pass # Ignore if the file doesn't exist
130
+
131
+ # Reset the response and recording status
132
+ responses[current_prompt_index] = None
133
+ recording_status[current_prompt_index] = False
134
+
135
+ # Update state
136
+ state["recording_status"] = recording_status
137
+ state["responses"] = responses
138
+
139
+ return (
140
+ f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
141
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
142
+ gr.update(value=None, visible=True), # Reset the audio input
143
+ gr.update(value=f"""<div class="success-alert">Your previous response has been erased. Please re-record your response.</div>""", visible=True),
144
+ state,
145
+ )
146
+ else:
147
+ return (
148
+ f"""<div class="prompt-class">Prompt {current_prompt_index + 1}/{len(prompts)}:</div>
149
+ <div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
150
+ gr.update(visible=True), # Reset the audio input
151
+ gr.update(value=f"""<div class="warning-alert">⚠️ Please record your response first.</div>""", visible=True),
152
+ state,
153
+ )
154
+ def save_and_next(state):
155
+ current_prompt_index = state["current_prompt_index"]
156
+ prompts = state["prompts"]
157
+ recording_status = state["recording_status"]
158
+ # Check if the response for the current prompt is recorded
159
+ if not recording_status[current_prompt_index]:
160
+ return (
161
+ f"""<div class ="prompt-class">Prompt {current_prompt_index + 1} of {len(prompts)}:</div><div class="prompt-text">{prompts[current_prompt_index]}</div>""",
162
+ gr.update(value=f"""<div class="warning-alert">⚠️ Please record your response before moving to the next prompt.</div>""", visible=True),
163
+ gr.update(value=None, visible=True), # Audio input is still visible
164
+ gr.update(value=f"Next Prompt ({current_prompt_index + 2} of {len(prompts)})", visible=True), # Update button text
165
+ gr.update(visible=True), # Erase button should still be visible
166
+ state,
167
+ )
168
+
169
+ # Increment prompt index if not the last prompt
170
+ if current_prompt_index < len(prompts) - 1:
171
+ current_prompt_index += 1
172
+ state["current_prompt_index"] = current_prompt_index # Update state with new prompt index
173
+
174
+ is_last_prompt = current_prompt_index == len(prompts) - 1
175
+ next_button_text = "Finish" if is_last_prompt else f"Next Prompt ({current_prompt_index + 2} of {len(prompts)})"
176
+
177
+ return (
178
+ f"""<div class ="prompt-class">Prompt {current_prompt_index + 1} of {len(prompts)}:</div><div class="prompt-text"> {prompts[current_prompt_index]}</div>""",
179
+ gr.update(value="", visible=False), # Clear the alert message
180
+ gr.update(value=None, visible=True), # Show the audio input for the next prompt
181
+ gr.update(value=next_button_text, visible=True), # Update button text
182
+ gr.update(visible=True), # Keep the Erase button visible until the last prompt
183
+ state,
184
+ )
185
+ else:
186
+ # "Finish" button clicked
187
+ threading.Thread(target=async_upload_to_gcs_and_cleanup, daemon=True).start()
188
+
189
+ # Hide the "Next" button and "Erase" button after Finish
190
+ return (
191
+ "Thank you for your participation in this research, all of your stories have been submitted. We place great value on your stories and will treat them with the respect they deserve.",
192
+ gr.update(value="", visible=True),
193
+ gr.update(visible=False), # Hide the audio input
194
+ gr.update(visible=False), # Hide the "Next" button
195
+ gr.update(visible=False), # Hide the "Erase" button
196
+ state,
197
+ )
198
+
199
+ GCS_BUCKET_NAME = "userrecordings"
200
+
201
+ # function to upload responses and generate transcripts
202
+ def upload_to_gcs_and_cleanup():
203
+ try:
204
+ # Initialize GCS client
205
+ client = storage.Client(project="story-legacy-442314")
206
+ bucket = client.bucket(GCS_BUCKET_NAME)
207
+
208
+ # Walk through the responses directory
209
+ for root, _, files in os.walk(f"responses/{PROJECT_CODE}"):
210
+ for file in files:
211
+ local_path = os.path.join(root, file)
212
+
213
+ # Define the relative path for GCS
214
+ relative_path = os.path.relpath(local_path, f"responses/{PROJECT_CODE}")
215
+ gcs_path = f"{PROJECT_CODE}/responses/{relative_path}"
216
+
217
+ # Upload the file to GCS
218
+ blob = bucket.blob(gcs_path)
219
+ blob.upload_from_filename(local_path)
220
+ print(f"Uploaded {local_path} to {gcs_path}")
221
+
222
+ # Delete the local response file
223
+ os.remove(local_path)
224
+
225
+ # Remove the responses directory after successful upload
226
+ response_dir = f"responses/{PROJECT_CODE}"
227
+ if os.path.exists(response_dir):
228
+ shutil.rmtree(response_dir)
229
+ print(f"Local directory {response_dir} has been deleted.")
230
 
231
+ return True, "All responses and transcripts have been uploaded to GCS, and local files deleted."
232
+ except Exception as e:
233
+ print(f"Error during GCS upload: {e}")
234
+ return False, f"Error during GCS upload: {str(e)}"
235
+
236
+ # Background task function
237
+ def async_upload_to_gcs_and_cleanup():
238
+ success, message = upload_to_gcs_and_cleanup()
239
+ print(message)
240
+
241
+ custom_html="""
242
  <style>
243
  /* Body Styles */
244
  .gr-container {
 
262
  padding: 10px 10px;
263
  border-radius: 10px;
264
  font-size:20px;
265
+ background-color: #dfdf8f
266
  }
267
 
268
  .gr-audio button[title="Clear"] {
 
339
  padding: 10px;
340
  background-color: #FF0000; /* Light red background for alert */
341
  }
342
+ .success-alert {
343
  font-size: 16px;
344
  color: black;
345
  margin-top: 2px;
 
383
  }
384
  </style>
385
  """
386
+ # JavaScript to detect microphone access on page load
387
+ js_code = """
388
+ async () => {
389
+ try {
390
+ const devices = await navigator.mediaDevices.enumerateDevices();
391
+ const mic = devices.find(device => device.kind === 'audioinput');
392
+ return mic ? "Microphone Array / Default" : "No Microphone Found";
393
+ } catch (err) {
394
+ return "No Microphone Found";
395
+ }
396
+ }
397
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  def gradio_app():
399
+ with gr.Blocks(theme="allenai/gradio-theme",css = custom_html) as demo:
400
+ # Initialize session state
401
+ state = gr.State(initialize_session_state())
402
+
403
  with gr.Row():
404
+ with gr.Blocks(theme="allenai/gradio-theme",css = custom_html):
405
+ gr.Markdown(
406
+ """# StoryLegacy""", elem_classes=["gr-story_legacy_heading"]
407
+ )
408
+ gr.Markdown(
409
+ f"""# Project: {PROJECT_CODE}""", elem_classes=["gr-project_code"]
410
+ )
411
+
412
  with gr.Row():
413
  alert_box = gr.Markdown("", elem_id="alert-box", visible=False)
414
+
415
  with gr.Row():
416
  prompt_display = gr.Markdown(
417
+ f"""<div class ="prompt-class">Prompt 1 of {len(state.value['prompts'])}:</div>
418
+ <div class="prompt-text">{state.value['prompts'][0] if state.value['prompts'] else 'No prompts available.'}</div>""",
419
+ elem_classes=["gr-prompt"],
420
  )
421
+
422
  with gr.Row():
423
  # Create a hidden label to dynamically update microphone status
424
  record_audio = gr.Audio(
425
+ sources="microphone",
426
+ type="filepath",
427
  label="Record your response",
428
+ elem_classes=["gr-audio"],
429
+ )
430
+ demo.load(js=js_code, inputs=[], outputs=[record_audio])
 
 
431
 
432
+ with gr.Row():
433
+ erase_button = gr.Button("Erase & Re-record Current Prompt", elem_classes=["gr-erase_button"])
434
+ save_next_button = gr.Button(f"Next Prompt (2 of {len(state.value['prompts'])})", elem_classes=["gr-next_button"])
435
 
436
+ record_audio.stop_recording(
437
+ submit_audio, inputs=[record_audio, state], outputs=[prompt_display, record_audio, alert_box, state]
 
 
 
 
 
 
 
 
 
438
  )
439
  erase_button.click(
440
+ erase_and_record, inputs=state, outputs=[prompt_display, record_audio, alert_box, state]
 
 
 
 
 
 
 
441
  )
442
+ save_next_button.click(
443
+ save_and_next, inputs=state, outputs=[prompt_display, alert_box, record_audio, save_next_button,erase_button, state]
444
+ )
445
+
446
+
447
+
448
+ return demo
449
+
450
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  app = gradio_app()
452
+ app.launch(share=True)