fc / apps /pdf_splitting /api /pdf_splitting_api.py
jun2024's picture
Upload 2241 files
b4f2238 verified
Raw History Blame Contribute Delete
5.08 kB
from __future__ import annotations
from typing import Any
from uuid import UUID
from django.http import FileResponse, HttpResponse
from ninja import File, Form, Router
from ninja.files import UploadedFile
from pydantic import BaseModel, Field
from apps.pdf_splitting.services import PdfSplitJobService, PdfSplitService
from apps.pdf_splitting.services.storage import PdfSplitStorage
router = Router(tags=["PDF 拆解"])
class SegmentOut(BaseModel):
id: int
order: int
page_start: int
page_end: int
segment_type: str
segment_label: str
filename: str
confidence: float
review_flag: str
review_flag_label: str
source_method: str
class JobOut(BaseModel):
job_id: str
status: str
split_mode: str
ocr_profile: str
progress: int
total_pages: int
processed_pages: int
current_page: int
summary: dict[str, Any]
segments: list[SegmentOut]
download_url: str = ""
pdf_url: str = ""
error_message: str = ""
class JobSubmitOut(BaseModel):
job_id: str = Field(..., description="任务ID")
status: str = Field(..., description="状态")
class ConfirmSegmentIn(BaseModel):
id: int | None = None
order: int | None = None
page_start: int
page_end: int
segment_type: str
filename: str
confidence: float | None = 0.0
review_flag: str | None = None
source_method: str | None = None
class ConfirmRequestIn(BaseModel):
segments: list[ConfirmSegmentIn]
@router.post("/jobs", response=JobSubmitOut)
def create_pdf_split_job(
request: Any,
file: UploadedFile | None = File(None), # type: ignore[type-arg]
source_path: str | None = Form(None), # type: ignore[type-arg]
template_key: str = Form("filing_materials_v1"), # type: ignore[type-arg]
split_mode: str = Form("content_analysis"), # type: ignore[type-arg]
ocr_profile: str = Form("balanced"), # type: ignore[type-arg]
) -> JobSubmitOut:
job = PdfSplitJobService().create_job(
file=file,
source_path=source_path,
template_key=template_key,
split_mode=split_mode,
ocr_profile=ocr_profile,
created_by=getattr(request, "user", None),
)
return JobSubmitOut(job_id=str(job.id), status=job.status)
@router.get("/jobs/{job_id}", response=JobOut)
def get_pdf_split_job(request: Any, job_id: UUID) -> JobOut:
job = PdfSplitJobService().get_job(job_id)
payload = PdfSplitJobService().build_job_payload(job)
return JobOut(**payload)
@router.get("/jobs/{job_id}/pages/{page_no}/preview")
def get_pdf_split_preview(request: Any, job_id: UUID, page_no: int) -> HttpResponse:
job = PdfSplitJobService().get_job(job_id)
preview_path = PdfSplitService().render_preview(job, page_no)
return FileResponse(preview_path.open("rb"), content_type="image/png", filename=preview_path.name)
@router.post("/jobs/{job_id}/confirm", response=JobSubmitOut)
def confirm_pdf_split_job(request: Any, job_id: UUID, payload: ConfirmRequestIn) -> JobSubmitOut:
job = PdfSplitJobService().confirm_segments(job_id=job_id, items=[item.model_dump() for item in payload.segments])
return JobSubmitOut(job_id=str(job.id), status=job.status)
@router.post("/jobs/{job_id}/cancel", response=JobSubmitOut)
def cancel_pdf_split_job(request: Any, job_id: UUID) -> JobSubmitOut:
job = PdfSplitJobService().request_cancel(job_id=job_id)
return JobSubmitOut(job_id=str(job.id), status=job.status)
@router.get("/jobs/{job_id}/download")
def get_pdf_split_download(request: Any, job_id: UUID) -> HttpResponse:
job = PdfSplitJobService().get_job(job_id)
storage = PdfSplitStorage(job.id)
if not storage.export_zip_path.exists():
return HttpResponse(status=404)
return FileResponse(storage.export_zip_path.open("rb"), content_type="application/zip", filename="split_result.zip")
@router.get("/jobs/{job_id}/pdf")
def get_pdf_split_raw(request: Any, job_id: UUID) -> HttpResponse:
"""获取原始 PDF 二进制流,供 PDF.js 在浏览器中渲染"""
job = PdfSplitJobService().get_job(job_id)
storage = PdfSplitStorage(job.id)
if not storage.source_pdf_path.exists():
return HttpResponse(status=404)
return FileResponse(
storage.source_pdf_path.open("rb"),
content_type="application/pdf",
filename=job.source_original_name or "document.pdf",
)
@router.get("/jobs/{job_id}/preview-page")
def get_pdf_preview_page(
request: Any,
job_id: UUID,
start_page: int = 1,
end_page: int = 1,
filename: str = "片段",
) -> HttpResponse:
"""返回PDF预览页面(HTML)"""
from django.shortcuts import render
job = PdfSplitJobService().get_job(job_id)
storage = PdfSplitStorage(job.id)
pdf_url = f"/api/v1/pdf-splitting/jobs/{job_id}/pdf"
return render(
request,
"admin/pdf_splitting/pdf_preview.html",
{
"pdf_url": pdf_url,
"start_page": start_page,
"end_page": end_page,
"filename": filename,
},
)