# TiDB social image pipeline

This directory is a portable reference implementation for generating TiDB campaign images. It was extracted from the aether-plus PLG Cloud repo and should be treated as both runnable code and a concrete recipe for LinkedIn/social image production.

## Pipeline overview

```text
campaign spec
  -> creative_director.py
     Claude Haiku returns scene_prompt, headlines, badge, subtitle, badge_color
  -> flux_client.py
     Flux 2 Pro renders a raw text-free scene
  -> compositor.py
     Pillow applies TiDB logo, gradients, headline, badge, event metadata, grain
  -> generate_campaign_images.py
     writes PNGs and updates image URLs in the spec
```

The default LinkedIn output is `1200 x 627`. Platform dimensions and copy rules live in `brand.py`.

## Required environment

Install dependencies:

```bash
pip install -r scripts/image_pipeline/requirements.txt
```

Required tokens:

```bash
export ANTHROPIC_API_KEY="..."
export REPLICATE_API_TOKEN="..."
```

Optional output routing:

```bash
export PLG_IMAGE_DIR="/absolute/path/to/output"
export PLG_IMAGE_BASE_URL="https://example.com/images"
```

If output routing is not set, `brand.py` falls back to the original viewer path from the source repo. In a new integration, set both environment variables explicitly.

## Run

```bash
python scripts/image_pipeline/generate_campaign_images.py /path/to/spec.json
```

The spec should contain `campaigns`, plus `emails` and/or `assets` referenced by campaign IDs. For each target, the script generates a platform-specific PNG and writes the corresponding image URL back into the spec.

## LinkedIn recipe

Use this structure for LinkedIn cards:

- Canvas: `1200 x 627`.
- Scene: dark, minimal, text-free AI illustration.
- Composition: left 55% black negative space, illustrated object in the right third.
- Logo: TiDB logo top-left.
- Badge: top-right compact label.
- Headline: 2-3 large lines on the left; exactly one accent line where possible.
- Accent colors: red, teal, or orange; remaining headline lines white.
- CTA: never in the image. Put post links in the first LinkedIn comment.

Scene prompt template:

```text
A stylized 3D cartoon illustration of [campaign metaphor],
small illustration positioned in the right third of the frame.
Left 55% is clean pure black negative space.
Brand colors: translucent red, teal, occasional orange accents.
Dark background, dramatic rim lighting, modern tech startup marketing illustration style.
Sophisticated minimal composition.
No text no words no letters anywhere in the image.
```

## Files

| File | Purpose |
|---|---|
| `brand.py` | TiDB colors, fonts, platform dimensions, platform copy rules, output routing. |
| `creative_director.py` | Converts a campaign into a structured creative spec using Claude Haiku. |
| `flux_client.py` | Calls Flux 2 Pro through Replicate and saves the raw scene. |
| `compositor.py` | Applies TiDB branding and layout with Pillow. |
| `generate_campaign_images.py` | End-to-end CLI coordinator. |
| `fonts/` | DM Sans font files used by the compositor. |
| `assets/` | TiDB logo and symbol PNGs. |

## Language behavior

`creative_director.py` detects obvious non-English campaigns and injects an explicit language instruction. The image-model scene prompt stays in English. Visible output text, including headline lines and badges, should match the campaign language.

Supported heuristics: Brazilian Portuguese, Spanish, Japanese, Korean, Chinese.

## Notes for maintainers

- The compositor intentionally does not render the subtitle; it was too small at feed sizes.
- HN, Reddit, GitHub, and Google Ads are no-image platforms by default.
- LinkedIn and Facebook ad creatives can receive generated visuals when their asset metadata detects those platforms.
- Event campaign metadata should come from structured spec fields, not from LLM inference.
