mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-18 21:08:07 +00:00
114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
"""Video transcript endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, File, Form, Header, HTTPException, Query, UploadFile
|
|
|
|
from server.models.schemas import VideoJob, VideoSearchHit, VideoSubmitRequest, VideoTranscript, VideoTranslation
|
|
from server.services.video_transcript_service import (
|
|
delete_job,
|
|
get_job_detail,
|
|
list_jobs,
|
|
search_jobs,
|
|
submit_job,
|
|
submit_upload,
|
|
translate_job_content,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _resolve_api_key(header_value: str | None) -> str | None:
|
|
return (header_value or "").strip() or None
|
|
|
|
|
|
@router.post("/submit", response_model=VideoJob, summary="Submit a video or audio transcript job")
|
|
async def submit_video_job(
|
|
body: VideoSubmitRequest,
|
|
x_gemini_api_key: str | None = Header(default=None),
|
|
) -> VideoJob:
|
|
job_id = await submit_job(
|
|
body.url,
|
|
body.source_type,
|
|
language=body.language,
|
|
api_key=_resolve_api_key(x_gemini_api_key),
|
|
)
|
|
detail = await get_job_detail(job_id)
|
|
if detail is None:
|
|
raise HTTPException(status_code=500, detail="Failed to create transcript job.")
|
|
return VideoJob(**detail["job"])
|
|
|
|
|
|
@router.post("/upload", response_model=VideoJob, summary="Upload local media and start transcript extraction")
|
|
async def upload_video_file(
|
|
file: UploadFile = File(...),
|
|
language: str | None = Form(default=None),
|
|
x_gemini_api_key: str | None = Header(default=None),
|
|
) -> VideoJob:
|
|
job_id = await submit_upload(
|
|
file,
|
|
language=language,
|
|
api_key=_resolve_api_key(x_gemini_api_key),
|
|
)
|
|
detail = await get_job_detail(job_id)
|
|
if detail is None:
|
|
raise HTTPException(status_code=500, detail="Failed to create transcript job.")
|
|
return VideoJob(**detail["job"])
|
|
|
|
|
|
@router.get("/jobs", response_model=list[VideoJob], summary="List recent transcript jobs")
|
|
async def video_jobs(limit: int = Query(50, ge=1, le=200)) -> list[VideoJob]:
|
|
rows = await list_jobs(limit=limit)
|
|
return [VideoJob(**row) for row in rows]
|
|
|
|
|
|
@router.get("/jobs/{job_id}", summary="Get transcript job details")
|
|
async def video_job_detail(job_id: str) -> dict[str, VideoJob | VideoTranscript | None]:
|
|
payload = await get_job_detail(job_id)
|
|
if payload is None:
|
|
raise HTTPException(status_code=404, detail="Transcript job not found.")
|
|
transcript = payload["transcript"]
|
|
return {
|
|
"job": VideoJob(**payload["job"]),
|
|
"transcript": None if transcript is None else VideoTranscript(**transcript),
|
|
}
|
|
|
|
|
|
@router.post("/jobs/{job_id}/translate", response_model=VideoTranslation, summary="Translate a stored transcript on demand")
|
|
async def translate_video_job(
|
|
job_id: str,
|
|
x_gemini_api_key: str | None = Header(default=None),
|
|
target_language: str = Query("ko", pattern="^[a-z]{2}$"),
|
|
) -> VideoTranslation:
|
|
try:
|
|
payload = await translate_job_content(
|
|
job_id,
|
|
target_language=target_language,
|
|
api_key=_resolve_api_key(x_gemini_api_key),
|
|
)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
except RuntimeError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
|
|
if payload is None:
|
|
raise HTTPException(status_code=404, detail="Transcript job not found.")
|
|
return VideoTranslation(**payload)
|
|
|
|
|
|
@router.get("/search", response_model=list[VideoSearchHit], summary="Full-text search saved transcripts")
|
|
async def search_transcripts(
|
|
q: str = Query(..., min_length=1, description="Query text"),
|
|
limit: int = Query(20, ge=1, le=100),
|
|
) -> list[VideoSearchHit]:
|
|
rows = await search_jobs(q, limit=limit)
|
|
return [VideoSearchHit(**row) for row in rows]
|
|
|
|
|
|
@router.delete("/jobs/{job_id}", summary="Delete a transcript job")
|
|
async def delete_video_job(job_id: str) -> dict[str, object]:
|
|
deleted = await delete_job(job_id)
|
|
if not deleted:
|
|
raise HTTPException(status_code=404, detail="Transcript job not found.")
|
|
return {"job_id": job_id, "deleted": True}
|