{"id":48269209,"url":"https://github.com/semhoun/claire-chatbot","last_synced_at":"2026-04-04T22:05:23.695Z","repository":{"id":325701870,"uuid":"1101572441","full_name":"semhoun/claire-chatbot","owner":"semhoun","description":"A minimal AI chat agent built with PHP (Slim 4 + Twig) that talks to an OpenAI‑compatible LLM, with a simple web UI and a small API.","archived":false,"fork":false,"pushed_at":"2026-03-30T22:47:31.000Z","size":7824,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-31T00:32:23.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/semhoun.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-21T21:48:39.000Z","updated_at":"2026-03-30T22:47:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/semhoun/claire-chatbot","commit_stats":null,"previous_names":["semhoun/claire-chatbot"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/semhoun/claire-chatbot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/semhoun%2Fclaire-chatbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/semhoun%2Fclaire-chatbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/semhoun%2Fclaire-chatbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/semhoun%2Fclaire-chatbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/semhoun","download_url":"https://codeload.github.com/semhoun/claire-chatbot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/semhoun%2Fclaire-chatbot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31416460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T20:09:54.854Z","status":"ssl_error","status_checked_at":"2026-04-04T20:09:44.350Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T22:05:21.895Z","updated_at":"2026-04-04T22:05:23.674Z","avatar_url":"https://github.com/semhoun.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Claire 1.3.1 — Agent de Chat IA (PHP, Slim 4)\n\n![PHP Version](https://img.shields.io/badge/PHP-8.4%2B-777bb4?logo=php\u0026logoColor=white) ![Slim](https://img.shields.io/badge/Slim-4.x-4B4B4B) ![FrankenPHP](https://img.shields.io/badge/FrankenPHP-Caddy-ffb300) ![License](https://img.shields.io/badge/License-MIT-blue) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/semhoun/claire-chatbot)\n\nClaire 1.3.1 est une application web de chat IA construite avec Slim 4, Twig et Neuron AI. Elle fournit une interface web, un endpoint API, une integration Telegram et un runtime Docker base sur FrankenPHP/Caddy pour piloter des LLM compatibles OpenAI.\n\n## Démarrage rapide\n\n```bash\n# 1. Cloner et installer les dépendances\ngit clone https://github.com/semhoun/claire-chatbot.git\ncd claire-chatbot\ncomposer install\n\n# 2. Créer un fichier .env avec votre clé API\ncat \u003e .env \u003c\u003cEOF\nOPENAPI_KEY=votre-clé-api\nOPENAPI_URL=https://api.openai.com/v1\nOPENAPI_MODEL=gpt-4o-mini\nSESSION_JWT_SECRET=$(openssl rand -hex 32)\nOTEL_LOGS_EXPORTER=console\nOTEL_LOGS_PROCESSOR=simple\nEOF\n\n# 3. Initialiser la base de données\n./console migrations:migrate\n\n# 4. Lancer le serveur de développement\ncomposer start\n# Ouvrir http://localhost:8080\n```\n\n**Ou avec Docker:**\n\nImage Docker prete a l'emploi: [semhoun/claire-chatbot](https://hub.docker.com/r/semhoun/claire-chatbot)\n\n```bash\ndocker build -t claire:latest -f docker/Dockerfile .\ndocker run -d -p 8080:80 \\\n  -e OPENAPI_KEY=votre-clé-api \\\n  -e SESSION_JWT_SECRET=$(openssl rand -hex 32) \\\n  -v claire_data:/data \\\n  claire:latest\n```\n\n## Fonctionnalités\n\n- Interface web de chat avec horodatage, annulation du dernier echange, affichage instantane du message utilisateur, mode streaming par defaut, raccourci pour revenir en bas de conversation et ajustements visuels sur les themes et la mise en page.\n- Endpoint API `POST /brain/chat` pour envoyer un message et récupérer la réponse de l'agent.\n- Healthcheck `GET /health` (JSON) pour la supervision.\n- Intégration d'un fournisseur LLM « OpenAI-like » (URL, clé et modèle configurables).\n- Ajout automatique de la date et l'heure courantes dans le contexte système des agents.\n- Memoire courte avec resume automatique pour contenir l'historique dans la fenetre de contexte.\n- Recherche web optionnelle via SearXNG et RAG fichier via embeddings OpenAI-like.\n- Génération d'images avec ComfyUI (optionnel).\n- Support d'agents personnalisés via classes PHP et fichiers YAML.\n- Intégration Telegram avec filtrage des balises `[OC]` sur les réponses envoyées, prise en charge des photos dans le premier message, meilleur rendu MarkdownV2 des listes et application du timeout de workflow pendant le traitement des updates.\n- Observabilite via OpenTelemetry pour traces, metriques et logs, y compris l'instrumentation interne des agents.\n- Historique de conversation avec separation entre messages LLM et messages affiches a l'utilisateur, y compris conservation du message d'ouverture dans l'affichage.\n\n## Pile technique\n\n- PHP 8.4+\n- [Slim 4](https://www.slimframework.com/) (routing, middlewares)\n- [PHP-DI](https://php-di.org/) (container)\n- [Twig](https://twig.symfony.com/) (templates)\n- [Monolog](https://github.com/Seldaek/monolog) (logs)\n- [Doctrine ORM](https://www.doctrine-project.org/) (persistance des données)\n- [Neuron AI](https://www.neuron-ai.dev/) (agent LLM)\n- [phptg/bot-api](https://github.com/phptg/bot-api) (bot Telegram)\n- [OpenTelemetry](https://opentelemetry.io/docs/languages/php/) (observabilité)\n- [Symfony YAML](https://symfony.com/doc/current/components/yaml.html) (cerveaux personnalisés)\n- FrankenPHP + Caddy (runtime HTTP principal en conteneur)\n- Docker (déploiement containerisé avec Supervisor)\n\n## Prérequis\n\n- PHP 8.4 ou supérieur avec les extensions:\n  - `ext-json`\n  - `ext-sqlite3` ou 'ext-mysql' ou 'ext-pgsql'\n  - `ext-libxml`\n- Composer\n- Ajustez `max_execution_time` dans php.ini (ex: `max_execution_time=300`) car les appels LLM peuvent être longs.\n\n## Installation\n\n1. Cloner le dépôt puis installer les dépendances:\n   ```bash\n   composer install\n   ```\n2. (Optionnel) Si vous comptez utiliser les migrations/Doctrine, initialisez votre base de données selon vos besoins.\n\n## Configuration\n\nLes paramètres sont chargés depuis `config/settings/*.php` et complétés par des variables d’environnement. Les clés importantes:\n\n- LLM (voir `config/settings/llm.php`):\n  - `OPENAPI_KEY`   — clé d'API du fournisseur (compatible OpenAI)\n  - `OPENAPI_URL`   — base URL de l'API (ex: https://api.openai.com/v1 ou un proxy type LiteLLM)\n  - `OPENAPI_MODEL` — identifiant du modèle par défaut (ex: gpt-4o-mini, gpt-5.1, etc.)\n  - `OPENAPI_MODEL_SUMMARY` — modèle dédié aux tâches de synthèse/résumé (optionnel; si absent, `OPENAPI_MODEL` sera utilisé)\n  - `OPENAPI_MODEL_EMBED` — modèle dédié aux embeddings (optionnel; si absent, le RAG est désactivé)\n  - `OPENAPI_CONTEXT_WINDOW` — taille de fenêtre de contexte cible utilisée par l'agent (défaut: `50000`)\n  - `llm.shortMemory.messageToKeep` — nombre de messages recents conserves lors d'un resume automatique\n  - `llm.shortMemory.maxTokens` — seuil de tokens a partir duquel la memoire courte compacte l'historique\n  - `llm.summary.minMessages` / `llm.summary.maxMessages` — bornes utilisees pour declencher la generation du titre ou resume de conversation\n  - `llm.workflow.timeout` — duree maximale d'execution d'un workflow d'agent\n  - `SEARXNG_URL` — URL de l'instance SearXNG pour la recherche web (optionnel)\n\n- Telegram (voir `config/settings/telegram.php`):\n  - `TELEGRAM_BOT_TOKEN` — Token de votre bot Telegram (obtenu via @BotFather).\n\n- Mode et logs:\n  - `DEBUG_MODE` = `true|false` (active un niveau de logs plus verbeux)\n  - `ENABLE_LETSENCRYPT` = `true|false` (active HTTPS automatique via Let's Encrypt dans le conteneur FrankenPHP/Caddy)\n  - `ENABLE_ACCESS_LOGS` = `true|false` (active les access logs HTTP sur la sortie standard du conteneur)\n  - `ACME_EMAIL` — email utilisé pour l'enregistrement ACME/Let's Encrypt (optionnel)\n\n- Stockage des fichiers et données:\n  - `DATA_PATH` — chemin racine pour les données persistantes (base de données SQLite, fichiers, cache; par défaut: `var/data`)\n  - `FILES_PATH` — chemin vers le répertoire de stockage des fichiers (par défaut: `var/filer`)\n\n- Observabilité (OpenTelemetry — requis):\n  - Journalisation OpenTelemetry: les logs de l’application sont émis via l’intégration Monolog/OpenTelemetry.\n  - Pour afficher les logs dans la console en développement, définissez `OTEL_LOGS_EXPORTER=console` (et éventuellement `OTEL_LOGS_PROCESSOR=simple`).\n  - Variables d’environnement principales (par signal):\n    - Générales\n      - `OTEL_PHP_AUTOLOAD_ENABLED` — active l’auto‑instrumentation PHP (true/false).\n      - `OTEL_SERVICE_NAME` — nom du service (utilisé par les 3 signaux).\n      - `OTEL_RESOURCE_ATTRIBUTES` — attributs ressource supplémentaires (ex: `deployment.environment=dev,service.version=1.3.1`).\n      - `OTEL_PROPAGATORS` — propagateurs de contexte (ex: `baggage,tracecontext`).\n    - Traces\n      - `OTEL_TRACES_EXPORTER` — exporteur des traces (`otlp`, `none`).\n      - `OTEL_TRACES_SAMPLER` — stratégie d’échantillonnage (ex: `parentbased_always_on`, `traceidratio`).\n      - `OTEL_TRACES_SAMPLER_ARG` — paramètre du sampler (ex: `0.1` pour 10%).\n    - Metrics\n      - `OTEL_METRICS_EXPORTER` — exporteur des métriques (`otlp`, `none`).\n    - Logs\n      - `OTEL_LOGS_EXPORTER` — exporteur des logs (`console`, `otlp`, `none`).\n      - `OTEL_LOGS_PROCESSOR` — processeur des logs (`simple` pour affichage immédiat, `batch` pour production).\n    - Export OTLP (commun, et surcharges par signal)\n      - `OTEL_EXPORTER_OTLP_PROTOCOL` — protocole (`http/protobuf` recommandé, ou `grpc`).\n      - `OTEL_EXPORTER_OTLP_ENDPOINT` — endpoint commun OTLP (optionnel, ex: `http://collector:4318`).\n      - `OTEL_EXPORTER_OTLP_HEADERS` — en‑têtes additionnels (optionnels, ex: `authorization=Bearer \u003ctoken\u003e`).\n      - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` — endpoint traces (optionnel; surcharge de `..._ENDPOINT`).\n      - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` — endpoint métriques (optionnel; surcharge de `..._ENDPOINT`).\n      - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` — endpoint logs (optionnel; surcharge de `..._ENDPOINT`).\n\n  Note: les endpoints OTLP et les headers sont optionnels. Si vous ne les définissez pas, l’exporteur appliquera ses valeurs par défaut. Par exemple, pour afficher les logs uniquement en console, il suffit de définir `OTEL_LOGS_EXPORTER=console` sans renseigner d’endpoint OTLP.\n\n### Avatars / Cerveaux (BrainRegistry)\n\nL'application permet de sélectionner différents « cerveaux » (avatars) pour l'agent (ex.: Claire, Einstein, Calliope). La sélection est mémorisée en session sous la clé `brain_avatar`.\n\n- La logique de sélection est gérée par le registre `BrainRegistry`.\n- Si une valeur invalide est fournie, l'application revient automatiquement sur l'avatar par défaut: `claire`.\n- Vous pouvez exposer ce choix dans l'UI (ex.: select) ou via un paramètre de requête selon vos besoins.\n- Cerveaux disponibles par défaut:\n  - `claire` — Assistante généraliste\n  - `einstein` — Expert scientifique\n  - `calliope` — Calliope la conteuse\n\n#### Ajout de cerveaux personnalisés via YAML\n\nVous pouvez créer vos propres agents sans écrire de code PHP en plaçant des fichiers YAML dans le répertoire `addons/agents/`. Chaque fichier définit un nouveau cerveau avec ses propres caractéristiques.\n\n**Structure d'un fichier YAML:**\n\n```yaml\nname: \"Nom de l'Assistant\"\ndescription: \"Description courte affichée dans l'interface\"\navatar: \"data:image/png;base64,iVBORw0K......\"        # URL ou data URI de l'avatar\ncss: \"\"           # Nom du fichier CSS dans public/css/ (optionnel)\ncss_inline: |     # CSS inline directement dans le fichier (optionnel)\n  :root {\n    --accent: #FF6B6B;\n  }\n  .chat-header {\n    background: #ffffff;\n  }\nwelcomes:\n  - \"Premier message d'accueil possible\"\n  - \"Deuxième message d'accueil possible\"\n  - \"Troisième message d'accueil possible\"\ninstruction: |\n  Le prompt système complet de l'assistant.\n  Définissez ici son rôle, son ton, ses compétences.\n  Utilisez plusieurs lignes si nécessaire.\n```\n\n**Exemple de fichier `addons/agents/coach.yaml`:**\n\n```yaml\nname: \"Coach Personnel\"\ndescription: \"Un coach motivant pour vous aider à atteindre vos objectifs\"\navatar: \"\"\ncss: \"\"\ncss_inline: |\n  :root {\n    --accent: #FF6B35;\n    --accent-light: #FF8C42;\n  }\n  .message--sent .message__bubble {\n    background: linear-gradient(135deg, var(--accent), var(--accent-light));\n  }\nwelcomes:\n  - \"Prêt à relever de nouveaux défis aujourd'hui ?\"\n  - \"Bonjour champion ! Que veux-tu accomplir ?\"\n  - \"Salut ! Je suis là pour te motiver et te guider.\"\ninstruction: |\n  Tu es un coach personnel motivant et bienveillant.\n  Ton rôle est d'aider l'utilisateur à définir ses objectifs,\n  à rester motivé et à surmonter les obstacles.\n  Sois encourageant, pose des questions pertinentes et propose\n  des plans d'action concrets.\n```\n\n**Champs disponibles:**\n\n| Champ | Type | Description |\n|-------|------|-------------|\n| `name` | string | Nom affiché de l'assistant (obligatoire) |\n| `description` | string | Description courte pour la sélection (obligatoire) |\n| `avatar` | string | URL ou data URI de l'image avatar (optionnel) |\n| `css` | string | Nom d'un fichier CSS externe dans `public/css/` (optionnel) |\n| `css_inline` | string | CSS inline directement dans le YAML (optionnel, recommandé) |\n| `welcomes` | array | Liste de messages d'accueil (un choisi aléatoirement) |\n| `instruction` | string | Prompt système complet de l'assistant (obligatoire) |\n\n**Notes sur le CSS:**\n\n- **Recommandé**: Utilisez `css_inline` pour embarquer le CSS directement dans le fichier YAML\n- **Alternative**: Utilisez `css` pour référencer un fichier externe (ex: `css: \"monbrain.css\"`)\n- Vous pouvez utiliser les deux simultanément si nécessaire\n- Le CSS inline est injecté via une balise `\u003cstyle\u003e` dans le `\u003chead\u003e`\n- Voir `addons/agents/calliope.yaml` pour un exemple complet avec CSS inline\n\n**Points importants:**\n\n- Le slug du cerveau est déterminé par le nom du fichier (ex: `coach.yaml` → slug `coach`)\n- Les fichiers YAML sont chargés automatiquement au démarrage\n- Un message d'accueil est choisi aléatoirement parmi la liste `welcomes`\n- Les cerveaux YAML apparaissent automatiquement dans l'interface aux côtés des cerveaux PHP\n- Voir le fichier exemple dans `addons/agents/calliope.yaml` (exemple complet d'un cerveau YAML avec CSS inline)\n\n### Blocs internes `[OC]`\n\nClaire utilise des balises internes `[OC]...[/OC]` pour porter des instructions ou contenus de contrôle qui ne doivent pas être affichés à l'utilisateur final.\n\n- Dans l'interface web, le filtre Twig `filter_oc_tags` supprime automatiquement ces blocs avant le rendu Markdown.\n- Dans Telegram, le même filtrage est appliqué avant conversion vers `MarkdownV2`.\n- Si un message ne contient plus rien après filtrage, il n'est pas affiché ni envoyé.\n- Le fichier `tmpl/partials/message.twig` applique ce filtrage avant rendu.\n\n### Contexte temporel automatique\n\nLes agents principaux ajoutent automatiquement la date et l'heure courantes à leurs instructions système.\n\n- Cela améliore la contextualisation des réponses sensibles au temps.\n- Le comportement est implémenté dans `App\\Brain\\Agent` et `App\\Brain\\RAG`.\n- Les messages de bienvenue générés par l'agent utilisent également un bloc `[OC]` pour éviter d'exposer l'instruction interne.\n\n#### Recherche Web (Web Search)\n\nL'application prend en charge la recherche web via SearXNG lorsque la variable d'environnement `SEARXNG_URL` est configurée. Cette fonctionnalité ajoute l'outil `web_search` aux agents, leur permettant d'effectuer des recherches sur internet pour enrichir leurs réponses.\n\n- Configuration: définissez `SEARXNG_URL` avec l'URL de votre instance SearXNG (ex: `http://searxng:8080`)\n- L'outil est automatiquement disponible pour tous les cerveaux lorsque la configuration est présente\n\n### Génération d'images avec ComfyUI\n\nL'application peut générer des images via ComfyUI lorsque la configuration appropriée est définie. Cette fonctionnalité ajoute l'outil `generate_image` aux agents, leur permettant de créer des images à partir de descriptions textuelles.\n\n**Configuration requise:**\n\n| Variable | Obligatoire | Description |\n|----------|-------------|-------------|\n| `COMFYUI_ENABLED` | Oui | Active la génération d'images (`true` ou `false`) |\n| `COMFYUI_URL` | Non | URL de l'instance ComfyUI (défaut: `http://localhost:8188`) |\n| `COMFYUI_WORKFLOW` | Oui | Workflow ComfyUI au format JSON avec placeholder `{{PROMPT}}` |\n| `COMFYUI_TIMEOUT` | Non | Timeout en secondes (défaut: 300) |\n| `COMFYUI_PROMPT_STYLE` | Non | Style de prompt: `sdxl` (keywords) ou `flux` (natural language) - défaut: `sdxl` |\n\n**Exemple de configuration:**\n\n```bash\n# Activation de ComfyUI\nexport COMFYUI_ENABLED=true\nexport COMFYUI_URL=http://comfyui:8188\nexport COMFYUI_WORKFLOW='{\"3\":{\"inputs\":{\"seed\":0,\"steps\":20,\"cfg\":8,\"sampler_name\":\"euler\",\"scheduler\":\"normal\",\"denoise\":1,\"model\":[\"4\",0],\"positive\":[\"6\",0],\"negative\":[\"7\",0],\"latent_image\":[\"5\",0]},\"class_type\":\"KSampler\"},...}'\nexport COMFYUI_PROMPT_STYLE=flux\n```\n\nNote: Le workflow doit contenir un placeholder `{{PROMPT}}` qui sera remplacé par la description de l'image à générer.\n\n**Styles de prompts:**\n- `sdxl`: Prompts optimisés pour SDXL (mots-clés séparés par des virgules)\n- `flux`: Prompts en langage naturel pour Flux\n\n**Fonctionnement:**\n- Lorsqu'activé, l'outil `generate_image` est disponible pour tous les cerveaux\n- L'agent peut décider de générer une image en réponse à une demande utilisateur\n- Les images générées sont stockées dans `var/generated_images/`\n- Les images sont servies via l'endpoint `/files/generated/{filename}`\n- Le bot Telegram supporte l'envoi des images générées\n\n### Authentification OpenID Connect (SSO)\n\nL’application prend en charge une authentification via SSO OpenID Connect, si les paramètres sont définis sinon elle utilise un utilisateur par défaut. La configuration est lue dans `config/settings/oidc.php` et repose sur les variables d’environnement suivantes:\n\n- `OPENID_WELLKNOWN_URL` — URL du document de découverte OpenID Connect 1.0 (ex: `https://votre-idp/.well-known/openid-configuration`).\n- `OPENID_CLIENT_ID` — identifiant du client OIDC (côté fournisseur).\n- `OPENID_CLIENT_SECRET` — secret du client OIDC (côté fournisseur).\n- `OPENID_REDIRECT_URI_BASE` — base d’URL publique de votre application (ex: `https://claire.example.com`). L’URI de redirection effective sera `${OPENID_REDIRECT_URI_BASE}/auth/callback` et doit être enregistrée à l’identique dans la fiche du client côté IdP.\n\nAutres détails:\n- Scopes utilisés par défaut: `openid email profile` (envoyés avec un séparateur espace, encodé en `+` dans l’URL d’autorisation).\n- Endpoints utilisés: `authorization_endpoint`, `token_endpoint` et `userinfo_endpoint` découverts via le document `.well-known`.\n- En cas d’échec d’authentification, l’application reste SSO‑only et ne propose pas de login/mot de passe.\n\nDépannage rapide:\n- Erreur `invalid_client` lors de l’échange de code: vérifiez l’ID et le secret, et surtout que la méthode d’authentification configurée pour VOTRE client au token endpoint côté IdP correspond à celle attendue (souvent `client_secret_basic` ou `client_secret_post`). Assurez‑vous également que l’URI de redirection enregistrée correspond exactement à `https://votre-domaine/auth/callback`.\n- Erreur de redirection: vérifiez `OPENID_REDIRECT_URI_BASE` et les règles de proxy/host (Traefik) afin que l’URL publique corresponde bien au host utilisé par les utilisateurs.\n\n### Session Management (JWT)\n\nClaire utilise un système de session stateless basé sur JWT. Les données de session sont stockées dans un cookie JWT signé, éliminant le besoin de stockage côté serveur.\n\n- Configuration: `config/settings/session.php`\n- Variables d'environnement obligatoires:\n  - `SESSION_JWT_SECRET` — Clé secrète pour la signature JWT (obligatoire)\n  - `SESSION_JWT_ALGORITHM` — Algorithme de signature (défaut: HS256)\n- Routes publiques (contournent la session): configurées dans `config/settings/security.php`\n\nPour plus de détails, voir `src/Session/README.md`.\n\n### Base de données (Doctrine ORM / DBAL)\n\nLe projet inclut Doctrine ORM/DBAL et peut fonctionner avec SQLite (par défaut), MySQL/MariaDB ou PostgreSQL. La configuration est lue depuis `config/settings/database.php` et pilotée par des variables d’environnement prefixées `DATABASE_`.\n\n- Variables d’environnement supportées:\n  - `DATABASE_KIND` — pilote de base de données. Valeurs possibles: `sqlite`, `mysql`, `postgres` (ou `pgsql`).\n  - `DATABASE_HOST` — hôte (MySQL/PostgreSQL uniquement).\n  - `DATABASE_PORT` — port (MySQL/PostgreSQL uniquement; ex: 3306 pour MySQL, 5432 pour PostgreSQL).\n  - `DATABASE_NAME` — nom de la base (MySQL/PostgreSQL uniquement).\n  - `DATABASE_USER` — utilisateur (MySQL/PostgreSQL uniquement).\n  - `DATABASE_PASSWORD` — mot de passe (MySQL/PostgreSQL uniquement).\n\n- SQLite\n  - Si `DATABASE_KIND=sqlite`, aucune autre variable n’est nécessaire.\n  - Le fichier de base de données est créé/lu à l’emplacement par défaut: `var/database.sqlite` (chemin défini dans `config/settings/database.php`). Assurez‑vous que le processus PHP a les droits d’écriture sur le dossier `var/`.\n\n- MySQL / MariaDB\n  - Exemple minimal:\n    ```env\n    DATABASE_KIND=mysql\n    DATABASE_HOST=localhost\n    DATABASE_PORT=3306\n    DATABASE_NAME=claire\n    DATABASE_USER=claire\n    DATABASE_PASSWORD=change_me\n    ```\n\n- PostgreSQL\n  - Exemple minimal:\n    ```env\n    DATABASE_KIND=postgres\n    DATABASE_HOST=localhost\n    DATABASE_PORT=5432\n    DATABASE_NAME=claire\n    DATABASE_USER=claire\n    DATABASE_PASSWORD=change_me\n    ```\n\nMigrations Doctrine\n- Pour initialiser la base de données et/ou la mettre à jour, exécutez:\n\n  ```bash\n  ./console migrations:migrate\n  ```\n\n- Cette commande applique toutes les migrations disponibles (dossier `migrations/`) et maintient la table de version `db_version` conformément à la configuration définie dans `config/settings/database.php`.\n\n## Démarrage\n\n### Via PHP intégré\n\n1. Exportez vos variables d’environnement (au besoin).\n2. Lancez le serveur de développement:\n   ```bash\n   composer start\n   ```\n   ou\n   ```bash\n   php -S localhost:8080 -t public public/index.php\n   ```\n3. Ouvrez http://localhost:8080\n\n### Via Docker\n\nClaire fournit une image Docker complete basee sur FrankenPHP, Caddy et PHP 8.4.\n\n#### Build de l'image\n\n```bash\ndocker build -t claire:latest -f docker/Dockerfile .\n```\n\n#### Utilisation avec Docker Compose\n\nL'extrait ci‑dessous présente une configuration Docker Compose de référence. Adaptez les variables d'environnement (OPENAPI_*, OTEL_*) et, le cas échéant, les labels Traefik à votre contexte.\n\n```yaml\nservices:\n  claire:\n    image: claire:latest\n    # Ou utilisez l'image de développement avec volumes montés:\n    # image: semhoun/webserver:8.4\n    # volumes:\n    #   - .:/www\n    volumes:\n      - claire_data:/data  # Persistance des données (base SQLite, fichiers uploadés, etc.)\n    ports:\n      - \"8080:80\"\n    environment:\n      SERVER_ADMIN: webmaster@example.com\n      SERVER_NAME: claire.example.com\n      DEBUG_MODE: \"false\"\n      ENABLE_ACCESS_LOGS: \"true\"\n      ENABLE_LETSENCRYPT: \"false\"\n      # ACME_EMAIL: admin@example.com\n\n      DATA_PATH: /data\n\n      # Session JWT (obligatoire)\n      SESSION_JWT_SECRET: ${SESSION_JWT_SECRET:?set_me}\n\n      # OpenTelemetry (requis)\n      OTEL_PHP_AUTOLOAD_ENABLED: \"true\"\n      OTEL_SERVICE_NAME: claire\n      OTEL_PHP_EXCLUDED_URLS: /health\n      OTEL_PROPAGATORS: baggage,tracecontext\n      OTEL_TRACES_EXPORTER: otlp\n      OTEL_METRICS_EXPORTER: otlp\n      # En développement, afficher les logs en console\n      OTEL_LOGS_EXPORTER: console\n      OTEL_LOGS_PROCESSOR: simple\n      # Optionnel: configuration OTLP commune (si vous envoyez vers un collecteur)\n      # OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf\n      # OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4318\n      # OTEL_EXPORTER_OTLP_HEADERS: authorization=Bearer \u003ctoken\u003e\n\n      # LLM (remplacez par vos valeurs / variables d'env)\n      OPENAPI_KEY: ${OPENAPI_KEY:?set_me}\n      OPENAPI_URL: https://api.openai.com/v1\n      OPENAPI_MODEL: gpt-5\n      # Optionnels (précisez si vous souhaitez des modèles dédiés)\n      OPENAPI_MODEL_SUMMARY: gpt-5-mini\n      OPENAPI_MODEL_EMBED: text-embedding-3-large\n      # NB: si `OPENAPI_MODEL_EMBED` est omis, le RAG est désactivé\n      # Optionnel\n      # SEARXNG_URL: http://searxng:8080\n\n      # ComfyUI (génération d'images, optionnel)\n      # COMFYUI_ENABLED: true\n      # COMFYUI_URL: http://comfyui:8188\n      # COMFYUI_WORKFLOW: '{\"3\":{\"inputs\":{...}},...}' # JSON avec placeholder {{PROMPT}}\n      # COMFYUI_PROMPT_STYLE: flux\n\n      # Telegram (optionnel)\n      # TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:?set_me}\n      # TELEGRAM_WEBHOOK_SECRET: ${TELEGRAM_WEBHOOK_SECRET:?set_me}\n\n      # OpenID Connect (SSO)\n      OPENID_WELLKNOWN_URL: https://auth.example.com/.well-known/openid-configuration\n      OPENID_CLIENT_ID: ${OPENID_CLIENT_ID:?set_me}\n      OPENID_CLIENT_SECRET: ${OPENID_CLIENT_SECRET:?set_me}\n      OPENID_REDIRECT_URI_BASE: https://claire.example.com\n\n      # Base de données\n      # Choix simple (par défaut): SQLite, aucune autre variable requise\n      DATABASE_KIND: sqlite\n\n      # Exemple MySQL/MariaDB (décommentez et ajustez)\n      # DATABASE_KIND: mysql\n      # DATABASE_HOST: mysql\n      # DATABASE_PORT: 3306\n      # DATABASE_NAME: claire\n      # DATABASE_USER: claire\n      # DATABASE_PASSWORD: change_me\n\n      # Exemple PostgreSQL (décommentez et ajustez)\n      # DATABASE_KIND: postgres\n      # DATABASE_HOST: postgres\n      # DATABASE_PORT: 5432\n      # DATABASE_NAME: claire\n      # DATABASE_USER: claire\n      # DATABASE_PASSWORD: change_me\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"--fail\", \"http://localhost/health\"]\n      interval: 15s\n      timeout: 5s\n      retries: 3\n      start_period: 60s\n\nvolumes:\n  claire_data:\n\nnetworks:\n  internal:\n    external: true\n    name: internal\n```\n\nNotes Docker/FrankenPHP:\n\n- L'image Docker utilise FrankenPHP avec Caddy comme serveur HTTP integre.\n- Si `ENABLE_LETSENCRYPT=true`, le conteneur sert directement votre domaine `SERVER_NAME` en HTTPS avec certificats Let's Encrypt automatiques.\n- Si `ENABLE_LETSENCRYPT=false`, le conteneur reste en HTTP sur le port 80, ce qui est recommande derriere un reverse proxy TLS.\n- `ENABLE_ACCESS_LOGS` permet d'activer ou couper les logs d'acces HTTP sans rebuilder l'image.\n- Pour Let's Encrypt, le domaine doit etre publiquement resolvable vers le conteneur et les ports 80/443 doivent etre accessibles.\n\n#### Points clés de l'image Docker\n\n- **Base**: Debian Trixie Slim avec PHP 8.4\n- **Services**: FrankenPHP + Caddy + Supervisor\n- **Extensions PHP**: SQLite3, MySQL, PostgreSQL, GD, Imagick, Redis, Memcache, etc.\n- **OpenTelemetry**: Extension pré-installée et configurée\n- **Modules Caddy**: `transform-encoder`, Mercure, Vulcain\n- **Volumes**: \n  - `/data` — Données persistantes (base SQLite, fichiers uploadés, cache, etc.)\n  - `/www` — Code de l'application (pré-copié dans l'image, ou monté en dev)\n- **Healthcheck**: Vérifie automatiquement l'endpoint `/health`\n- **Ports**: Expose `80` et `443`\n\n#### Démarrage\n\n```bash\n# Démarrer la stack\ndocker compose up -d\n\n# Voir les logs\ndocker compose logs -f claire\n\n# Exécuter des commandes dans le conteneur\ndocker compose exec claire ./console migrations:migrate\ndocker compose exec claire ./console cache:clear\n```\n\n#### Développement avec volumes montés\n\nPour un développement actif avec rechargement automatique, utilisez l'image `semhoun/webserver:8.4` avec un volume monté:\n\n```yaml\nservices:\n  claire:\n    image: semhoun/webserver:8.4\n    volumes:\n      - .:/www\n    # ... reste de la configuration\n```\n\n## API et routes\n\n### Healthcheck\n\n- `GET /health` — endpoint JSON simple pour supervision (liveness/readiness).\n  - Réponse 200 (exemple):\n    ```json\n    {\n      \"version\": \"1.3.1\",\n      \"date\": \"2025-01-01T12:34:56+00:00\"\n    }\n    ```\n  - Utilisation typique: sonde de conteneur/orchestrateur (Docker, Traefik, Kubernetes, etc.).\n  - Aucun corps requis, pas d’authentification par défaut.\n\n### Gestion des fichiers (/files)\n\n- `GET /files/count` — Nombre total de fichiers stockés\n- `GET /files/list` — Liste des fichiers (JSON)\n- `POST /files/upload` — Upload de fichier(s) standard\n- `POST /files/upload_rag` — Upload de fichier pour le RAG (vectorisation)\n- `DELETE /files/delete/{id}` — Suppression d'un fichier\n- `GET /files/generated/{filename}` — Récupération d'une image générée\n\n### Historique des conversations (/history)\n\n- `GET /history/count` — Nombre de conversations\n- `GET /history/list` — Liste des conversations\n- `GET /history/open/{threadId}` — Ouvrir une conversation existante\n- `POST /history/new` — Créer une nouvelle conversation\n- `DELETE /history/exchange/last` — Annuler le dernier échange de la conversation courante\n- `DELETE /history/delete/{threadId}` — Supprimer une conversation\n\n### Configuration (/config)\n\n- `POST /config/chat_mode` — Changer le mode de chat (sync/stream)\n- `POST /config/layout_mode` — Changer le mode d'affichage\n- `POST /config/brain_avatar` — Changer l'avatar/cerveau actif\n- `POST /config/telegram` — Configurer Telegram\n- `GET /config/telegram_form` — Formulaire de configuration Telegram\n\n### Streaming SSE (Server‑Sent Events) et proxy HTTP\n\nL’endpoint de streaming utilise le type `text/event-stream` et écrit au fil de l’eau (pas de buffer côté application). Cependant, certains reverse proxies / frontaux web peuvent bufferiser la réponse et empêcher l’affichage progressif côté navigateur.\n\nPour garantir un streaming fluide, désactivez la bufferisation au niveau du proxy. Exemple avec Apache quand PHP est servi via `mod_proxy_fcgi`:\n\n```apache\n# Assurez-vous que mod_proxy et mod_proxy_fcgi sont activés\n# a2enmod proxy proxy_fcgi\n\n# Votre mapping vers PHP-FPM (à adapter à votre environnement)\n# ProxyPassMatch ^/(.*\\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1\n\n# Désactiver la bufferisation pour le backend FastCGI\n\u003cProxy \"fcgi://localhost/\" flushpackets=on flushwait=20\u003e\n\u003c/Proxy\u003e\n```\n\nNotes:\n- Remplacez l’URL FastCGI (`fcgi://localhost/` ou `fcgi://127.0.0.1:9000/…`) par celle de votre instance PHP‑FPM.\n- Selon la version d’Apache, vous pouvez également utiliser `ProxySet` à l’intérieur du bloc `\u003cProxy\u003e`:\n  ```apache\n  \u003cProxy \"fcgi://127.0.0.1:9000\"\u003e\n      ProxySet flushpackets=on flushwait=20\n  \u003c/Proxy\u003e\n  ```\n- Si vous utilisez un autre proxy (Nginx, Traefik, etc.), désactivez la bufferisation équivalente (ex. Nginx: `proxy_buffering off;` sur l’emplacement concerné).\n\n### Endpoint de chat: POST /brain/chat\n\nL’agent supporte deux modes de réponse:\n\n- Mode « chat » (synchrone): la réponse complète est rendue côté serveur et renvoyée en une fois.\n- Mode streaming SSE: la réponse est envoyée progressivement via un flux `text/stream` (utilise une sortie non tamponnée côté application; veillez à désactiver la bufferisation côté proxy, voir plus haut).\n\nLa sélection du mode peut se faire via le champ `mode` dans le corps de la requête (`chat` par défaut, ou `stream`).\n\n#### Requête JSON simple (mode chat)\n\n```http\nPOST /brain/chat HTTP/1.1\nContent-Type: application/json\n\n{\n  \"message\": \"Bonjour Claire !\",\n  \"mode\": \"chat\"\n}\n```\n\nRéponses possibles:\n- 200: corps HTML fragment (ex.: rendu Twig `partials/message.twig`) ou contenu texte selon l’intégration front.\n- 422: si le champ `message` est vide.\n\n#### Streaming SSE (mode stream)\n\n```http\nPOST /brain/chat HTTP/1.1\nAccept: text/event-stream\nContent-Type: application/json\n\n{\n  \"message\": \"Explique-moi la relativité en 3 points\",\n  \"mode\": \"stream\"\n}\n```\n\nLa réponse aura des en-têtes: `content-type: text/stream`, `cache-control: no-cache`. Les chunks contiendront du texte (et potentiellement des informations d’outillage) au fil de l’eau.\n\n#### Pièces jointes et fichiers\n\nDeux mécanismes sont pris en charge côté serveur pour enrichir le contexte utilisateur:\n\n1) Upload direct de fichiers via `multipart/form-data` avec le champ `upload_files[]`.\n2) Référence à des fichiers déjà connus de l’application via une liste d’identifiants `file_ids` (IDs de l’entité `App\\Entity\\File`).\n\nExemple multipart (upload direct):\n\n```http\nPOST /brain/chat HTTP/1.1\nContent-Type: multipart/form-data; boundary=----BOUND\n\n------BOUND\nContent-Disposition: form-data; name=\"message\"\n\nAnalyse ces documents, s'il te plaît.\n------BOUND\nContent-Disposition: form-data; name=\"mode\"\n\nchat\n------BOUND\nContent-Disposition: form-data; name=\"upload_files[]\"; filename=\"notes.txt\"\nContent-Type: text/plain\n\n(contenu du fichier)\n------BOUND--\n```\n\nExemple JSON (fichiers déjà stockés):\n\n```http\nPOST /brain/chat HTTP/1.1\nContent-Type: application/json\n\n{\n  \"message\": \"Utilise mes fichiers pour répondre.\",\n  \"mode\": \"chat\",\n  \"file_ids\": [\"e7a4f2d8-...\", \"6b0e9c1a-...\"]\n}\n```\n\nComportement serveur:\n- Si `message` est vide ou absent → 422.\n- Les fichiers uploadés sont lus en mémoire et intégrés au contexte interne du message utilisateur.\n- Les erreurs de lecture d’un fichier n’interrompent pas la requête: elles sont journalisées (best‑effort).\n\n## Sécurité\n\n- Ne commitez jamais vos clés ou secrets (`OPENAPI_KEY`, etc.).\n- En production, désactivez `DEBUG_MODE` et vérifiez les permissions du répertoire `var/` (cache, logs, tmp).\n- Si l’agent dispose d’outils web (lecture d’URL, recherche), restreignez l’accès public ou placez l’instance derrière une authentification/reverse proxy.\n- Configurez le CORS en amont si vous exposez l’API à des origines externes.\n\n### Bot Telegram\n\nClaire peut être utilisée comme bot Telegram avec deux modes de fonctionnement : **webhook** (recommandé pour la production) ou **daemon** (polling, utile pour le développement local).\n\n#### Vue d'ensemble\n\nL'intégration Telegram permet d'interagir avec Claire directement depuis l'application Telegram. Le bot supporte les messages texte, les photos et les documents, avec une historique de conversation persistante par utilisateur.\n\n#### Prérequis\n\n1. Créez un bot via [@BotFather](https://t.me/BotFather) sur Telegram.\n2. Récupérez le token API fourni (format: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`).\n\n#### Configuration\n\nVariable d'environnement (définie dans `.env` ou via Docker):\n\n| Variable | Obligatoire | Description |\n|----------|-------------|-------------|\n| `TELEGRAM_BOT_TOKEN` | Oui | Token du bot fourni par @BotFather |\n| `TELEGRAM_WEBHOOK_SECRET` | Recommandé | Token secret pour sécuriser le webhook (générez une chaîne aléatoire de 32+ caractères) |\n\n#### Mode Webhook (recommandé pour la production)\n\nLe mode webhook permet à Telegram d'envoyer les mises à jour directement à votre serveur via HTTPS.\n\n**Configuration du webhook:**\n\n1. Définissez `TELEGRAM_WEBHOOK_SECRET` dans votre fichier `.env` (générez une chaîne aléatoire sécurisée)\n2. Configurez le webhook:\n\n```bash\n# Option 1: Utiliser --domain (recommandé, HTTPS forcé)\n./console telegram:webhook --domain=votre-domaine.com\n\n# Option 2: Utiliser --url (URL complète personnalisée)\n./console telegram:webhook --url=https://votre-domaine.com/webhook/telegram\n\n# Vérifier le statut\n./console telegram:webhook --info\n\n# Supprimer le webhook (revenir au mode polling manuel)\n./console telegram:webhook --delete\n```\n\n**Points d'entrée:**\n- Endpoint webhook: `POST /webhook/telegram`\n- Doit être accessible publiquement en HTTPS\n- Vérifie le header `X-Telegram-Bot-Api-Secret-Token` (si `TELEGRAM_WEBHOOK_SECRET` est configuré)\n\n**Exemple Docker Compose (webhook):**\n```yaml\nenvironment:\n  TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:?set_me}\n  TELEGRAM_WEBHOOK_SECRET: ${TELEGRAM_WEBHOOK_SECRET:?set_me}\n```\n\n#### Mode Daemon (polling, utile pour le développement)\n\nLe mode daemon interroge périodiquement les serveurs Telegram pour récupérer les nouveaux messages.\n\n**Lancer le daemon:**\n\n```bash\n# Mode simple\n./console telegram:daemon\n\n# Avec options personnalisées\n./console telegram:daemon --timeout=60 --limit=50\n\n# Arrêt gracieux: Ctrl+C\n```\n\n**Options disponibles:**\n- `--timeout`: Timeout des requêtes long polling (défaut: 30s)\n- `--limit`: Nombre maximum de messages à récupérer par requête (défaut: 100)\n\n**Configuration Docker Compose (daemon):**\n```yaml\nservices:\n  claire:\n    # ... configuration web ...\n    environment:\n      TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:?set_me}\n```\n\n#### Fonctionnalités\n\nLe bot Telegram supporte:\n\n- **Messages texte**: Dialogue standard avec historique persistant\n- **Photos**: Envoi d'images avec analyse (si un modèle de vision est configuré)\n- **Documents**: Upload de fichiers pour analyse\n- **Génération d'images**: Création d'images via ComfyUI (si configuré)\n- **Changement de cerveau**: Commande `/\u003cnom_du_cerveau\u003e` pour basculer d'avatar\n- **Commandes intégrées:**\n  - `/start` — Démarrer une nouvelle conversation\n  - `/help` — Afficher l'aide\n  - `/list` — Lister les personnalités\n  - `/brain` — Voir ou changer de personnalité\n\n#### Configuration de la base de données\n\nLe bot Telegram nécessite une colonne supplémentaire dans la table des utilisateurs pour stocker l'identifiant Telegram:\n\n```bash\n./console migrations:migrate\n```\n\n#### Exemples d'utilisation\n\n**Démarrer une conversation:**\n```\n/start\nBonjour Claire, peux-tu m'aider avec un problème de mathématiques?\n```\n\n**Changer de cerveau:**\n```\n/einstein\nQuelle est la théorie de la relativité restreinte?\n```\n\n**Envoyer une photo:**\n- Joindre une image avec ou sans légende\n- Le bot analyse l'image si un modèle de vision est configuré\n\n**Envoyer un document:**\n- Joindre un fichier PDF, texte, etc.\n- Le bot peut analyser le contenu du document\n\n**Demander une génération d'image:**\n```\nClaire, peux-tu générer une image d'un chat sur la lune?\n```\n- L'agent génère l'image via ComfyUI et l'envoie sur Telegram\n- Nécessite la configuration de ComfyUI (voir section dédiée)\n\n## Développement \u0026 Qualité\n\n### Commandes Composer\n\n- Démarrer le serveur de développement:\n  ```bash\n  composer start\n  ```\n\n- Rector (modernisation PHP 8.4):\n  - Vérifier: `composer rector-check`\n  - Appliquer: `composer rector-fix`\n\n- PHP Insights (qualité):\n  - Vérifier: `composer insights-check`\n  - Corriger: `composer insights-fix`\n\n- Pre-commit (tous les checks):\n  ```bash\n  composer pre-commit\n  ```\n  Corrige les fins de ligne (LF), applique PHP Insights et Rector.\n\n### Commandes Console\n\nLe fichier `./console` fournit des commandes pour la gestion du cache et des migrations:\n\n- **Cache:**\n  - `./console cache:clear` — Vide le cache (conteneur, routes, etc.)\n  - `./console cache:init` — Initialise/régénère le cache\n  - `./console generate:proxies` — Génère les proxies Doctrine\n\n- **Migrations Doctrine:**\n  - `./console migrations:migrate` — Applique les migrations\n  - `./console migrations:diff` — Génère une migration depuis les entités\n  - `./console migrations:generate` — Crée une migration vide\n  - `./console migrations:status` — Affiche le statut des migrations\n\n- **Telegram:**\n  - `./console telegram:webhook --url=https://...` — Configure le webhook\n  - `./console telegram:webhook --domain=...` — Configure le webhook avec domaine (HTTPS forcé)\n  - `./console telegram:webhook --info` — Vérifie le statut du webhook\n  - `./console telegram:webhook --delete` — Supprime le webhook\n  - `./console telegram:daemon` — Lance le daemon (polling)\n  - `./console telegram:set-commands` — Configure le menu des commandes du bot Telegram (SetMyCommands)\n\n### Tests\n\nPHPUnit est configuré pour les tests unitaires:\n\n```bash\nvendor/bin/phpunit                              # Tous les tests\nvendor/bin/phpunit test/Unit/Services/FooTest.php      # Fichier spécifique\nvendor/bin/phpunit --filter testMethodName    # Méthode spécifique\n```\n\n### Debug\n\n- Slim Tracy (debug console) est activable en mode debug via la configuration.\n- Définissez `DISABLE_TRACY_BAR=false` pour activer la barre de debug.\n\n## Dépannage\n\n- 500 au `GET /`:  vérifiez les permissions du dossier var/ (cache, logs, tmp).\n- 404 partout: vérifiez que le serveur pointe bien sur `public/index.php` et que vos règles de réécriture sont actives.\n- Pas de logs: les logs sont gérés par OpenTelemetry. Pour les voir dans la console, définissez `OTEL_LOGS_EXPORTER=console` (et `OTEL_LOGS_PROCESSOR=simple` pour un affichage immédiat). En alternance, configurez un export OTLP (`OTEL_LOGS_EXPORTER=otlp`) vers un collecteur comme l’OTel Collector.\n- RAG inactif: assurez-vous que `OPENAPI_MODEL_EMBED` est défini. S’il est absent, le RAG est désactivé par conception.\n- Génération d'images non disponible: vérifiez que `COMFYUI_ENABLED=true` et que `COMFYUI_WORKFLOW` contient un workflow JSON valide avec le placeholder `{{PROMPT}}`. Assurez-vous que l'instance ComfyUI est accessible à l'URL définie dans `COMFYUI_URL`.\n\n## Licence\n\nCe projet est distribué sous licence MIT. Voir le fichier `LICENSE` pour plus d’informations.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsemhoun%2Fclaire-chatbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsemhoun%2Fclaire-chatbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsemhoun%2Fclaire-chatbot/lists"}