Skip to main content

Python client for the Pure Frame API — search any moment inside your videos with natural language

Project description

Pureframe Python API library

PyPI version

Pureframe Python library provides convenient access to the Pureframe REST API from any Python 3.9+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by httpx.

It is generated from our OpenAPI specification with Fern. The import name is pureframe; the PyPI distribution is pureframe-ai.

Documentation

The REST API documentation can be found on docs.pureframe.ai.

Installation

# install from PyPI
pip install pureframe-ai

Usage

The primary workflow is: create a collection, upload videos to it, then search across indexed video segments with natural language, an image, or both.

from pureframe import Pureframe

client = Pureframe(
    token="pf_...",
)

collection = client.collections.create_collection(name="Product demos")

results = client.search.search(
    query="pricing objection",
    collection_id=collection.data.id,
)

for result in results.data:
    print(result.filename, [segment.timestamp_start for segment in result.segments])

While you can provide a token keyword argument, we recommend using python-dotenv to store your API key in a .env file and reading it with os.environ.get(...) so that your API key is not stored in source control.

import os
from pureframe import Pureframe

client = Pureframe(
    token=os.environ.get("PUREFRAME_API_KEY"),
)

Uploading videos

Upload a video to a collection for indexing. Processing happens asynchronously — use the returned job_id to poll the job until it completes.

from pathlib import Path
from pureframe import Pureframe

client = Pureframe(token="pf_...")

upload = client.upload.upload_video(
    collection_id=collection.data.id,
    file=Path("input.mp4"),
)

job = client.jobs.get_job(upload.data.job_id)
print(job.data.status)  # "queued" -> "processing" -> "done" (or "failed")

Once the job status is done, the video is fully searchable.

Search

At least one of query, image, or image_url is required. Results are grouped by video and include timestamped segments.

from pureframe import Pureframe

client = Pureframe(token="pf_...")

# Text search
results = client.search.search(query="pricing objection")

# Image search, by file
with open("path/to/frame.png", "rb") as image_file:
    results = client.search.search(image=image_file)

# Image search, by URL
results = client.search.search(image_url="https://example.com/frame.png")

You can also submit feedback on a search result to help improve ranking:

client.search.submit_search_feedback(
    video_id=results.data[0].video_id,
    timestamp_start=results.data[0].segments[0].timestamp_start,
    signal="positive",
    query="pricing objection",
)

Async usage

Simply import AsyncPureframe instead of Pureframe and use await with each API call:

import os
import asyncio
from pureframe import AsyncPureframe

client = AsyncPureframe(
    token=os.environ.get("PUREFRAME_API_KEY"),
)

async def main() -> None:
    results = await client.search.search(query="pricing objection")
    print(results.data)

asyncio.run(main())

Functionality between the synchronous and asynchronous clients is otherwise identical.

Using types

Responses are Pydantic models which also provide helper methods for things like:

  • Serializing back into JSON, model.model_dump_json() (or model.json() on Pydantic v1)
  • Converting to a dictionary, model.model_dump() (or model.dict() on Pydantic v1)

Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set python.analysis.typeCheckingMode to basic.

Pagination

List methods in the Pureframe API are paginated via page and per_page parameters. Each list response includes a meta object with pagination details (total, page, per_page).

from pureframe import Pureframe

client = Pureframe(token="pf_...")

all_videos = []
page = 1
while True:
    response = client.videos.list_videos(
        collection_id=collection.data.id,
        page=page,
        per_page=50,
    )
    all_videos.extend(response.data)
    if len(all_videos) >= (response.meta.total or 0):
        break
    page += 1

print(all_videos)

Or, asynchronously:

import asyncio
from pureframe import AsyncPureframe

client = AsyncPureframe(token="pf_...")

async def main() -> None:
    all_videos = []
    page = 1
    while True:
        response = await client.videos.list_videos(
            collection_id="collection_id",
            page=page,
            per_page=50,
        )
        all_videos.extend(response.data)
        if len(all_videos) >= (response.meta.total or 0):
            break
        page += 1
    print(all_videos)

asyncio.run(main())

File uploads

Request parameters that correspond to file uploads (video uploads, image search) can be passed as bytes, a PathLike instance, a file-like object, or a tuple of (filename, contents, media type).

from pathlib import Path
from pureframe import Pureframe

client = Pureframe(token="pf_...")

client.upload.upload_video(
    collection_id="collection_id",
    file=Path("input.mp4"),
)

The async client uses the exact same interface.

Webhooks

Register a webhook endpoint to receive notifications about processing job events instead of polling.

from pureframe import Pureframe

client = Pureframe(token="pf_...")

endpoint = client.webhooks.create_endpoint(
    url="https://example.com/webhook",
    events=["job.completed", "job.failed"],
)

# Update, list, or delete endpoints
client.webhooks.update_endpoint("we_abc123", is_active=False)
client.webhooks.list_endpoints()
client.webhooks.delete_endpoint("we_abc123")

You can also pass a webhook_url directly when uploading a video, to be notified once that specific job finishes:

client.upload.upload_video(
    collection_id="collection_id",
    file=Path("input.mp4"),
    webhook_url="https://example.com/webhook",
)

AI agent tool-calling

The agent client exposes an OpenAI-compatible tool schema so LLM agents can call Pureframe tools directly.

from pureframe import Pureframe

client = Pureframe(token="pf_...")

schema = client.agent.agent_schema()

result = client.agent.agent_call(
    tool="search_videos",
    input={"query": "pricing objection"},
)

search_videos results include thumbnail_base64 — a base64-encoded JPEG that vision-capable models (GPT-4o, Claude) can consume directly.

Handling errors

When the API returns a non-success status code (4xx or 5xx response), a pureframe.core.api_error.ApiError is raised, containing status_code and body properties. For 422 validation errors, an UnprocessableEntityError (a subclass of ApiError) is raised with a structured body.

from pureframe import Pureframe
from pureframe.core.api_error import ApiError
from pureframe.errors import UnprocessableEntityError

client = Pureframe(token="pf_...")

try:
    client.collections.create_collection(name="Product demos")
except UnprocessableEntityError as e:
    print("Validation error:", e.body)
except ApiError as e:
    print(e.status_code)
    print(e.body)

Retries

Certain requests can be retried by passing max_retries via request_options. Retries use a short exponential backoff. This is off by default (max_retries=0) and is configured per-request rather than on the client:

from pureframe import Pureframe

client = Pureframe(token="pf_...")

client.videos.list_videos(
    collection_id="collection_id",
    request_options={"max_retries": 3},
)

Timeouts

By default requests time out after 60 seconds. You can configure this globally on the client, or per-request via request_options:

from pureframe import Pureframe

# Configure the default for all requests:
client = Pureframe(
    token="pf_...",
    timeout=20.0,
)

# Override per-request:
client.videos.list_videos(
    collection_id="collection_id",
    request_options={"timeout_in_seconds": 5},
)

Advanced

Undocumented request params

If you want to explicitly send an extra param, you can do so via the additional_query_parameters, additional_body_parameters, and additional_headers keys of request_options.

client.videos.list_videos(
    collection_id="collection_id",
    request_options={
        "additional_query_parameters": {"debug": "true"},
    },
)

Configuring the HTTP client

You can directly override the httpx client to customize it for your use case, including support for proxies, custom transports, and other advanced functionality.

import httpx
from pureframe import Pureframe

client = Pureframe(
    token="pf_...",
    base_url="https://api.pureframe.ai",
    httpx_client=httpx.Client(
        proxy="http://my.test.proxy.example.com",
        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    ),
)

Requirements

Python 3.9 or higher.

Versioning

This package generally follows SemVer conventions, though certain backwards-incompatible changes may be released as minor versions:

  1. Changes that only affect static types, without breaking runtime behavior.
  2. Changes to library internals which are technically public but not intended or documented for external use.
  3. Changes that we do not expect to impact the vast majority of users in practice.

We are keen for your feedback; please open an issue with questions, bugs, or suggestions.

Contributing

This library is generated from our OpenAPI specification, so most code changes need to happen at the spec level — see the contributing documentation for details on what to file where.

License

MIT

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

pureframe_ai-1.0.0.tar.gz (32.0 kB view details)

Uploaded Source

Built Distribution

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

pureframe_ai-1.0.0-py3-none-any.whl (64.4 kB view details)

Uploaded Python 3

File details

Details for the file pureframe_ai-1.0.0.tar.gz.

File metadata

  • Download URL: pureframe_ai-1.0.0.tar.gz
  • Upload date:
  • Size: 32.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.1

File hashes

Hashes for pureframe_ai-1.0.0.tar.gz
Algorithm Hash digest
SHA256 12f30052565d51b73be6d3075f35f7039d3e7e94953ae8152ac0a559febf3a68
MD5 146e5859d94d8b60ab2b72672d18492e
BLAKE2b-256 04219a5f9a795a918eb067fc7feaee481c2d9a28f8262a94bf7c1055dfd787fc

See more details on using hashes here.

File details

Details for the file pureframe_ai-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pureframe_ai-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 927ebb2b7f2ae463d88777f5606e312a89faa3be1009e73dfe56ac7015895957
MD5 230024fe920dff1066dd9ccfb6f7e613
BLAKE2b-256 e9f88d160ad8c83f9cb427f0f98b3cce35a7e884c20920fc96283d76b7d58049

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