Skip to content

Resume Routes

route

Resume upload and management API routes.

This module provides protected API endpoints for uploading resumes, listing user resumes, and deleting resumes. All routes require authentication and appropriate OAuth scopes.

Classes

Functions

create_resume async
create_resume(
    request, file=File(...), db=Depends(get_session)
)

Upload and process a resume file.

Accepts a resume file (PDF supported), extracts text, runs it through the extraction agent to get structured data, and stores both the file and metadata.

Parameters:

Name Type Description Default
request Request

FastAPI request object (contains auth_info in state).

required
file UploadFile

Uploaded resume file (must be PDF).

File(...)
db AsyncSession

Database session dependency.

Depends(get_session)

Returns:

Type Description
dict[str, Any]

Dictionary containing extracted resume data (ExtractionAgentResponse).

Raises:

Type Description
HTTPException

400 if file type is unsupported or processing fails.

Source code in bitonicai/routes/vb1/protected/resume/route.py
@resume_router.post("/upload")
@require_scopes(["upload:resume"])
async def create_resume(
    request: Request, file: UploadFile = File(...), db: AsyncSession = Depends(get_session)
) -> dict[str, Any]:
    """Upload and process a resume file.

    Accepts a resume file (PDF supported), extracts text, runs it through
    the extraction agent to get structured data, and stores both the file
    and metadata.

    Args:
        request: FastAPI request object (contains auth_info in state).
        file: Uploaded resume file (must be PDF).
        db: Database session dependency.

    Returns:
        Dictionary containing extracted resume data (ExtractionAgentResponse).

    Raises:
        HTTPException: 400 if file type is unsupported or processing fails.
    """
    type = file.content_type
    file_bytes = await file.read()
    await file.seek(0)
    if type not in supported_file_types:
        raise HTTPException(status_code=400, detail="Unsupported file type")
    if type == "application/pdf":
        text = await process_pdf(file_bytes)
    elif type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
        # text = await process_word_document(file_bytes)
        raise HTTPException(status_code=400, detail="Unsupported file type")
    else:
        raise HTTPException(status_code=400, detail="Unsupported file type")
    await save_file(request.state.auth_info.sub, file_bytes, file.filename, db)
    extraction_agent = ExtractionAgent(session_id=str(uuid4()))
    session = SQLModelSession.from_url(
        session_id=extraction_agent.session_id, url=os.getenv("DATABASE_URL")
    )
    response = await Runner.run(extraction_agent, text, session=session)
    model_output = response.final_output
    # final_output_as returns a Pydantic model instance, convert to dict for FastAPI
    return model_output.model_dump()
list_resumes async
list_resumes(request, db=Depends(get_session))

List all resumes for the authenticated user.

Parameters:

Name Type Description Default
request Request

FastAPI request object (contains auth_info in state).

required
db AsyncSession

Database session dependency.

Depends(get_session)

Returns:

Type Description
dict[str, list[str]]

Dictionary with "resumes" key containing list of file paths.

Source code in bitonicai/routes/vb1/protected/resume/route.py
@resume_router.get("/list")
@require_scopes(["read:resume"])
async def list_resumes(
    request: Request, db: AsyncSession = Depends(get_session)
) -> dict[str, list[str]]:
    """List all resumes for the authenticated user.

    Args:
        request: FastAPI request object (contains auth_info in state).
        db: Database session dependency.

    Returns:
        Dictionary with "resumes" key containing list of file paths.
    """
    resumes = await db.exec(select(Resume).where(Resume.user_id == request.state.auth_info.sub))
    return {"resumes": [resume.file_path for resume in resumes.all()]}
delete_all_resumes async
delete_all_resumes(request, db=Depends(get_session))

Delete all resumes for the authenticated user.

Removes both database records and files from S3 storage.

Parameters:

Name Type Description Default
request Request

FastAPI request object (contains auth_info in state).

required
db AsyncSession

Database session dependency.

Depends(get_session)

Returns:

Type Description
dict[str, str]

Dictionary with success message.

Source code in bitonicai/routes/vb1/protected/resume/route.py
@resume_router.delete("/all")
@require_scopes(["delete:resume"])
async def delete_all_resumes(
    request: Request, db: AsyncSession = Depends(get_session)
) -> dict[str, str]:
    """Delete all resumes for the authenticated user.

    Removes both database records and files from S3 storage.

    Args:
        request: FastAPI request object (contains auth_info in state).
        db: Database session dependency.

    Returns:
        Dictionary with success message.
    """
    s3_tool = S3Tool()
    resumes = await db.exec(select(Resume).where(Resume.user_id == request.state.auth_info.sub))
    for resume in resumes.all():
        s3_tool.delete_file(garage_settings.bucket_name, resume.file_path)
        await db.delete(resume)
    await db.commit()
    s3_tool.close()
    return {"message": "All resumes deleted successfully"}