Spaces:
Sleeping
Sleeping
| import json | |
| import uvicorn | |
| from typing import Optional | |
| from fastapi import FastAPI, UploadFile, File, Form, HTTPException | |
| from fastapi.responses import JSONResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| # Absolute imports from the project structure | |
| from core.stt_service import STTService | |
| from core.processing import parse_transcript_into_qa | |
| from core.gemini_service import score_interview, postprocess_transcript | |
| from core.resume_service import get_text_from_file, score_resume_with_gemini, extract_info_from_resume | |
| from examples.mock_data import mock_qa_pairs, mock_job_description, mock_rubric_content | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| app = FastAPI( | |
| title="Intelcruit API", | |
| description="API for AI-powered interview and resume analysis.", | |
| version="0.2.0" | |
| ) | |
| # --- CORS Middleware --- | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], # Allow all origins for development | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"] | |
| ) | |
| def read_root(): | |
| return {"message": "Welcome to the Intelcruit AI Scoring Engine"} | |
| async def analyze_mock_interview(): | |
| """ | |
| Analyzes an interview using mock data. This is useful for testing the scoring | |
| and processing logic without needing a live audio file. | |
| """ | |
| try: | |
| print("--- USING MOCK DATA FOR ANALYSIS ---") | |
| qa_pairs = mock_qa_pairs | |
| jd_to_use = mock_job_description | |
| rubric_to_use = mock_rubric_content | |
| if not qa_pairs: | |
| raise HTTPException(status_code=400, detail="Mock Q&A pairs are empty.") | |
| scoring_results = score_interview(qa_pairs, jd_to_use, rubric_to_use) | |
| return { | |
| "message": "Mock analysis complete.", | |
| "filename": "mock_audio.mp3", | |
| "results": scoring_results | |
| } | |
| except HTTPException as e: | |
| # Re-raise HTTPException to let FastAPI handle it | |
| raise e | |
| except Exception as e: | |
| print(f"An unexpected error occurred during mock analysis: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def analyze_interview( | |
| job_description: str = Form(...), | |
| rubric_content: str = Form(...), | |
| audio_file: Optional[UploadFile] = File(None), | |
| transcript_content: Optional[str] = Form(None) | |
| ): | |
| """ | |
| Analyzes a live interview from an audio file or a provided transcript. | |
| It transcribes the audio (if provided), parses it into Q&A pairs, | |
| and then scores it against the provided job description and rubric. | |
| """ | |
| try: | |
| jd_to_use = job_description | |
| rubric_to_use = rubric_content | |
| if audio_file: | |
| print("--- PROCESSING LIVE AUDIO FILE ---") | |
| audio_bytes = await audio_file.read() | |
| mimetype = audio_file.content_type | |
| stt_service = STTService() | |
| transcript, deepgram_response = await stt_service.transcribe_audio(audio_bytes, mimetype) | |
| cleaned_transcript = transcript # Using raw transcript for now | |
| elif transcript_content: | |
| print("--- PROCESSING PROVIDED TRANSCRIPT ---") | |
| cleaned_transcript = transcript_content | |
| else: | |
| raise HTTPException(status_code=400, detail="Either audio_file or transcript_content must be provided.") | |
| if not cleaned_transcript: | |
| raise HTTPException(status_code=500, detail="Transcript is empty after processing.") | |
| qa_pairs = parse_transcript_into_qa(cleaned_transcript) | |
| if not qa_pairs: | |
| raise HTTPException(status_code=400, detail="Could not parse any Q&A pairs from the transcript.") | |
| scoring_results = score_interview(qa_pairs, jd_to_use, rubric_to_use) | |
| return { | |
| "message": "Analysis complete.", | |
| "filename": audio_file.filename if audio_file else "transcript_input", # Adjust filename based on input | |
| "results": scoring_results | |
| } | |
| except HTTPException as e: | |
| raise e | |
| except Exception as e: | |
| print(f"Unhandled exception in /analyze/: {e}") | |
| return JSONResponse(status_code=500, content={"error": f"An unexpected error occurred: {str(e)}"}) | |
| async def extract_resume_endpoint(resume_file: UploadFile = File(...)): | |
| try: | |
| print(f"Received resume for extraction: {resume_file.filename}") | |
| file_bytes = await resume_file.read() | |
| resume_text = get_text_from_file(file_bytes, resume_file.content_type) | |
| if resume_text is None: | |
| return JSONResponse(status_code=400, content={"error": "Could not extract text from the resume. The file might be corrupted or in an unsupported format."}) | |
| extracted_data = extract_info_from_resume(resume_text) | |
| if "error" in extracted_data: | |
| return JSONResponse(status_code=500, content=extracted_data) | |
| return JSONResponse(content=extracted_data) | |
| except Exception as e: | |
| print(f"Error in /extract_from_resume/ endpoint: {e}") | |
| return JSONResponse(status_code=500, content={"error": f"An unexpected error occurred: {str(e)}"}) | |
| async def analyze_resume( | |
| resume_file: UploadFile = File(...), | |
| job_description: str = Form(...) | |
| ): | |
| try: | |
| if not resume_file or not job_description: | |
| raise HTTPException(status_code=400, detail="Resume file and job description are required.") | |
| resume_bytes = await resume_file.read() | |
| mimetype = resume_file.content_type | |
| resume_text = get_text_from_file(resume_bytes, mimetype) | |
| if resume_text is None or not resume_text.strip(): | |
| raise HTTPException(status_code=400, detail=f"Could not extract text from the uploaded file: {resume_file.filename}. The file might be empty, corrupted, or an unsupported format.") | |
| scoring_results = score_resume_with_gemini(resume_text, job_description) | |
| if "error" in scoring_results: | |
| raise HTTPException(status_code=500, detail=scoring_results["error"]) | |
| return { | |
| "message": "Resume analysis complete.", | |
| "filename": resume_file.filename, | |
| "results": scoring_results | |
| } | |
| except HTTPException as e: | |
| raise e | |
| except Exception as e: | |
| print(f"An unexpected error occurred during resume analysis: {e}") | |
| raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}") | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=8000) | |