Metadata-Version: 2.5
Name: visionstory
Version: 0.0.1
Summary: Official Python SDK for the VisionStory API - AI talking-avatar video generation.
Project-URL: Homepage, https://openapi.visionstory.ai/docs
Project-URL: Documentation, https://openapi.visionstory.ai/docs
Author-email: VisionStory <register@visionstory.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: ai,avatar,talking-avatar,text-to-video,video-generation,visionstory
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# VisionStory Python SDK

Official Python SDK for the [VisionStory API](https://openapi.visionstory.ai/docs) — generate AI talking-avatar videos from text or audio.

- **Zero dependencies** — Python standard library only, Python 3.10+.
- **Blocking semantics built in** — `generate_video()` submits the job and polls until the video is ready: one call in, a finished video out.
- **Agent-friendly** — auth via environment variable, actionable error messages, idempotent retries.

## Installation

```bash
pip install visionstory
```

## Quick start

Create an API key at [visionstory.ai/openapi](https://www.visionstory.ai/openapi) and export it:

```bash
export VISIONSTORY_API_KEY="sk-vs-xxxxxxxxxxxxxxxxxxx"
```

Text in, talking-avatar video out — five lines:

```python
from pathlib import Path
from visionstory import VisionStoryClient, build_video_payload

client = VisionStoryClient.from_env()  # reads VISIONSTORY_API_KEY
video = client.generate_video(build_video_payload(avatar_id="4321918387609092991", text="Hello World, this is my first test video.", voice_id="Alice"))
client.download(video["video_url"], Path("result.mp4"))
```

`generate_video()` blocks until the task reaches a terminal state (default timeout 600s, polling every 5s) and returns the finished video object, including `video_url`. Completed videos are retained for **7 days** — download the file if you need permanent storage.

Before building a production integration, discover current IDs instead of hardcoding them:

```python
client.list_models()   # GET /api/v1/models
client.list_avatars()  # GET /api/v1/avatars
client.list_voices()   # GET /api/v1/voices
```

To use your own audio instead of text, pass `audio_url=` or `audio_file=` (a local file, base64-encoded automatically) to `build_video_payload()` in place of `text=` — exactly one source is allowed.

### Non-blocking mode

Prefer to manage polling yourself? Submit and poll separately:

```python
created = client.generate_video(payload, wait=False)   # returns {"video_id": ...} immediately
video = client.wait_for_video(created["video_id"])      # or client.get_video(video_id) manually
```

## Idempotent retries (`client_request_id`)

Video creation charges credits, so retrying a request that may have already succeeded is risky. Add a `client_request_id` (an idempotency key of your choice) to make resubmission safe — within 24 hours, the same key returns the original task instead of creating and charging a new one:

```python
payload = build_video_payload(avatar_id="4321918387609092991", text="Hello!", voice_id="Alice")
payload["client_request_id"] = "order-42-intro-video"  # ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$
video = client.generate_video(payload)                  # safe to retry on network errors
```

If the first submission is still in flight, a retry gets HTTP 409 with a hint to retry shortly.

## Error handling

All API failures raise `VisionStoryAPIError`. The message embeds the API's error body, which carries an `error.hint` field — a one-sentence, actionable next step (e.g. out of credits → top up at the pricing page). Print it as-is or feed it to your agent:

```python
from visionstory import VisionStoryAPIError

try:
    video = client.generate_video(payload)
except VisionStoryAPIError as e:
    print(e)  # e.g. POST /api/v1/video failed with HTTP 403: {"error": {"code": ..., "message": ..., "hint": "..."}}
```

Failed generations are refunded automatically; `generate_video()` raises with that context instead of returning a failed task.

## Configuration

| Environment variable | Purpose | Default |
|---|---|---|
| `VISIONSTORY_API_KEY` | API key (required for `from_env()`) | — |
| `VISIONSTORY_API_BASE` | API base URL override | `https://openapi.visionstory.ai` |

You can also construct the client explicitly: `VisionStoryClient(api_key, base_url=..., request_timeout=...)`.

## More resources

- [API documentation](https://openapi.visionstory.ai/docs) — full reference, guides, and error codes.
- [Quick start guide](https://openapi.visionstory.ai/docs/guides/quick-start)
- [For agents](https://openapi.visionstory.ai/docs/guides/for-agents) — MCP server, Agent Skill package, and llms.txt.

## Development

This SDK is **not** generated from the OpenAPI spec. The API surface is intentionally small (~21 operations), and the repository already maintains a mature zero-dependency client layer (`src/open_api/client/core.py`) with blocking-poll semantics shared by the MCP server and the Agent Skill package. v0.1 packages that client directly; `visionstory/_core.py` is a script-generated copy kept in lockstep by `scripts/check_sdk_sync.py` (CI-gated — run with `--fix` to re-sync). Generator pipelines (Fern / OpenAPI Generator) will be re-evaluated once the endpoint surface grows enough to justify them.
