Metadata-Version: 2.4
Name: chat-vision-sdk
Version: 0.1.1
Summary: Typed synchronous Python SDK for the Chat Vision HTTPS API.
Project-URL: Homepage, https://chat.trendflowing.com/docs
Project-URL: Documentation, https://chat.trendflowing.com/docs
Project-URL: Source, https://github.com/xuyuanquant/chat-vision-sdk
Project-URL: Issues, https://github.com/xuyuanquant/chat-vision-sdk/issues
Project-URL: API Docs, https://chat.trendflowing.com/docs
Project-URL: GitHub Demo, https://github.com/xuyuanquant/chat-vision-demo
Author: Trendflowing
License: MIT
License-File: LICENSE
Keywords: api,chat-vision,http,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: twine>=5; extra == 'dev'
Description-Content-Type: text/markdown

# Chat Vision Python SDK

Typed synchronous Python SDK for the deployed Chat Vision HTTPS API at
`https://chat.trendflowing.com`.

This package is only an HTTP wrapper. It does not include OCR, image recognition,
cross-frame merge algorithms, server schemas, deployment configuration, API keys, or
private screenshots.

## Install

```bash
pip install chat-vision-sdk
```

Import name:

```python
from chat_vision import ChatVision
```

Request API access at https://chat.trendflowing.com/#early-access. The SDK sends the API
key as the public API contract requires: `X-API-Key`.

API docs: https://chat.trendflowing.com/docs
GitHub demo: https://github.com/xuyuanquant/chat-vision-demo

## Quickstart

```python
from chat_vision import ChatVision

with ChatVision(api_key="cv_live_...") as client:
    session = client.sessions.create(platform="wechat")

    frame = session.push("frame_001.png")
    frame.wait(timeout=60)

    for event in session.messages.iter_all():
        print(event.operation, event.revision, event.message.role, event.message.text)

    session.close()
```

Sessions use temporary retention according to the API response. Inspect
`session.info.retention.ttl_seconds` and `session.info.expires_at` for the server-provided
retention window.

## Push Two Frames

```python
from chat_vision import ChatVision

with ChatVision(api_key="cv_live_...") as client:
    session = client.sessions.create(platform="wechat")
    try:
        session.push("frame_001.png").wait(timeout=60)
        session.push("frame_002.png").wait(timeout=60)

        for event in session.messages.iter_all(limit=50):
            print(event.message.text)
    finally:
        session.close()
```

## Interleaved Push and Pull

You can pull message updates between frame uploads. You do not need to upload every
screenshot or close the session before reading messages.

```python
frame_1 = session.push("frame_001.png")

page = session.messages.list()
cursor = page.next_cursor

frame_2 = session.push("frame_002.png")

page = session.messages.list(cursor=cursor)
cursor = page.next_cursor
```

Frame processing is asynchronous, so the first Get may return an empty page. That is a
normal result. The cursor is an opaque next read position: keep it exactly as returned and
pass it to the next `messages.list()` call. Message events may add new messages or `upsert`
existing messages, so apply updates by message ID and revision instead of appending every
event as a new row.

For complete pagination, upsert handling, and a final messages drain, see:

```text
examples/interleaved_push_pull.py
```

This is ordinary polling with explicit stopping points. It is not SSE, WebSocket, or a
permanent listener.

## Explicit `frame_id` Retry

If you need to retry across processes, pass the same `frame_id`. SDK retries within one
`push()` call reuse the same `frame_id`.

```python
from chat_vision import ChatVision

with ChatVision(api_key="cv_live_...") as client:
    session = client.sessions.create(platform="wechat")
    frame = session.push("frame_001.png", frame_id="upload-2026-01-01-001")
    frame.wait(timeout=60)
```

If no `frame_id` is provided, the SDK generates a UUID for that call.

## Cursor Pagination

Cursors are opaque. Do not parse, edit, sort by, or replace them with message IDs.

```python
page = session.messages.list(limit=25)
for event in page.items:
    print(event.revision, event.operation, event.message.text)

if page.has_more:
    next_page = session.messages.list(cursor=page.next_cursor, limit=25)
```

## Error Handling

```python
from chat_vision import ChatVision, RateLimitError, WaitTimeoutError, ChatVisionError

try:
    with ChatVision(api_key="cv_live_...") as client:
        session = client.sessions.create(platform="wechat")
        session.push("frame_001.png").wait(timeout=30)
except RateLimitError as exc:
    print("retry after", exc.retry_after, "request", exc.request_id)
except WaitTimeoutError:
    print("local wait timed out; the frame may still be processing")
except ChatVisionError as exc:
    print(type(exc).__name__, exc)
```

The SDK keeps API keys and image bytes out of exception messages.

## Custom Base URL

```python
client = ChatVision(
    api_key="cv_live_...",
    base_url="https://gateway.example.com",
    connect_timeout=5,
    read_timeout=60,
    poll_interval=1.5,
)
client.close()
```

## Closing Client Connections

Use the client as a context manager or call `client.close()`:

```python
client = ChatVision(api_key="cv_live_...")
try:
    print(client.ready().ok)
finally:
    client.close()
```

## Low-Level Parse Compatibility

`client.parse(...)` wraps `/v1/parse` for compatibility. The recommended SDK workflow is
Session -> Frame -> Messages. The SDK does not depend on deprecated `/history`.

## Demo

The companion demo repository shows a desktop screenshot-to-session workflow using this SDK:

```text
https://github.com/xuyuanquant/chat-vision-demo
```

In that demo, enable SDK mode with `CHAT_VISION_DRIVER=sdk` or `--driver sdk`.

## Development

```bash
python -m pip install -e ".[dev]"
ruff check .
mypy src
pytest
python -m build
python -m twine check dist/*
```

Contract check:

```bash
python scripts/check_openapi_contract.py
```

Online smoke test, disabled by default:

```bash
CHAT_VISION_API_KEY=... pytest tests/test_smoke_online.py
```
