Files
fallout-venice/README.md
T

232 lines
9.9 KiB
Markdown
Raw 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.
# Fallout: Venice of Wasteland — Moteur de simulation JDR
Simulation autonome d'un univers **Fallout 2D20** situé en Louisiane post-nucléaire.
Le moteur simule des PNJ, des factions, des rencontres et une économie — sans MJ humain permanent.
Un LLM joue le rôle de MJ narrateur, un second LLM anime les PNJ.
**Dashboard** → [fallout.coyoteos.ovh](https://fallout.coyoteos.ovh) (PipBoy)
**Gitea** → [git.coyoteos.ovh](https://git.coyoteos.ovh) — repo `Corback/fallout-venice`
> ⚠️ Les informations de connexion (IPs, credentials, clés SSH) sont dans `INFRA_PRIVATE.md` (local uniquement, non commité).
---
## Architecture générale
```
┌─────────────────────────────────────────────────────────┐
│ AMPÈRE (Oracle ARM) │
│ │
│ ┌──────────────┐ ┌───────────────┐ ┌────────────┐ │
│ │ run.py S1 │ │ run.py S2 │ │ PipBoy │ │
│ │ (sim engine)│ │ (sim engine) │ │ Flask │ │
│ └──────┬───────┘ └───────┬───────┘ └─────┬──────┘ │
│ │ │ │ │
│ ┌──────▼───────────────────▼────────────────▼──────┐ │
│ │ Ollama (localhost:11434) │ │
│ │ qwen2.5:14b (MJ) + qwen2.5:7b (PNJ) │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ ChromaDB :8800 — collection fallout_lore │ │
│ │ 1403 chunks : règles 2D20, lore canon, ambiance │ │
│ └────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────┘
│ SSH tunnel :15432
┌────────────────────────▼────────────────────────────────┐
│ VIGILE (OVH) │
│ PostgreSQL — base "fallout" │
└─────────────────────────────────────────────────────────┘
```
---
## Stack technique
| Composant | Technologie | Détail |
|-----------|------------|--------|
| Moteur sim | Python 3.11 | `src/engine/` |
| Dashboard | Flask + Jinja2 | Docker `fallout-visu` |
| LLM MJ | qwen2.5:14b via Ollama | ~30s/réponse warm |
| LLM PNJ | qwen2.5:7b via Ollama | ~5s/réponse warm |
| Base de données | PostgreSQL 15 (Vigile) | SSH tunnel depuis Ampère |
| RAG | ChromaDB v1.0.0 (API v2) | collection `fallout_lore` |
| Proxy | nginx-proxy-manager | SSL Let's Encrypt auto |
| Gitea | git.coyoteos.ovh:2222 | repo Corback/fallout-venice |
---
## Structure du projet
```
fallout-venice/
├── src/
│ ├── engine/
│ │ ├── run.py # Lanceur principal (hot-reload config, status check loop)
│ │ ├── tick.py # Orchestration d'un tick
│ │ ├── encounter.py # Rencontres (safe zones, raids, commerce PNJ)
│ │ ├── combat_engine.py # Résolution combats 2D20
│ │ ├── sim_config.py # Chargement + deep-merge config JSON
│ │ ├── init_pnj.py # Initialisation PNJ en DB
│ │ ├── lore_enricher.py # Enrichissement lore via LLM + RAG Chroma
│ │ └── db.py # Accès PostgreSQL
│ ├── config/
│ │ ├── sim_001.json # Config session 1 (référence des 5 modes)
│ │ ├── sim_002.json # Config session 2
│ │ └── crash_results.json # Résultats derniers tests LLM (lu par PipBoy)
│ └── data/
│ └── encounter_tables.json # Tables rencontres, zones sûres, pools entités
├── dashboard/
│ └── app.py # Source PipBoy — copier dans /home/ubuntu/fallout-visu/
├── tools/
│ ├── llm_crash_test.py # Stress test LLM (modes: simultane/decale/solo)
│ └── capacity_test.py # Test capacité N joueurs simultanés
├── README.md
└── ROADMAP.md
```
> ⚠️ Le dashboard actif est `/home/ubuntu/fallout-visu/app.py` (monté dans Docker).
> `dashboard/app.py` est la source de vérité — toujours synchroniser les deux après modification.
---
## Système de PNJ — 4 tiers
| Tier | Label | Comportement | LLM actuel |
|------|-------|-------------|-----------|
| 0 | BOSS | Immortel, chef de faction | Non (prévu 14b) |
| 1 | ACTIFS SIM | Simulés chaque tick, mémoire persistante | Non (prévu 7b) |
| 2 | PNJ+ | Réagissent aux événements importants | Non (prévu 7b) |
| 3 | PASSAGE | Décor narratif | Jamais |
Actuellement tous les PNJ sont animés par le **moteur Python seul**.
Le LLM PNJ sera déclenché uniquement sur **interaction joueur directe** (Phase 5).
---
## Zones sûres
`independance` | `nola_vieux_carre` | `baton_rouge` | `laplace`
Règles : pas de rencontres lambda/groupe. Seuls les raids de faction (faible probabilité) et le commerce PNJ-à-PNJ sont possibles.
---
## Modes de simulation
Configurables depuis le PipBoy — prise en compte au **prochain jour** (hot-reload).
| Mode | Rencontres | Drain | Économie | Usage |
|------|-----------|-------|---------|-------|
| `pacifiste` | ×0.4 | ×0.7 | normal | Test/debug |
| `politique` | ×0.6 | ×1.0 | normal | Intrigues factions |
| `guerre_commerciale` | ×1.2 | ×1.5 | ×1.5 caps | Blocus, routes coupées |
| `guerre` | ×2.0 | ×1.8 | pénurie | Front de guerre actif |
| `survie_extreme` | ×1.8 | ×2.5 | ×0.3 | Stress test pur |
---
## ChromaDB — collection `fallout_lore`
**1403 chunks** — source de vérité en lecture seule.
| Catégorie | Chunks | Contenu |
|-----------|--------|---------|
| `regles_core` | ~934 | Règles 2D20 Fallout |
| `regles_supplement` | 279 | Suppléments et extensions |
| `lore_inspiration` | 86 | Inspiration univers Fallout |
| `ambiance` | 43 | Descriptions atmosphériques |
| `aventure` | 29 | Scénarios de référence |
| `lore_canon` | 32 | **Bible Venice of Wasteland v1.1 & v2.0** |
`fallout_lore_enriched` → reçoit les propositions lore **acceptées** depuis le PipBoy.
---
## Performances LLM mesurées (Ampère ARM)
| Joueurs simultanés | Tick complet | Actions/heure | Viable tick 10min |
|-------------------|-------------|---------------|-----------------|
| 1 | 35s | 103 | ✓ |
| 5 | 57s | 62 | ✓ |
| 10 | 1m17 | 46 | ✓ |
| 50 | 3m32 | 16 | ✓ (8 timeouts) |
**Plafond recommandé V1 : 10-15 joueurs actifs simultanés.**
---
## Lancement des simulations
```bash
# SSH sur Ampère (voir INFRA_PRIVATE.md pour la clé et l'IP)
cd /home/ubuntu/fallout-venice/src/engine
# Session 1
nohup env SESSION_ID=1 TICK_SLEEP_SEC=60 PYTHONUNBUFFERED=1 \
python3 -u run.py > ~/fallout_sim_s1.log 2>&1 &
# Session 2
nohup env SESSION_ID=2 TICK_SLEEP_SEC=60 PYTHONUNBUFFERED=1 \
python3 -u run.py > ~/fallout_sim_s2.log 2>&1 &
tail -f ~/fallout_sim_s1.log
```
**Reset propre d'une session :**
1. PipBoy → Paramètres → **STOP** (attendre max 5 ticks)
2. PipBoy → Paramètres → **Reset Jour/Tick**
3. Relancer via terminal
---
## Enrichissement lore
```bash
cd /home/ubuntu/fallout-venice/src/engine
python3 lore_enricher.py --faction grand_krewe # une faction
python3 lore_enricher.py --faction all # toutes
python3 lore_enricher.py --list-factions # liste
```
Valider les propositions → PipBoy onglet **ENRICHISSEMENT**
---
## Variables d'environnement clés
| Variable | Défaut | Description |
|----------|--------|-------------|
| `SESSION_ID` | 1 | Session simulée |
| `TICK_SLEEP_SEC` | 60 | Durée d'un tick (secondes) |
| `PYTHONUNBUFFERED` | — | `1` pour logs temps réel |
| `OLLAMA_URL` | `http://localhost:11434` | Endpoint Ollama |
| `MODEL_MJ` | `qwen2.5:14b` | Modèle MJ narrateur |
| `MODEL_PNJ` | `qwen2.5:7b` | Modèle animation PNJ |
| `DB_HOST` / `DB_PORT` | voir INFRA_PRIVATE.md | PostgreSQL via tunnel SSH |
---
## ⚠️ Points critiques — à ne jamais oublier
**ChromaDB**
- API v2 uniquement — `/api/v1/` retourne `{"error":"Unimplemented"}`
- La collection `fallout_vst` **n'existe pas** — c'est `fallout_lore`
- 299 chunks avaient le champ `type` au lieu de `category` — corrigé en juin 2026
**Dashboard**
- Le fichier actif est `/home/ubuntu/fallout-visu/app.py` (monté Docker), pas `dashboard/app.py`
- Toujours copier les deux après modification
**Simulation**
- `run.py` vérifie le statut DB toutes les **5 ticks** — STOP depuis PipBoy n'est pas instantané
- Hot-reload config JSON au **début de chaque jour** (tick 0), pas immédiatement
**Réseau Docker**
- Le container PipBoy accède à Ollama via `host.docker.internal:11434`
- Une règle iptables autorise le subnet Docker → port 11434. Voir INFRA_PRIVATE.md si disparaît après reboot.
**Infos de connexion**
- Voir `INFRA_PRIVATE.md` (local uniquement, dans `.gitignore`)