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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user