diff --git a/backend/app/main.py b/backend/app/main.py index f10e1a5..8ecf813 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,11 +1,18 @@ from contextlib import asynccontextmanager -from fastapi import Depends, FastAPI, HTTPException +from fastapi import Depends, FastAPI, File, HTTPException, UploadFile from fastapi.middleware.cors import CORSMiddleware from sqlalchemy.orm import Session from .database import Base, engine, get_db from . import models, schemas from .curriculum import QUESTIONS -from .services import build_llm_reply, ensure_student_mastery, evaluate_answer, pick_next_skill, seed_skills +from .services import ( + build_llm_reply, + ensure_student_mastery, + evaluate_answer, + pick_next_skill, + seed_skills, + transcribe_audio, +) @asynccontextmanager @@ -21,8 +28,6 @@ async def lifespan(app: FastAPI): app = FastAPI(title="Professeur Virtuel API", version="0.1.0", lifespan=lifespan) -from fastapi.middleware.cors import CORSMiddleware - app.add_middleware( CORSMiddleware, allow_origins=[ @@ -87,6 +92,23 @@ def chat(payload: schemas.ChatRequest, db: Session = Depends(get_db)): return schemas.ChatResponse(reply=reply) +@app.post("/transcribe") +async def transcribe(file: UploadFile = File(...)): + if not file.filename: + raise HTTPException(status_code=400, detail="Fichier audio manquant") + + audio_bytes = await file.read() + if not audio_bytes: + raise HTTPException(status_code=400, detail="Fichier audio vide") + + try: + text = transcribe_audio(file.filename, audio_bytes, file.content_type) + except Exception as exc: + raise HTTPException(status_code=502, detail=f"Erreur de transcription: {exc}") from exc + + return {"text": text} + + @app.get("/progress/{student_id}", response_model=schemas.ProgressResponse) def get_progress(student_id: int, db: Session = Depends(get_db)): student = db.query(models.Student).filter_by(id=student_id).first() diff --git a/backend/app/services.py b/backend/app/services.py index 2ef0cc2..da1f374 100644 --- a/backend/app/services.py +++ b/backend/app/services.py @@ -88,6 +88,15 @@ def build_llm_reply(db: Session, student_id: int, user_message: str) -> str: return response.output_text.strip() +def transcribe_audio(filename: str, audio_bytes: bytes, content_type: str | None = None) -> str: + file_payload = (filename, audio_bytes, content_type or "application/octet-stream") + transcript = client.audio.transcriptions.create( + model="gpt-4o-mini-transcribe", + file=file_payload, + ) + return (getattr(transcript, "text", "") or "").strip() + + def pick_next_skill(db: Session, student_id: int) -> models.Skill: weakest = ( db.query(models.StudentSkillMastery) diff --git a/backend/requirements.txt b/backend/requirements.txt index 829452c..bf7c8ea 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -4,6 +4,7 @@ sqlalchemy==2.0.40 psycopg2-binary==2.9.10 pydantic==2.10.6 python-dotenv==1.0.1 +python-multipart==0.0.20 openai==1.72.0 redis==5.2.1 alembic==1.15.2