mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
classifier
This commit is contained in:
parent
c9a9620527
commit
0febf0e6d5
4 changed files with 30 additions and 10 deletions
|
|
@ -5,8 +5,8 @@ from enum import Enum
|
||||||
from typing import Any, Optional, TypeVar
|
from typing import Any, Optional, TypeVar
|
||||||
|
|
||||||
from infrastructure.column_classifier import (
|
from infrastructure.column_classifier import (
|
||||||
|
BaseColumnClassifier,
|
||||||
ClassificationError,
|
ClassificationError,
|
||||||
ColumnClassifier,
|
|
||||||
)
|
)
|
||||||
from infrastructure.chatgpt.chatgpt import ChatGPT
|
from infrastructure.chatgpt.chatgpt import ChatGPT
|
||||||
from infrastructure.chatgpt.exceptions import ChatGPTClientError
|
from infrastructure.chatgpt.exceptions import ChatGPTClientError
|
||||||
|
|
@ -14,7 +14,7 @@ from infrastructure.chatgpt.exceptions import ChatGPTClientError
|
||||||
E = TypeVar("E", bound=Enum)
|
E = TypeVar("E", bound=Enum)
|
||||||
|
|
||||||
|
|
||||||
class ChatGptColumnClassifier(ColumnClassifier[E]):
|
class ChatGptColumnClassifier(BaseColumnClassifier[E]):
|
||||||
"""ColumnClassifier backed by ChatGPT, parametrised by a category enum.
|
"""ColumnClassifier backed by ChatGPT, parametrised by a category enum.
|
||||||
|
|
||||||
The same classification path -- prompt, JSON parsing, UNKNOWN fallback --
|
The same classification path -- prompt, JSON parsing, UNKNOWN fallback --
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@ class ClassificationError(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ColumnClassifier(ABC, Generic[E]):
|
class BaseColumnClassifier(ABC, Generic[E]):
|
||||||
"""Port: resolves free-text descriptions into a category enum ``E``.
|
"""Adapter base: shared scaffolding for concrete column classifiers.
|
||||||
|
|
||||||
One classifier handles one landlord-CSV column. Implementations decide
|
One classifier handles one landlord-CSV column. Implementations decide
|
||||||
*how* the mapping is performed (an LLM, a lookup table, a rules engine);
|
*how* the mapping is performed (an LLM, a lookup table, a rules engine).
|
||||||
``LandlordDescriptionOverridesOrchestrator`` depends only on this interface.
|
Consumers do not depend on this class -- they depend on the structural
|
||||||
|
``ColumnClassifier`` Protocol declared in the orchestration layer; this
|
||||||
|
ABC merely gives adapters a common base for the ``classify`` contract.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, Protocol, TypeVar, runtime_checkable
|
||||||
|
|
||||||
from infrastructure.column_classifier import ColumnClassifier
|
|
||||||
from repositories.landlord_overrides.landlord_override_repository import (
|
from repositories.landlord_overrides.landlord_override_repository import (
|
||||||
LandlordOverrideRepository,
|
LandlordOverrideRepository,
|
||||||
)
|
)
|
||||||
|
|
@ -12,6 +11,26 @@ from repositories.landlord_overrides.landlord_override_repository import (
|
||||||
E = TypeVar("E", bound=Enum)
|
E = TypeVar("E", bound=Enum)
|
||||||
|
|
||||||
|
|
||||||
|
@runtime_checkable
|
||||||
|
class ColumnClassifier(Protocol[E]):
|
||||||
|
"""Port: resolves free-text descriptions into a category enum ``E``.
|
||||||
|
|
||||||
|
The orchestration layer owns this contract because it is the consumer.
|
||||||
|
Any object exposing a matching ``classify`` satisfies it structurally --
|
||||||
|
e.g. ``infrastructure.chatgpt.ChatGptColumnClassifier`` -- so orchestration
|
||||||
|
never imports an adapter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def classify(self, descriptions: set[str]) -> dict[str, E]:
|
||||||
|
"""Classify each description into a category enum member.
|
||||||
|
|
||||||
|
Every input description appears as a key in the result. A description
|
||||||
|
that cannot be resolved maps to the enum's UNKNOWN member. A wholesale
|
||||||
|
failure raises the adapter's ``ClassificationError``.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ClassifiableColumn(Generic[E]):
|
class ClassifiableColumn(Generic[E]):
|
||||||
"""Pairs a column's classifier with the repository that persists its results.
|
"""Pairs a column's classifier with the repository that persists its results.
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ from typing import Any, Optional
|
||||||
|
|
||||||
from domain.addresses.unstandardised_address import AddressList, UnstandardisedAddress
|
from domain.addresses.unstandardised_address import AddressList, UnstandardisedAddress
|
||||||
from domain.epc.built_form_type import BuiltFormType
|
from domain.epc.built_form_type import BuiltFormType
|
||||||
from infrastructure.column_classifier import ColumnClassifier
|
|
||||||
from domain.epc.property_type import PropertyType
|
from domain.epc.property_type import PropertyType
|
||||||
from domain.epc.wall_type import WallType
|
from domain.epc.wall_type import WallType
|
||||||
from domain.postcode import Postcode
|
from domain.postcode import Postcode
|
||||||
from orchestration.classifiable_column import ClassifiableColumn
|
from orchestration.classifiable_column import ClassifiableColumn, ColumnClassifier
|
||||||
from orchestration.landlord_description_overrides_orchestrator import (
|
from orchestration.landlord_description_overrides_orchestrator import (
|
||||||
LandlordDescriptionOverridesOrchestrator,
|
LandlordDescriptionOverridesOrchestrator,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue