# AI Story Livestream

An endless AI-generated visual storytelling livestream powered by the
[Reactor Python SDK](https://github.com/reactor-team/py-sdk) and OpenAI.

The app connects to the **livecore** model (LongLive), which generates real-time
video frames.  Stories are written by ChatGPT as a sequence of 7 cinematic
scenes, and the scene descriptions are scheduled as prompt transitions across
the 240-frame generation window — producing smooth, continuous visual
storytelling streamed live to YouTube (or any RTMP endpoint).

## Features

- **AI-written stories** — each story is generated by OpenAI ChatGPT with 7
  visual scenes and 6 smooth transitions.
- **Pipeline** — while the current story renders, the next story is generated in
  the background so there is zero downtime between stories.
- **Endless streaming** — topics are loaded from `topics.txt` and cycled
  through forever.
- **Auto-reconnect** — if the WebRTC connection to Reactor drops, the app
  reconnects and resumes from the next story.  The RTMP stream to YouTube stays
  alive across reconnections.
- **RTMP output** — streams to YouTube Live, Twitch, or any RTMP server via
  ffmpeg.

## Prerequisites

1. **ffmpeg** must be installed and in your `PATH`:
   ```bash
   # macOS
   brew install ffmpeg
   # Ubuntu / Debian
   apt install ffmpeg
   ```

2. **OpenAI API key** — set the `OPENAI_API_KEY` environment variable:
   ```bash
   export OPENAI_API_KEY=sk-...
   ```

3. **Python 3.10+** with dependencies:
   ```bash
   pip install -r requirements.txt
   ```

## Usage

### Stream to YouTube Live

```bash
# Using Reactor cloud
python main.py \
    --api-key YOUR_REACTOR_API_KEY \
    --rtmp-url "rtmp://a.rtmp.youtube.com/live2/YOUR_STREAM_KEY"

# Using local coordinator (development)
python main.py \
    --local \
    --rtmp-url "rtmp://a.rtmp.youtube.com/live2/YOUR_STREAM_KEY"
```

### With background audio

```bash
python main.py \
    --api-key KEY \
    --rtmp-url "rtmp://a.rtmp.youtube.com/live2/STREAM_KEY" \
    --audio background_music.mp3
```

### With YouTube live chat integration

Stories are driven by what the audience types in chat.  The app reads the
last 5 messages; if they are new (not yet used), they become the next
story topic.  Otherwise it falls back to `topics.txt`.

```bash
export YOUTUBE_API_KEY=AIza...
python main.py \
    --api-key KEY \
    --rtmp-url "rtmp://a.rtmp.youtube.com/live2/STREAM_KEY" \
    --youtube-video-id dQw4w9WgXcQ
```

> **Note:** You need a YouTube Data API v3 key.  Create one in the
> [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
> and enable the **YouTube Data API v3**.

### All options

| Flag                   | Default        | Description                                      |
|------------------------|----------------|--------------------------------------------------|
| `--model`, `-m`        | `livecore`     | Reactor model name                               |
| `--api-key`, `-k`      | —              | Reactor API key (required unless --local)         |
| `--local`, `-l`        | off            | Use local coordinator                            |
| `--rtmp-url`, `-r`     | *(required)*   | RTMP URL with stream key                         |
| `--fps`, `-f`          | `20`           | Output frame rate                                |
| `--audio`, `-a`        | silent         | MP3 file to loop as background audio             |
| `--topics-file`        | `./topics.txt` | Path to the topics file                          |
| `--openai-model`       | `gpt-4o-mini`  | OpenAI model for story generation                |
| `--youtube-video-id`   | disabled       | YouTube video ID to read live chat (needs `YOUTUBE_API_KEY`) |
| `--verbose`, `-v`      | off            | Enable debug logging                             |

## How It Works

```
┌─────────────────────────────────────────────────────────┐
│                    AI Story Livestream                   │
│                                                         │
│  ┌──────────┐    schedule_prompt ×7    ┌─────────────┐  │
│  │  OpenAI  │ ──────────────────────>  │  livecore   │  │
│  │ ChatGPT  │        + start           │  (Reactor)  │  │
│  └──────────┘                          └──────┬──────┘  │
│       ▲                                       │         │
│       │ pipeline:                        frames│         │
│       │ generate next                    (WebRTC)       │
│       │ story while                           │         │
│       │ rendering                             ▼         │
│       │                                ┌─────────────┐  │
│       └─ on complete ◄──── state ◄──── │   ffmpeg    │  │
│                                        │  (RTMP/FLV) │  │
│                                        └──────┬──────┘  │
│                                               │         │
└───────────────────────────────────────────────┼─────────┘
                                                │
                                                ▼
                                       YouTube Live / Twitch
```

1. A topic is picked from `topics.txt`.
2. ChatGPT generates a story as 7 cinematic scene descriptions.
3. The 7 prompts are scheduled on livecore at frames 0, 34, 68, 102, 136, 170,
   and 204 (6 transitions across 240 frames).
4. `start` is sent — livecore begins generating video frames.
5. Frames arrive via WebRTC and are piped to ffmpeg for RTMP streaming.
6. **While rendering**, the next story is generated in the background (pipeline).
7. When all 240 frames are done, the next story is immediately scheduled and
   started.
8. If the connection drops, the app reconnects and picks up from the next topic.

## Customizing Topics

Edit `topics.txt` — one topic per line.  Lines starting with `#` are comments.
The app shuffles the list at startup and cycles through it endlessly.

## Production Considerations

- **YouTube stream key**: Use a persistent stream key so reconnections resume
  the same broadcast.
- **Audio**: YouTube requires an audio track.  Without `--audio`, a silent track
  is generated.  For a better experience, provide a royalty-free MP3.
- **Monitoring**: The app logs frame counts, story completions, and
  reconnection attempts.  Pipe logs to a file for long-running streams.
