feat(T03): OCR-Erfassung via OpenRouter Qwen2.5-VL + OCR UI with drag-and-drop
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
"""SQLAlchemy model for OCR results."""
|
||||
|
||||
import enum
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import DateTime, Enum, Float, ForeignKey, String, Text, func
|
||||
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class OCRStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
processing = "processing"
|
||||
completed = "completed"
|
||||
failed = "failed"
|
||||
manual_review = "manual_review"
|
||||
|
||||
|
||||
class OCRResult(Base):
|
||||
"""OCR result entity linked to a vehicle (optional) and an uploaded scan file."""
|
||||
|
||||
__tablename__ = "ocr_results"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
primary_key=True,
|
||||
default=uuid.uuid4,
|
||||
)
|
||||
vehicle_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("vehicles.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
file_path: Mapped[str] = mapped_column(String(512), nullable=False)
|
||||
file_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
mime_type: Mapped[str] = mapped_column(String(100), nullable=False, default="image/png")
|
||||
status: Mapped[str] = mapped_column(
|
||||
Enum(OCRStatus, name="ocr_status", create_constraint=True),
|
||||
nullable=False,
|
||||
default=OCRStatus.pending,
|
||||
index=True,
|
||||
)
|
||||
raw_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
structured_data: Mapped[dict[str, Any] | None] = mapped_column(
|
||||
JSONB,
|
||||
nullable=True,
|
||||
)
|
||||
confidence_score: Mapped[float | None] = mapped_column(
|
||||
Float,
|
||||
nullable=True,
|
||||
)
|
||||
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
)
|
||||
|
||||
vehicle = relationship("Vehicle", backref="ocr_results")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<OCRResult id={self.id} status={self.status}>"
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Serialize OCR result for API responses."""
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"vehicle_id": str(self.vehicle_id) if self.vehicle_id else None,
|
||||
"file_path": self.file_path,
|
||||
"file_name": self.file_name,
|
||||
"mime_type": self.mime_type,
|
||||
"status": self.status.value if isinstance(self.status, OCRStatus) else str(self.status),
|
||||
"raw_text": self.raw_text,
|
||||
"structured_data": self.structured_data,
|
||||
"confidence_score": self.confidence_score,
|
||||
"error_message": self.error_message,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
||||
}
|
||||
Reference in New Issue
Block a user