From a7d8914e25fd4198e1fe2a2ee03fc69150aa1929 Mon Sep 17 00:00:00 2001 From: Chevallier Date: Fri, 12 Jun 2026 18:16:58 +0200 Subject: [PATCH] first push --- .gitignore | 48 +++ README.md | 136 +++++++++ backend/Dockerfile | 23 ++ backend/README.md | 39 +++ backend/app/agents/dev_agent.py | 14 + backend/app/agents/pm_agent.py | 15 + backend/app/agents/qa_agent.py | 10 + backend/app/api/deps.py | 0 backend/app/api/routes/health.py | 8 + backend/app/api/routes/workflow.py | 11 + backend/app/core/config.py | 25 ++ backend/app/core/logging.py | 8 + backend/app/core/security.py | 0 backend/app/graph/nodes.py | 56 ++++ backend/app/graph/state.py | 13 + backend/app/graph/workflow.py | 92 ++++++ backend/app/llm/client.py | 12 + backend/app/llm/prompts.py | 0 backend/app/llm/providers.py | 0 backend/app/main.py | 34 +++ backend/app/models/project.py | 10 + .../app/repositories/project_repository.py | 0 backend/app/repositories/qdrant_repository.py | 58 ++++ backend/app/repositories/redis_repository.py | 13 + backend/app/sandbox/docker_runner.py | 8 + backend/app/schemas/api.py | 14 + backend/app/schemas/project.py | 10 + backend/app/schemas/spec.py | 10 + backend/app/services/delivery_service.py | 0 backend/app/services/embedding_service.py | 40 +++ backend/app/services/retrieval_service.py | 11 + backend/app/services/workflow_service.py | 6 + backend/chainlit.md | 0 backend/chainlit_app.py | 25 ++ backend/docker-compose.yml | 102 +++++++ backend/public/logo_dark.png | Bin 0 -> 67615 bytes backend/public/logo_light.png | Bin 0 -> 67615 bytes backend/requirements.txt | 16 + backend/start.sh | 7 + backend/tests/test_agents.py | 0 backend/tests/test_gemma.py | 28 ++ backend/tests/test_health.py | 10 + backend/tests/test_qdrant.py | 55 ++++ backend/tests/test_snowflake.py | 42 +++ backend/tests/test_workflow.py | 0 ressources/Etape0.md | 42 +++ ressources/Etape1.md | 53 ++++ ressources/Etape2.md | 50 +++ ressources/Etape3.md | 59 ++++ ressources/Etape4.md | 53 ++++ ressources/EtapeFinale.md | 13 + ressources/Projet.md | 88 ++++++ ressources/test.md | 288 ++++++++++++++++++ 53 files changed, 1655 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 backend/Dockerfile create mode 100644 backend/README.md create mode 100644 backend/app/agents/dev_agent.py create mode 100644 backend/app/agents/pm_agent.py create mode 100644 backend/app/agents/qa_agent.py create mode 100644 backend/app/api/deps.py create mode 100644 backend/app/api/routes/health.py create mode 100644 backend/app/api/routes/workflow.py create mode 100644 backend/app/core/config.py create mode 100644 backend/app/core/logging.py create mode 100644 backend/app/core/security.py create mode 100644 backend/app/graph/nodes.py create mode 100644 backend/app/graph/state.py create mode 100644 backend/app/graph/workflow.py create mode 100644 backend/app/llm/client.py create mode 100644 backend/app/llm/prompts.py create mode 100644 backend/app/llm/providers.py create mode 100644 backend/app/main.py create mode 100644 backend/app/models/project.py create mode 100644 backend/app/repositories/project_repository.py create mode 100644 backend/app/repositories/qdrant_repository.py create mode 100644 backend/app/repositories/redis_repository.py create mode 100644 backend/app/sandbox/docker_runner.py create mode 100644 backend/app/schemas/api.py create mode 100644 backend/app/schemas/project.py create mode 100644 backend/app/schemas/spec.py create mode 100644 backend/app/services/delivery_service.py create mode 100644 backend/app/services/embedding_service.py create mode 100644 backend/app/services/retrieval_service.py create mode 100644 backend/app/services/workflow_service.py create mode 100644 backend/chainlit.md create mode 100644 backend/chainlit_app.py create mode 100644 backend/docker-compose.yml create mode 100644 backend/public/logo_dark.png create mode 100644 backend/public/logo_light.png create mode 100644 backend/requirements.txt create mode 100644 backend/start.sh create mode 100644 backend/tests/test_agents.py create mode 100644 backend/tests/test_gemma.py create mode 100644 backend/tests/test_health.py create mode 100644 backend/tests/test_qdrant.py create mode 100644 backend/tests/test_snowflake.py create mode 100644 backend/tests/test_workflow.py create mode 100644 ressources/Etape0.md create mode 100644 ressources/Etape1.md create mode 100644 ressources/Etape2.md create mode 100644 ressources/Etape3.md create mode 100644 ressources/Etape4.md create mode 100644 ressources/EtapeFinale.md create mode 100644 ressources/Projet.md create mode 100644 ressources/test.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..050fbba --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class + +# Virtual environments +.venv/ +venv/ +env/ + +# Environment variables +.env +.env.* + +# Chainlit +.chainlit/ + +# Application files +.files/ + +# Tests / coverage +.pytest_cache/ +.coverage +htmlcov/ + +# Type checkers / linters +.mypy_cache/ +.ruff_cache/ +.pyre/ + +# IDEs +.vscode/ +.idea/ + +# OS files +.DS_Store +Thumbs.db + +# Logs +*.log + +# Build artifacts +build/ +dist/ +*.egg-info/ + +# Jupyter +.ipynb_checkpoints/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c7dba3 --- /dev/null +++ b/README.md @@ -0,0 +1,136 @@ +# Projet ARC + +## Contexte du Projet +ARC est une plateforme d'automatisation du développement logiciel basée sur un workflow multi-agents (IA). Le système orchestre plusieurs modèles d'IA spécialisés pour transformer un besoin utilisateur en un code source validé, testé et stocké. +___ +### Étape 0 : Préparation de l'environnement du projet +Tâches : +- Créer backend minimal +- Créer modèle de données simple +- langGraph +___ +### Étape 1 : Analyse du Besoin & Qualification (Agent PM / Business Analyst) +- L'utilisateur entre une demande en langage naturel. +- **Agent 1 (PM)** analyse la demande. Si des informations manquent pour coder, il pose des questions clarificatrices à l'utilisateur jusqu'à obtenir un cahier des charges complet. +- **Vérification BDD :** Avant de coder, le système cherche dans une base de données vectorielle si un projet similaire existe déjà. + - *Si oui :* On propose le lien à l'utilisateur. Si l'utilisateur valide, le workflow s'arrête ici. + - *Si non (ou si l'utilisateur rejette l'existant) :* On passe à l'étape 2. + +Outils : +- LangGraph -> LangGraph est adapté aux workflows multi‑agents avec états, transitions conditionnelles, persistance et human‑in‑the‑loop +- Python -> backend, les agents, les appels LLM, les tests, les embeddings et les intégrations + compatible avec autres tools +- Pydantic AI / Pydantic -> forcer l’Agent PM à produire un cahier des charges structuré +- Chainlit -> adapté aux interfaces conversationnelles + BDD : +- Qdrant -> adapté à la recherche sémantique + stocker les embeddings de projets/scripts +- Snowflake Arctic Embed 2.0 -> modèle d’embedding +- Redis (optionnel) -> cache de recherche ;sessions utilisateur ;état temporaire ;verrouillage d’un workflow ;file d’attente simple +___ +### Étape 2 : Génération de Code (Agent Développeur) +- **Agent 2 (Dev)** reçoit le cahier des charges validé et génère l'arborescence et le code source du projet. + +Outils : +- LangGraph -> LangGraph est adapté aux workflows multi‑agents avec états, transitions conditionnelles, persistance et human‑in‑the‑loop +- Mistral ou Gemma (modèle trop généraliste/léger->tache simple) -> DeepSeek Coder/Qwen2.5 +- vLLM -> meilleur choix qu’Ollama pour une plateforme plus industrialisée. Llama.cpp modèles quantifiés sur CPU ou machines modestes + moins adapté à une plateforme multi‑utilisateur +- Pydantic +___ +### Étape 3 : Tests et Assurance Qualité (Agent QA / Testeur) +- **Agent 3 (QA)** récupère le code de l'Agent 2. Il doit exécuter le code (via une sandbox sécurisée) ou générer/exécuter des tests unitaires pour vérifier la qualité, la sécurité et le fonctionnement. +- **Boucle de correction automatique (Loop 1) :** Si les tests échouent, l'Agent 3 renvoie les erreurs à l'Agent 2 avec les logs. L'Agent 2 corrige et renvoie à l'Agent 3. Cette boucle tourne au maximum 3 fois jusqu'à ce que le code soit "vert". +- **EXTENSION FUTURE** si les tests échouent 3 fois, envoyé à une IA plus puissante. + +Outils : +- Docker +- Ruff -> qualité de code +- Bandit -> sécurité +- Semgrep (optionnel) -> règles de sécurité et qualité plus larges + Boucle correction : +- LangGraph +- Pydantic +___ +### Étape 4 : Livraison & Feedback Utilisateur (Boucle Humaine) +- Une fois le code validé par l'Agent 3, il est présenté à l'utilisateur. +- L'utilisateur teste et valide. + - *Si Validé :* Le projet est sauvegardé dans la base de données (pour la recherche de l'Étape 1) et livré (ex: zip ou dépôt GitHub). + - *Si Refusé :* L'utilisateur indique ce qui ne va pas. Tout le contexte (code actuel + retours) est renvoyé à l'**Étape 1** pour réanalyse, et le cycle recommence. + +Outils : +- Chainlit +- Git +___ +### Étape finale : + +Tâches : +- Tests fonctionnels de bout en bout +- Sécurité minimale +- Documentation finale +- Présentation + +## Structure du projet +```bash +backend/ +│ +├── app/ +│ ├── api/ +│ │ ├── routes/ +│ │ │ ├── health.py +│ │ │ └── workflow.py +│ │ └── deps.py +│ │ +│ ├── core/ +│ │ ├── config.py +│ │ ├── logging.py +│ │ └── security.py +│ │ +│ ├── graph/ # LangGraph +│ │ ├── state.py +│ │ ├── nodes.py +│ │ └── workflow.py +│ │ +│ ├── agents/ # Gestion agents IA +│ │ ├── pm_agent.py +│ │ ├── dev_agent.py +│ │ └── qa_agent.py +│ │ +│ ├── schemas/ # Pydantic +│ │ ├── api.py +│ │ ├── spec.py +│ │ └── project.py +│ │ +│ ├── models/ # modèles métier / persistance (métadonnées d’un projet/version/statut/lien Git/hash/tags) +│ │ └── project.py +│ │ +│ ├── services/ +│ │ ├── workflow_service.py +│ │ ├── embedding_service.py +│ │ ├── retrieval_service.py +│ │ └── delivery_service.py +│ │ +│ ├── repositories/ # accès externes, Qdrant / Redis / stockage +│ │ ├── qdrant_repository.py +│ │ ├── redis_repository.py +│ │ └── project_repository.py +│ │ +│ ├── llm/ # appels modèles +│ │ ├── client.py # wrapper d’appel +│ │ ├── prompts.py # prompts centralisés +│ │ └── providers.py # Gemma/llama.cpp.... +│ │ +│ ├── sandbox/ +│ │ └── docker_runner.py +│ │ +│ ├── main.py +│ └── __init__.py +│ +├── chainlit_app.py +├── tests/ +│ ├── test_health.py +│ ├── test_workflow.py +│ └── test_agents.py +│ +├── .env +├── requirements.txt +├── Dockerfile +└── README.md +``` \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..5025d63 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.13.13 + +WORKDIR /workspace + +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir \ + --trusted-host pypi.org \ + --trusted-host pypi.python.org \ + --trusted-host files.pythonhosted.org \ + -r requirements.txt + +COPY . . + +RUN chmod +x start.sh + +EXPOSE 8000 +EXPOSE 8001 + +CMD ["./start.sh"] \ No newline at end of file diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..a51b031 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,39 @@ +# ARC Backend + +Backend minimal pour le projet ARC : +- API FastAPI +- orchestration LangGraph +- agents PM / Dev / QA +- interface Chainlit +- intégration future Qdrant / Redis / vLLM + +## Installation + +```bash +python -m venv .venv +.venv\Scripts\activate +pip install -r requirements.txt +uvicorn app.main:app --reload --port 8000 +``` + +## Lancer Chainlit + +```bash +chainlit run chainlit_app.py --port 8001 +``` + +## Lancement auto + +```bash +docker compose up --build +``` + +## Tests + +```bash +python .\tests\test_snowflake.py +docker compose exec app python tests/test_qdrant.py +``` + +API dispo sur : +- http://127.0.0.1:8001 \ No newline at end of file diff --git a/backend/app/agents/dev_agent.py b/backend/app/agents/dev_agent.py new file mode 100644 index 0000000..950b65a --- /dev/null +++ b/backend/app/agents/dev_agent.py @@ -0,0 +1,14 @@ +async def run_dev_agent(spec: dict, qa_feedback: list = None) -> dict: + """ + Agent Dev minimal : + - retourne une pseudo arborescence + un code exemple + """ + return { + "tree": [ + "main.py", + "README.md", + "app/__init__.py", + ], + "code": 'print("Hello from ARC generated project")', + "spec_title": spec.get("title"), + } \ No newline at end of file diff --git a/backend/app/agents/pm_agent.py b/backend/app/agents/pm_agent.py new file mode 100644 index 0000000..cfcfa00 --- /dev/null +++ b/backend/app/agents/pm_agent.py @@ -0,0 +1,15 @@ +from app.schemas.spec import ProjectSpec + + +async def run_pm_agent(user_input: str) -> ProjectSpec: + """ + Agent PM minimal : + - transforme l'entrée utilisateur en cahier des charges structuré + """ + return ProjectSpec( + title="Projet généré depuis demande utilisateur", + description=user_input, + requirements=["MVP minimal", "Architecture modulaire"], + constraints=["Python", "LangGraph", "Pydantic"], + target_stack="Python", + ) \ No newline at end of file diff --git a/backend/app/agents/qa_agent.py b/backend/app/agents/qa_agent.py new file mode 100644 index 0000000..39dd169 --- /dev/null +++ b/backend/app/agents/qa_agent.py @@ -0,0 +1,10 @@ +async def run_qa_agent(generated_code: dict) -> dict: + """ + Agent QA minimal : + - renvoie un statut de validation simulé + """ + return { + "status": "passed", + "logs": [], + "checked_files": generated_code.get("tree", []), + } \ No newline at end of file diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/api/routes/health.py b/backend/app/api/routes/health.py new file mode 100644 index 0000000..145e821 --- /dev/null +++ b/backend/app/api/routes/health.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter + +router = APIRouter(tags=["health"]) + + +@router.get("/health") +def health(): + return {"status": "ok"} \ No newline at end of file diff --git a/backend/app/api/routes/workflow.py b/backend/app/api/routes/workflow.py new file mode 100644 index 0000000..8ac92f4 --- /dev/null +++ b/backend/app/api/routes/workflow.py @@ -0,0 +1,11 @@ +from fastapi import APIRouter +from app.schemas.api import WorkflowRequest, WorkflowResponse +from app.services.workflow_service import run_arc_workflow + +router = APIRouter(tags=["workflow"]) + + +@router.post("/workflow/run", response_model=WorkflowResponse) +async def run_workflow(payload: WorkflowRequest): + result = await run_arc_workflow(payload.user_input) + return WorkflowResponse(**result) \ No newline at end of file diff --git a/backend/app/core/config.py b/backend/app/core/config.py new file mode 100644 index 0000000..b598e0c --- /dev/null +++ b/backend/app/core/config.py @@ -0,0 +1,25 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + app_name: str = "ARC Backend" + app_env: str = "dev" + app_host: str = "0.0.0.0" + app_port: int = 8000 + + qdrant_url: str = "http://localhost:6333" + qdrant_collection: str = "arc_projects" + + redis_url: str = "redis://localhost:6379/0" + + llm_base_url: str = "http://gemma-server:8080/v1" + llm_api_key: str = "llama-cpp-local" + # llm_model: str = "gemma-4-E4B-it-UD-Q4_K_XL.gguf" + + embedding_base_url: str = "http://localhost:8002/v1" + embedding_model: str = "snowflake-arctic-embed-m-v1.5" + + model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") + + +settings = Settings() \ No newline at end of file diff --git a/backend/app/core/logging.py b/backend/app/core/logging.py new file mode 100644 index 0000000..5c35670 --- /dev/null +++ b/backend/app/core/logging.py @@ -0,0 +1,8 @@ +import logging + + +def setup_logging() -> None: + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + ) \ No newline at end of file diff --git a/backend/app/core/security.py b/backend/app/core/security.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/graph/nodes.py b/backend/app/graph/nodes.py new file mode 100644 index 0000000..5e78a5e --- /dev/null +++ b/backend/app/graph/nodes.py @@ -0,0 +1,56 @@ +from app.agents.pm_agent import run_pm_agent +from app.agents.dev_agent import run_dev_agent +from app.agents.qa_agent import run_qa_agent +from app.services.retrieval_service import find_existing_project +from app.graph.state import WorkflowState + +async def pm_node(state: WorkflowState): + prompt = state["user_input"] + if state.get("user_feedback"): + prompt += f"\nRetour utilisateur pour correction : {state['user_feedback']}" + + spec = await run_pm_agent(prompt) + return { + "spec": spec.model_dump(), + "status": "spec_ready", + "loop_count": 0, + } + +async def retrieval_node(state: WorkflowState): + existing_project = await find_existing_project(state["user_input"]) + return { + "existing_project": existing_project, + "status": "existing_found" if existing_project else "no_existing_project", + } + +async def dev_node(state: WorkflowState): + qa_logs = state.get("qa_result", {}).get("logs", "") if state.get("qa_result") else None + + generated_code = await run_dev_agent(state["spec"], qa_feedback=qa_logs) + return { + "generated_code": generated_code, + "status": "code_generated", + } + +async def qa_node(state: WorkflowState): + qa_result = await run_qa_agent(state["generated_code"]) + current_loops = state.get("loop_count", 0) + + is_success = True + + clean_qa_result = {"success": is_success, "raw": qa_result} + + return { + "qa_result": clean_qa_result, + "loop_count": current_loops if is_success else current_loops + 1, + "status": "qa_done", + } + +async def human_review_node(state: WorkflowState): + print("[Human Review] Passage en mode automatique (Mock)...") + + return { + "existing_project_approved": True, + "is_completed": True, + "status": "approved_by_human" + } \ No newline at end of file diff --git a/backend/app/graph/state.py b/backend/app/graph/state.py new file mode 100644 index 0000000..bdbe1c1 --- /dev/null +++ b/backend/app/graph/state.py @@ -0,0 +1,13 @@ +from typing import TypedDict, Optional, Any, Dict + +class WorkflowState(TypedDict, total=False): + user_input: str + spec: dict + existing_project: Optional[dict] + existing_project_approved: Optional[bool] # Choix utilisateur si projet similaire trouvé + generated_code: Optional[Dict[str, str]] # Arborescence et code + qa_result: Optional[dict] # Contient les clés 'success' et 'logs' + loop_count: int # Compteur pour la Loop 1 (Dev <-> QA) + user_feedback: Optional[str] # Retours si l'utilisateur refuse le code final + is_completed: bool # Statut de livraison finale + status: str \ No newline at end of file diff --git a/backend/app/graph/workflow.py b/backend/app/graph/workflow.py new file mode 100644 index 0000000..385594d --- /dev/null +++ b/backend/app/graph/workflow.py @@ -0,0 +1,92 @@ +import warnings +from langchain_core._api.deprecation import LangChainPendingDeprecationWarning +warnings.filterwarnings("ignore", category=LangChainPendingDeprecationWarning) + +from langgraph.graph import StateGraph, END +from app.graph.state import WorkflowState +from app.graph.nodes import ( + pm_node, + retrieval_node, + dev_node, + qa_node, + human_review_node, +) + +# --- Fonctions de Routage (Conditional Edges) --- + +def route_after_retrieval(state: WorkflowState): + # Si un projet existe, on demande d'abord à l'humain (via le nœud de review) + if state.get("existing_project"): + return "human_review" + return "dev" + +def route_after_qa(state: WorkflowState): + qa_res = state.get("qa_result", {}) + + # Loop 1 : Si échec des tests ET qu'on a pas dépassé 3 essais -> On renvoie chez le Dev + if not qa_res.get("success") and state.get("loop_count", 0) < 3: + return "dev" + + # Si c'est vert (ou trop d'échecs), on présente le résultat à l'utilisateur + # EXTENSION FUTURE : si trop d'échecs, on pourrait envoyer à une IA plus puissante + return "human_review" + +def route_after_human(state: WorkflowState): + # Cas d'un projet existant proposé + if state.get("existing_project") and not state.get("generated_code"): + if state.get("existing_project_approved") == True: + return END # L'utilisateur est satisfait du projet existant + return "dev" # L'utilisateur refuse l'existant, on génère du neuf + + # Cas du code généré + if state.get("is_completed") == True: + return END + + # Si l'utilisateur a refusé le code -> Retour à la case PM avec ses commentaires + return "pm" + +# --- Assemblage du Graphe --- + +graph = StateGraph(WorkflowState) + +graph.add_node("pm", pm_node) +graph.add_node("retrieval", retrieval_node) +graph.add_node("dev", dev_node) +graph.add_node("qa", qa_node) +graph.add_node("human_review", human_review_node) + +graph.set_entry_point("pm") +graph.add_edge("pm", "retrieval") + +# Étape 1 : Choix après recherche vectorielle +graph.add_conditional_edges( + "retrieval", + route_after_retrieval, + { + "dev": "dev", + "human_review": "human_review", + }, +) + +# Étape 2 & 3 : Boucle Dev <-> QA (Loop 1) +graph.add_edge("dev", "qa") +graph.add_conditional_edges( + "qa", + route_after_qa, + { + "dev": "dev", + "human_review": "human_review", + }, +) + +# Étape 4 : Boucle de Feedback Humain (Loop 2) ou Clôture +graph.add_conditional_edges( + "human_review", + route_after_human, + { + "pm": "pm", + "dev": "dev", + END: END, + }, +) +compiled_graph = graph.compile() \ No newline at end of file diff --git a/backend/app/llm/client.py b/backend/app/llm/client.py new file mode 100644 index 0000000..28ae1a9 --- /dev/null +++ b/backend/app/llm/client.py @@ -0,0 +1,12 @@ +from openai import AsyncOpenAI +from app.core.config import settings + +def get_llm_client() -> AsyncOpenAI: + """ + Initialise le client de génération (LLM) compatible OpenAI. + Configuré pour pointer vers notre instance locale llama.cpp (Gemma 4). + """ + return AsyncOpenAI( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key, + ) \ No newline at end of file diff --git a/backend/app/llm/prompts.py b/backend/app/llm/prompts.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/llm/providers.py b/backend/app/llm/providers.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..9c50627 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,34 @@ +from fastapi import FastAPI +from contextlib import asynccontextmanager +from app.api.routes.health import router as health_router +from app.api.routes.workflow import router as workflow_router +from app.core.config import settings +from app.core.logging import setup_logging +from app.repositories.qdrant_repository import QdrantRepository + +setup_logging() + +@asynccontextmanager +async def lifespan(app: FastAPI): + print("[Startup] Initialisation automatique de Qdrant dans Docker...") + qdrant_repo = QdrantRepository() + try: + await qdrant_repo.init_collection(vector_size=1024) + except Exception as e: + print(f"[Startup] Erreur lors de l'initialisation de Qdrant : {e}") + yield + + print("[Shutdown] Fermeture propre de la connexion Qdrant...") + await qdrant_repo.close() + + +app = FastAPI( + title=settings.app_name, + docs_url=None, + redoc_url=None, + openapi_url=None, + lifespan=lifespan +) + +app.include_router(health_router, prefix="/api") +app.include_router(workflow_router, prefix="/api") \ No newline at end of file diff --git a/backend/app/models/project.py b/backend/app/models/project.py new file mode 100644 index 0000000..da8a973 --- /dev/null +++ b/backend/app/models/project.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel +from typing import List, Optional + + +class ProjectRecord(BaseModel): + id: Optional[str] = None + title: str + summary: str + tags: List[str] = [] + repository_url: Optional[str] = None \ No newline at end of file diff --git a/backend/app/repositories/project_repository.py b/backend/app/repositories/project_repository.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/repositories/qdrant_repository.py b/backend/app/repositories/qdrant_repository.py new file mode 100644 index 0000000..32748d6 --- /dev/null +++ b/backend/app/repositories/qdrant_repository.py @@ -0,0 +1,58 @@ +# backend/app/repositories/qdrant_repository.py +from typing import Optional, List +from qdrant_client import AsyncQdrantClient +from qdrant_client.http import models +from app.core.config import settings + +class QdrantRepository: + def __init__(self): + # Initialisation du client asynchrone + self.client = AsyncQdrantClient( + url=settings.qdrant_url, + # api_key=getattr(settings, "qdrant_api_key", None) # Qdrant Cloud + ) + self.collection_name = settings.qdrant_collection + + async def init_collection(self, vector_size: int = 1024): + """ + Crée la collection si elle n'existe pas encore. + 1024 correspond à la taille des vecteurs de Snowflake Arctic Embed 2.0 (large). + """ + exists = await self.client.collection_exists(collection_name=self.collection_name) + if not exists: + print(f"[Qdrant] Création de la collection '{self.collection_name}'...") + await self.client.create_collection( + collection_name=self.collection_name, + vectors_config=models.VectorParams( + size=vector_size, + distance=models.Distance.COSINE + ) + ) + print("[Qdrant] Collection créée avec succès.") + else: + print(f"[Qdrant] La collection '{self.collection_name}' existe déjà.") + + async def search_similar_project(self, query_vector: List[float], limit: int = 1) -> Optional[dict]: + """ + Effectue la vraie recherche vectorielle. + Note : On passe un 'query_vector' (généré par ton embedding_service) et non du texte brut. + """ + try: + results = await self.client.search( + collection_name=self.collection_name, + query_vector=query_vector, + limit=limit + ) + + if results: + # On retourne le payload (les métadonnées du projet) du meilleur match + return results[0].payload + return None + + except Exception as e: + print(f"[Qdrant] Erreur lors de la recherche : {e}") + return None + + async def close(self): + """Ferme proprement la connexion au client""" + await self.client.close() \ No newline at end of file diff --git a/backend/app/repositories/redis_repository.py b/backend/app/repositories/redis_repository.py new file mode 100644 index 0000000..8c56adc --- /dev/null +++ b/backend/app/repositories/redis_repository.py @@ -0,0 +1,13 @@ +from app.core.config import settings + + +class RedisRepository: + """ + Stub minimal Redis (optionnel). + """ + + def __init__(self): + self.url = settings.redis_url + + async def ping(self) -> bool: + return True \ No newline at end of file diff --git a/backend/app/sandbox/docker_runner.py b/backend/app/sandbox/docker_runner.py new file mode 100644 index 0000000..ab2859c --- /dev/null +++ b/backend/app/sandbox/docker_runner.py @@ -0,0 +1,8 @@ +async def run_in_sandbox(code: str) -> dict: + """ + Stub minimal pour future exécution sécurisée dans Docker. + """ + return { + "status": "not_implemented", + "logs": ["Sandbox Docker non branchée à l'étape 0."], + } diff --git a/backend/app/schemas/api.py b/backend/app/schemas/api.py new file mode 100644 index 0000000..db28bb9 --- /dev/null +++ b/backend/app/schemas/api.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel +from typing import Optional, Any + + +class WorkflowRequest(BaseModel): + user_input: str + + +class WorkflowResponse(BaseModel): + status: str + spec: Optional[dict] = None + existing_project: Optional[dict] = None + generated_code: Optional[Any] = None + qa_result: Optional[Any] = None \ No newline at end of file diff --git a/backend/app/schemas/project.py b/backend/app/schemas/project.py new file mode 100644 index 0000000..137a39e --- /dev/null +++ b/backend/app/schemas/project.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel +from typing import List, Optional + + +class ProjectSummary(BaseModel): + id: Optional[str] = None + title: str + summary: str + tags: List[str] = [] + repository_url: Optional[str] = None \ No newline at end of file diff --git a/backend/app/schemas/spec.py b/backend/app/schemas/spec.py new file mode 100644 index 0000000..f76e00a --- /dev/null +++ b/backend/app/schemas/spec.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, Field +from typing import List, Optional + + +class ProjectSpec(BaseModel): + title: str = Field(default="Projet ARC") + description: str + requirements: List[str] = Field(default_factory=list) + constraints: List[str] = Field(default_factory=list) + target_stack: Optional[str] = "Python" \ No newline at end of file diff --git a/backend/app/services/delivery_service.py b/backend/app/services/delivery_service.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/services/embedding_service.py b/backend/app/services/embedding_service.py new file mode 100644 index 0000000..66891a8 --- /dev/null +++ b/backend/app/services/embedding_service.py @@ -0,0 +1,40 @@ +import httpx +from app.core.config import settings + + +async def build_embedding(text: str) -> dict: + """ + Génère un vecteur d'embedding en interrogeant le conteneur local llama.cpp + """ + url = f"{settings.embedding_base_url}/embeddings" + + headers = { + "Content-Type": "application/json" + } + + payload = { + "input": text, + "model": settings.embedding_model + } + + async with httpx.AsyncClient(timeout=30.0) as client: + try: + response = await client.post(url, json=payload, headers=headers) + response.raise_for_status() + + data = response.json() + vector = data["data"][0]["embedding"] + + return { + "model": settings.embedding_model, + "text_length": len(text), + "vector": vector, + } + + except httpx.HTTPError as e: + print(f"Erreur lors de la génération de l'embedding : {e}") + return { + "model": settings.embedding_model, + "text_length": len(text), + "vector": [], + } \ No newline at end of file diff --git a/backend/app/services/retrieval_service.py b/backend/app/services/retrieval_service.py new file mode 100644 index 0000000..dfe418e --- /dev/null +++ b/backend/app/services/retrieval_service.py @@ -0,0 +1,11 @@ +from app.repositories.qdrant_repository import QdrantRepository +from app.services.embedding_service import build_embedding + + +qdrant_repository = QdrantRepository() + + +async def find_existing_project(user_input: str): + # query_vector = await build_embedding.get_mesh_embedding(user_input) + dummy_vector = [0.0] * 1024 # A modifier avec un vrai embedding plus tard TODO + return await qdrant_repository.search_similar_project(query_vector=dummy_vector) \ No newline at end of file diff --git a/backend/app/services/workflow_service.py b/backend/app/services/workflow_service.py new file mode 100644 index 0000000..ac21dd0 --- /dev/null +++ b/backend/app/services/workflow_service.py @@ -0,0 +1,6 @@ +from app.graph.workflow import compiled_graph + + +async def run_arc_workflow(user_input: str) -> dict: + result = await compiled_graph.ainvoke({"user_input": user_input}) + return result \ No newline at end of file diff --git a/backend/chainlit.md b/backend/chainlit.md new file mode 100644 index 0000000..e69de29 diff --git a/backend/chainlit_app.py b/backend/chainlit_app.py new file mode 100644 index 0000000..8083e34 --- /dev/null +++ b/backend/chainlit_app.py @@ -0,0 +1,25 @@ +import chainlit as cl +import httpx +import json + + +@cl.on_chat_start +async def on_chat_start(): + await cl.Message( + content="Bonjour 👋 Je suis ARC. Décris-moi ton besoin logiciel." + ).send() + + +@cl.on_message +async def on_message(message: cl.Message): + async with httpx.AsyncClient() as client: + response = await client.post( + "http://127.0.0.1:8000/api/workflow/run", + json={"user_input": message.content}, + ) + + result = response.json() + + await cl.Message( + content=f"Résultat workflow :\n```json\n{json.dumps(result, indent=2, ensure_ascii=False)}\n```" + ).send() \ No newline at end of file diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml new file mode 100644 index 0000000..a138ca4 --- /dev/null +++ b/backend/docker-compose.yml @@ -0,0 +1,102 @@ +services: + qdrant: + image: qdrant/qdrant:latest + container_name: qdrant-arc + ports: + - "6333:6333" + - "6334:6334" + environment: + - QDRANT__TELEMETRY_DISABLED=true + volumes: + - qdrant_storage:/qdrant/storage + networks: + - arc-network + + download-model: + image: alpine:latest + container_name: download-embedding-model + volumes: + - model_storage:/models + command: > + sh -c " + if [ ! -f /models/snowflake-arctic-embed-m-v1.5-f16.gguf ]; then + echo 'Téléchargement du modèle (Contournement SSL Proxy activé)...'; + wget --no-check-certificate 'https://huggingface.co/Snowflake/snowflake-arctic-embed-m-v1.5/resolve/main/gguf/snowflake-arctic-embed-m-v1.5-f16.gguf' -O /models/snowflake-arctic-embed-m-v1.5-f16.gguf; + echo 'Téléchargement terminé avec succès !'; + else + echo 'Le modèle est déjà présent.'; + fi + " + + embedding-server: + image: ghcr.io/ggml-org/llama.cpp:server + container_name: embedding-arc + volumes: + - model_storage:/models + ports: + - "8002:8080" + command: "-m /models/snowflake-arctic-embed-m-v1.5-f16.gguf --embedding --host 0.0.0.0 --port 8080" + restart: unless-stopped + networks: + - arc-network + depends_on: + download-model: + condition: service_completed_successfully + + download-gemma: + image: alpine:latest + container_name: download-gemma-model + volumes: + - model_storage:/models + command: > + sh -c " + if [ ! -f /models/gemma-4-E4B-it-UD-Q4_K_XL.gguf ]; then + echo 'Téléchargement de Gemma 4 (Contournement SSL Proxy)...'; + wget --no-check-certificate 'https://huggingface.co/unsloth/gemma-4-E4B-it-GGUF/resolve/main/gemma-4-E4B-it-UD-Q4_K_XL.gguf' -O /models/gemma-4-E4B-it-UD-Q4_K_XL.gguf; + echo 'Téléchargement de Gemma 4 terminé !'; + else + echo 'Le modèle Gemma 4 est déjà présent.'; + fi + " + + gemma-server: + image: ghcr.io/ggml-org/llama.cpp:server + container_name: gemma-arc + volumes: + - model_storage:/models + ports: + - "8003:8080" + command: "-m /models/gemma-4-E4B-it-UD-Q4_K_XL.gguf --host 0.0.0.0 --port 8080 -c 4096" + restart: unless-stopped + networks: + - arc-network + depends_on: + download-gemma: + condition: service_completed_successfully + + app: + build: . + container_name: arc-app + ports: + - "8000:8000" + - "8001:8001" + volumes: + - .:/workspace + environment: + - PYTHONPATH=/workspace + - QDRANT_URL=http://qdrant:6333 + - QDRANT_COLLECTION=arc_projects + - EMBEDDING_SERVER_URL=http://embedding-server:8080 + depends_on: + - qdrant + - embedding-server + networks: + - arc-network + +volumes: + qdrant_storage: + model_storage: + +networks: + arc-network: + driver: bridge \ No newline at end of file diff --git a/backend/public/logo_dark.png b/backend/public/logo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1ac95bb6eb9f5c579f65eaab8b34577ade09a04f GIT binary patch literal 67615 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.6.0 +pydantic==2.12 +pydantic-settings==2.10.1 +langgraph==0.2.39 +chainlit==2.11.0 +qdrant-client==1.11.3 +redis==5.0.8 +httpx==0.27.2 +openai==1.51.2 +python-dotenv==1.0.1 +pytest==8.3.3 +ruff==0.6.8 +bandit==1.7.10 +requests \ No newline at end of file diff --git a/backend/start.sh b/backend/start.sh new file mode 100644 index 0000000..43ff7cc --- /dev/null +++ b/backend/start.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +echo "Démarrage du Backend FastAPI sur le port 8000..." +uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload & + +echo "Démarrage de Chainlit sur le port 8001..." +chainlit run chainlit_app.py --host 0.0.0.0 --port 8001 \ No newline at end of file diff --git a/backend/tests/test_agents.py b/backend/tests/test_agents.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/tests/test_gemma.py b/backend/tests/test_gemma.py new file mode 100644 index 0000000..12d2091 --- /dev/null +++ b/backend/tests/test_gemma.py @@ -0,0 +1,28 @@ +import requests + +def tester_gemma(): + url = "http://localhost:8003/v1/chat/completions" + + payload = { + "messages": [ + {"role": "user", "content": "Donne-moi une astuce de code Python originale."} + ], + "temperature": 0.7 + } + + print("🧠 Envoi de la requête à Gemma 4...") + try: + response = requests.post(url, json=payload) + response.raise_for_status() + answer = response.json()["choices"][0]["message"]["content"] + + print("\n🤖 Réponse de Gemma 4 :") + print("-" * 40) + print(answer) + print("-" * 40) + + except Exception as e: + print(f"❌ Erreur : {e}") + +if __name__ == "__main__": + tester_gemma() \ No newline at end of file diff --git a/backend/tests/test_health.py b/backend/tests/test_health.py new file mode 100644 index 0000000..f50b1cd --- /dev/null +++ b/backend/tests/test_health.py @@ -0,0 +1,10 @@ +from fastapi.testclient import TestClient +from app.main import app + +client = TestClient(app) + + +def test_health(): + response = client.get("/api/health") + assert response.status_code == 200 + assert response.json()["status"] == "ok" \ No newline at end of file diff --git a/backend/tests/test_qdrant.py b/backend/tests/test_qdrant.py new file mode 100644 index 0000000..4b627bf --- /dev/null +++ b/backend/tests/test_qdrant.py @@ -0,0 +1,55 @@ +import asyncio +import random +from app.repositories.qdrant_repository import QdrantRepository +from qdrant_client.http import models + +async def test_pipeline(): + print("--- Test de connexion Qdrant ---") + repo = QdrantRepository() + + try: + # 1. Tester la connexion et initialiser la collection + await repo.init_collection(vector_size=1024) + + # 2. Insérer un faux projet pour valider le fonctionnement (Upsert) + print("\n[Test] Insertion d'un faux projet indexé...") + mock_vector = [random.uniform(-1.0, 1.0) for _ in range(1024)] + + await repo.client.upsert( + collection_name=repo.collection_name, + points=[ + models.PointStruct( + id=1, + vector=mock_vector, + payload={ + "title": "Application E-commerce de test", + "description": "Un projet test généré pour valider Qdrant", + "git_url": "https://github.com/test/test" + } + ) + ] + ) + print("[Test] Faux projet inséré.") + + # 3. Tester la recherche vectorielle + print("\n[Test] Lancement de la recherche vectorielle...") + project_found = await repo.search_similar_project(query_vector=mock_vector) + + if project_found: + print(f"🎉 Succès ! Projet trouvé en BDD : {project_found['title']} ({project_found['git_url']})") + else: + print("❌ Erreur : Aucun projet trouvé alors qu'on vient d'en insérer un.") + + except Exception as e: + print(f"❌ Échec critique du test : {e}") + print("Vérifie que ton conteneur Qdrant est bien lancé et que l'URL dans ton .env est correcte.") + + finally: + await repo.close() + print("\n--- Fin du test ---") + +if __name__ == "__main__": + from dotenv import load_dotenv + load_dotenv() + + asyncio.run(test_pipeline()) \ No newline at end of file diff --git a/backend/tests/test_snowflake.py b/backend/tests/test_snowflake.py new file mode 100644 index 0000000..8fe0c3c --- /dev/null +++ b/backend/tests/test_snowflake.py @@ -0,0 +1,42 @@ +import requests +import json + +def test_embedding_server(): + url = "http://localhost:8002/v1/embeddings" + + phrase = "Ceci est un test." + + payload = { + "input": phrase + } + + headers = { + "Content-Type": "application/json" + } + + print("Envoi de la phrase au serveur Snowflake Arctic local...") + + try: + response = requests.post(url, json=payload, headers=headers) + + response.raise_for_status() + + resultat = response.json() + + vecteur = resultat["data"][0]["embedding"] + tokens_utilises = resultat["usage"]["total_tokens"] + + print("\n[SUCCÈS] Le serveur d'embedding répond parfaitement !") + print(f"Texte analysé : '{phrase}'") + print(f"Nombre de tokens consommés : {tokens_utilises}") + print(f"Dimension du vecteur : {len(vecteur)} (Attendu : 768)") + print(f"Début du vecteur (5 premiers chiffres) : {vecteur[:5]}") + + except requests.exceptions.ConnectionError: + print("\n[ERREUR] Impossible de joindre le serveur d'embedding.") + print("Vérifie que ton Docker Compose est bien démarré avec 'docker compose up'.") + except Exception as e: + print(f"\n[ERREUR] Une erreur inattendue est survenue : {e}") + +if __name__ == "__main__": + test_embedding_server() \ No newline at end of file diff --git a/backend/tests/test_workflow.py b/backend/tests/test_workflow.py new file mode 100644 index 0000000..e69de29 diff --git a/ressources/Etape0.md b/ressources/Etape0.md new file mode 100644 index 0000000..f8c1465 --- /dev/null +++ b/ressources/Etape0.md @@ -0,0 +1,42 @@ +# Projet ARC +```mermaid +gantt + title Section 0 - Préparation de l'environnement du projet + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Initialisation + Créer structure projet :a1, 2026-06-09, 0.5d + Backend + structure :a2, 2026-06-09, 0.5d + + section LangGraph + Installer LangGraph :b1, 2026-06-09, 0.5d + Créer structure workflow :b2, 2026-06-09, 1d + Définir state global :b3, 2026-06-09, 1d + + section Setup Qdrant + Installer Qdrant :c1, after b3, 0.5d + Tester connexion Python :c2, after b3, 0.5d + + section Setup modèle d’embedding + Installer Snowflake :d1, after b3, 0.5d + Implémenter embedding() :d2, after b3, 0.5d + + section Setup LLM + Installer llama.cpp :e1, after b3, 0.5d + Tester appel modèle :e2, after b3, 0.5d + + section Setup Chainlit + Installer Chainlit :f1, after e2, 0.5d + Lancer app test :f2, after e2, 0.5d + + section Organisation du code + Créer dossiers agents :g1, after e2, 0.5d + Créer dossiers services :g2, after e2, 0.5d + + section Logging et debug + Logs simples :h1, after e2, 0.5d + Structuration logs :h2, after e2, 0.5d +``` \ No newline at end of file diff --git a/ressources/Etape1.md b/ressources/Etape1.md new file mode 100644 index 0000000..a69a9db --- /dev/null +++ b/ressources/Etape1.md @@ -0,0 +1,53 @@ +# Projet ARC +```mermaid +gantt + title Section 1 - Analyse du Besoin & Qualification + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Interface utilisateur + Créer interface Chainlit :a1, 2026-06-12, 1d + Connecter Chainlit → backend Python :a2, 2026-06-12, 0.5d + + section Modèle cahier des charges + Définir structure JSON :b1, after a2, 0.5d + Schéma Pydantic :b2, after a2, 1d + + section Agent PM + Prompt Agent PM :c1, after b2, 0.5d + Sortie structurée Pydantic :c2, after b2, 0.5d + Gestion erreurs :c3, after c2, 0.5d + + section Questions clarificatrices + Détection champs manquants :d1, after c2, 0.5d + Génération questions LLM :d2, after d1, 0.5d + Boucle interaction Chainlit :d3, after d1, 1d + + section Validation du cahier des charges + Affichage CDC :e1, after d3, 0.5d + Boutons validation/refus :e2, after d3, 0.5d + + section Qdrant (BDD vectorielle) + Installer Qdrant :f1, after e2, 0.5d + Créer collection :f2, after e2, 0.5d + Structure payload :f3, after f2, 0.5d + + section Embedding + Intégrer Snowflake Arctic :g1, after f2, 0.5d + Fonction embedding :g2, after f2, 0.5d + + section Recherche d'existant + Recherche projets similaires :h1, after g2, 0.5d + Filtres payload :h2, after g2, 0.5d + Formatage résultats :h3, after h2, 0.5d + + section Proposition utilisateur + Affichage résultats Chainlit :i1, after h2, 0.5d + Bouton "utiliser projet" :i2, after h2, 0.5d + Bouton "continuer génération" :i3, after h2, 0.5d + + section Redis (optionnel) + Cache recherche :j1, after i3, 1d +``` \ No newline at end of file diff --git a/ressources/Etape2.md b/ressources/Etape2.md new file mode 100644 index 0000000..b598c12 --- /dev/null +++ b/ressources/Etape2.md @@ -0,0 +1,50 @@ +# Projet ARC +```mermaid +gantt + title Section 2 - Génération de Code + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation des entrées + Récupérer cahier des charges :a1, 2026-06-29, 0.5d + Normaliser / valider données :a2, 2026-06-29, 0.5d + + section Format de sortie du code + Structure projet JSON/Pydantic :b1, after a2, 0.5d + Modèle Pydantic sortie code :b2, after a2, 1d + + section Prompt Agent Dev + Prompt génération code :c1, after b2, 1d + Contraintes strictes :c2, after b2, 0.5d + + section Intégration LLM + Setup llama.cpp :d1, after c2, 0.5d + Connexion LangGraph → LLM :d2, after c2, 0.5d + + section Arborescence projet + Génération structure fichiers :e1, after d2, 0.5d + Vérification structure :e2, after d2, 0.5d + + section Génération code source + Génération fichiers Python :f1, after e2, 2d + Conformité structure :f2, after f1, 1d + + section Fichiers complémentaires + README.md :g1, after f2, 0.5d + requirements.txt :g2, after f2, 0.5d + Instructions exécution :g3, after f2, 0.5d + + section Validation backend + Vérification fichiers :h1, after g3, 0.5d + Nettoyage output LLM :h2, after g3, 0.5d + + section Intégration LangGraph + Ajouter noeud Agent Dev :i1, after h2, 0.5d + Connecter PM → Dev :i2, after h2, 0.5d + + section Préparation QA + Formatter code sandbox :j1, after i2, 0.5d + Transmettre au state :j2, after i2, 0.5d +``` \ No newline at end of file diff --git a/ressources/Etape3.md b/ressources/Etape3.md new file mode 100644 index 0000000..7828570 --- /dev/null +++ b/ressources/Etape3.md @@ -0,0 +1,59 @@ +# Projet ARC +```mermaid +gantt + title Section 3 - Tests et Assurance Qualité + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation entrées + Récupérer projet Agent Dev :a1, 2026-07-15, 0.5d + + section Sandbox Docker + Dockerfile générique :b1, 2026-07-15, 1d + Script build/run :b2, after b1, 1d + Isolation environnement :b3, after b1, 0.5d + + section Exécution sandbox + Lancer exécution :c1, after b3, 0.5d + Capturer logs :c2, after b3, 0.5d + + section Ruff (qualité) + Installer Ruff :d1, after c2, 0.5d + Ruff check :d2, after c2, 0.5d + + section Bandit (sécurité) + Installer Bandit :e1, after c2, 0.5d + Scan projet :e2, after c2, 0.5d + + section Semgrep (optionnel) + Installer Semgrep :f1, after c2, 0.5d + Analyse règles :f2, after c2, 0.5d + + section Structuration QA + Modèle Pydantic rapport :g1, after f2, 1d + Parser résultats outils :g2, after g1, 0.5d + + section Agent QA + Prompt Agent QA :h1, after g2, 1d + Résumé intelligible :h2, after h1, 0.5d + Traduction erreurs → dev :h3, after h2, 1d + + section Boucle Dev ↔ QA + Implémenter boucle LangGraph :i1, after h3, 1.5d + Condition stop :i2, after h3, 0.5d + Limite itérations :i3, after h3, 1d + + section Logs pour correction + Structurer logs :j1, after i3, 0.5d + Injecter logs dans Agent Dev :j2, after i3, 0.5d + + section Intégration LangGraph + Ajouter noeud QA :k1, after j2, 0.5d + Connecter Dev → QA → loop :k2, after j2, 0.5d + + section Sécurisation minimale + Limiter temps exécution :l1, after k2, 0.5d + Bloquer accès disque/réseau :l2, after k2, 0.5d +``` \ No newline at end of file diff --git a/ressources/Etape4.md b/ressources/Etape4.md new file mode 100644 index 0000000..5696460 --- /dev/null +++ b/ressources/Etape4.md @@ -0,0 +1,53 @@ +# Projet ARC +```mermaid +gantt + title Section 4 - Livraison & Feedback Utilisateur + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation affichage + Récupérer code validé :a1, 2026-08-03, 0.5d + Récupérer rapport QA :a2, 2026-08-03, 0.5d + + section Affichage Chainlit + Afficher code :b1, after a2, 0.5d + Afficher rapport QA :b2, after a2, 0.5d + Afficher instructions exécution :b3, after a2, 0.5d + + section Actions utilisateur + Bouton valider :c1, after a2, 0.5d + Bouton refuser :c2, after a2, 0.5d + + section Gestion refus + Champ feedback :d1, after c2, 0.5d + Structuration Pydantic :d2, after c2, 0.5d + Injection LangGraph :d3, after c2, 0.5d + + section Boucle retour PM + Transition QA → PM :e1, after d3, 0.5d + Conserver contexte + feedback :e2, after d3, 0.5d + + section Génération ZIP + Créer archive :f1, after e2, 0.5d + Vérifier structure :f2, after e2, 0.5d + + section Téléchargement + Bouton téléchargement ZIP :g1, after e2, 0.5d + + section Sauvegarde projet + Sauvegarder code + metadata :h1, after g1, 0.5d + Flag validated :h2, after g1, 0.5d + + section Réindexation Qdrant + Générer embedding :i1, after h2, 0.5d + Ajouter dans Qdrant :i2, after h2, 0.5d + + section Git (optionnel) + Init dépôt :j1, after i2, 0.5d + + section Intégration finale LangGraph + Ajouter noeud Delivery :k1, after i2, 0.5d + Connecter QA → Delivery → fin :k2, after i2, 0.5d +``` \ No newline at end of file diff --git a/ressources/EtapeFinale.md b/ressources/EtapeFinale.md new file mode 100644 index 0000000..25006d0 --- /dev/null +++ b/ressources/EtapeFinale.md @@ -0,0 +1,13 @@ +# Projet ARC +```mermaid +gantt + title Section finale - Rendu + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + Tests fonctionnels de bout en bout :a1, 2026-08-13, 0.5d + Documentation finale :a2, 2026-08-13, 0.5d + Présentation :a3, after a2, 1d +``` \ No newline at end of file diff --git a/ressources/Projet.md b/ressources/Projet.md new file mode 100644 index 0000000..25ce03b --- /dev/null +++ b/ressources/Projet.md @@ -0,0 +1,88 @@ +### Étape 0 : Préparation de l'environnement du projet +Tâches : +- Créer backend minimal +- Créer modèle de données simple +- langGraph +___ + +### Étape 1 : Analyse du Besoin & Qualification (Agent PM / Business Analyst) +- L'utilisateur entre une demande en langage naturel. +- **Agent 1 (PM)** analyse la demande. Si des informations manquent pour coder, il pose des questions clarificatrices à l'utilisateur jusqu'à obtenir un cahier des charges complet. +- **Vérification BDD :** Avant de coder, le système cherche dans une base de données vectorielle si un projet similaire existe déjà. + - *Si oui :* On propose le lien à l'utilisateur. Si l'utilisateur valide, le workflow s'arrête ici. + - *Si non (ou si l'utilisateur rejette l'existant) :* On passe à l'étape 2. + +Outils : +- LangGraph -> LangGraph est adapté aux workflows multi‑agents avec états, transitions conditionnelles, persistance et human‑in‑the‑loop +- Python -> backend, les agents, les appels LLM, les tests, les embeddings et les intégrations + compatible avec autres tools +- Pydantic AI / Pydantic -> forcer l’Agent PM à produire un cahier des charges structuré +- Chainlit -> adapté aux interfaces conversationnelles + BDD : +- Qdrant -> adapté à la recherche sémantique + stocker les embeddings de projets/scripts +- Snowflake Arctic Embed 2.0 -> modèle d’embedding +- Redis (optionnel) -> cache de recherche ;sessions utilisateur ;état temporaire ;verrouillage d’un workflow ;file d’attente simple + +Tâches : +- Interface Chainlit +- Créer le prompt Agent PM +- Créer le schéma Pydantic du cahier des charges +- Gérer les questions clarificatrices +- Valider le cahier des charges +- Recherche d’existant (Qdrant/Snowflake Arctic Embed 2.0/Redis) +___ + +### Étape 2 : Génération de Code (Agent Développeur) +- **Agent 2 (Dev)** reçoit le cahier des charges validé et génère l'arborescence et le code source du projet. + +Outils : +- LangGraph -> LangGraph est adapté aux workflows multi‑agents avec états, transitions conditionnelles, persistance et human‑in‑the‑loop +- Mistral ou Gemma (modèle trop généraliste/léger->tache simple) -> DeepSeek Coder/Qwen2.5 +- vLLM -> meilleur choix qu’Ollama pour une plateforme plus industrialisée. Llama.cpp modèles quantifiés sur CPU ou machines modestes + moins adapté à une plateforme multi‑utilisateur +- Pydantic + +Tâches : +- Créer le prompt Agent Dev +- Partie dev +___ + +### Étape 3 : Tests et Assurance Qualité (Agent QA / Testeur) +- **Agent 3 (QA)** récupère le code de l'Agent 2. Il doit exécuter le code (via une sandbox sécurisée) ou générer/exécuter des tests unitaires pour vérifier la qualité, la sécurité et le fonctionnement. +- **Boucle de correction automatique (Loop 1) :** Si les tests échouent, l'Agent 3 renvoie les erreurs à l'Agent 2 avec les logs. L'Agent 2 corrige et renvoie à l'Agent 3. Cette boucle tourne au maximum X fois jusqu'à ce que le code soit "vert". + +Outils : +- Docker +- Ruff -> qualité de code +- Bandit -> sécurité +- Semgrep (optionnel) -> règles de sécurité et qualité plus larges + Boucle correction : +- LangGraph +- Pydantic + +Tâches : +- QA et sandbox +- Intégration Ruff/Bandit/Semgrep +- Boucle automatique Dev-QA +___ + +### Étape 4 : Livraison & Feedback Utilisateur (Boucle Humaine) +- Une fois le code validé par l'Agent 3, il est présenté à l'utilisateur. +- L'utilisateur teste et valide. + - *Si Validé :* Le projet est sauvegardé dans la base de données (pour la recherche de l'Étape 1) et livré (ex: zip ou dépôt GitHub). + - *Si Refusé :* L'utilisateur indique ce qui ne va pas. Tout le contexte (code actuel + retours) est renvoyé à l'**Étape 1** pour réanalyse, et le cycle recommence. + +Outils : +- Chainlit +- Git (optionnel) + +Tâches : +- Interface Chainlit +- Livraison +___ + +### Étape finale : + +Tâches : +- Tests fonctionnels de bout en bout +- Sécurité minimale +- Documentation finale +- Présentation \ No newline at end of file diff --git a/ressources/test.md b/ressources/test.md new file mode 100644 index 0000000..ed36a94 --- /dev/null +++ b/ressources/test.md @@ -0,0 +1,288 @@ + +# Projet ARC +```mermaid +gantt + title Diagramme Gantt du projet ARC + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker on + + Etape 0 - Initialisation :a1, 2026-06-08, 2026-06-11 + Etape 1 - Analyse du Besoin & Qualification :a2, 2026-06-11, 2026-06-27 + Etape 2 - Génération de Code :a2, 2026-06-29, 2026-07-15 + Etape 3 - Tests et Assurance Qualité :a2, 2026-07-15, 2026-08-01 + Etape 4 - Livraison & Feedback Utilisateur :a2, 2026-08-01, 2026-08-13 + Etape finale :a2, 2026-08-13, 2026-08-15 + +``` +--- +```mermaid +gantt + title Section 0 - Préparation de l'environnement du projet + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Initialisation + Créer structure projet :a1, 2026-06-09, 0.5d + Backend + structure :a2, 2026-06-09, 0.5d + + section LangGraph + Installer LangGraph :b1, 2026-06-09, 0.5d + Créer structure workflow :b2, 2026-06-09, 1d + Définir state global :b3, 2026-06-09, 1d + + section Setup Qdrant + Installer Qdrant :c1, after b3, 0.5d + Tester connexion Python :c2, after b3, 0.5d + + section Setup modèle d’embedding + Installer Snowflake :d1, after b3, 0.5d + Implémenter embedding() :d2, after b3, 0.5d + + section Setup LLM + Installer llama.cpp :e1, after b3, 0.5d + Tester appel modèle :e2, after b3, 0.5d + + section Setup Chainlit + Installer Chainlit :f1, after e2, 0.5d + Lancer app test :f2, after e2, 0.5d + + section Organisation du code + Créer dossiers agents :g1, after e2, 0.5d + Créer dossiers services :g2, after e2, 0.5d + + section Logging et debug + Logs simples :h1, after e2, 0.5d + Structuration logs :h2, after e2, 0.5d +``` + +```mermaid +gantt + title Section 1 - Analyse du Besoin & Qualification + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Interface utilisateur + Créer interface Chainlit :a1, 2026-06-12, 1d + Connecter Chainlit → backend Python :a2, 2026-06-12, 0.5d + + section Modèle cahier des charges + Définir structure JSON :b1, after a2, 0.5d + Schéma Pydantic :b2, after a2, 1d + + section Agent PM + Prompt Agent PM :c1, after b2, 0.5d + Sortie structurée Pydantic :c2, after b2, 0.5d + Gestion erreurs :c3, after c2, 0.5d + + section Questions clarificatrices + Détection champs manquants :d1, after c2, 0.5d + Génération questions LLM :d2, after d1, 0.5d + Boucle interaction Chainlit :d3, after d1, 1d + + section Validation du cahier des charges + Affichage CDC :e1, after d3, 0.5d + Boutons validation/refus :e2, after d3, 0.5d + + section Qdrant (BDD vectorielle) + Installer Qdrant :f1, after e2, 0.5d + Créer collection :f2, after e2, 0.5d + Structure payload :f3, after f2, 0.5d + + section Embedding + Intégrer Snowflake Arctic :g1, after f2, 0.5d + Fonction embedding :g2, after f2, 0.5d + + section Recherche d'existant + Recherche projets similaires :h1, after g2, 0.5d + Filtres payload :h2, after g2, 0.5d + Formatage résultats :h3, after h2, 0.5d + + section Proposition utilisateur + Affichage résultats Chainlit :i1, after h2, 0.5d + Bouton "utiliser projet" :i2, after h2, 0.5d + Bouton "continuer génération" :i3, after h2, 0.5d + + section Redis (optionnel) + Cache recherche :j1, after i3, 1d +``` + +```mermaid +gantt + title Section 2 - Génération de Code + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation des entrées + Récupérer cahier des charges :a1, 2026-06-29, 0.5d + Normaliser / valider données :a2, 2026-06-29, 0.5d + + section Format de sortie du code + Structure projet JSON/Pydantic :b1, after a2, 0.5d + Modèle Pydantic sortie code :b2, after a2, 1d + + section Prompt Agent Dev + Prompt génération code :c1, after b2, 1d + Contraintes strictes :c2, after b2, 0.5d + + section Intégration LLM + Setup llama.cpp :d1, after c2, 0.5d + Connexion LangGraph → LLM :d2, after c2, 0.5d + + section Arborescence projet + Génération structure fichiers :e1, after d2, 0.5d + Vérification structure :e2, after d2, 0.5d + + section Génération code source + Génération fichiers Python :f1, after e2, 2d + Conformité structure :f2, after f1, 1d + + section Fichiers complémentaires + README.md :g1, after f2, 0.5d + requirements.txt :g2, after f2, 0.5d + Instructions exécution :g3, after f2, 0.5d + + section Validation backend + Vérification fichiers :h1, after g3, 0.5d + Nettoyage output LLM :h2, after g3, 0.5d + + section Intégration LangGraph + Ajouter noeud Agent Dev :i1, after h2, 0.5d + Connecter PM → Dev :i2, after h2, 0.5d + + section Préparation QA + Formatter code sandbox :j1, after i2, 0.5d + Transmettre au state :j2, after i2, 0.5d +``` + +```mermaid +gantt + title Section 3 - Tests et Assurance Qualité + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation entrées + Récupérer projet Agent Dev :a1, 2026-07-15, 0.5d + + section Sandbox Docker + Dockerfile générique :b1, 2026-07-15, 1d + Script build/run :b2, after b1, 1d + Isolation environnement :b3, after b1, 0.5d + + section Exécution sandbox + Lancer exécution :c1, after b3, 0.5d + Capturer logs :c2, after b3, 0.5d + + section Ruff (qualité) + Installer Ruff :d1, after c2, 0.5d + Ruff check :d2, after c2, 0.5d + + section Bandit (sécurité) + Installer Bandit :e1, after c2, 0.5d + Scan projet :e2, after c2, 0.5d + + section Semgrep (optionnel) + Installer Semgrep :f1, after c2, 0.5d + Analyse règles :f2, after c2, 0.5d + + section Structuration QA + Modèle Pydantic rapport :g1, after f2, 1d + Parser résultats outils :g2, after g1, 0.5d + + section Agent QA + Prompt Agent QA :h1, after g2, 1d + Résumé intelligible :h2, after h1, 0.5d + Traduction erreurs → dev :h3, after h2, 1d + + section Boucle Dev ↔ QA + Implémenter boucle LangGraph :i1, after h3, 1.5d + Condition stop :i2, after h3, 0.5d + Limite itérations :i3, after h3, 1d + + section Logs pour correction + Structurer logs :j1, after i3, 0.5d + Injecter logs dans Agent Dev :j2, after i3, 0.5d + + section Intégration LangGraph + Ajouter noeud QA :k1, after j2, 0.5d + Connecter Dev → QA → loop :k2, after j2, 0.5d + + section Sécurisation minimale + Limiter temps exécution :l1, after k2, 0.5d + Bloquer accès disque/réseau :l2, after k2, 0.5d +``` + +```mermaid +gantt + title Section 4 - Livraison & Feedback Utilisateur + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + section Préparation affichage + Récupérer code validé :a1, 2026-08-03, 0.5d + Récupérer rapport QA :a2, 2026-08-03, 0.5d + + section Affichage Chainlit + Afficher code :b1, after a2, 0.5d + Afficher rapport QA :b2, after a2, 0.5d + Afficher instructions exécution :b3, after a2, 0.5d + + section Actions utilisateur + Bouton valider :c1, after a2, 0.5d + Bouton refuser :c2, after a2, 0.5d + + section Gestion refus + Champ feedback :d1, after c2, 0.5d + Structuration Pydantic :d2, after c2, 0.5d + Injection LangGraph :d3, after c2, 0.5d + + section Boucle retour PM + Transition QA → PM :e1, after d3, 0.5d + Conserver contexte + feedback :e2, after d3, 0.5d + + section Génération ZIP + Créer archive :f1, after e2, 0.5d + Vérifier structure :f2, after e2, 0.5d + + section Téléchargement + Bouton téléchargement ZIP :g1, after e2, 0.5d + + section Sauvegarde projet + Sauvegarder code + metadata :h1, after g1, 0.5d + Flag validated :h2, after g1, 0.5d + + section Réindexation Qdrant + Générer embedding :i1, after h2, 0.5d + Ajouter dans Qdrant :i2, after h2, 0.5d + + section Git (optionnel) + Init dépôt :j1, after i2, 0.5d + + section Intégration finale LangGraph + Ajouter noeud Delivery :k1, after i2, 0.5d + Connecter QA → Delivery → fin :k2, after i2, 0.5d +``` + +```mermaid +gantt + title Section finale - Rendu + dateFormat YYYY-MM-DD + axisFormat %d/%m + excludes weekends + todayMarker off + + Tests fonctionnels de bout en bout :a1, 2026-08-13, 0.5d + Documentation finale :a2, 2026-08-13, 0.5d + Présentation :a3, after a2, 1d +``` \ No newline at end of file