Refactorisation du code, correction des quelques bugs, Clear de Readme principal, Ajout de l'entrée utilisateur pour la modification du nom de projet

This commit is contained in:
Chevallier
2026-07-17 17:12:25 +02:00
parent 9d464fb261
commit 75e035cc82
12 changed files with 248 additions and 411 deletions

View File

@@ -1,10 +1,11 @@
import chainlit as cl
import asyncio
import unicodedata
import zipfile
import httpx
import json
import os
import io
import re
# --- CONFIGURATION GITEA ---
GITEA_TOKEN = os.getenv("GITEA_TOKEN", "ton_token_gitea_ici")
@@ -143,7 +144,7 @@ def inject_conforme_badge(state: dict) -> dict:
return state
async def reset_to_start(message_text: str = "Bonjour 👋 Je suis ARC. Décris-moi ton besoin logiciel."):
async def reset_to_start(message_text: str = "Bonjour 👋 Je suis ARC. Décrivez-moi votre besoin logiciel."):
"""
Réinitialise complètement l'état de la session utilisateur.
"""
@@ -166,6 +167,25 @@ async def reset_to_start(message_text: str = "Bonjour 👋 Je suis ARC. Décris-
await cl.Message(content=message_text).send()
def sanitize_repo_name(name: str) -> str:
"""
Nettoie une chaîne pour la rendre 100% compatible avec un nom de dépôt Git.
Gère les accents, les espaces et supprime les caractères interdits.
"""
if not name:
return "mon-projet"
normalized = unicodedata.normalize('NFKD', name)
no_accent = normalized.encode('ascii', 'ignore').decode('utf-8')
lowered = no_accent.lower()
spaced_to_hyphen = lowered.replace(" ", "_")
cleaned = re.sub(r'[^a-z0-9-_]', '', spaced_to_hyphen)
cleaned = re.sub(r'-+', '-', cleaned)
cleaned = re.sub(r'_+', '_', cleaned)
return cleaned.strip('-_')
async def render_workflow_state(new_state: dict):
"""
Fonction centrale pour aiguiller l'affichage Chainlit
@@ -181,7 +201,7 @@ async def render_workflow_state(new_state: dict):
elif current_status == "spec_ready":
spec = new_state.get("spec", {})
summary = "### Éléments importants à retenir de ton projet :\n\n"
summary = "### Éléments importants à retenir de votre projet :\n\n"
summary += f"- **Nom du projet** : {spec.get('title')}\n"
summary += f"- **Description** : {spec.get('description')}\n"
summary += "- **Actions** :\n"
@@ -189,10 +209,12 @@ async def render_workflow_state(new_state: dict):
summary += "- **Contraintes** :\n"
summary += "\n".join(f" - {constraint}" for constraint in spec.get("constraints", [])) + "\n"
summary += f"- **Langage** : {spec.get('language')}\n\n"
summary += "**Est-ce que cela vous convient ?**"
summary += "💡 *(Le nom du projet indiqué pourra être modifié par la suite)*"
await cl.Message(content=summary).send()
res = await cl.AskActionMessage(
content=summary,
content="**Est-ce que cela vous convient ?**",
actions=[
cl.Action(name="oui", payload={"value": "oui"}, label="Oui, c'est parfait 👍"),
cl.Action(name="non", payload={"value": "non"}, label="Non, modifier ❌")
@@ -207,6 +229,34 @@ async def render_workflow_state(new_state: dict):
return
if res and res.get("name") == "oui":
proposed_title = spec.get('title', 'mon_projet')
name_choice = await cl.AskActionMessage(
content=f"Le nom proposé pour le projet est : **{proposed_title}**.\nSouhaitez-vous le conserver ou le modifier ?",
actions=[
cl.Action(name="garder_nom", payload={"value": "keep"}, label="Conserver ce nom 🏷️"),
cl.Action(name="modifier_nom", payload={"value": "change"}, label="Choisir un autre nom ✏️")
],
timeout=3600
).send()
if name_choice is None:
await cl.Message(content="⏰ **Session expirée.** Envoie un message pour reprendre.").send()
return
if name_choice.get("name") == "modifier_nom":
new_name_res = await cl.AskUserMessage(
content="Saisissez le nouveau nom de votre projet : 👇",
timeout=600
).send()
if new_name_res and new_name_res.get("output"):
raw_title = new_name_res["output"].strip()
custom_title = sanitize_repo_name(raw_title)
spec['title'] = custom_title
new_state['spec'] = spec
await cl.Message(content=f"🏷️ Nom du projet configuré sur : **{custom_title}**").send()
await cl.Message(content="🚀 **Spécifications validées !** Lancement de la génération du code...").send()
new_state["status"] = "spec_approved"
@@ -216,7 +266,7 @@ async def render_workflow_state(new_state: dict):
response = await client.post(
"http://127.0.0.1:8000/api/workflow/run",
json=new_state,
timeout=600.0
timeout=1200.0
)
final_state = response.json()
cl.user_session.set("graph_state", final_state)
@@ -228,7 +278,7 @@ async def render_workflow_state(new_state: dict):
cl.user_session.set("graph_state", new_state)
await cl.Message(
content="🔄 **Compris.** Qu'est-ce qui ne convient pas ? S'il te plaît, précise les éléments manquants ou à corriger :"
content="🔄 **Compris.** Qu'est-ce qui ne convient pas ? S'il vous plaît, précisez les éléments manquants ou à corriger :"
).send()
elif current_status in ["wait_human_review", "approved_by_human"]:
@@ -334,7 +384,7 @@ async def render_workflow_state(new_state: dict):
cl.user_session.set("graph_state", new_state)
async with httpx.AsyncClient() as client:
resp = await client.post("http://127.0.0.1:8000/api/workflow/run", json=new_state, timeout=600.0)
resp = await client.post("http://127.0.0.1:8000/api/workflow/run", json=new_state, timeout=1200.0)
final_state = resp.json()
cl.user_session.set("graph_state", final_state)
@@ -342,7 +392,7 @@ async def render_workflow_state(new_state: dict):
elif res and res.get("name") == "refuser_projet":
feedback_user = await cl.AskUserMessage(
content="Veuillez décrire les corrections ou les modifications à apporter au projet.",
timeout=600
timeout=1200
).send()
if feedback_user:
@@ -353,7 +403,7 @@ async def render_workflow_state(new_state: dict):
await cl.Message(content="🔄 **Feedback transmis.** Prise en compte des modifications...").send()
async with httpx.AsyncClient() as client:
resp = await client.post("http://127.0.0.1:8000/api/workflow/run", json=new_state, timeout=600.0)
resp = await client.post("http://127.0.0.1:8000/api/workflow/run", json=new_state, timeout=1200.0)
loop_state = resp.json()
cl.user_session.set("graph_state", loop_state)
@@ -392,13 +442,13 @@ async def render_workflow_state(new_state: dict):
if res.get("name") == "recommencer_projet":
reset_msg = (
"🔄 **Ancien projet supprimé avec succès.**\n\n"
"Faisons table rase ! Décris-moi ton besoin logiciel pour repartir sur de nouvelles bases : 👇"
"Faisons table rase ! Décrivez-moi votre besoin logiciel pour repartir sur de nouvelles bases : 👇"
)
await reset_to_start(reset_msg)
else:
reset_msg = (
"❌ **Session fermée et dépôt nettoyé.**\n\n"
"Si tu as un nouveau besoin à soumettre plus tard, envoie simplement un message pour démarrer."
"Si vous avez un nouveau besoin à soumettre plus tard, envoie simplement un message pour démarrer."
)
await reset_to_start(reset_msg)
@@ -466,7 +516,7 @@ async def on_message(message: cl.Message):
response = await client.post(
"http://127.0.0.1:8000/api/workflow/run",
json=state,
timeout=600.0
timeout=1200.0
)
new_state = response.json()