Co-MJ v1 : quêtes de première classe, guidage de préparation, assistant IA,
All checks were successful
All checks were successful
mode séance, battlemaps multiples et export Foundry ciblé
- Quêtes (Niveau 1) : entité Quest orthogonale à l'arbre, rattachée à un arc HUB
ou libre (migrations V9-V12, V18, V20 ; réconciliation des jumeaux V10).
Fusion quête/conteneur dans la sidebar, progression par partie (statuts
disponible/en cours/terminée), et quêtes libres avec espace de scènes créé
automatiquement (arc technique « Quêtes libres », V21 : levée de la
contrainte arcs.type héritée du baseline).
- Guidage (Pilier B) : bilan de préparation 100 % dérivé (règles arc/chapitre/
scène/quête), panneau « Prochaines étapes » avec boutons « Corriger », et
pastilles détaillées (tooltip des manques) dans l'arbre.
- Assistant IA (Pilier A) : étoffage champ par champ (scène, chapitre, arc) et
brouillons de scènes en propose→applique (brain : narrative-fields,
scene-drafts).
- Horloges & menaces (V15-V17) : clocks à segments avec déclencheurs, fronts.
- Mode séance : préparation de séance (readiness + quêtes dispo), scène
épinglée (V19), récap « précédemment » (brain : session-recap), onglet
« Partie » du panneau de référence, graphe amélioré (pan/zoom, éditeur de
liens).
- Perf : endpoint agrégé GET /api/campaigns/{id}/tree — la sidebar charge en
1 requête au lieu de ~15.
- Battlemaps multiples par scène (variantes jour/nuit, étages…) : liste JSON
étiquetée (V22, reprise automatique de la carte existante), rendu PDF avec
légendes, export/import rétro-compatible.
- Export Foundry ciblé : modale de périmètre (cartes+ennemis / journaux /
tables), bundle filtré côté serveur (zip allégé), module Foundry à jour
(respect du périmètre + une Scene Foundry par variante de carte,
rétro-compatible anciens bundles).
This commit is contained in:
50
brain/app/application/prompts/narrative_fields.py
Normal file
50
brain/app/application/prompts/narrative_fields.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""Prompt d'étoffage des champs d'une entité narrative (arc / chapitre / scène) — Pilier A.
|
||||
|
||||
Générique : le Core (Java) est la SOURCE DE VÉRITÉ des champs (clé + libellé) et les
|
||||
passe en entrée ; ce module ne fait que formuler le prompt. Le modèle ne renvoie que les
|
||||
clés fournies et OMET celles pour lesquelles il n'a rien de pertinent (pas de remplissage forcé).
|
||||
"""
|
||||
from app.core.language import language_name
|
||||
|
||||
# Étiquette lisible du type d'entité, pour la formulation du prompt.
|
||||
ENTITY_LABEL: dict[str, str] = {
|
||||
"arc": "cet arc narratif",
|
||||
"chapter": "ce chapitre",
|
||||
"scene": "cette scène",
|
||||
}
|
||||
|
||||
|
||||
def narrative_fields_prompt(entity_type: str, entity_context: str, instruction: str,
|
||||
fields: list[dict], language: str) -> str:
|
||||
"""Construit le prompt d'étoffage. `fields` = [{key, label}] (whitelist du Core)."""
|
||||
label = ENTITY_LABEL.get(entity_type or "", "cette entité narrative")
|
||||
lines = []
|
||||
for f in fields or []:
|
||||
key = str(f.get("key") or "").strip()
|
||||
if not key:
|
||||
continue
|
||||
flabel = str(f.get("label") or key).strip()
|
||||
lines.append(f'- "{key}" : {flabel}')
|
||||
fields_list = "\n".join(lines)
|
||||
instruction_block = (
|
||||
f"\nConsigne particulière du MJ : {instruction.strip()}\n"
|
||||
if instruction and instruction.strip() else ""
|
||||
)
|
||||
return (
|
||||
f"Tu es un co-Maître de Jeu. On te donne l'état ACTUEL d'{label} de jeu de rôle. "
|
||||
"Propose des valeurs pour l'ÉTOFFER, cohérentes avec ce qui existe déjà.\n\n"
|
||||
f"{entity_context.strip()}\n"
|
||||
f"{instruction_block}\n"
|
||||
"Champs que tu peux remplir (n'utilise QUE ces clés) :\n"
|
||||
f"{fields_list}\n\n"
|
||||
"Règles IMPÉRATIVES :\n"
|
||||
"- Réponds UNIQUEMENT par un objet JSON valide, sans texte autour.\n"
|
||||
'- Format exact : {"fields": {"cle": "valeur proposée", ...}}\n'
|
||||
"- N'inclus QUE des clés de la liste ci-dessus. N'invente AUCUNE autre clé.\n"
|
||||
"- Si un champ est déjà bien rempli ou si tu n'as rien de pertinent, OMETS-le "
|
||||
"(ne le renvoie pas) plutôt que de le remplir de force.\n"
|
||||
"- Reste cohérent avec le contexte : n'invente pas d'élément qui contredit "
|
||||
"l'entité ou la campagne.\n"
|
||||
f"- Rédige les valeurs en {language_name(language)}.\n"
|
||||
"Renvoie maintenant le JSON."
|
||||
)
|
||||
Reference in New Issue
Block a user