from __future__ import annotations from dataclasses import dataclass, field, asdict from pathlib import Path from typing import Any, Literal import json, time, uuid OperationType = Literal[ "insert_text","whiteout_region","rotate_page","delete_page", "reorder_pages","highlight","comment","rectangle","redact" ] @dataclass class PDFOperation: type: OperationType page: int | None = None rect: tuple | None = None text: str | None = None position: tuple | None = None color: tuple | None = None pages: list | None = None rotation: int | None = None author: str = "Local PDF AI Orchestrator" metadata: dict = field(default_factory=dict) @dataclass class InspectionReport: page_count: int metadata: dict pages: list ocr_required_pages: list has_text: bool has_images: bool @dataclass class JobConfig: input_pdf: Path output_dir: Path run_ocr: bool = False force_ocr: bool = False ocr_language: str = "eng" pipeline: str = "full_document" operations: list = field(default_factory=list) job_id: str = field(default_factory=lambda: uuid.uuid4().hex) keep_intermediate: bool = True @dataclass class JobResult: job_id: str success: bool final_pdf: Path | None log_file: Path manifest_file: Path stages: list errors: list = field(default_factory=list) def to_json(self) -> str: return json.dumps({ "job_id": self.job_id, "success": self.success, "final_pdf": str(self.final_pdf) if self.final_pdf else None, "log_file": str(self.log_file), "manifest_file": str(self.manifest_file), "stages": self.stages, "errors": self.errors, }, indent=2) def dataclass_to_dict(obj: Any) -> dict: def convert(v): if isinstance(v, Path): return str(v) if isinstance(v, dict): return {k: convert(x) for k, x in v.items()} if isinstance(v, list): return [convert(x) for x in v] return v return {k: convert(v) for k, v in asdict(obj).items()}