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