Metadata-Version: 2.4
Name: contentflow-sdk
Version: 0.1.0
Summary: Python SDK for the ContentFlow Podcast Intelligence API
Project-URL: Homepage, https://gocontentflow.com
Project-URL: Documentation, https://gocontentflow.com/docs/api
Project-URL: Repository, https://github.com/gocontentflow/contentflow-python
Project-URL: Issues, https://github.com/gocontentflow/contentflow-python/issues
Project-URL: Changelog, https://github.com/gocontentflow/contentflow-python/blob/main/CHANGELOG.md
Author-email: ContentFlow <developers@gocontentflow.com>
License: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
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 :: Sound/Audio
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: anyio<5,>=3.0.0
Requires-Dist: eval-type-backport>=0.2.0; python_version < '3.10'
Requires-Dist: httpx<1,>=0.25.0
Requires-Dist: pydantic<3,>=2.0.0
Provides-Extra: cli
Requires-Dist: click<9,>=8.0.0; extra == 'cli'
Requires-Dist: rich<14,>=13.0.0; extra == 'cli'
Provides-Extra: dev
Requires-Dist: pyright>=1.1; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# ContentFlow Python SDK

> Podcast intelligence API — transcripts, semantic search, entity extraction, topic classification, and AI summaries from 50,000+ hours of business podcasts.

[![PyPI version](https://img.shields.io/pypi/v/contentflow-sdk.svg)](https://pypi.org/project/contentflow-sdk/)
[![CI](https://github.com/gocontentflow/contentflow-python/actions/workflows/ci.yml/badge.svg)](https://github.com/gocontentflow/contentflow-python/actions/workflows/ci.yml)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

## Installation

```bash
pip install contentflow-sdk
```

## Quick Start

```python
from contentflow import ContentFlow

client = ContentFlow(api_key="pk_live_...")

# Search 50,000+ hours of podcast content
results = client.search.hybrid(query="AI fundraising strategies")
for result in results.results:
    print(f"{result.title}: {result.best_chunk_text[:100]}")

# Transcribe any YouTube video
job = client.jobs.create(youtube_url="https://youtube.com/watch?v=...")
job = client.jobs.wait(job.id)  # polls until complete

summary = client.jobs.get_summary(job.id)
print(summary.summaries[0].content)
```

## Async Support

```python
from contentflow import AsyncContentFlow

async with AsyncContentFlow() as client:
    job = await client.jobs.create(youtube_url="https://youtube.com/watch?v=...")
    job = await client.jobs.wait(job.id)
    transcript = await client.jobs.get_transcript(job.id)
```

## Features

- **Typed responses** — full Pydantic models with IDE autocomplete
- **Sync + async** — `ContentFlow` and `AsyncContentFlow` clients
- **Smart polling** — `jobs.wait()` with exponential backoff
- **Automatic retries** — configurable retry with backoff on transient errors
- **Rate limit handling** — parsed rate limit headers on `RateLimitError`
- **CLI tool** — `pip install contentflow-sdk[cli]` for terminal access

## API Reference

### Jobs

| Method | Description |
|--------|-------------|
| `client.jobs.create(youtube_url=...)` | Submit a video for transcription |
| `client.jobs.get(job_id)` | Get job status and details |
| `client.jobs.wait(job_id)` | Poll until job completes |
| `client.jobs.create_and_wait(youtube_url=...)` | Submit and wait in one call |
| `client.jobs.get_transcript(job_id, format=...)` | Download transcript (json/srt/markdown/plain) |
| `client.jobs.get_summary(job_id)` | AI summary with citations |
| `client.jobs.get_speakers(job_id)` | Identified speakers and roles |
| `client.jobs.get_segments(job_id)` | Topical video sections |
| `client.jobs.get_entities(job_id)` | Companies, people, products mentioned |
| `client.jobs.get_topics(job_id)` | Topic classifications |

### Search

| Method | Description |
|--------|-------------|
| `client.search.hybrid(query, ...)` | Keyword + semantic search with filters |
| `client.search.semantic(query, ...)` | Pure meaning-based search |

**Search filters:** `limit`, `alpha` (keyword vs semantic balance), `speaker_ids`, `entity_ids`, `topic_ids`, `channel_ids`, `date_from`, `date_to`

## CLI

```bash
pip install contentflow-sdk[cli]
export CONTENTFLOW_API_KEY=pk_live_...

# Submit and wait for transcription
contentflow jobs create "https://youtube.com/watch?v=..." --wait

# Download transcript
contentflow jobs transcript JOB_ID --format markdown --output transcript.md

# Get AI summary
contentflow jobs summary JOB_ID

# Search across all content
contentflow search hybrid "startup fundraising" --limit 5
contentflow search semantic "how to handle investor objections"
```

## Configuration

```python
client = ContentFlow(
    api_key="pk_live_...",            # or set CONTENTFLOW_API_KEY env var
    base_url="https://custom.url",    # default: https://api.gocontentflow.com
    timeout=60.0,                     # request timeout in seconds (default: 30)
    max_retries=5,                    # retry count for transient errors (default: 3)
)
```

## Error Handling

```python
from contentflow import ContentFlow, RateLimitError, NotFoundError, AuthenticationError

client = ContentFlow(api_key="pk_live_...")

try:
    job = client.jobs.get("nonexistent-id")
except NotFoundError:
    print("Job not found")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
    print(f"Remaining: {e.remaining}/{e.limit}")
except AuthenticationError:
    print("Invalid API key")
```

**Exception hierarchy:**

```
ContentFlowError
├── APIError
│   ├── APIConnectionError
│   │   └── APITimeoutError
│   └── APIStatusError
│       ├── BadRequestError        (400)
│       ├── AuthenticationError    (401)
│       ├── PermissionDeniedError  (403)
│       ├── NotFoundError          (404)
│       ├── RateLimitError         (429)
│       └── InternalServerError    (5xx)
├── JobFailedError
└── JobTimeoutError
```

## Get Your API Key

Sign up at [gocontentflow.com](https://gocontentflow.com) to get your API key.
