Skip to main content

Python SDK for the Overton platform.

Project description

Overton SDK

Overton is a probabilistic knowledge graph that resolves entities and relations from unstructured text. You write raw evidence in natural language; Overton handles LLM-based extraction, entity deduplication, and uncertainty quantification.

Prerequisites

You need two things from Overton:

  • An API token (ovtn_...)
  • Your hostname (e.g. api.overton.bio)

Overton is a hosted platform — there's nothing to run or operate on your side. Contact us to get a token.

Installation

pip install overton-sdk

Requires Python 3.11+. The only dependency is httpx.

Authorization and client initialization

Overton authenticates with the bearer token (ovtn_...) Overton issued you. Construct an auth object and pass it to the client, along with your hostname:

import os
import overton_sdk

client = overton_sdk.OvertonClient(
    auth=overton_sdk.UserTokenAuth(os.environ["OVERTON_TOKEN"]),
    hostname="overton.example.com",   # bare host; scheme defaults to https
)

Environment variables

If OVERTON_TOKEN and OVERTON_HOSTNAME are set, the client picks them up with no arguments:

export OVERTON_TOKEN=ovtn_...
export OVERTON_HOSTNAME=overton.example.com
client = overton_sdk.OvertonClient()

Configuration

Tune transport behavior with a Config object:

from overton_sdk import Config

client = overton_sdk.OvertonClient(
    auth=overton_sdk.UserTokenAuth(token),
    hostname="overton.example.com",
    config=Config(timeout=60.0, max_retries=3, verify=True),
)

Use the client as a context manager to ensure connections are closed:

with overton_sdk.OvertonClient() as client:
    m = client.manifold("my-manifold")
    ...

[!TIP] For local development you can point at a server over plain HTTP by passing a full hostname="http://localhost:8000" — an explicit scheme is respected.

Core concepts

Concept What it is
Manifold A named knowledge graph. Create as many as you need — one per domain, project, or dataset.
Evidence A piece of text you write in. Overton extracts entities and relations from it using an LLM.
Contributor ID What write() returns — the ID of the evidence you just wrote. Use it for raw reads and curation.
Entity ID The ID of a resolved real-world entity. Different from a contributor ID. Get entity IDs from query().
Covariate Structured metadata on evidence ({"source": "reuters", "year": "2024"}). Overton uses it to build conditional distributions.

Quickstart

import os
import overton_sdk

client = overton_sdk.OvertonClient(
    auth=overton_sdk.UserTokenAuth(os.environ["OVERTON_TOKEN"]),
    hostname="overton.example.com",
)
m = client.manifold("earnings")

# Write evidence
ids = m.write("Apple reported record profits of $94B in Q1 2024, driven by iPhone sales")

# Query resolved entities
results = m.query("tech company earnings", top_k=5)
for entity in results:
    print(entity.entity_id, entity.point_estimate(), entity.type_distribution)

# Manifold statistics
stats = m.measures()
print(f"{stats.entity_count} entities, entropy={stats.aggregate_entropy:.3f}")

Writing evidence

# Single string
m.write("Google acquired DeepMind for £400M in 2014")

# Multiple items in one call
m.write(
    "Apple reported record Q1 profits",
    "Microsoft Azure revenue grew 29% year over year",
)

# With source and covariates
m.write({
    "text": "Apple reported record Q1 profits",
    "source": "reuters",
    "covariates": {"quarter": "Q1-2024", "sentiment": "positive"},
})

# Mix of strings and dicts
m.write(
    "Apple reported record profits",
    {"text": "Google missed analyst estimates", "covariates": {"sentiment": "negative"}},
)

write() returns a list of contributor IDs — one per entity or relation mention extracted from your text by the LLM.

Reading

# Raw read — get back the original text using a contributor ID
text = m.read(contributor_id, raw=True)

# Resolved read — get the entity distribution using an entity ID
# Note: entity IDs come from query(), not from write()
entity = m.read(entity_id)
print(entity.type_distribution)    # {"ORG": 0.91, "PERSON": 0.09}
print(entity.point_estimate())     # "ORG"
print(entity.contributor_weights)  # which evidence pieces contributed and how much

# Read a relation
relation = m.read_relation(relation_id)
print(relation.type_distribution)
print(relation.point_estimate({"cell_line": "HeLa"}))   # conditional on a covariate

Querying

results = m.query("pharmaceutical company", top_k=10)

for entity in results:
    print(entity.entity_id)
    print(entity.point_estimate())      # most likely type
    print(entity.type_distribution)     # full probability distribution
    print(entity.alias_ids)             # other IDs this entity was known by

Results are EntityDistribution objects ranked by semantic similarity.

Measures

# Manifold-level
mm = m.measures()
mm.entity_count          # number of resolved entities
mm.relation_count        # number of resolved relations
mm.aggregate_entropy     # average type uncertainty across all entities (nats)
mm.component_count       # number of connected subgraphs
mm.uncertainty_map       # {entity_id: entropy} for every entity

# Entity-level
em = m.entity_measures(entity_id)
em.type_entropy            # uncertainty over entity type (0 = certain, ln(N) = maximally uncertain)
em.evidence_concentration  # 1.0 = one source dominates, 0.0 = evidence spread evenly
em.effective_sample_size   # Kish ESS — effective number of independent evidence pieces

# Relation-level
rm = m.relation_measures(relation_id)
rm.marginal_entropy        # uncertainty over relation type
rm.marginal_perplexity     # effective number of competing relation types
rm.is_contradictory        # True if evidence strongly conflicts
rm.mutual_information      # list[CovariateMI] — which covariates are informative

# Divergence between two entities or relations
div = m.divergence(entity_id_a, entity_id_b)               # Jensen-Shannon (default)
div = m.divergence(entity_id_a, entity_id_b, metric="kl")  # KL divergence
print(div.value)    # 0.0 = identical distributions, 1.0 = maximally different

Curation

# Retract — soft delete, reversible. Evidence is ignored in future resolutions.
event = m.retract(contributor_id)
print(event.reversible)   # True

# Hard delete — permanent. Evidence is removed entirely.
event = m.hard_delete(contributor_id)
print(event.reversible)   # False

# Merge — declare that two entity IDs refer to the same real-world entity
new_entity_id, events = m.merge(["entity-abc", "entity-xyz"])

# Split — declare that one entity ID actually contains multiple distinct entities.
# partition is a list of contributor ID groups, one group per new entity.
new_entity_ids, events = m.split(entity_id, partition=[
    ["contributor-1", "contributor-2"],   # -> entity A
    ["contributor-3"],                     # -> entity B
])

# Full audit log
log = m.event_log()
for event in log:
    print(event.kind, event.timestamp, event.actor, event.reversible)

Error handling

All SDK exceptions subclass OvertonError, which exposes .status_code. Concrete subclasses are keyed by HTTP status code:

from overton_sdk import NotFoundError, UnauthorizedError, OvertonError

try:
    entity = m.read("entity-123")
except NotFoundError:
    print("entity not found")
except UnauthorizedError:
    print("invalid or expired API token")
except OvertonError as e:
    print(f"API error {e.status_code}: {e}")
Exception HTTP status When
BadRequestError 400 Malformed request
UnauthorizedError 401 Missing or invalid API token
PermissionDeniedError 403 Token lacks permission for this action
NotFoundError 404 Entity, relation, or contributor not found
UnprocessableEntityError 422 Request failed validation
InternalServerError 5xx Server-side failure
OvertonError any Base class — exposes .status_code

[!NOTE] AuthError and ValidationError remain available as aliases of UnauthorizedError and UnprocessableEntityError for backwards compatibility.

Static type analysis

The SDK ships a py.typed marker (PEP 561), so type checkers like mypy and pyright resolve its annotations out of the box.

from overton_sdk import (
    OvertonClient,
    ManifoldHandle,
    EntityDistribution,
    RelationDistribution,
    ManifoldMeasures,
    EntityMeasures,
    RelationMeasures,
    DivergenceResult,
    CurationEvent,
)

def analyse(m: ManifoldHandle) -> list[EntityDistribution]:
    return m.query("some query", top_k=20)

Full example — biomedical literature

import os
import overton_sdk

client = overton_sdk.OvertonClient(
    auth=overton_sdk.UserTokenAuth(os.environ["OVERTON_TOKEN"]),
    hostname="overton.example.com",
)
m = client.manifold("biomedical")

# Ingest papers with provenance
m.write(
    {
        "text": "BRCA1 strongly activates PARP1 in the presence of DNA damage",
        "source": "pmid:12345678",
        "covariates": {"cell_line": "HeLa", "year": "2021"},
    },
    {
        "text": "BRCA1 was shown to inhibit PARP1 under normoxic conditions",
        "source": "pmid:99887766",
        "covariates": {"cell_line": "MCF7", "year": "2023"},
    },
)

# Find the BRCA1-PARP1 relation
results = m.query("BRCA1 PARP1 interaction", top_k=5)
if results:
    entity = results[0]
    print(f"Entity: {entity.point_estimate()} (confidence: {max(entity.type_distribution.values()):.2f})")

# Check manifold health
mm = m.measures()
print(f"Manifold: {mm.entity_count} entities, {mm.relation_count} relations")
print(f"Mean uncertainty: {mm.aggregate_entropy:.3f} nats")

Version

import overton_sdk
print(overton_sdk.__version__)   # "0.1.0"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

overton_sdk-0.1.0.tar.gz (22.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

overton_sdk-0.1.0-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

File details

Details for the file overton_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: overton_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 22.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for overton_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0c523347279a2933d592fc387634a2fc0e1a9e23644d827e4888125d47caa75b
MD5 341bc6e87cd6befb89ac1086cce4c608
BLAKE2b-256 02d1fb4a1e6946d32ebbd61900ec14a29c336cfd376da0ed3a4e45e27eb0d2ba

See more details on using hashes here.

File details

Details for the file overton_sdk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: overton_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for overton_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3d37af4bc175fccd8d6035dfe294efbd6cff0de90c0f3fe85c9687460564dada
MD5 6768325e6380156c0c7aab9c8574b966
BLAKE2b-256 ad9c88fa7636b573910769097e1397424218e79b2938560b70df9ab07e1335df

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page