akpande2 commited on
Commit
c5a8295
Β·
verified Β·
1 Parent(s): 1a64a8e

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +44 -32
main.py CHANGED
@@ -6,7 +6,7 @@ from fastapi import FastAPI, UploadFile, File, HTTPException
6
  from fastapi.middleware.cors import CORSMiddleware
7
  from kid_coach_pipeline import KidCoachEngine
8
 
9
- app = FastAPI(title="Kid-Speech Coach API")
10
 
11
  app.add_middleware(
12
  CORSMiddleware,
@@ -15,79 +15,91 @@ app.add_middleware(
15
  allow_headers=["*"],
16
  )
17
 
 
18
  engine = None
19
 
20
  @app.on_event("startup")
21
  async def startup_event():
22
  global engine
23
- # Use 'base' for CPU hosting (Hugging Face Free Tier)
24
- print("πŸš€ Server starting... Loading Whisper Model...")
25
- engine = KidCoachEngine(model_size="base")
26
- print("βœ… Kid Coach Engine Ready!")
 
 
 
 
 
 
 
 
27
 
28
  def convert_to_wav(input_path, output_path):
29
  """
30
- Forces conversion to 16kHz Mono WAV using system FFmpeg.
31
- This fixes issues with M4A/AAC files from iPhones.
32
  """
33
  try:
34
  command = [
35
  "ffmpeg",
36
  "-i", input_path,
37
- "-ar", "16000", # 16kHz sample rate
38
- "-ac", "1", # Mono channel
39
- "-c:a", "pcm_s16le", # Standard WAV codec
40
  output_path,
41
- "-y" # Overwrite if exists
42
  ]
43
- # Run conversion silently
44
  subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
45
  return True
46
  except Exception as e:
47
- print(f"❌ FFmpeg conversion failed: {e}")
48
  return False
49
 
50
  @app.post("/coach")
51
  async def coach_audio(file: UploadFile = File(...)):
 
52
  if not engine:
53
- raise HTTPException(status_code=500, detail="Engine not ready")
54
 
55
- # 1. Save the raw upload (likely .m4a)
56
  raw_filename = f"raw_{file.filename}"
57
  clean_wav_filename = f"clean_{file.filename}.wav"
58
-
59
  try:
 
60
  with open(raw_filename, "wb") as buffer:
61
  shutil.copyfileobj(file.file, buffer)
62
 
63
- # 2. CONVERT to WAV (The Fix)
64
- # This ensures Librosa/Whisper gets a perfect file every time
65
- print(f" πŸ”„ Converting {raw_filename} to WAV...")
66
  success = convert_to_wav(raw_filename, clean_wav_filename)
67
 
68
  if not success:
69
- raise HTTPException(status_code=400, detail="Audio file corrupted or unreadable")
 
 
 
 
70
 
71
- # 3. Analyze the CLEAN WAV file
72
- result = engine.analyze_audio(clean_wav_filename)
73
-
74
  if "error" in result:
75
- # Pass the specific error from the engine back to the app
76
- raise HTTPException(status_code=400, detail=result["error"])
77
-
78
  return result
79
 
80
  except HTTPException as he:
81
  raise he
82
  except Exception as e:
83
- import traceback
84
- traceback.print_exc()
85
- raise HTTPException(status_code=500, detail="Internal Server Error")
86
 
87
  finally:
88
- # 4. Cleanup both files
89
- if os.path.exists(raw_filename): os.remove(raw_filename)
90
- if os.path.exists(clean_wav_filename): os.remove(clean_wav_filename)
 
 
91
 
92
  if __name__ == "__main__":
 
93
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
6
  from fastapi.middleware.cors import CORSMiddleware
7
  from kid_coach_pipeline import KidCoachEngine
8
 
9
+ app = FastAPI(title="Public Speaking Coach API")
10
 
11
  app.add_middleware(
12
  CORSMiddleware,
 
15
  allow_headers=["*"],
16
  )
17
 
18
+ # Global Engine Instance
19
  engine = None
20
 
21
  @app.on_event("startup")
22
  async def startup_event():
23
  global engine
24
+
25
+ # 1. Get Token from Secrets
26
+ hf_token = os.environ.get("HF_TOKEN")
27
+ if not hf_token:
28
+ print("❌ CRITICAL: HF_TOKEN not found in environment variables!")
29
+
30
+ print("πŸš€ Initializing KidCoach Engine (Production Mode)...")
31
+ try:
32
+ engine = KidCoachEngine(hf_token=hf_token)
33
+ print("βœ… Engine Ready! Waiting for audio...")
34
+ except Exception as e:
35
+ print(f"❌ Engine initialization failed: {e}")
36
 
37
  def convert_to_wav(input_path, output_path):
38
  """
39
+ Sanitizes audio for AI processing.
40
+ Converts any input (m4a, mp3, webm) to 16kHz Mono WAV.
41
  """
42
  try:
43
  command = [
44
  "ffmpeg",
45
  "-i", input_path,
46
+ "-ar", "16000", # Standard AI Sample Rate
47
+ "-ac", "1", # Mono
48
+ "-c:a", "pcm_s16le", # Raw WAV
49
  output_path,
50
+ "-y"
51
  ]
 
52
  subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
53
  return True
54
  except Exception as e:
55
+ print(f"❌ FFmpeg error: {e}")
56
  return False
57
 
58
  @app.post("/coach")
59
  async def coach_audio(file: UploadFile = File(...)):
60
+ global engine
61
  if not engine:
62
+ raise HTTPException(status_code=500, detail="AI Engine is not initialized")
63
 
64
+ # 1. Save Raw File
65
  raw_filename = f"raw_{file.filename}"
66
  clean_wav_filename = f"clean_{file.filename}.wav"
67
+
68
  try:
69
+ # Write upload to disk
70
  with open(raw_filename, "wb") as buffer:
71
  shutil.copyfileobj(file.file, buffer)
72
 
73
+ # 2. Convert to Pristine WAV
74
+ print(f"πŸ”„ Processing file: {file.filename}")
 
75
  success = convert_to_wav(raw_filename, clean_wav_filename)
76
 
77
  if not success:
78
+ raise HTTPException(status_code=400, detail="Audio file unreadable. Please upload MP3, WAV, or M4A.")
79
+
80
+ # 3. Run The Full AI Pipeline
81
+ # This calls our robust logic in kid_coach_pipeline.py
82
+ result = engine.process_pipeline(clean_wav_filename)
83
 
 
 
 
84
  if "error" in result:
85
+ print(f"Pipeline Error: {result['error']}")
86
+ raise HTTPException(status_code=500, detail=result["error"])
87
+
88
  return result
89
 
90
  except HTTPException as he:
91
  raise he
92
  except Exception as e:
93
+ print(f"Server Error: {e}")
94
+ raise HTTPException(status_code=500, detail="Internal Processing Error")
 
95
 
96
  finally:
97
+ # 4. Cleanup temp files to save disk space
98
+ if os.path.exists(raw_filename):
99
+ os.remove(raw_filename)
100
+ if os.path.exists(clean_wav_filename):
101
+ os.remove(clean_wav_filename)
102
 
103
  if __name__ == "__main__":
104
+ # Hugging Face Spaces expects port 7860
105
  uvicorn.run(app, host="0.0.0.0", port=7860)