Metadata-Version: 2.4
Name: slide-skills
Version: 0.2.2
Summary: AI slide generation skills — fill .pptx/SVG templates with AI text, images, themes, and animations
Author: Phat Huynh
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: python-pptx>=1.0
Requires-Dist: openai>=1.40
Requires-Dist: pillow>=10.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: lxml>=4.9
Requires-Dist: resvg-py>=0.1
Provides-Extra: svg-convert
Requires-Dist: pymupdf>=1.24; extra == "svg-convert"
Provides-Extra: svg-fallback
Requires-Dist: svglib>=1.5; extra == "svg-fallback"
Requires-Dist: reportlab>=4.0; extra == "svg-fallback"
Provides-Extra: all
Requires-Dist: pymupdf>=1.24; extra == "all"
Requires-Dist: svglib>=1.5; extra == "all"
Requires-Dist: reportlab>=4.0; extra == "all"

# Slide Generator Lab

AI slide generation in Python. Take a template (a Canva/PowerPoint `.pptx`, or
a hand-designed SVG collection), and generate a finished deck whose **text,
colors, images, and animations** are produced by AI to fit a topic — while the
**layout stays exactly as designed**.

Built as composable skills so the whole thing can be wired into a FastAPI app.
Published on PyPI as [`slide-skills`](https://pypi.org/project/slide-skills/).

---

## Install

**As a library (use in any project):**
```bash
pip install slide-skills                 # latest release from PyPI
# or, the bleeding edge straight from source:
pip install "git+https://github.com/phatgg221/Slide-generator-lab.git"
```

**For development (edit the code, changes apply instantly):**
```bash
git clone https://github.com/phatgg221/Slide-generator-lab.git
cd Slide-generator-lab
python3 -m venv .venv && source .venv/bin/activate
pip install -e .                         # editable install
```

Optional extras:
```bash
pip install "slide-skills[svg-convert]"  # PyMuPDF, for .pptx -> SVG conversion
pip install "slide-skills[all]"          # everything optional
```

## Requirements

| What | Needed for | Notes |
|---|---|---|
| **`OPENAI_API_KEY`** | any AI step (text, images, planning) | put in env or a `.env` file |
| Python ≥ 3.9 | everything | |
| `resvg-py` (auto-installed) | rendering SVG/web decks | bundled, no system deps |
| **LibreOffice** | `svg_template_maker` only (.pptx → SVG) | `brew install --cask libreoffice`; optional |

Environment variables (all optional):
```bash
OPENAI_API_KEY=sk-...            # required for AI calls
OPENAI_TEXT_MODEL=gpt-4o         # default
OPENAI_IMAGE_MODEL=gpt-image-1   # skip image-model auto-detection
SLIDE_TEMPLATES_DIR=/path/to/svg/templates   # where your SVG collections/categories live
SLIDE_LIBRARY_DIR=/path/to/pptx/templates    # where your .pptx templates live
```
The two `*_DIR` vars are the key to using this as an installed package: set
them once and the library finds your templates wherever you keep them — your
designs live outside the code package.

---

## Two paths

The project supports two delivery targets that share most of the same skills:

| | **PPTX path** | **Web path** (current focus) |
|---|---|---|
| Output | Downloadable PowerPoint file | Self-contained animated HTML for your website |
| Template source | Canva/PowerPoint `.pptx` | Hand-designed SVG collections (Figma/Inkscape) |
| Animation | PowerPoint transitions + entrance effects | Native SVG/CSS animation (Canva-like) |
| Main CLI | `examples/build_course_deck.py` | `examples/web_deck.py` |

The web path is preferred because SVG keeps text editable, colors remappable,
and animations playable in the browser — and it needs no desktop renderer.

---

## Use as a Python library

Once installed, import the skills from anywhere:

```python
from slide_skills import generate_web_deck

# Topic -> animated HTML deck (writes the file, returns a summary dict)
result = generate_web_deck(
    collection="starter",                 # folder under SLIDE_TEMPLATES_DIR
    brief="Khóa học nhập môn Machine Learning",
    output_path="out/deck.html",
    palette="teal",                       # "auto" | preset name | (primary, secondary, accent) | None
    language="Vietnamese",
    animation="rise",                     # rise | fade | scale | none
)
print(result["output_path"], result["slides"])
print(result["usage"]["report"])          # tokens + estimated USD for this call
```

Every `generate_*` call returns a `usage` block with the total cost of that run:
```python
result["usage"]   # {input_tokens, output_tokens, total_tokens, requests,
                  #  estimated_cost_usd, report}
```

**Category library + variant-selecting agent** (your plan names categories; the
agent picks the best design variant per slide):
```python
from slide_skills import generate_deck_from_plan, scan_template_library

lib = scan_template_library("templates")     # discover categories + variants
print(lib.category_map())                     # registry for a UI / planner

plan = {"title": "ML 101", "slides": [
    {"category": "Title Slide", "topic": "Intro to Machine Learning"},
    {"category": "KPI & Big Numbers", "talking_points": ["78%", "3x", "12M"]},
    {"category": "Conclusion & Summary", "talking_points": ["Recap", "Next steps"]},
]}
generate_deck_from_plan(plan, "templates", "out/deck.html", palette="auto", language="Vietnamese")
```

**Add a collection at runtime** (e.g. a user uploads a Figma export):
```python
from slide_skills import import_collection
import_collection("/path/to/figma_export_folder", "my_style")   # copies + validates
```

**Track cost of any run:**
```python
from slide_skills import usage_tracker
before = usage_tracker.snapshot()
# ... generate ...
print((usage_tracker.snapshot() - before).report())
```

In a **FastAPI** app, wrap blocking calls in a thread:
```python
import asyncio
from fastapi import FastAPI
from fastapi.responses import FileResponse
from slide_skills import generate_web_deck

app = FastAPI()

@app.post("/generate")
async def generate(topic: str, collection: str = "starter"):
    out = "out/deck.html"
    await asyncio.to_thread(generate_web_deck, collection, topic, out)
    return FileResponse(out, media_type="text/html")
```
(Set `SLIDE_TEMPLATES_DIR` so the app finds your collections.)

---

## Quick start (CLI) — Web deck from an SVG collection

```bash
# 1. See available collections
.venv/bin/python examples/web_deck.py list

# 2. Validate a collection — what placeholders did it find? (free, offline)
.venv/bin/python examples/web_deck.py check starter

# 3. Visual preview with stub text (free, offline)
.venv/bin/python examples/web_deck.py demo starter
open out/starter_demo.html

# 4. Generate a real deck from a topic (~$0.02)
.venv/bin/python examples/web_deck.py generate starter \
    "Khóa học nhập môn Machine Learning" -o out/ml_deck.html --language Vietnamese
open out/ml_deck.html
```

In the browser deck: **→/←** to navigate, **f** for fullscreen, elements
animate in as each slide appears.

Options: `--palette teal` (force a theme), `--animation rise|fade|scale|none`,
`--pptx` (also export a PowerPoint copy).

---

## Designing your own SVG collections

You design collections once in Figma/Inkscape; every generated deck reuses
them. A collection is a folder of slide-type SVGs sharing one visual style:

```
svg_templates/<collection>/
  collection.json     # optional: description, palette, fonts, tags
  title.svg           # filename = slide type the planner picks from
  statistic.svg
  comparison.svg ...
```

Rules (see `svg_templates/README.md` for the full guide):

- **Export SVG with "Outline Text" UNCHECKED** — text must stay live `<text>`.
- Placeholders are the text content: `{{title}}`, `{{quote|120}}` (120-char
  budget), `{{body.1}}` / `{{body.2}}` (multi-line).
- One uniform style per placeholder (don't bold half a word — it splits the text).
- Name files by function (`title`, `statistic`, `quote`…); use common fonts.

Then `web_deck.py check` / `demo` your folder before spending on generation.

---

## Category library + variant-selecting agent

For richer decks, organize templates into **categories**, each holding several
**variant** designs for the same layout function. The user's plan names a
category per slide; an agent picks the best-fitting variant for the data.

```
templates/
  TITLE_SLIDE/
    category.json        # optional: descriptions guiding variant choice
    centered.svg         # variants — multiple designs, same purpose
    left_aligned.svg
  KPI_BIG_NUMBERS/
    category.json
    three_stats.svg
    list_style.svg
```

`category.json` (optional but recommended — it's the "map" the agent reads):
```json
{
  "description": "Highlight key metrics with large, scannable numbers.",
  "variants": {
    "three_stats": "Three stat callouts — use for 2-3 key numbers.",
    "list_style":  "A vertical list — use for 4+ numbers or rankings."
  }
}
```

How a variant gets chosen, per slide:
1. **schema-fit shortlist** (code) — keep variants whose slot count fits the data
2. **AI tiebreak** (GPT-4o) — read each finalist's description + slots and the
   slide content, pick the best, and write its text

Adding designs is pure data:
- **New variant** → drop a `.svg` in the category folder (instantly usable;
  add a `category.json` line so the agent knows when to choose it).
- **New category** → make a new folder; it appears in `category_map()` automatically.

Category names match plan labels ignoring case/spaces/`&`/`-`/`_`
(`"KPI & Big Numbers"` → `KPI_BIG_NUMBERS`), but not plurals — name folders to
match your plan labels.

---

## Quick start — PowerPoint deck from a .pptx template

```bash
# Ingest any .pptx into the reusable template library (cleans junk, classifies slides)
.venv/bin/python examples/prepare_template.py "~/Downloads/My Design.pptx" my_template

# See what's editable (free, offline)
.venv/bin/python examples/test_template.py my_template

# Full pipeline: research -> plan -> write -> images -> theme -> animate
.venv/bin/python examples/build_course_deck.py library/my_template.pptx \
    "your topic" --transition fade --animate fade -o out/deck.pptx
```

Cost controls: `--no-research`, `--no-images`, `--svg-images` (cheap vector
illustrations instead of AI photos).

---

## Skills reference (`slide_skills/`)

**Foundation**
- `config.py` — OpenAI client + model config from `.env`
- `usage.py` — token & cost tracking across all AI calls (`usage_tracker`)
- `template_parser.py` — parse a `.pptx` into a fill-spec; classify text roles,
  char budgets; skip tip-bubbles & navigation buttons

**Research → Plan → Write**
- `research.py` — `extract_keywords`, `web_research`
- `planner.py` — `plan_deck`: AI picks slide count, types, order, theme
- `content_generator.py` — `generate_content`: AI writes budget-aware text
- `agent.py` — `SlideGeneratorAgent`: fill one template from a brief
- `pipeline.py` — `CourseDeckPipeline`: the full chained pipeline

**Images**
- `image_generator.py` — `generate_image`: AI photos, auto-detects account's model
- `svg_image_generator.py` — `generate_svg_image`: GPT-4o vector art (~5× cheaper)

**Filling & assembly**
- `slide_filler.py` — write text keeping formatting, auto-shrink overflow, swap images
- `assembler.py` — build a deck by picking/reordering/repeating library slides

**Templating**
- `template_maker.py` — `prepare_template`: ingest + clean + AI-classify a `.pptx`
- `merge_template.py` — `{{placeholder}}` form + schema; AI fills; render
- `svg_template_maker.py` — `.pptx` → folder of live-text SVGs *(needs LibreOffice/PowerPoint)*

**Theme & motion**
- `theme.py` — contrast-safe recoloring, 8 presets, `propose_palette`
- `transitions.py` — PowerPoint slide transitions
- `animations.py` — PowerPoint element entrance animations

**Web decks**
- `svg_collections.py` — scan collections, fill placeholders, retheme,
  `import_collection`, `generate_web_deck`
- `svg_categories.py` — category library + variant-selecting agent:
  `scan_template_library`, `select_and_fill_slide`, `generate_deck_from_plan`
- `html_deck.py` — build a self-contained animated HTML presentation
- `svg_slide_renderer.py` — filled SVGs → PNG → `.pptx` export

---

## Command-line tools (`examples/`)

| Command | Purpose |
|---|---|
| `web_deck.py` | SVG collections → animated web deck (`list`/`check`/`demo`/`generate`) |
| `build_course_deck.py` | Full pipeline → `.pptx` |
| `generate_deck.py` | Fill one template from a brief |
| `prepare_template.py` | Ingest a `.pptx` into the template library |
| `test_template.py` | Dry-run marker fill — see what's editable (free) |
| `recolor_deck.py` | Re-theme an existing deck's colors |
| `merge_deck.py` | `{{placeholder}}` workflow (make/render/generate) |

---

## What can be customized per deck

- **Words** — every `{{placeholder}}` is AI-written, any language
- **Colors** — preset, AI-picked, or custom; always contrast-safe
- **Animation** — rise / fade / scale / none (web) or PowerPoint effects (pptx)
- **Slides** — the planner chooses which template types to use, and their order

Fixed by design: your layout, and (for now) fonts.

---

## Tests (offline, no API key)

```bash
.venv/bin/python tests/test_offline_pipeline.py   # parse / fill / image swap
.venv/bin/python tests/test_assembler.py          # library assembly
```

---

## Known limits

- **Canva exports lose animation and live text.** `.pptx` from Canva is static;
  Canva SVG outlines all text. Design real SVG templates in Figma/Inkscape.
- **`svg_template_maker.py` needs a renderer.** Install LibreOffice
  (`brew install --cask libreoffice`) for headless, server-ready conversion;
  the desktop-PowerPoint fallback is fragile.
- **Charts aren't data-driven yet.** Chart-style slides render as designed art,
  not recomputed from numbers.
- **FastAPI app** is a later milestone; all skills are import-ready for it.

---

## Releasing a new version (maintainers)

```bash
# 1. bump version in BOTH pyproject.toml and slide_skills/__init__.py
# 2. rebuild fresh and publish
rm -rf dist && python -m build
twine upload dist/*          # username: __token__   password: your pypi-... token
# 3. tag it
git tag v0.2.2 && git push origin main --tags
```
PyPI versions are permanent — never reuse a number; bump to the next one.
