Files
videogen/README.md
2026-08-17 23:41:49 +02:00

140 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BrandLoop (videogen)
KI-Video-Generierung mit lernender Brand-Knowledge-Base (Elo-Scoring über Attribute).
- **Prototyp:** [prototyp-app.html](prototyp-app.html) statische Preview unter `videogen.project.webklar.com`
- **Desktop-Ansicht:** Design-Handoff für die Desktop-Adaption in [design/desktop-ansicht/](design/desktop-ansicht/) (Spezifikation: [README.md](design/desktop-ansicht/README.md))
- **Backend:** selbst gehostetes Appwrite (`https://appwrite.webklar.com/v1`), Projekt **BrandLoop** `6a5cee34002bb8360c34`, Datenbank `brandloop`
## App (`client/`)
Expo / React Native, eine Codebase für Web und nativ. Stand: Gerüst aus E1
drei Tabs, sonst leer.
```bash
npm --prefix client run web
```
## Bildgenerierung
Zwei Job-Typen arbeitet der Dispatcher ab **serverseitig**, weil der
Anbieter-Schlüssel nicht ins Client-Bundle darf:
| Job | Entsteht bei | Ergebnis |
|---|---|---|
| `modell_gen` | Modell anlegen (Person, Produkt, Kulisse) | 4 Varianten als Entwurfs-Versionen, eine wird freigegeben |
| `bild_gen` | Post erstellen | Bilderkette in `post_images` |
**Logo-Sonderfall:** Wer eine Datei hochlädt, bekommt sie unverändert als
freigegebene Version ab da wird sie nie neu generiert. Wer keine hat, bekommt
Entwürfe. Sobald etwas freigegeben ist, weist der Dispatcher jede weitere
Generierung auf dieses Asset ab. So bleibt die Brand-Regel gewahrt, ohne Marken
ohne Logo auszusperren.
```bash
node scripts/job-dispatcher.mjs
```
Ohne Angabe läuft er auf `auto` und probiert der Reihe nach **Ark → OpenRouter →
Platzhalter**. Ark steht vorn, weil Seedream mit 0,0450,090 $ je Bild günstiger
ist als Gemini mit 0,14 $ und in `eu-west` läuft. Ist Ark nicht freigeschaltet,
fällt die Kette still auf OpenRouter zurück; jede Zeile im Log nennt den
Anbieter, der geliefert hat.
Unterschieden wird zwischen „Anbieter nicht verfügbar" (Konto zu, kein Guthaben)
und einem echten Fehler nur beim ersten Fall wird weitergereicht, damit ein
inhaltlicher Fehler nicht stillschweigend überdeckt wird.
Fest wählen geht weiterhin: `BILD_ANBIETER=stub|ark|openrouter`.
**Voraussetzungen je Anbieter:** OpenRouter braucht gekauftes Guthaben (eine
hinterlegte Karte genügt nicht es ist ein Prepaid-Konto). BytePlus Ark braucht
die Aktivierung je Modell in der Konsole unter *Model activation*; das ist keine
Zahlungsfrage, verlangt aber die Zustimmung zu mehreren Verträgen.
## Demo-Daten
Demo-Daten zum Anschauen (Marke, zwei Ordner, vier Modelle mit echten Bildern
aus `uploads/`) legt alles als **Client** an, belegt damit nebenbei die
Rechte, und ist idempotent:
```bash
node scripts/seed-demo.mjs
```
Die Mandantentrennung lässt sich jederzeit nachprüfen legt zwei echte Konten an,
prüft über die API und räumt sich selbst auf:
```bash
node scripts/test-mandanten.mjs
```
Die Appwrite-SDKs sind **exakt** gepinnt (`appwrite@23.0.0`,
`react-native-appwrite@0.25.0`): der Server läuft 1.8.1, neuere SDKs sprechen
Response-Format 1.9.x. Beim Server-Upgrade beide zusammen anheben.
Konfiguration (Endpoint, Projekt-ID, DB-ID) steht in `client/app.json` unter
`expo.extra.appwrite`. Der Appwrite-**Server-Key** gehört dort **nicht** hinein
er landet sonst im Client-Bundle; er steht in der `.env` im Repo-Root und wird
nur von `scripts/` und später von Appwrite-Functions benutzt.
## Datenbank-Setup
Das komplette Schema (22 Tabellen, Indizes, 5 Storage-Buckets, internes Dev-Team) legt
[scripts/setup-appwrite.mjs](scripts/setup-appwrite.mjs) an idempotent, kann nach
Plan-Erweiterungen jederzeit erneut laufen:
```bash
# API-Key liegt als BRANDLOOP_APPWRITE_API_KEY in /home/webklar/apps/.env, dann einfach:
node scripts/setup-appwrite.mjs
# oder explizit:
APPWRITE_API_KEY=... node scripts/setup-appwrite.mjs
```
Der API-Key braucht die Scopes **Databases/Tables (read+write), Storage/Buckets (read+write), Teams (read+write)**.
## Prompt-Templates (P1P18)
Alle 18 Prompts des Prompt-Inventars liegen versioniert in [prompts/](prompts/) (Konventionen
und Slot-Registry: [prompts/README.md](prompts/README.md)) und werden mit
[scripts/seed-prompts.mjs](scripts/seed-prompts.mjs) in die Tabelle `prompt_templates`
geseedet — idempotent: Inhaltsänderung ⇒ neue Zeile `version+1`, alte Zeilen `aktiv=false`.
P8 ist eine Familie (1× Regie-Kern + 4 Modell-Adapter seedance/veo/sora/wan) = 22 Zeilen.
Das Skript seedet außerdem die 4 globalen Brand-Regeln in `rules`.
```bash
node scripts/seed-prompts.mjs
```
### Bewusste Abweichungen vom DB-Plan
- **Referenzen als indizierte String-Spalten (size 64) statt Relationship-Spalten.**
Appwrite-Relationships sind nicht filter-/indizierbar der Top-N-Index auf
`attribute_scores` (`brand_id, folder_id, category_id, score DESC`) und alle
Listen-Queries brauchen aber genau das. Many-to-many (`videos.attribute_ids`) ist ein String-Array
(`Query.contains`). IDs mit 64 Zeichen, weil uuid4 = 36 Zeichen.
- **`created_at`-Spalten entfallen** Appwrite pflegt `$createdAt` automatisch
(Indizes nutzen `$createdAt` direkt, z. B. `score_events`, `jobs`).
- **Enum-Werte ohne Umlaute** (`laeuft` statt `läuft`).
- **`attributes.tags`: Key-Index statt Volltext-Index** Appwrite verbietet
Fulltext auf Array-Spalten; Tag-Suche läuft über `Query.contains`.
- **S3/Hetzner-Backend für Storage** ist eine *instanzweite* Appwrite-Einstellung
(`_APP_STORAGE_DEVICE`) und betrifft alle Projekte auf dem Server wird daher
nicht vom Skript gesetzt, sondern muss bewusst am Server konfiguriert werden.
Aktuell: lokales Storage.
### Rechte-Modell
- `rules` + `prompt_templates`: Tabellen-Rechte nur für Team `internal` (Dev-Modus) 🔒
- Alle anderen Tabellen: `rowSecurity` an, keine Tabellen-Rechte Zeilen bekommen
beim Anlegen die Team-Permission der jeweiligen Brand (Multi-Tenant).
- `consents`-Bucket: zusätzlich Lese-Recht für Team `internal`.
- Append-only per Konvention (Server-Key schreibt): `score_events`, `video_metrics`, `jobs`.
### Noch offen (laut Plan)
- Appwrite **Functions**: `elo-update`, `favorit-berechnen`, `ads-metriken-holen`,
`kategorie-durchschnitt`, `archivierung`, `job-dispatcher`
- Stripe-Anbindung (metered billing über `usage_records`)