Metadata-Version: 2.4
Name: slide-stream
Version: 2.9.1
Summary: An AI-powered tool to automatically create video presentations from Markdown and PowerPoint files
Project-URL: Homepage, https://github.com/michael-borck/slide-stream
Project-URL: Repository, https://github.com/michael-borck/slide-stream
Project-URL: Issues, https://github.com/michael-borck/slide-stream/issues
Author-email: Michael Borck <michael.borck@curtin.edu.au>
License: MIT
License-File: LICENSE
Keywords: ai,cli,markdown,presentation,video
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
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: Topic :: Multimedia :: Video
Classifier: Topic :: Text Processing :: Markup
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: gtts>=2.4.0
Requires-Dist: markdown>=3.5.0
Requires-Dist: moviepy<3.0.0,>=2.0.0
Requires-Dist: pillow>=10.1.0
Requires-Dist: python-pptx>=1.0.2
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: requests>=2.31.0
Requires-Dist: rich>=13.0.0
Requires-Dist: typer>=0.9.0
Requires-Dist: typing-extensions>=4.8.0
Provides-Extra: all-ai
Requires-Dist: anthropic>=0.7.0; extra == 'all-ai'
Requires-Dist: elevenlabs<3.0.0,>=1.5.0; extra == 'all-ai'
Requires-Dist: google-genai>=1.0.0; extra == 'all-ai'
Requires-Dist: google-generativeai>=0.3.0; extra == 'all-ai'
Requires-Dist: groq>=0.4.0; extra == 'all-ai'
Requires-Dist: openai>=1.0.0; extra == 'all-ai'
Provides-Extra: claude
Requires-Dist: anthropic>=0.7.0; extra == 'claude'
Provides-Extra: dev
Requires-Dist: basedpyright>=1.8.0; extra == 'dev'
Requires-Dist: fastapi>=0.110.0; extra == 'dev'
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: python-multipart>=0.0.9; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: uvicorn>=0.29.0; extra == 'dev'
Provides-Extra: elevenlabs
Requires-Dist: elevenlabs<3.0.0,>=1.5.0; extra == 'elevenlabs'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
Requires-Dist: google-generativeai>=0.3.0; extra == 'gemini'
Provides-Extra: groq
Requires-Dist: groq>=0.4.0; extra == 'groq'
Provides-Extra: local-tts
Requires-Dist: kokoro-onnx>=0.4.0; extra == 'local-tts'
Requires-Dist: soundfile>=0.12.0; extra == 'local-tts'
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == 'openai'
Provides-Extra: serve
Requires-Dist: fastapi>=0.110.0; extra == 'serve'
Requires-Dist: python-multipart>=0.0.9; extra == 'serve'
Requires-Dist: uvicorn>=0.29.0; extra == 'serve'
Description-Content-Type: text/markdown

# Slide Stream 2.0

<!-- BADGES:START -->
[![ai](https://img.shields.io/badge/-ai-ff6f00?style=flat-square)](https://github.com/topics/ai) [![cli-tool](https://img.shields.io/badge/-cli--tool-blue?style=flat-square)](https://github.com/topics/cli-tool) [![markdown-to-video](https://img.shields.io/badge/-markdown--to--video-blue?style=flat-square)](https://github.com/topics/markdown-to-video) [![natural-language-processing](https://img.shields.io/badge/-natural--language--processing-blue?style=flat-square)](https://github.com/topics/natural-language-processing) [![python](https://img.shields.io/badge/-python-3776ab?style=flat-square)](https://github.com/topics/python) [![text-to-speech](https://img.shields.io/badge/-text--to--speech-blue?style=flat-square)](https://github.com/topics/text-to-speech) [![video-creation](https://img.shields.io/badge/-video--creation-blue?style=flat-square)](https://github.com/topics/video-creation) [![image-sourcing](https://img.shields.io/badge/-image--sourcing-blue?style=flat-square)](https://github.com/topics/image-sourcing) [![powerpoint-to-video](https://img.shields.io/badge/-powerpoint--to--video-blue?style=flat-square)](https://github.com/topics/powerpoint-to-video) [![presentation-automation](https://img.shields.io/badge/-presentation--automation-blue?style=flat-square)](https://github.com/topics/presentation-automation)
<!-- BADGES:END -->

🎬 **Professional AI-powered video presentations from Markdown and PowerPoint files.**

[![PyPI version](https://badge.fury.io/py/slide-stream.svg)](https://badge.fury.io/py/slide-stream)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Transform your content into stunning video presentations with AI-generated images, premium text-to-speech, and smart content enhancement. **Version 2.0** introduces a modern configuration system and professional-grade providers.

## ✨ What's New in 2.0

- 🖼️ **AI Image Generation**: DALL-E 3 creates custom images for your slides
- 🎙️ **Premium Voices**: ElevenLabs delivers studio-quality narration  
- 📸 **Stock Photos**: Pexels & Unsplash integration with API keys
- ⚙️ **Configuration System**: YAML-based setup with environment variables
- 🎯 **Simplified CLI**: Clean commands, no more option overload
- 🔄 **Smart Fallbacks**: Graceful degradation when services unavailable

## 🚀 Quick Start

### 1. Installation

```bash
# Install with all AI providers
pip install slide-stream[all-ai]

# Or install with specific providers
pip install slide-stream[openai,elevenlabs]
```

### 2. Setup Configuration

```bash
# Create configuration file
slide-stream init

# Check available providers
slide-stream providers
```

### 3. Configure API Keys

Set environment variables for the services you want to use:

```bash
# For AI image generation
export OPENAI_API_KEY="your-openai-key"

# For premium text-to-speech  
export ELEVENLABS_API_KEY="your-elevenlabs-key"

# For stock photos (optional)
export PEXELS_API_KEY="your-pexels-key"
export UNSPLASH_ACCESS_KEY="your-unsplash-key"
```

### 4. Create Your First Video

```bash
# Create from Markdown
slide-stream create presentation.md output.mp4

# Create from PowerPoint
slide-stream create slides.pptx video.mp4
```

## 🎯 Usage Examples

### Basic Video Creation

```bash
# Simple creation (uses default config)
slide-stream create slides.md presentation.mp4

# With custom configuration
slide-stream create --config my-config.yaml presentation.pptx video.mp4
```

### Example Markdown File

```markdown
# Welcome to AI-First Development

- Build smarter applications with integrated AI
- Learn practical implementation patterns
- Deploy production-ready solutions

# Why Choose AI-First?

- Faster development cycles
- Enhanced user experiences  
- Competitive advantage in the market

# Getting Started

- Set up your development environment
- Choose the right AI services
- Build your first AI-powered feature
```

## ⚙️ Configuration

SlideStream layers configuration so you set shared things (a TTS server URL,
API keys) once and keep per-deck settings separate. Later layers win:

1. Built-in defaults
2. **`~/.slidestream.yaml`** — personal: your Chatterbox/LLM server URLs and
   API-key references, shared across every project
3. **`./slidestream.yaml`** (or `--config FILE`) — settings for the deck at hand
4. **CLI flags** (`--voice`, `--tts-base-url`, `--narration-seconds`, …) — win
   over everything, for one-off runs

Run `slide-stream init` to write a starter `slidestream.yaml`. API keys are
read from the environment via `${VAR}` expansion, so secrets never live in the
files. Example:

```yaml
# slidestream.yaml
providers:
  llm:
    provider: openai        # Content enhancement
    model: gpt-4o-mini
    
  images:
    provider: dalle3        # AI-generated images
    fallback: text         # Fallback when DALL-E unavailable
    
  tts:
    provider: elevenlabs   # Premium text-to-speech
    voice: rachel          # Voice selection

# API Keys (use environment variables for security)
api_keys:
  openai: "${OPENAI_API_KEY}"
  elevenlabs: "${ELEVENLABS_API_KEY}"
  pexels: "${PEXELS_API_KEY}"
  unsplash: "${UNSPLASH_ACCESS_KEY}"

settings:
  video:
    resolution: [1920, 1080]
    fps: 24
    codec: libx264
  cleanup: true
```

### Configuration Discovery

SlideStream automatically finds your config in this order:
1. `./slidestream.yaml` (current directory)
2. `~/.slidestream.yaml` (home directory)  
3. Built-in defaults

## 🔧 Available Providers

### Image Providers

| Provider | Description | Requirements |
|----------|------------|--------------|
| `dalle3` | AI image generation via DALL-E 3 | OpenAI API key |
| `pexels` | Professional stock photos | Pexels API key |
| `unsplash` | High-quality stock photos | Unsplash API key |
| `text` | Text-based slides (always available) | None |

### Text-to-Speech Providers

| Provider | Description | Requirements |
|----------|------------|--------------|
| `elevenlabs` | Premium AI voices with emotion | ElevenLabs API key |
| `openai` | Natural OpenAI TTS voices | OpenAI API key |
| `gtts` | Google Text-to-Speech (free) | None |

### LLM Providers

| Provider | Description | Requirements |
|----------|------------|--------------|
| `openai` | GPT models for content enhancement | OpenAI API key |
| `gemini` | Google Gemini models | Gemini API key |
| `claude` | Anthropic Claude models | Anthropic API key |
| `groq` | Fast inference with Groq | Groq API key |
| `ollama` | Local models via Ollama | Ollama installation |

## 📋 CLI Commands

### Core Commands

```bash
# Create video presentation
slide-stream create <input_file> <output_file>

# Generate example configuration
slide-stream init [config_file]

# List available providers and their status
slide-stream providers

# Web UI: upload a deck + voice + photo in the browser, render, download
slide-stream serve                    # needs: pip install "slide-stream[serve]"

# Show help
slide-stream --help
```

### Web UI

```bash
pip install "slide-stream[serve]"
slide-stream serve                    # local: binds 127.0.0.1, opens a browser
slide-stream serve --host 0.0.0.0 --token "$(openssl rand -hex 24)"   # VPS, token-gated
```

Upload a deck (`.md`/`.pptx`) plus an optional **voice sample** and **photo**;
it renders as a background job and returns a video. Token-authenticated (set
`--token` / `SLIDESTREAM_TOKEN`; auto-minted on a non-local bind). The server
is **stateless about biometric data** — an uploaded voice/photo is used only
for that render and deleted afterwards; the lecturer's **browser** remembers
them (IndexedDB) so they need not re-pick each job, keeping the data on their
own laptop. Voice server, image provider, avatar engine, and API keys come
from the server's own layered config (`~/.slidestream.yaml`).

### Examples

```bash
# Basic usage
slide-stream create slides.md presentation.mp4

# With custom config
slide-stream create --config prod.yaml deck.pptx video.mp4

# Check what's available
slide-stream providers

# Create config file
slide-stream init my-config.yaml
```

## 🎨 Advanced Features

### PowerPoint Integration

- **Slide Content**: Extracts titles, bullet points, and images
- **Speaker Notes**: Uses notes for enhanced AI narration
- **Layouts**: Preserves slide structure and hierarchy

### AI Enhancement

- **Content Improvement**: LLMs enhance slide text for better flow
- **Image Generation**: DALL-E 3 creates relevant, professional images
- **Voice Selection**: Choose from multiple TTS voices and styles

### Professional Output

- **HD Video**: 1920x1080 resolution by default
- **Quality Audio**: Synchronized speech with proper timing
- **Custom Timing**: Configurable slide durations and padding

## 🔑 Getting API Keys

### OpenAI (for DALL-E 3 & GPT)
1. Visit [OpenAI Platform](https://platform.openai.com)
2. Sign up and create an API key
3. Add billing method (pay-per-use)

### ElevenLabs (for Premium TTS)
1. Visit [ElevenLabs](https://elevenlabs.io)
2. Create account and get API key
3. Choose from 900+ voices

### Pexels (for Stock Photos)
1. Visit [Pexels API](https://www.pexels.com/api/)
2. Sign up for free API access
3. Get your API key

### Unsplash (for Stock Photos)
1. Visit [Unsplash Developers](https://unsplash.com/developers)
2. Create application
3. Get your access key

## 📦 Installation Options

```bash
# Core package only
pip install slide-stream

# With specific AI providers
pip install slide-stream[openai]
pip install slide-stream[elevenlabs]
pip install slide-stream[gemini]
pip install slide-stream[claude]
pip install slide-stream[groq]

# All AI providers
pip install slide-stream[all-ai]

# Development dependencies
pip install slide-stream[dev]
```

## 📋 Requirements

- **Python**: 3.10 or higher
- **FFmpeg**: For video processing
- **Internet**: For AI services and stock photos (offline mode available)

### Installing FFmpeg

```bash
# macOS
brew install ffmpeg

# Ubuntu/Debian
sudo apt update && sudo apt install ffmpeg

# Windows
# Download from https://ffmpeg.org/download.html
```

## 🔧 Configuration Reference

### Provider Options

**Image Providers:**
- `text`: Always available, no setup required
- `local`: Pick images from a local folder by filename keywords (`providers.images.folder`); pair with `slide-stream scan` to AI-name them
- `dalle3`: Requires `OPENAI_API_KEY`
- `gemini`: Google Imagen generation, cheap (~$0.02/image) — `pip install "slide-stream[gemini]"` + `GEMINI_API_KEY`; set `providers.images.model` for the Imagen tier (default Fast)
- `swarmui`: Self-hosted [SwarmUI](https://github.com/mcmonkeyprojects/SwarmUI) server (`base_url`), free local generation via its native API — set `providers.images.model` (e.g. `juggernautXL_v9`), optional `steps`/`width`/`height`/`api_key`
- `pexels`: Requires `PEXELS_API_KEY`  
- `unsplash`: Requires `UNSPLASH_ACCESS_KEY`

### Enriching a deck with images (`enrich` / `scan`)

Beyond making videos, SlideStream can add an image to each slide and write a
**new editable deck** — no narration, no video, your original untouched:

```bash
# Markdown deck + images/ folder (default). Add --pptx for a PowerPoint too.
slide-stream enrich deck.md out/ --image-provider dalle3
slide-stream enrich deck.md out/ --image-provider local --image-folder ./pics --pptx
```

The output is a real artifact you can review, hand-edit, or narrate as a second
pass (`slide-stream create out/deck.md video.mp4`). For a one-pass video that
adds images *and* narrates internally, just run `create` with an image
provider configured — `enrich` is the deck-only track.

`scan` AI-renames a folder of images to keyword slugs so the `local` provider
can match them to slides (dry-run by default):

```bash
slide-stream scan ./pics --provider claude          # preview renames
slide-stream scan ./pics --provider claude --apply  # actually rename + write report
```

**TTS Providers:**
- `gtts`: Free, always available (needs internet). English accent via `providers.tts.accent` (`australian`, `british`, `american`, `canadian`, `indian`, `irish`, `south-african`).
- `kokoro`: Fully offline, no API key — `pip install "slide-stream[local-tts]"` (~340MB one-time model download; voices include `af_sarah`, `af_bella`, `am_adam`, `am_michael`)
- `chatterbox`: Voice cloning via a self-hosted [Chatterbox TTS Server](https://github.com/devnen/Chatterbox-TTS-Server) (`base_url`); see "Privacy-first voice cloning" below
- `elevenlabs`: Requires `ELEVENLABS_API_KEY`
- `openai`: Requires `OPENAI_API_KEY`
- `openai-compatible`: Any OpenAI-compatible speech endpoint via `base_url` (local or hosted)

### Privacy-first voice cloning

The `chatterbox` provider narrates videos in your own voice without storing it
on the server between runs:

```yaml
providers:
  tts:
    provider: chatterbox
    base_url: https://chatterbox.example.org
    voice_sample: ./my_voice.wav       # 10-30s of clean speech (<5s fails)
    api_key: "${CHATTERBOX_TOKEN}"     # if your proxy checks a Bearer token
settings:
  strict: true                         # never fall back to the wrong voice
```

- `voice_sample` is uploaded **once per run under a random UUID filename** and
  referenced only for that render — no recognisable voice name ever exists on
  the server, and other users can neither find nor select it.
- Schedule `contrib/chatterbox/cleanup_uuid_voices.sh` on the server (cron) to
  delete UUID files after a grace period. Zero-shot cloning has no training
  step, so re-uploading each run costs only ~1-2 seconds.
- Prefer a stock server voice instead? Set `voice: Emily.wav` (or any name
  from `slide-stream voices`, which lists server voices and hides ephemeral
  UUID uploads).

### Narration

By default (when an LLM provider is configured) SlideStream writes narration
that *complements* the slides instead of reading them aloud, choosing a source
per slide:

1. **Speaker notes** (`.pptx`) — cleaned into speakable prose and fitted to the
   target length (long notes are summarised, thin ones expanded).
2. **Slide content** — turned into what a presenter would *say*, not a recital
   of the bullets.
3. **Slide image** — image-only slides are described by a vision-capable
   provider (`claude`, `openai`, `gemini`) and tied to the slide title.
4. **Title only** — a brief spoken introduction.

Control it per run:

```bash
# Aim for ~30 seconds of narration per slide
slide-stream create deck.pptx out.mp4 --llm-provider claude --narration-seconds 30

# Speak the PowerPoint speaker notes exactly as written (no LLM rewriting)
slide-stream create deck.pptx out.mp4 --verbatim-notes

# Provide your own script: one block per slide, separated by lines of ---
slide-stream create deck.md out.mp4 --script narration.txt
```

`--llm-model` selects a specific model (e.g. `claude-haiku-4-5`, the default for
Claude). API keys are read from the environment (`ANTHROPIC_API_KEY`,
`OPENAI_API_KEY`, `GEMINI_API_KEY`, `GROQ_API_KEY`). A `--script` file looks
like:

```
Welcome to the course. Today we cover neural networks.
---
A perceptron is the simplest building block of a network.
---
Thanks for watching.
```

**Avatar Providers (talking-head overlay):**
- `none`: Disabled (default)
- `static`: A **static mascot image** in the corner (no lip-sync, no GPU). Use a built-in character (`slide-stream avatars` lists `teddy`, `panda`, `koala`, `robot`, `wizard`, `owl`) or your own image: `providers.avatar: {provider: static, source: teddy}`. A fun character + a chosen accent dodges the "looks like me but isn't quite me" uncanny valley. **Note:** SadTalker/Wav2Lip only lip-sync *photorealistic human* faces — stylized/animal mascots stay static here, or lip-sync via a stylized-capable engine like `d-id`.
- `puppet`: A **cartoon mouth-flap** on a mascot, driven by the audio's loudness (open when loud, closed on silence) — no AI, no face detection, no GPU. The reliable *animated* tier for mascots: `providers.avatar: {provider: puppet, source: teddy}`. For a custom image, set the mouth region with `mouth: [cx, cy, w, h]` (fractions).
- `precomputed`: Composites `head_1.mp4`, `head_2.mp4`, … from `providers.avatar.assets_dir` as a circle in a corner of each slide — no GPU or service needed.
- `sadtalker`: Self-hosted talking head from a **photo**, via [SadTalker](https://github.com/OpenTalker/SadTalker) as a ComfyUI node — `providers.avatar.base_url` + `source_image`.
- `wav2lip`: Self-hosted talking head from a short **video**, via Wav2Lip as a ComfyUI node — `base_url` + `source_video` (a ~15s idle clip; loops under longer narration). More natural than a photo; see [docs/wav2lip-api.md](docs/wav2lip-api.md).
- `comfyui`: **Auto-router** — set `base_url` + a `source` that's either a photo or a video, and it picks SadTalker or Wav2Lip automatically. Ideal for the web UI. See [docs/talking-head-options.md](docs/talking-head-options.md).
- `d-id`: Lip-synced talking head generated from a source image via the [D-ID](https://www.d-id.com/) API (BYOK) — set `providers.avatar.source_image` (lecturer photo) and `api_key`/`DID_API_KEY`. Bills per minute of video (~$1–2/min), so pricier than voice/images.

Enable per run with `--avatar`, disable with `--no-avatar`; appearance via `settings.avatar` (`position`, `size`, `margin`).

**LLM Providers:**
- `none`: No content enhancement
- `openai`: Requires `OPENAI_API_KEY`
- `gemini`: Requires `GEMINI_API_KEY`
- `claude`: Requires `ANTHROPIC_API_KEY`
- `groq`: Requires `GROQ_API_KEY`
- `ollama`: Requires local Ollama installation

### Voice Options

**ElevenLabs Voices:**
- `rachel`: Professional female voice
- `adam`: Clear male voice
- `aria`: Expressive female voice
- (See [ElevenLabs docs](https://elevenlabs.io/docs) for full list)

**OpenAI Voices:**
- `alloy`: Balanced and natural
- `echo`: Clear and articulate  
- `fable`: Warm and engaging
- `nova`: Bright and energetic
- `onyx`: Deep and authoritative
- `shimmer`: Gentle and soothing

## 🤝 Contributing

We welcome contributions! See our documentation:

- **[User Guide](docs/USER_GUIDE.md)** - Comprehensive usage examples
- **[Development Workflow](docs/DEVELOPMENT_WORKFLOW.md)** - Setup and testing
- **[Type Safety](docs/TYPE_SAFETY.md)** - Code quality standards

## 🆕 Version History

- **2.0.0**: Configuration system, provider architecture, AI image generation
- **1.1.x**: PowerPoint support, bug fixes, stability improvements  
- **1.0.0**: Initial release with Markdown support

## 📄 License

MIT License - see [LICENSE](LICENSE) file for details.

## 🙏 Acknowledgments

Built with these excellent tools:
- [Typer](https://typer.tiangolo.com/) - Modern CLI framework
- [Rich](https://rich.readthedocs.io/) - Beautiful terminal output
- [MoviePy](https://moviepy.readthedocs.io/) - Video processing
- [OpenAI](https://openai.com/) - AI image generation and LLM
- [ElevenLabs](https://elevenlabs.io/) - Premium text-to-speech
- [PyYAML](https://pyyaml.org/) - Configuration parsing

---

**Ready to create professional presentations?** Get started with `pip install slide-stream[all-ai]` 🚀