parapilot / app /schemas.py
LaelaZ's picture
Deploy ParaPilot to HF Spaces (Docker)
d787a09 verified
"""Pydantic schemas: the shared response contract.
Every substantive answer ParaPilot returns is an ``AnswerEnvelope`` carrying
citations, a confidence score, the standing disclaimer, ``is_legal_information``,
and an escalation block — the SPEC §6 UPL/safety contract.
"""
from __future__ import annotations
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel, Field
class AnswerKind(str, Enum):
"""How an answer was produced."""
GROUNDED = "grounded" # supported by retrieved corpus chunks
REFUSAL_SCOPE = "refusal_scope" # out of scope (non-IL / non-divorce)
REFUSAL_ADVICE = "refusal_advice" # advice-seeking ("what should I do")
REFUSAL_LOW_CONFIDENCE = "refusal_low_confidence" # no grounded answer found
class Citation(BaseModel):
"""A clickable pointer back to an authoritative source chunk."""
marker: str = Field(..., description="Inline marker, e.g. '1'.")
source_id: str
chunk_id: str
title: str
url: str
publisher: str
retrieved: str
snippet: str = Field(..., description="Short supporting excerpt from the source.")
class Escalation(BaseModel):
"""Where to get real legal help. Always present."""
message: str = (
"For advice about your specific situation, contact a licensed Illinois "
"attorney or legal aid."
)
legal_aid_name: str = "Illinois Legal Aid Online (ILAO)"
legal_aid_url: str = "https://www.illinoislegalaid.org/get-legal-help"
lawyer_finder_name: str = "Illinois Lawyer Finder (ISBA)"
lawyer_finder_url: str = "https://www.isba.org/public/illinoislawyerfinder"
class AnswerEnvelope(BaseModel):
"""The single response shape returned by the Ask endpoint."""
kind: AnswerKind
question: str
answer: str
citations: List[Citation] = Field(default_factory=list)
confidence: float = Field(0.0, ge=0.0, le=1.0)
is_legal_information: bool = True
disclaimer: str
escalation: Escalation = Field(default_factory=Escalation)
provider: str = "stub"
@property
def is_refusal(self) -> bool:
return self.kind != AnswerKind.GROUNDED
class RetrievedChunk(BaseModel):
"""A retrieval hit (internal)."""
source_id: str
chunk_id: str
title: str
url: str
publisher: str
retrieved: str
heading: str
text: str
score: float