Ajoute l'assistant IA "Ruby" (Claude + Scenario) et corrige plusieurs bugs de la scène
Build and deploy / test-python (push) Successful in 12m24s
Build and deploy / test-js (push) Successful in 1m9s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Intègre un chat IA capable de manipuler la scène via les mêmes fonctions
que l'éditeur manuel (objets, variables, déclencheurs, images générées),
avec conversations multiples par écran façon Claude. Corrige au passage
le rafraîchissement pjax hors-ordre, l'onglet IA/déclencheurs vide après
sélection d'un objet, la comparaison de booléens dans les conditions, et
le blocage du glisser-déposer hors du cadre caméra après un redimensionnement
de fond par l'IA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-09 19:40:31 +02:00
co-authored by Claude Sonnet 5
parent ab6635eee0
commit b07b231a61
62 changed files with 2928 additions and 62 deletions
+33
View File
@@ -0,0 +1,33 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
_DEFAULT_TITLE = "Nouvelle conversation"
_TITLE_MAX_LENGTH = 50
def add_ia_chat_message(slug, conversation_id, role, content):
"""Ajoute un message (role "user" ou "assistant") à une conversation
— voir routes/ia/ia_chat.py, seul appelant.
Titre automatique (comme claude.ai) : le premier message "user" d'une
conversation encore au titre par défaut renomme la conversation avec
ses ~50 premiers caractères, pour que la colonne de gauche affiche
autre chose que "Nouvelle conversation" pour toutes les entrées."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
conn.execute(
"INSERT INTO _ia_chat_messages (conversation_id, role, content) VALUES (?, ?, ?)",
(conversation_id, role, content),
)
message_id = conn.execute("SELECT last_insert_rowid() AS id").fetchone()["id"]
if role == "user":
conversation = conn.execute(
"SELECT title FROM _ia_conversations WHERE id = ?", (conversation_id,)
).fetchone()
if conversation and conversation["title"] == _DEFAULT_TITLE:
title = content.strip()[:_TITLE_MAX_LENGTH]
conn.execute("UPDATE _ia_conversations SET title = ? WHERE id = ?", (title, conversation_id))
conn.commit()
conn.close()
return message_id
+16
View File
@@ -0,0 +1,16 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
def create_ia_conversation(slug, screen_id):
""""+ Nouvelle conversation" (voir static/js/ia/ia-chat.js) : créée
IMMÉDIATEMENT, vide — visible tout de suite dans la colonne, pas
besoin d'attendre un premier message."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
conn.execute("INSERT INTO _ia_conversations (screen_id) VALUES (?)", (screen_id,))
conversation_id = conn.execute("SELECT last_insert_rowid() AS id").fetchone()["id"]
conn.commit()
conn.close()
return conversation_id
+13
View File
@@ -0,0 +1,13 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
def delete_ia_conversation(slug, conversation_id):
"""Cascade sur les messages (ON DELETE CASCADE, voir
ensure_ia_chat_schema.py)."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
conn.execute("DELETE FROM _ia_conversations WHERE id = ?", (conversation_id,))
conn.commit()
conn.close()
+38
View File
@@ -0,0 +1,38 @@
import db
def ensure_ia_chat_schema(slug):
"""Chat "Générer avec l'IA" — plusieurs CONVERSATIONS par écran
(demande explicite : gérer plusieurs fils, comme claude.ai), chacune
portant sa propre liste de messages. ON DELETE CASCADE à chaque
niveau (écran supprimé -> ses conversations -> leurs messages),
même patron que _scene_objects (screens/scenes/ensure_scene_schema.py)."""
conn = db.connect(slug)
# _ia_chat_messages existait déjà (phase précédente, une seule
# conversation par écran, colonne screen_id directe) sur les projets
# déjà testés avant ce chantier — CREATE TABLE IF NOT EXISTS ne
# migrerait pas son schéma. Aucune donnée à préserver (fonctionnalité
# tout juste testée manuellement) : on repart d'une table neuve plutôt
# que d'écrire une vraie migration pour quelques messages de test.
cols = {row["name"] for row in conn.execute("PRAGMA table_info(_ia_chat_messages)").fetchall()}
if cols and "conversation_id" not in cols:
conn.execute("DROP TABLE _ia_chat_messages")
conn.executescript(
"""
CREATE TABLE IF NOT EXISTS _ia_conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT 'Nouvelle conversation',
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS _ia_chat_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id INTEGER NOT NULL REFERENCES _ia_conversations(id) ON DELETE CASCADE,
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
"""
)
conn.commit()
conn.close()
+16
View File
@@ -0,0 +1,16 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
def get_ia_conversation(slug, conversation_id):
"""Renvoie aussi screen_id — indispensable pour vérifier
l'appartenance à CE jeu avant de supprimer/lire/écrire (voir
routes/ia/ia_chat.py), même patron que auth.get_user_asset."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
row = conn.execute(
"SELECT id, screen_id, title, created_at FROM _ia_conversations WHERE id = ?", (conversation_id,)
).fetchone()
conn.close()
return dict(row) if row else None
+16
View File
@@ -0,0 +1,16 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
def list_ia_chat_messages(slug, conversation_id):
"""Historique d'UNE conversation, dans l'ordre chronologique (voir
static/js/ia/ia-chat.js, qui les affiche tels quels)."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
rows = conn.execute(
"SELECT id, role, content, created_at FROM _ia_chat_messages WHERE conversation_id = ? ORDER BY id ASC",
(conversation_id,),
).fetchall()
conn.close()
return [dict(row) for row in rows]
+16
View File
@@ -0,0 +1,16 @@
import db
from .ensure_ia_chat_schema import ensure_ia_chat_schema
def list_ia_conversations(slug, screen_id):
"""Conversations d'un écran, plus récente en premier (voir la
colonne de gauche de l'onglet "Générer avec l'IA")."""
ensure_ia_chat_schema(slug)
conn = db.connect(slug)
rows = conn.execute(
"SELECT id, title, created_at FROM _ia_conversations WHERE screen_id = ? ORDER BY id DESC",
(screen_id,),
).fetchall()
conn.close()
return [dict(row) for row in rows]