fariedalfarizi commited on
Commit
4838f88
·
1 Parent(s): 78c30f0

Fix: Resolve Content-Length error with explicit JSONResponse serialization

Browse files
Files changed (1) hide show
  1. api/routes.py +70 -56
api/routes.py CHANGED
@@ -7,9 +7,10 @@ from fastapi import FastAPI, File, UploadFile, Form, HTTPException
7
  from fastapi.responses import JSONResponse
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from pydantic import BaseModel
10
- from typing import Optional, List
11
  import tempfile
12
  import os
 
13
  from pathlib import Path
14
 
15
  from core.scoring_engine import AdvancedVocalScoringSystem, ScoreResult
@@ -114,26 +115,29 @@ async def shutdown_event():
114
  # API ENDPOINTS
115
  # =======================================
116
 
117
- @app.get("/", response_model=dict)
118
  async def root():
119
  """Root endpoint"""
120
- return {
121
- "message": "Vocal Articulation Assessment API v2",
122
- "version": "2.0.0",
123
- "features": [
124
- "Whisper ASR-based clarity scoring",
125
- "Multi-level support (Level 1-5)",
126
- "6 scoring metrics",
127
- "Comprehensive audio analysis"
128
- ],
129
- "endpoints": {
130
- "health": "/health",
131
- "levels": "/levels",
132
- "score": "/score",
133
- "batch_score": "/batch_score",
134
- "docs": "/docs"
135
- }
136
- }
 
 
 
137
 
138
  @app.get("/health", response_model=HealthResponse)
139
  async def health_check():
@@ -153,7 +157,7 @@ async def get_levels():
153
  total_levels=len(ARTICULATION_LEVELS)
154
  )
155
 
156
- @app.post("/score", response_model=ScoreResponse)
157
  async def score_audio(
158
  audio: UploadFile = File(..., description="Audio file (WAV, MP3, M4A, etc.)"),
159
  target_text: str = Form(..., description="Target text yang seharusnya diucapkan"),
@@ -204,25 +208,31 @@ async def score_audio(
204
  # Clean up temp file
205
  os.unlink(tmp_path)
206
 
207
- # Return response
208
- return ScoreResponse(
209
- success=True,
210
- overall_score=result.overall_score,
211
- grade=result.grade,
212
- clarity_score=result.clarity_score,
213
- energy_score=result.energy_score,
214
- speech_rate_score=result.speech_rate_score,
215
- pitch_consistency_score=result.pitch_consistency_score,
216
- snr_score=result.snr_score,
217
- articulation_score=result.articulation_score,
218
- transcription=result.transcription,
219
- target=result.target,
220
- similarity=result.similarity,
221
- wer=result.wer,
222
- feedback=result.feedback,
223
- suggestions=result.suggestions,
224
- audio_features=result.audio_features,
225
- level=result.level
 
 
 
 
 
 
226
  )
227
 
228
  except Exception as e:
@@ -290,25 +300,26 @@ async def batch_score_audio(
290
  # Clean up
291
  os.unlink(tmp_path)
292
 
 
293
  results.append({
294
  "filename": audio.filename,
295
  "success": True,
296
- "overall_score": result.overall_score,
297
- "grade": result.grade,
298
- "clarity_score": result.clarity_score,
299
- "energy_score": result.energy_score,
300
- "speech_rate_score": result.speech_rate_score,
301
- "pitch_consistency_score": result.pitch_consistency_score,
302
- "snr_score": result.snr_score,
303
- "articulation_score": result.articulation_score,
304
- "transcription": result.transcription,
305
- "target": result.target,
306
- "similarity": result.similarity,
307
- "wer": result.wer,
308
- "feedback": result.feedback,
309
- "suggestions": result.suggestions,
310
- "audio_features": result.audio_features,
311
- "level": result.level
312
  })
313
 
314
  except Exception as e:
@@ -321,7 +332,10 @@ async def batch_score_audio(
321
  "error": str(e)
322
  })
323
 
324
- return {"results": results, "total": len(results)}
 
 
 
325
 
326
  # =======================================
327
  # RUN SERVER
 
7
  from fastapi.responses import JSONResponse
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from pydantic import BaseModel
10
+ from typing import Optional, List, Dict, Any
11
  import tempfile
12
  import os
13
+ import json
14
  from pathlib import Path
15
 
16
  from core.scoring_engine import AdvancedVocalScoringSystem, ScoreResult
 
115
  # API ENDPOINTS
116
  # =======================================
117
 
118
+ @app.get("/", response_class=JSONResponse)
119
  async def root():
120
  """Root endpoint"""
121
+ return JSONResponse(
122
+ content={
123
+ "message": "Vocal Articulation Assessment API v2",
124
+ "version": "2.0.0",
125
+ "features": [
126
+ "Whisper ASR-based clarity scoring",
127
+ "Multi-level support (Level 1-5)",
128
+ "6 scoring metrics",
129
+ "Comprehensive audio analysis"
130
+ ],
131
+ "endpoints": {
132
+ "health": "/health",
133
+ "levels": "/levels",
134
+ "score": "/score",
135
+ "batch_score": "/batch_score",
136
+ "docs": "/docs"
137
+ }
138
+ },
139
+ media_type="application/json"
140
+ )
141
 
142
  @app.get("/health", response_model=HealthResponse)
143
  async def health_check():
 
157
  total_levels=len(ARTICULATION_LEVELS)
158
  )
159
 
160
+ @app.post("/score", response_class=JSONResponse)
161
  async def score_audio(
162
  audio: UploadFile = File(..., description="Audio file (WAV, MP3, M4A, etc.)"),
163
  target_text: str = Form(..., description="Target text yang seharusnya diucapkan"),
 
208
  # Clean up temp file
209
  os.unlink(tmp_path)
210
 
211
+ # Convert result to dict and ensure proper serialization
212
+ response_data = {
213
+ "success": True,
214
+ "overall_score": float(result.overall_score),
215
+ "grade": str(result.grade),
216
+ "clarity_score": float(result.clarity_score),
217
+ "energy_score": float(result.energy_score),
218
+ "speech_rate_score": float(result.speech_rate_score),
219
+ "pitch_consistency_score": float(result.pitch_consistency_score),
220
+ "snr_score": float(result.snr_score),
221
+ "articulation_score": float(result.articulation_score),
222
+ "transcription": str(result.transcription),
223
+ "target": str(result.target),
224
+ "similarity": float(result.similarity),
225
+ "wer": float(result.wer),
226
+ "feedback": str(result.feedback),
227
+ "suggestions": [str(s) for s in result.suggestions],
228
+ "audio_features": {k: (float(v) if isinstance(v, (int, float)) else str(v)) for k, v in result.audio_features.items()},
229
+ "level": int(result.level)
230
+ }
231
+
232
+ # Return with explicit JSON response
233
+ return JSONResponse(
234
+ content=response_data,
235
+ media_type="application/json"
236
  )
237
 
238
  except Exception as e:
 
300
  # Clean up
301
  os.unlink(tmp_path)
302
 
303
+ # Properly serialize result
304
  results.append({
305
  "filename": audio.filename,
306
  "success": True,
307
+ "overall_score": float(result.overall_score),
308
+ "grade": str(result.grade),
309
+ "clarity_score": float(result.clarity_score),
310
+ "energy_score": float(result.energy_score),
311
+ "speech_rate_score": float(result.speech_rate_score),
312
+ "pitch_consistency_score": float(result.pitch_consistency_score),
313
+ "snr_score": float(result.snr_score),
314
+ "articulation_score": float(result.articulation_score),
315
+ "transcription": str(result.transcription),
316
+ "target": str(result.target),
317
+ "similarity": float(result.similarity),
318
+ "wer": float(result.wer),
319
+ "feedback": str(result.feedback),
320
+ "suggestions": [str(s) for s in result.suggestions],
321
+ "audio_features": {k: (float(v) if isinstance(v, (int, float)) else str(v)) for k, v in result.audio_features.items()},
322
+ "level": int(result.level)
323
  })
324
 
325
  except Exception as e:
 
332
  "error": str(e)
333
  })
334
 
335
+ return JSONResponse(
336
+ content={"results": results, "total": len(results)},
337
+ media_type="application/json"
338
+ )
339
 
340
  # =======================================
341
  # RUN SERVER