mulasagg commited on
Commit
49bbbf9
·
1 Parent(s): 8ad2ab3
Files changed (1) hide show
  1. app.py +480 -4
app.py CHANGED
@@ -1,7 +1,483 @@
1
- from fastapi import FastAPI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  app = FastAPI()
4
 
5
- @app.get("/hello")
6
- def hello():
7
- return {"message": "Hello, World!"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, HTTPException
2
+ from fastapi.responses import JSONResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ import sys
5
+ import os
6
+ import shutil
7
+ import uuid
8
+
9
+ # Ensure sibling module fluency is discoverable
10
+ #sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__))))
11
+
12
+ from fluency.fluency_api import main as analyze_fluency_main
13
+ from tone_modulation.tone_api import main as analyze_tone_main
14
+ from vcs.vcs_api import main as analyze_vcs_main
15
+ from vers.vers_api import main as analyze_vers_main
16
+ from voice_confidence_score.voice_confidence_api import main as analyze_voice_confidence_main
17
+ from vps.vps_api import main as analyze_vps_main
18
+ from ves.ves import calc_voice_engagement_score
19
+ from transcribe import transcribe_audio
20
+ from filler_count.filler_score import analyze_fillers
21
+
22
+ import logging
23
+
24
+ # Configure logging
25
+ logging.basicConfig(
26
+ level=logging.INFO, # Or DEBUG for more verbose logs
27
+ format="%(asctime)s - %(levelname)s - %(message)s",
28
+ handlers=[
29
+ logging.StreamHandler(sys.stdout)
30
+ ]
31
+ )
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
 
42
  app = FastAPI()
43
 
44
+ app.add_middleware(
45
+ CORSMiddleware,
46
+ allow_origins=["*"], # In production, replace "*" with allowed frontend domains
47
+ allow_credentials=True,
48
+ allow_methods=["*"],
49
+ allow_headers=["*"],
50
+ )
51
+
52
+ @app.get("/")
53
+ def home():
54
+ return {"status": "Running"}
55
+
56
+ @app.get("/health")
57
+ def health_check():
58
+ return {"status": "ok"}
59
+
60
+
61
+ # this will just rturen that audio file is being ready for analysis
62
+ @app.post("/audio_status/")
63
+ async def audio_status(file: UploadFile):
64
+ """
65
+ Endpoint to check the status of an uploaded audio file (.wav or .mp3).
66
+ """
67
+ if not file.filename.endswith(('.wav', '.mp3')):
68
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
69
+
70
+ # Generate a safe temporary file path
71
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
72
+ temp_dir = "temp_uploads"
73
+ temp_filepath = os.path.join(temp_dir, temp_filename)
74
+ os.makedirs(temp_dir, exist_ok=True)
75
+
76
+ try:
77
+ # Save uploaded file
78
+ with open(temp_filepath, "wb") as buffer:
79
+ shutil.copyfileobj(file.file, buffer)
80
+
81
+ return JSONResponse(content={"status": "File is ready for analysis"})
82
+
83
+ except Exception as e:
84
+ raise HTTPException(status_code=500, detail=f"File status check failed: {str(e)}")
85
+
86
+ finally:
87
+ # Clean up temporary file
88
+ if os.path.exists(temp_filepath):
89
+ os.remove(temp_filepath)
90
+
91
+
92
+
93
+ @app.post("/analyze_fluency/")
94
+ async def analyze_fluency(file: UploadFile):
95
+ # idk if we can use pydantic model here If we need I can add later
96
+ if not file.filename.endswith(('.wav', '.mp3')):
97
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
98
+
99
+ # Generate a safe temporary file path for temporary storage of the uploaded file this will be deleted after processing
100
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
101
+ temp_dir = "temp_uploads"
102
+ temp_filepath = os.path.join(temp_dir, temp_filename)
103
+ os.makedirs(temp_dir, exist_ok=True)
104
+
105
+ try:
106
+ # Save uploaded file
107
+ with open(temp_filepath, "wb") as buffer:
108
+ shutil.copyfileobj(file.file, buffer)
109
+
110
+
111
+ result = analyze_fluency_main(temp_filepath, model_size="base")
112
+
113
+ return JSONResponse(content=result)
114
+
115
+ except Exception as e:
116
+ raise HTTPException(status_code=500, detail=f"Fluency analysis failed: {str(e)}")
117
+
118
+ finally:
119
+ # Clean up temporary file
120
+ if os.path.exists(temp_filepath):
121
+ os.remove(temp_filepath)
122
+
123
+ # @app.post('/analyze_tone/')
124
+ # async def analyze_tone(file: UploadFile):
125
+ # """
126
+ # Endpoint to analyze tone of an uploaded audio file (.wav or .mp3).
127
+ # """
128
+ # if not file.filename.endswith(('.wav', '.mp3')):
129
+ # raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
130
+
131
+ # # Generate a safe temporary file path
132
+ # temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
133
+ # temp_dir = "temp_uploads"
134
+ # temp_filepath = os.path.join(temp_dir, temp_filename)
135
+ # os.makedirs(temp_dir, exist_ok=True)
136
+
137
+ # try:
138
+ # # Save uploaded file
139
+ # with open(temp_filepath, "wb") as buffer:
140
+ # shutil.copyfileobj(file.file, buffer)
141
+
142
+ # # Analyze tone using your custom function
143
+ # result = analyze_tone_main(temp_filepath)
144
+
145
+ # return JSONResponse(content=result)
146
+
147
+ # except Exception as e:
148
+ # raise HTTPException(status_code=500, detail=f"Tone analysis failed: {str(e)}")
149
+
150
+ # finally:
151
+ # # Clean up temporary file
152
+ # if os.path.exists(temp_filepath):
153
+ # os.remove(temp_filepath)
154
+
155
+ @app.post('/analyze_tone/')
156
+ async def analyze_tone(file: UploadFile):
157
+ logger.info(f"Received file for tone analysis: {file.filename}")
158
+
159
+ if not file.filename.endswith(('.wav', '.mp3')):
160
+ logger.warning("Invalid file type received")
161
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
162
+
163
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
164
+ temp_dir = "temp_uploads"
165
+ temp_filepath = os.path.join(temp_dir, temp_filename)
166
+ os.makedirs(temp_dir, exist_ok=True)
167
+
168
+ try:
169
+ logger.info(f"Saving uploaded file to {temp_filepath}")
170
+ with open(temp_filepath, "wb") as buffer:
171
+ shutil.copyfileobj(file.file, buffer)
172
+
173
+ logger.info("Calling analyze_tone_main...")
174
+ result = analyze_tone_main(temp_filepath)
175
+ logger.info("Tone analysis completed successfully")
176
+
177
+ return JSONResponse(content=result)
178
+
179
+ except Exception as e:
180
+ logger.error(f"Tone analysis failed: {str(e)}", exc_info=True)
181
+ raise HTTPException(status_code=500, detail=f"Tone analysis failed: {str(e)}")
182
+
183
+ finally:
184
+ if os.path.exists(temp_filepath):
185
+ logger.info(f"Cleaning up temporary file: {temp_filepath}")
186
+ os.remove(temp_filepath)
187
+
188
+
189
+
190
+
191
+ @app.post('/analyze_vcs/')
192
+ async def analyze_vcs(file: UploadFile):
193
+ """
194
+ Endpoint to analyze voice clarity of an uploaded audio file (.wav or .mp3).
195
+ """
196
+ if not file.filename.endswith(('.wav', '.mp3')):
197
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
198
+
199
+ # Generate a safe temporary file path
200
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
201
+ temp_dir = "temp_uploads"
202
+ temp_filepath = os.path.join(temp_dir, temp_filename)
203
+ os.makedirs(temp_dir, exist_ok=True)
204
+
205
+ try:
206
+ # Save uploaded file
207
+ with open(temp_filepath, "wb") as buffer:
208
+ shutil.copyfileobj(file.file, buffer)
209
+
210
+ # Analyze voice clarity using your custom function
211
+ result = analyze_vcs_main(temp_filepath)
212
+
213
+ return JSONResponse(content=result)
214
+
215
+ except Exception as e:
216
+ raise HTTPException(status_code=500, detail=f"Voice clarity analysis failed: {str(e)}")
217
+
218
+ finally:
219
+ # Clean up temporary file
220
+ if os.path.exists(temp_filepath):
221
+ os.remove(temp_filepath)
222
+
223
+ @app.post('/analyze_vers/')
224
+ async def analyze_vers(file: UploadFile):
225
+ """
226
+ Endpoint to analyze VERS of an uploaded audio file (.wav or .mp3).
227
+ """
228
+ if not file.filename.endswith(('.wav', '.mp3')):
229
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
230
+
231
+ # Generate a safe temporary file path
232
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
233
+ temp_dir = "temp_uploads"
234
+ temp_filepath = os.path.join(temp_dir, temp_filename)
235
+ os.makedirs(temp_dir, exist_ok=True)
236
+
237
+ try:
238
+ # Save uploaded file
239
+ with open(temp_filepath, "wb") as buffer:
240
+ shutil.copyfileobj(file.file, buffer)
241
+
242
+ # Analyze VERS using your custom function
243
+ result = analyze_vers_main(temp_filepath)
244
+
245
+ return JSONResponse(content=result)
246
+
247
+ except Exception as e:
248
+ raise HTTPException(status_code=500, detail=f"VERS analysis failed: {str(e)}")
249
+
250
+ finally:
251
+ # Clean up temporary file
252
+ if os.path.exists(temp_filepath):
253
+ os.remove(temp_filepath)
254
+
255
+ @app.post('/voice_confidence/')
256
+ async def analyze_voice_confidence(file: UploadFile):
257
+ """
258
+ Endpoint to analyze voice confidence of an uploaded audio file (.wav or .mp3).
259
+ """
260
+ if not file.filename.endswith(('.wav', '.mp3')):
261
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
262
+
263
+ # Generate a safe temporary file path
264
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
265
+ temp_dir = "temp_uploads"
266
+ temp_filepath = os.path.join(temp_dir, temp_filename)
267
+ os.makedirs(temp_dir, exist_ok=True)
268
+
269
+ try:
270
+ # Save uploaded file
271
+ with open(temp_filepath, "wb") as buffer:
272
+ shutil.copyfileobj(file.file, buffer)
273
+
274
+ # Analyze voice confidence using your custom function
275
+ result = analyze_voice_confidence_main(temp_filepath)
276
+
277
+ return JSONResponse(content=result)
278
+
279
+ except Exception as e:
280
+ raise HTTPException(status_code=500, detail=f"Voice confidence analysis failed: {str(e)}")
281
+
282
+ finally:
283
+ # Clean up temporary file
284
+ if os.path.exists(temp_filepath):
285
+ os.remove(temp_filepath)
286
+
287
+ @app.post('/analyze_vps/')
288
+ async def analyze_vps(file: UploadFile):
289
+ """
290
+ Endpoint to analyze voice pacing score of an uploaded audio file (.wav or .mp3).
291
+ """
292
+ if not file.filename.endswith(('.wav', '.mp3')):
293
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
294
+
295
+ # Generate a safe temporary file path
296
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
297
+ temp_dir = "temp_uploads"
298
+ temp_filepath = os.path.join(temp_dir, temp_filename)
299
+ os.makedirs(temp_dir, exist_ok=True)
300
+
301
+ try:
302
+ # Save uploaded file
303
+ with open(temp_filepath, "wb") as buffer:
304
+ shutil.copyfileobj(file.file, buffer)
305
+
306
+ # Analyze voice pacing score using your custom function
307
+ result = analyze_vps_main(temp_filepath)
308
+
309
+ return JSONResponse(content=result)
310
+
311
+ except Exception as e:
312
+ raise HTTPException(status_code=500, detail=f"Voice pacing score analysis failed: {str(e)}")
313
+
314
+ finally:
315
+ # Clean up temporary file
316
+ if os.path.exists(temp_filepath):
317
+ os.remove(temp_filepath)
318
+
319
+ @app.post('/voice_engagement_score/')
320
+ async def analyze_voice_engagement_score(file: UploadFile):
321
+ """
322
+ Endpoint to analyze voice engagement score of an uploaded audio file (.wav or .mp3).
323
+ """
324
+ if not file.filename.endswith(('.wav', '.mp3')):
325
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
326
+
327
+ # Generate a safe temporary file path
328
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
329
+ temp_dir = "temp_uploads"
330
+ temp_filepath = os.path.join(temp_dir, temp_filename)
331
+ os.makedirs(temp_dir, exist_ok=True)
332
+
333
+ try:
334
+ # Save uploaded file
335
+ with open(temp_filepath, "wb") as buffer:
336
+ shutil.copyfileobj(file.file, buffer)
337
+
338
+ # Analyze voice engagement score using your custom function
339
+ result = calc_voice_engagement_score(temp_filepath)
340
+
341
+ return JSONResponse(content=result)
342
+
343
+ except Exception as e:
344
+ raise HTTPException(status_code=500, detail=f"Voice engagement score analysis failed: {str(e)}")
345
+
346
+ finally:
347
+ # Clean up temporary file
348
+ if os.path.exists(temp_filepath):
349
+ os.remove(temp_filepath)
350
+
351
+ @app.post('/analyze_fillers/')
352
+ async def analyze_fillers_count(file: UploadFile):
353
+ """
354
+ Endpoint to analyze filler words in an uploaded audio file (.wav or .mp3).
355
+ """
356
+ if not file.filename.endswith(('.wav', '.mp3','.mp4')):
357
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
358
+
359
+ # Generate a safe temporary file path
360
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
361
+ temp_dir = "temp_uploads"
362
+ temp_filepath = os.path.join(temp_dir, temp_filename)
363
+ os.makedirs(temp_dir, exist_ok=True)
364
+
365
+ try:
366
+ # Save uploaded file
367
+ with open(temp_filepath, "wb") as buffer:
368
+ shutil.copyfileobj(file.file, buffer)
369
+
370
+ # Call the analysis function with the file path
371
+ result = analyze_fillers(temp_filepath) # Pass the file path, not the UploadFile object
372
+
373
+ return JSONResponse(content=result)
374
+
375
+ except Exception as e:
376
+ raise HTTPException(status_code=500, detail=f"Filler analysis failed: {str(e)}")
377
+
378
+ finally:
379
+ # Clean up temporary file
380
+ if os.path.exists(temp_filepath):
381
+ os.remove(temp_filepath)
382
+
383
+
384
+ import time
385
+
386
+
387
+
388
+ @app.post('/transcribe/')
389
+ async def transcribe(file: UploadFile):
390
+ """
391
+ Endpoint to transcribe an uploaded audio file (.wav or .mp3).
392
+ """
393
+ #calculate time to transcribe
394
+ start_time = time.time()
395
+ if not file.filename.endswith(('.wav', '.mp3')):
396
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
397
+
398
+ # Generate a safe temporary file path
399
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
400
+ temp_dir = "temp_uploads"
401
+ temp_filepath = os.path.join(temp_dir, temp_filename)
402
+ os.makedirs(temp_dir, exist_ok=True)
403
+
404
+ try:
405
+ # Save uploaded file
406
+ with open(temp_filepath, "wb") as buffer:
407
+ shutil.copyfileobj(file.file, buffer)
408
+
409
+ # Transcribe using your custom function
410
+ result = transcribe_audio(temp_filepath)
411
+ end_time = time.time()
412
+ transcription_time = end_time - start_time
413
+ response = {
414
+ "transcription": result,
415
+ "transcription_time": transcription_time
416
+ }
417
+
418
+ return JSONResponse(content=response)
419
+
420
+ except Exception as e:
421
+ raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
422
+
423
+ finally:
424
+ # Clean up temporary file
425
+ if os.path.exists(temp_filepath):
426
+ os.remove(temp_filepath)
427
+
428
+
429
+
430
+ @app.post('/analyze_all/')
431
+ async def analyze_all(file: UploadFile):
432
+ """
433
+ Endpoint to analyze all aspects of an uploaded audio file (.wav or .mp3).
434
+ """
435
+ if not file.filename.endswith(('.wav', '.mp3')):
436
+ raise HTTPException(status_code=400, detail="Invalid file type. Only .wav and .mp3 files are supported.")
437
+
438
+ # Generate a safe temporary file path
439
+ temp_filename = f"temp_{uuid.uuid4()}{os.path.splitext(file.filename)[1]}"
440
+ temp_dir = "temp_uploads"
441
+ temp_filepath = os.path.join(temp_dir, temp_filename)
442
+ os.makedirs(temp_dir, exist_ok=True)
443
+
444
+ try:
445
+ # Save uploaded file
446
+ with open(temp_filepath, "wb") as buffer:
447
+ shutil.copyfileobj(file.file, buffer)
448
+
449
+ # Analyze all aspects using your custom functions
450
+ fluency_result = analyze_fluency_main(temp_filepath, model_size="base")
451
+ tone_result = analyze_tone_main(temp_filepath)
452
+ vcs_result = analyze_vcs_main(temp_filepath)
453
+ vers_result = analyze_vers_main(temp_filepath)
454
+ voice_confidence_result = analyze_voice_confidence_main(temp_filepath)
455
+ vps_result = analyze_vps_main(temp_filepath)
456
+ ves_result = calc_voice_engagement_score(temp_filepath)
457
+ transcript = transcribe_audio(temp_filepath)
458
+
459
+ # Combine results into a single response
460
+ combined_result = {
461
+ "fluency": fluency_result,
462
+ "tone": tone_result,
463
+ "vcs": vcs_result,
464
+ "vers": vers_result,
465
+ "voice_confidence": voice_confidence_result,
466
+ "vps": vps_result,
467
+ "ves": ves_result,
468
+ "transcript": transcript
469
+ }
470
+
471
+ return JSONResponse(content=combined_result)
472
+
473
+ except Exception as e:
474
+ raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
475
+
476
+ finally:
477
+ # Clean up temporary file
478
+ if os.path.exists(temp_filepath):
479
+ os.remove(temp_filepath)
480
+
481
+ # if __name__ == "__main__":
482
+ # import uvicorn
483
+ # uvicorn.run("main:app", host="0.0.0.0", port=int(os.environ.get("PORT", 10000)), reload=False)