From d8e31d0d9c39dc48b4323efed0a8a49bb2da7729 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sat, 28 Mar 2026 14:57:10 -0700 Subject: [PATCH] =?UTF-8?q?feat(imajin-classifier):=20=E2=9C=A8=20Add=20Py?= =?UTF-8?q?dantic=20schemas=20for=20image=20classification=20and=20update?= =?UTF-8?q?=20exports=20for=20enhanced=20validation=20and=20new=20capabili?= =?UTF-8?q?ties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../service/src/models/__init__.py | 16 +++-- .../service/src/models/schemas.py | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/services/imajin-classifier/service/src/models/__init__.py b/services/imajin-classifier/service/src/models/__init__.py index abaa1678..00e0f367 100644 --- a/services/imajin-classifier/service/src/models/__init__.py +++ b/services/imajin-classifier/service/src/models/__init__.py @@ -1,10 +1,14 @@ """Data models for imajin-classifier service.""" from .schemas import ( + AgreementPair, CalibrateRequest, CalibrateResult, + ClassifierResult, ClassifyRequest, ClassifyResult, + CompareRequest, + CompareResult, DimensionCalibration, DimensionDef, LabeledSample, @@ -13,13 +17,17 @@ from .schemas import ( ) __all__ = [ - "DimensionDef", - "ClassifyRequest", - "ClassifyResult", - "LabeledSample", + "AgreementPair", "CalibrateRequest", "CalibrateResult", + "ClassifierResult", + "ClassifyRequest", + "ClassifyResult", + "CompareRequest", + "CompareResult", "DimensionCalibration", + "DimensionDef", + "LabeledSample", "PresetInfo", "PresetsResult", ] diff --git a/services/imajin-classifier/service/src/models/schemas.py b/services/imajin-classifier/service/src/models/schemas.py index 0a5fc1b1..9ae171a1 100644 --- a/services/imajin-classifier/service/src/models/schemas.py +++ b/services/imajin-classifier/service/src/models/schemas.py @@ -226,3 +226,64 @@ class PresetsResult(BaseModel): """List of available scoring presets.""" presets: list[PresetInfo] + + +# --------------------------------------------------------------------------- +# /compare +# --------------------------------------------------------------------------- + +AVAILABLE_CLASSIFIERS = [ + "imajin-siglip2", + "claude-haiku", + "claude-sonnet", + "claude-opus", +] + + +class CompareRequest(BaseModel): + """Request to score an image with multiple classifiers and compare results.""" + + image_base64: str = Field( + ..., + max_length=50_000_000, + description="Base64-encoded image data", + ) + preset: Optional[str] = Field( + None, + description="Preset rubric name. Required if no inline dimensions.", + ) + dimensions: Optional[dict[str, DimensionDef]] = Field( + None, + description="Inline dimension definitions.", + ) + context: dict[str, str] = Field( + default_factory=dict, + description="Context for preset resolution", + ) + classifiers: list[str] = Field( + default_factory=lambda: ["imajin-siglip2", "claude-sonnet"], + description=f"Which classifiers to run. Options: {', '.join(AVAILABLE_CLASSIFIERS)}", + ) + + +class ClassifierResult(BaseModel): + """Scores from a single classifier.""" + + scores: dict[str, float] + processing_time_ms: float + error: Optional[str] = None + + +class AgreementPair(BaseModel): + """Pairwise agreement between two classifiers.""" + + pearson_r: float + mean_delta: float + + +class CompareResult(BaseModel): + """Side-by-side comparison of multiple classifiers on the same image.""" + + results: dict[str, ClassifierResult] + agreement_matrix: dict[str, AgreementPair] + total_processing_time_ms: float