Bot & Automation

jorgasisten

/root/hermes-projects/jorgasisten

apps/jorgasisten/schemas.py text
from typing import Any, Literal

from pydantic import BaseModel, Field, field_validator

Intent = Literal[
    "tanya_data",
    "input_data",
    "update_data",
    "hapus_data",
    "ringkasan_data",
    "struktur_sheet",
    "chat_umum",
    "tidak_jelas",
]
Operation = Literal[
    "read",
    "create",
    "update",
    "delete",
    "summarize",
    "create_sheet",
    "update_headers",
    "rename_sheet",
    "delete_sheet",
    "chat",
    "ask_clarification",
]


class SheetSchema(BaseModel):
    title: str
    headers: list[str] = Field(default_factory=list)
    sample_rows: list[dict[str, Any]] = Field(default_factory=list)
    context_lines: list[str] = Field(default_factory=list)
    field_options: dict[str, list[str]] = Field(default_factory=dict)
    field_validation_messages: dict[str, str] = Field(default_factory=dict)
    header_row_number: int = 1
    row_count: int = 0


class SheetRow(BaseModel):
    sheet_name: str
    row_number: int
    values: dict[str, Any] = Field(default_factory=dict)


class AssistantDecision(BaseModel):
    intent: Intent = "tidak_jelas"
    sheet_name: str = ""
    operation: Operation = "ask_clarification"
    confidence: int = Field(default=0, ge=0, le=100)
    missing_fields: list[str] = Field(default_factory=list)
    data: dict[str, Any] = Field(default_factory=dict)
    filters: dict[str, Any] = Field(default_factory=dict)
    reason: str = ""
    user_reply: str = ""

    @field_validator("sheet_name", "reason", "user_reply", mode="before")
    @classmethod
    def stringify_text(cls, value: Any) -> str:
        return "" if value is None else str(value).strip()

    @field_validator("missing_fields", mode="before")
    @classmethod
    def normalize_missing_fields(cls, value: Any) -> list[str]:
        if value is None:
            return []
        if isinstance(value, list):
            return [str(item).strip() for item in value if str(item).strip()]
        return [str(value).strip()]

    @field_validator("data", "filters", mode="before")
    @classmethod
    def normalize_dict(cls, value: Any) -> dict[str, Any]:
        return value if isinstance(value, dict) else {}


class OperationResult(BaseModel):
    ok: bool
    user_message: str
    decision: AssistantDecision
    rows: list[SheetRow] = Field(default_factory=list)
    requires_confirmation: bool = False
    prepared_data: dict[str, Any] = Field(default_factory=dict)