Skip to content

schemacast.ground

The model copies a quote; SchemaCast finds it in the episode and records the character offsets. Offsets are never taken from the model. A quote that cannot be found is a hallucination flag, handled by validation.

A cast's record graph carries each quote and span in graflo's evidence, as {"quote": str, "span": {"start": int, "end": int, "context": str}} (context only when set); :func:evidence, :func:quote_of and :func:span_of write and read it.

Attributes

Span = TextSpan module-attribute

Classes

Grounding

Bases: BaseModel

One assertion and the span of text it was read from.

A grounding names the record or relation of the cast's record graph it supports, by ref; resolution maps refs to entities. Carried in the cast result only; nothing here is written to the graph.

Source code in schemacast/ground.py
class Grounding(BaseModel):
    """One assertion and the span of text it was read from.

    A grounding names the record or relation of the cast's record graph it
    supports, by ref; resolution maps refs to entities. Carried in the cast
    result only; nothing here is written to the graph.
    """

    source_id: str = Field(description="Episode the assertion was read from.")
    kind: Literal["vertex", "edge", "property"]
    vertex: str | None = Field(
        default=None, description="Vertex type, for a vertex or its property."
    )
    ref: str | None = Field(
        default=None, description="Record ref, for a vertex or its property."
    )
    edge: EdgeId | None = Field(
        default=None, description="Edge, for an edge or its property."
    )
    source_ref: str | None = Field(
        default=None, description="Ref of the edge's source record."
    )
    target_ref: str | None = Field(
        default=None, description="Ref of the edge's target record."
    )
    property: str | None = Field(
        default=None, description="Property name, for a property."
    )
    char_start: int
    char_end: int
    in_context: str | None = Field(
        default=None,
        description="Source id of the context item the span points into; None "
        "for the episode's own text. Only key values ground in context.",
    )
    quote: str = Field(description="The text at the span, as it stands in the source.")
    extractor: str = Field(description="``schemacast/<version>``.")
    model: str | None = Field(
        default=None, description="Model that produced the reply."
    )
    schema_ref: str = Field(description="``<schema name>@<version>``.")
    reference_time: datetime | None = None

Attributes

char_end instance-attribute
char_start instance-attribute
edge = Field(default=None, description='Edge, for an edge or its property.') class-attribute instance-attribute
extractor = Field(description='``schemacast/<version>``.') class-attribute instance-attribute
in_context = Field(default=None, description="Source id of the context item the span points into; None for the episode's own text. Only key values ground in context.") class-attribute instance-attribute
kind instance-attribute
model = Field(default=None, description='Model that produced the reply.') class-attribute instance-attribute
property = Field(default=None, description='Property name, for a property.') class-attribute instance-attribute
quote = Field(description='The text at the span, as it stands in the source.') class-attribute instance-attribute
ref = Field(default=None, description='Record ref, for a vertex or its property.') class-attribute instance-attribute
reference_time = None class-attribute instance-attribute
schema_ref = Field(description='``<schema name>@<version>``.') class-attribute instance-attribute
source_id = Field(description='Episode the assertion was read from.') class-attribute instance-attribute
source_ref = Field(default=None, description="Ref of the edge's source record.") class-attribute instance-attribute
target_ref = Field(default=None, description="Ref of the edge's target record.") class-attribute instance-attribute
vertex = Field(default=None, description='Vertex type, for a vertex or its property.') class-attribute instance-attribute

TextSpan

Bases: BaseModel

Character offsets, end exclusive, into the episode's text, or into the text of the context item context names.

Source code in schemacast/ground.py
class TextSpan(BaseModel):
    """Character offsets, end exclusive, into the episode's text, or into the
    text of the context item ``context`` names."""

    model_config = ConfigDict(extra="forbid")

    start: int
    end: int
    context: str | None = Field(
        default=None, description="Source id of the context item, if not the text."
    )

Attributes

context = Field(default=None, description='Source id of the context item, if not the text.') class-attribute instance-attribute
end instance-attribute
model_config = ConfigDict(extra='forbid') class-attribute instance-attribute
start instance-attribute

UnmappedText

Bases: BaseModel

Something the text states that no type covers.

Source code in schemacast/ground.py
class UnmappedText(BaseModel):
    """Something the text states that no type covers."""

    model_config = ConfigDict(extra="forbid")

    quote: str
    note: str
    span: TextSpan

Attributes

model_config = ConfigDict(extra='forbid') class-attribute instance-attribute
note instance-attribute
quote instance-attribute
span instance-attribute

Functions:

evidence(quote, span)

The evidence of a record, relation or property read at span.

Source code in schemacast/ground.py
def evidence(quote: str, span: TextSpan) -> dict[str, Any]:
    """The ``evidence`` of a record, relation or property read at *span*."""
    return {"quote": quote, "span": span.model_dump(exclude_none=True)}

groundings(graph, episode, *, extractor, model=None)

One grounding per record, relation and stated property of graph whose evidence holds a span; none for a known entity's record.

Source code in schemacast/ground.py
def groundings(
    graph: RecordGraph,
    episode: Episode,
    *,
    extractor: str,
    model: str | None = None,
) -> list[Grounding]:
    """One grounding per record, relation and stated property of *graph* whose
    ``evidence`` holds a span; none for a known entity's record."""
    out: list[Grounding] = []

    def add(found: dict[str, Any] | None, **target: Any) -> None:
        span = span_of(found)
        if span is None:
            return
        text = episode.text
        if span.context is not None:
            text = [i.text for i in episode.context if i.source_id == span.context][-1]
        out.append(
            Grounding(
                source_id=episode.source_id,
                char_start=span.start,
                char_end=span.end,
                in_context=span.context,
                quote=text[span.start : span.end],
                extractor=extractor,
                model=model,
                schema_ref=graph.schema_ref,
                reference_time=episode.reference_time,
                **target,
            )
        )

    for record in graph.records:
        if "known" in (record.evidence or {}):
            continue  # stated by the source, not read from the text
        target = {"vertex": record.type, "ref": record.ref}
        add(record.evidence, kind="vertex", **target)
        for name, prop in record.props.items():
            add(prop.evidence, kind="property", property=name, **target)
    for relation in graph.relations:
        target = {
            "edge": relation.edge_id,
            "source_ref": relation.source,
            "target_ref": relation.target,
        }
        add(relation.evidence, kind="edge", **target)
        for name, prop in relation.props.items():
            add(prop.evidence, kind="property", property=name, **target)
    return out

locate(quote, text, *, near=None)

Find quote in text: exactly, then ignoring case, accents, whitespace runs and typographic quotes and dashes, then also without surrounding punctuation. Of several occurrences, the one nearest near wins, else the first.

Source code in schemacast/ground.py
def locate(quote: str, text: str, *, near: Span | None = None) -> Span | None:
    """Find *quote* in *text*: exactly, then ignoring case, accents, whitespace
    runs and typographic quotes and dashes, then also without surrounding
    punctuation. Of several occurrences, the one nearest *near* wins, else the
    first."""
    if not quote.strip():
        return None
    spans = _occurrences(quote, text)
    if not spans:
        return None
    if near is None:
        return spans[0]
    return min(spans, key=lambda span: (_gap(span, near), span.start))

quote_of(evidence)

The quote an evidence holds, if any.

Source code in schemacast/ground.py
def quote_of(evidence: dict[str, Any] | None) -> str | None:
    """The quote an ``evidence`` holds, if any."""
    quote = (evidence or {}).get("quote")
    return quote if isinstance(quote, str) else None

span_of(evidence)

The span an evidence holds, if any.

Source code in schemacast/ground.py
def span_of(evidence: dict[str, Any] | None) -> TextSpan | None:
    """The span an ``evidence`` holds, if any."""
    span = (evidence or {}).get("span")
    return TextSpan.model_validate(span) if isinstance(span, dict) else None