Files
notebook-tools/src/notebook_tools/api.py

75 lines
2.3 KiB
Python

"""FastAPI application entrypoint.
This file is intentionally small:
- Routes call into a job manager.
- The job manager calls the pipeline.
Keeping the web layer thin makes the business logic easier to test and maintain.
"""
from __future__ import annotations
import logging
from fastapi import BackgroundTasks, Depends, FastAPI, HTTPException
from notebook_tools.jobs import JobManager, get_job_manager
from notebook_tools.logging_utils import configure_logging
from notebook_tools.models import JobStartRequest, JobStatusResponse
from notebook_tools.settings import Settings, get_settings
app = FastAPI(title="notebook-tools", version="0.1.0")
logger = logging.getLogger("notebook_tools.api")
@app.on_event("startup")
async def _startup() -> None:
# Load settings once at startup so we fail fast if env vars are missing.
settings = get_settings()
configure_logging(level=settings.log_level)
logger.info("Service starting up")
@app.get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/jobs/paperless/{document_id}", response_model=JobStatusResponse)
async def start_job_for_paperless_document(
document_id: int,
req: JobStartRequest,
background: BackgroundTasks,
settings: Settings = Depends(get_settings),
manager: JobManager = Depends(get_job_manager),
) -> JobStatusResponse:
"""Start an OCR job for an existing Paperless document id."""
if document_id <= 0:
raise HTTPException(status_code=422, detail="document_id must be a positive integer")
job = manager.create_job(document_id=document_id, notebook_id=req.notebook_id)
logger.info(
"Job created job_id=%s paperless_document_id=%s notebook_id=%s",
job.job_id,
document_id,
req.notebook_id,
)
background.add_task(
manager.run_job,
job_id=job.job_id,
settings=settings,
ocr_prompt_override=req.ocr_prompt,
title_prefix=req.title_prefix,
)
return job
@app.get("/jobs/{job_id}", response_model=JobStatusResponse)
async def get_job(job_id: str, manager: JobManager = Depends(get_job_manager)) -> JobStatusResponse:
job = manager.get_job(job_id)
if not job:
raise HTTPException(status_code=404, detail="job not found")
return job