Claire — Chatbot IA multi-brain avec Telegram, ComfyUI, PDF et OpenTelemetry
Claire est une application de chat IA construite avec Slim 4, Twig et Neuron AI. Elle s'exécute dans un conteneur Docker basé sur FrankenPHP/Caddy et fournit une interface web, une API REST, une intégration Telegram et une observabilité complète via OpenTelemetry.
- Interface web de chat avec streaming SSE, horodatage, suppression du dernier message
- Mode widget embarqué (
/embed) injecté viawindow.claireEmbed(...)pour intégration sur site tiers - API REST
POST /brain/messageset healthcheckGET /health - Multi-brain : sélection dynamique d'agents IA (Claire, Einstein, Calliope...)
- Création d'agents personnalisés via fichiers YAML dans
/opt/addons/agents/ - Mémoire courte avec résumé automatique de l'historique
- Recherche web via SearXNG et RAG fichier via embeddings
- Génération d'images avec ComfyUI (workflows multiples)
- Génération de documents PDF depuis HTML ou Markdown
- Intégration Telegram complète (messages, photos, documents, Mini-App)
- Queue de fond Redis pour traitements asynchrones
- Observabilité OpenTelemetry (traces, métriques, logs)
- Authentification SSO OpenID Connect obligatoire
- Runtime : FrankenPHP + Caddy (PHP 8.5)
- Framework : Slim 4 avec PHP-DI
- Templates : Twig
- ORM : Doctrine ORM/DBAL (SQLite, MySQL, PostgreSQL)
- LLM : Neuron AI avec support OpenAI-compatible
- Queue : Redis (BRPOP/LPUSH)
- Observabilité : OpenTelemetry SDK + auto-instrumentation
- PDF : mPDF (génération de documents)
- Bot : phptg/bot-api (Telegram)
| Variable | Description |
|---|---|
BASE_URL |
URL publique de l'application (ex: https://claire.example.com) |
OPENAPI_KEY |
Clé API du fournisseur LLM |
OPENAPI_URL |
URL de l'API LLM |
OPENAPI_MODEL |
Modèle par défaut |
OPENID_WELLKNOWN_URL |
URL de découverte OpenID Connect |
OPENID_CLIENT_ID |
Identifiant client OIDC |
SESSION_JWT_SECRET |
Clé secrète JWT (min 32 caractères) |
| Variable | Description | Défaut |
|---|---|---|
OPENAPI_MODEL_SUMMARY |
Modèle pour les résumés | valeur de OPENAPI_MODEL |
OPENAPI_MODEL_EMBED |
Modèle pour embeddings (RAG) | désactivé |
OPENAPI_REQUEST_TIMEOUT |
Timeout des requêtes API (secondes) | 180 |
SESSION_LIFETIME |
Durée de vie des JWT de session (secondes) | 900 |
SESSION_REFRESH_BEFORE_EXPIRE |
Marge avant expiration pour déclencher le refresh (secondes) | 120 |
SESSION_REFRESH_MIN_INTERVAL |
Intervalle minimal entre deux tentatives de refresh (secondes) | 30 |
SEARXNG_URL |
URL SearXNG pour recherche web | - |
TELEGRAM_BOT_TOKEN |
Token du bot Telegram | - |
TELEGRAM_WEBHOOK_SECRET |
Secret webhook Telegram | - |
COMFYUI_ENABLED |
Active la génération d'images | false |
COMFYUI_URL |
URL de l'instance ComfyUI | http://localhost:8188 |
PDF_ENABLED |
Active la génération de PDF | true |
PDF_DEFAULT_FORMAT |
Format d'entrée par défaut (html, markdown) |
html |
PDF_DEFAULT_PAGE_SIZE |
Format de page par défaut (A4, Letter, A3, A5) |
A4 |
PDF_TEMP_DIR |
Répertoire temporaire pour la génération PDF | <app>/var/tmp |
DATABASE_KIND |
Type de base (sqlite, mysql, postgres) |
sqlite |
DEBUG_MODE |
Mode debug | false |
QUEUE_WORKERS |
Nombre de workers de queue | 8 |
QUEUE_WORKER_TIMEOUT |
Timeout BRPOP du worker (secondes) | 5 |
QUEUE_WORKER_MAX_JOBS |
Nombre max de jobs par worker | 0 (illimité) |
QUEUE_WORKER_MAX_TIME |
Durée de vie max d'un worker (secondes) | 0 (illimité) |
SSE_QUEUE_TTL |
Durée de vie des messages SSE en file d'attente (secondes) | 60 |
SSE_POP_TIMEOUT |
Timeout de lecture bloquante SSE (secondes) | 15 |
Voir docker/compose.yml pour un exemple complet avec toutes les variables.
| Chemin | Usage |
|---|---|
/opt/data |
Base SQLite, fichiers uploadés, données persistantes |
/opt/addons |
Agents YAML personnalisés, workflows ComfyUI |
# Démarrer la stack
docker compose up -d
# Voir les logs
docker compose logs -f claire
# Exécuter des commandes
docker compose exec claire ./console migrations:migrate
docker compose exec claire ./console cache:clear
docker compose exec claire ./console telegram:set-commands
docker compose exec claire ./console telegram:webhook --set
# Lancer le worker de queue
docker compose exec claire ./console queue:workCréez vos propres agents sans coder en ajoutant des fichiers YAML dans /opt/addons/agents/ :
name: "Coach Personnel"
description: "Un coach motivant pour vous aider à atteindre vos objectifs"
avatar: "data:image/png;base64,..."
css_inline: |
:root { --claire-accent: #FF6B35; }
welcomes:
- "Prêt à relever de nouveaux défis ?"
- "Bonjour champion !"
instruction: |
Tu es un coach personnel motivant et bienveillant...Les cerveaux par défaut : claire (généraliste), einstein (scientifique), calliope (conteuse).
Activez avec COMFYUI_ENABLED=true et ajoutez des workflows dans /opt/addons/comfyui/ :
label: Portrait Flux
workflow: |
{
"3": { "inputs": { "seed": {{SEED}} }, "class_type": "KSampler" },
"6": { "inputs": { "text": "{{PROMPT}}" }, "class_type": "CLIPTextEncode" }
}Activez par défaut (PDF_ENABLED=true). Les agents peuvent générer des documents PDF depuis du HTML ou du Markdown via l'outil generate_pdf :
- Formats supportés : HTML, Markdown
- Formats de page : A4, Letter, A3, A5
- Orientations : portrait, paysage
- Marges configurables
Les fichiers générés sont liés à la conversation et accessibles dans l'historique de chat.
| Variable | Description |
|---|---|
TELEGRAM_BOT_TOKEN |
Token de @BotFather |
TELEGRAM_WEBHOOK_SECRET |
Secret pour sécuriser le webhook |
# Configurer le webhook
docker compose exec claire ./console telegram:webhook --set
# Vérifier le statut
docker compose exec claire ./console telegram:webhook --info
# Configurer le bouton Mini-App
docker compose exec claire ./console telegram:menu-button --setLe bot supporte les commandes /start, /help, /brain, /comfyui.
Nécessaire pour Telegram et le streaming SSE multi-instance :
# Lancer le worker
docker compose exec claire ./console queue:work
# Options
--once # Traiter un seul job
--timeout=5 # Timeout BRPOP
--max-jobs=100Claire expose un mode widget prêt à intégrer dans une page externe.
- Endpoint HTML :
GET /embed - Bootstrap JS :
public/js/embed.js - Échange SSO -> session Claire :
POST /auth/embed/exchange - Fonction globale d'initialisation :
window.claireEmbed({ baseUrl, target, token|ssoToken }) - Fonction de teardown :
window.destroyClaireEmbed()
Exemple minimal :
<div id="claire-root"></div>
<script src="https://claire.example.com/js/embed.js"></script>
<script>
window.claireEmbed({
baseUrl: 'https://claire.example.com',
target: '#claire-root',
ssoToken: '<TOKEN_SSO>'
});
</script>Une page de validation locale est fournie dans public/embed.html.
- Le frontend envoie le JWT de session via l'en-tête
X-Claire-Auth. - Le backend peut renvoyer un JWT rafraîchi via
X-Claire-Tokenet un mini-token viaX-Claire-Minitoken. - Endpoint de refresh silencieux:
GET /auth/refresh(retour204avec en-têtes de session si renouvellement). - Endpoint d'échange SSO pour le widget:
POST /auth/embed/exchange. - Les ressources protégées (fichiers servis) acceptent un paramètre de query
tokenpour les liens/images signés côté client.
GET /health — Retourne la version et la date.
POST /brain/messages HTTP/1.1
Content-Type: multipart/form-data; boundary=----BOUND
------BOUND
Content-Disposition: form-data; name="message"
Bonjour Claire !
------BOUND
Content-Disposition: form-data; name="sessionId"
sess-abc123
------BOUND--GET /files/count,GET /files/listPOST /files/upload,POST /files/upload_ragDELETE /files/delete/{id}GET /files/img_serve/{id}(images et PDF générés)
GET /history/count,GET /history/listGET /history/open/{threadId},POST /history/newDELETE /history/exchange/last,DELETE /history/delete/{threadId}
# Lancer Claire avec Docker
docker run -d \
--name claire \
-p 8080:80 \
-v claire_data:/opt/data \
-e OPENAPI_KEY=votre-clé-api \
-e OPENAPI_URL=https://api.openai.com/v1 \
-e OPENAPI_MODEL=gpt-4o-mini \
-e SESSION_JWT_SECRET=$(openssl rand -hex 32) \
-e OTEL_PHP_AUTOLOAD_ENABLED=true \
-e OTEL_SERVICE_NAME=claire \
-e OTEL_LOGS_EXPORTER=console \
-e OTEL_LOGS_PROCESSOR=simple \
semhoun/claire-chatbot:latest
# Initialiser la base de données
docker exec claire ./console migrations:migrate
# Accéder à l'application
# Ouvrir http://localhost:8080Avec Docker Compose:
services:
claire:
image: semhoun/claire-chatbot:latest
container_name: claire
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- claire-data:/opt/data
- claire-addons:/opt/addons
environment:
# === Configuration serveur ===
BASE_URL: https://claire.example.com
SERVER_NAME: claire.example.com
ENABLE_LETSENCRYPT: true
ACME_EMAIL: admin@example.com
# === LLM Configuration ===
OPENAPI_KEY: ${OPENAPI_KEY:?set_me}
OPENAPI_URL: https://api.mistral.ai/v1
OPENAPI_MODEL: mistral-large-latest
# === Authentification OpenID (obligatoire) ===
OPENID_WELLKNOWN_URL: https://lastlogin.net/.well-known/openid-configuration
OPENID_CLIENT_ID: https://claire.example.com
# === Sécurité ===
SESSION_JWT_SECRET: ${SESSION_JWT_SECRET:?set_me}
# === Observabilité ===
OTEL_PHP_AUTOLOAD_ENABLED: true
OTEL_SERVICE_NAME: claire
OTEL_LOGS_EXPORTER: console
OTEL_LOGS_PROCESSOR: simple
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
claire-data:
claire-addons:
claire-redis:Image Docker : semhoun/claire-chatbot
Pour contribuer ou modifier le code :
# Cloner et installer
git clone https://github.com/semhoun/claire-chatbot.git
cd claire-chatbot
composer install
# Exporter les variables
export OPENAPI_KEY=votre-clé-api
export OPENAPI_URL=https://api.openai.com/v1
export OPENAPI_MODEL=gpt-4o-mini
export SESSION_JWT_SECRET=$(openssl rand -hex 32)
# Initialiser et lancer
./console migrations:migrate
composer startcomposer rector-check # Vérifier
composer rector-fix # Appliquer
composer insights-check # Analyser
composer insights-fix # Corriger
vendor/bin/phpunit # Tests
composer pre-commit # Tous les checks| Problème | Solution |
|---|---|
500 au GET / |
Vérifiez les permissions du dossier var/ |
| Pas de logs | Définissez OTEL_LOGS_EXPORTER=console |
| RAG inactif | Vérifiez OPENAPI_MODEL_EMBED |
| ComfyUI non dispo | Vérifiez COMFYUI_ENABLED=true et les workflows |
| Worker bloqué | Vérifiez Redis et REDIS_READ_TIMEOUT |
MIT — Voir le fichier LICENSE.