63 lines
2.0 KiB
Python
63 lines
2.0 KiB
Python
import os
|
|
from pathlib import Path
|
|
from typing import Any, Dict
|
|
|
|
from fastapi import Depends, FastAPI, HTTPException, Path as ApiPath
|
|
|
|
from .models import SentenceBoundaryDocument
|
|
from .store import BoundaryStore
|
|
|
|
|
|
DEFAULT_INDEX_PATH = Path(__file__).resolve().parent / "data" / "sentence_boundaries.json"
|
|
|
|
|
|
def create_app(store: BoundaryStore = None) -> FastAPI:
|
|
application = FastAPI(
|
|
title="Oral Trainer Sentence Boundary API",
|
|
version="1.0.0",
|
|
description="Looks up pre-generated sentence boundaries by video SHA-256.",
|
|
)
|
|
index_path = Path(os.getenv("SENTENCE_BOUNDARIES_FILE", str(DEFAULT_INDEX_PATH)))
|
|
application.state.boundary_store = store or BoundaryStore(index_path)
|
|
|
|
def get_store() -> BoundaryStore:
|
|
return application.state.boundary_store
|
|
|
|
@application.get("/healthz")
|
|
def healthz(boundary_store: BoundaryStore = Depends(get_store)) -> Dict[str, Any]:
|
|
return {"status": "ok", "video_count": boundary_store.count()}
|
|
|
|
@application.get(
|
|
"/api/v1/videos/{video_hash}/sentence-boundaries",
|
|
response_model=SentenceBoundaryDocument,
|
|
)
|
|
@application.get(
|
|
"/api/v1/sentence-boundaries/{video_hash}",
|
|
response_model=SentenceBoundaryDocument,
|
|
include_in_schema=False,
|
|
)
|
|
def get_sentence_boundaries(
|
|
video_hash: str = ApiPath(
|
|
min_length=64,
|
|
max_length=64,
|
|
pattern=r"^[A-Fa-f0-9]{64}$",
|
|
description="SHA-256 hex digest of the exact video bytes",
|
|
),
|
|
boundary_store: BoundaryStore = Depends(get_store),
|
|
) -> SentenceBoundaryDocument:
|
|
document = boundary_store.get(video_hash)
|
|
if document is None:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail={
|
|
"code": "SENTENCE_BOUNDARIES_NOT_FOUND",
|
|
"message": "No sentence boundaries are registered for this video hash.",
|
|
},
|
|
)
|
|
return document
|
|
|
|
return application
|
|
|
|
|
|
app = create_app()
|