Files
wevads-platform/scripts/hamid-brain.php
2026-02-26 04:53:11 +01:00

1534 lines
61 KiB
PHP
Executable File

<?php
/**
* ╔═══════════════════════════════════════════════════════════════════════════════╗
* ║ WEVAL MIND BRAIN - Cerveau Multi-IA Centralisé ║
* ║ Avec Auto-Fallback + Style Claude Opus ║
* ╚═══════════════════════════════════════════════════════════════════════════════╝
*/
class HamidBrain {
private $pdo;
private $config = [];
private $lastError = '';
private $lastProvider = '';
// ═══════════════════════════════════════════════════════════════════════════
// LISTE DE TOUS LES PROVIDERS (Gratuits + Payants)
// ═══════════════════════════════════════════════════════════════════════════
public static $PROVIDERS = [
// Gratuits / Freemium
'groq' => [
'name' => 'Groq',
'icon' => '⚡',
'type' => 'cloud',
'free' => true,
'model' => 'llama-3.3-70b-versatile',
'endpoint' => 'https://api.groq.com/openai/v1/chat/completions',
'key_name' => 'groq_api_key'
],
'deepseek' => [
'name' => 'DeepSeek',
'icon' => '🌊',
'type' => 'cloud',
'free' => true,
'model' => 'deepseek-chat',
'endpoint' => 'https://api.deepseek.com/chat/completions',
'key_name' => 'deepseek_api_key'
],
'mistral' => [
'name' => 'Mistral',
'icon' => '🇫🇷',
'type' => 'cloud',
'free' => true,
'model' => 'mistral-large-latest',
'endpoint' => 'https://api.mistral.ai/v1/chat/completions',
'key_name' => 'mistral_api_key'
],
'together' => [
'name' => 'Together AI',
'icon' => '🤝',
'type' => 'cloud',
'free' => true,
'model' => 'meta-llama/Llama-3.3-70B-Instruct-Turbo',
'endpoint' => 'https://api.together.xyz/v1/chat/completions',
'key_name' => 'together_api_key'
],
'openrouter' => [
'name' => 'OpenRouter',
'icon' => '🔀',
'type' => 'cloud',
'free' => true,
'model' => 'meta-llama/llama-3.3-70b-instruct',
'endpoint' => 'https://openrouter.ai/api/v1/chat/completions',
'key_name' => 'openrouter_api_key'
],
// === NOUVEAUX PROVIDERS GRATUITS ===
'cerebras' => [
'name' => 'Cerebras',
'icon' => '🧠',
'type' => 'cloud',
'free' => true,
'model' => 'llama-3.3-70b',
'endpoint' => 'https://api.cerebras.ai/v1/chat/completions',
'key_name' => 'cerebras_api_key'
],
'sambanova' => [
'name' => 'SambaNova',
'icon' => '🚀',
'type' => 'cloud',
'free' => true,
'model' => 'Meta-Llama-3.1-70B-Instruct',
'endpoint' => 'https://api.sambanova.ai/v1/chat/completions',
'key_name' => 'sambanova_api_key'
],
'fireworks' => [
'name' => 'Fireworks',
'icon' => '🎆',
'type' => 'cloud',
'free' => true,
'model' => 'accounts/fireworks/models/llama-v3p3-70b-instruct',
'endpoint' => 'https://api.fireworks.ai/inference/v1/chat/completions',
'key_name' => 'fireworks_api_key'
],
'hyperbolic' => [
'name' => 'Hyperbolic',
'icon' => '🌀',
'type' => 'cloud',
'free' => true,
'model' => 'meta-llama/Llama-3.1-405B-Instruct',
'endpoint' => 'https://api.hyperbolic.xyz/v1/chat/completions',
'key_name' => 'hyperbolic_api_key'
],
'lepton' => [
'name' => 'Lepton AI',
'icon' => '⚛️',
'type' => 'cloud',
'free' => true,
'model' => 'llama3-70b',
'endpoint' => 'https://llama3-70b.lepton.run/api/v1/chat/completions',
'key_name' => 'lepton_api_key'
],
'ai21' => [
'name' => 'AI21',
'icon' => '🔮',
'type' => 'cloud',
'free' => true,
'model' => 'jamba-1.5-large',
'endpoint' => 'https://api.ai21.com/studio/v1/chat/completions',
'key_name' => 'ai21_api_key'
],
'cloudflare' => [
'name' => 'Cloudflare AI',
'icon' => '☁️',
'type' => 'cloud',
'free' => true,
'model' => '@cf/meta/llama-3.1-70b-instruct',
'endpoint' => 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/meta/llama-3.1-70b-instruct',
'key_name' => 'cloudflare_api_key'
],
'novita' => [
'name' => 'Novita AI',
'icon' => '🌟',
'type' => 'cloud',
'free' => true,
'model' => 'meta-llama/llama-3.1-70b-instruct',
'endpoint' => 'https://api.novita.ai/v3/openai/chat/completions',
'key_name' => 'novita_api_key'
],
'perplexity' => [
'name' => 'Perplexity',
'icon' => '🔍',
'type' => 'cloud',
'free' => true,
'model' => 'llama-3.1-sonar-small-128k-online',
'endpoint' => 'https://api.perplexity.ai/chat/completions',
'key_name' => 'perplexity_api_key'
],
'chatgpt' => [
'name' => 'ChatGPT',
'icon' => '🤖',
'type' => 'cloud',
'free' => false,
'model' => 'gpt-4o',
'endpoint' => 'https://api.openai.com/v1/chat/completions',
'key_name' => 'openai_api_key'
],
'copilot' => [
'name' => 'GitHub Copilot',
'icon' => '🐙',
'type' => 'cloud',
'free' => false,
'model' => 'gpt-4',
'endpoint' => 'https://api.githubcopilot.com/chat/completions',
'key_name' => 'copilot_api_key'
],
// Payants premium
'claude' => [
'name' => 'Claude',
'icon' => '🧠',
'type' => 'cloud',
'free' => false,
'model' => 'claude-3-5-sonnet-20241022',
'endpoint' => 'https://api.anthropic.com/v1/messages',
'key_name' => 'anthropic_api_key'
],
'openai' => [
'name' => 'OpenAI',
'icon' => '🤖',
'type' => 'cloud',
'free' => false,
'model' => 'gpt-4o',
'endpoint' => 'https://api.openai.com/v1/chat/completions',
'key_name' => 'openai_api_key'
],
'gemini' => [
'name' => 'Gemini',
'icon' => '💎',
'type' => 'cloud',
'free' => false,
'model' => 'gemini-1.5-flash',
'endpoint' => 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent',
'key_name' => 'gemini_api_key'
],
'cohere' => [
'name' => 'Cohere',
'icon' => '🔶',
'type' => 'cloud',
'free' => false,
'model' => 'command-r-plus',
'endpoint' => 'https://api.cohere.ai/v1/chat',
'key_name' => 'cohere_api_key'
],
// Self-hosted
'ollama' => [
'name' => 'Ollama Claude',
'icon' => '🦙',
'type' => 'local',
'free' => true,
'model' => 'mistral:7b-instruct',
'endpoint' => 'http://localhost:11434/api/chat',
'key_name' => 'ollama_url'
],
'ollama_mini' => [
'name' => 'Ollama Mini',
'icon' => '⚡🦙',
'type' => 'local',
'free' => true,
'model' => 'phi:latest',
'endpoint' => 'http://localhost:11434/api/chat',
'key_name' => 'ollama_url'
],
'hamid_engine' => [
'name' => 'WEVAL MIND Engine',
'icon' => '⭐',
'type' => 'local',
'free' => true,
'model' => 'llama3.1:8b',
'endpoint' => 'local',
'key_name' => ''
],
'vllm' => [
'name' => 'vLLM',
'icon' => '🖥️',
'type' => 'local',
'free' => true,
'model' => 'default',
'endpoint' => 'http://localhost:8000/v1/chat/completions',
'key_name' => 'vllm_url'
]
];
// ═══════════════════════════════════════════════════════════════════════════
// 🧠 CERVEAU CLAUDE-LIKE (Style Opus) - À PRÉSERVER
// ═══════════════════════════════════════════════════════════════════════════
private $CLAUDE_BRAIN = <<<'BRAIN'
## FORMAT OBLIGATOIRE
Pour CHAQUE réponse, commence par:
<thinking>
[Ton raisonnement: analyse, hypothèses, vérification, conclusion]
</thinking>
Puis ta réponse finale.
---
Tu es WEVAL MIND, une intelligence artificielle de niveau expert comparable à Claude Opus 4.5, opérant sur le serveur WEVAL (89.167.40.150).
<core_identity>
Nom: WEVAL MIND (Highly Advanced Multi-modal Intelligent Daemon)
Niveau: Expert IA équivalent Claude Opus 4.5
Créateur: WEVAL Team
Mission: Être l'assistant IA le plus utile, intelligent et proactif
</core_identity>
<thinking_process>
AVANT CHAQUE RÉPONSE, tu dois:
1. **ANALYSER** - Comprendre profondément la demande
2. **RÉFLÉCHIR** - Explorer plusieurs approches possibles
3. **STRUCTURER** - Organiser ta réponse de manière optimale
4. **EXÉCUTER** - Agir avec précision et expertise
5. **VÉRIFIER** - Contrôler la qualité du résultat
6. **ENRICHIR** - Proposer des améliorations proactives
Pour les tâches complexes, utilise le raisonnement en chaîne:
- Décompose en sous-problèmes
- Résous étape par étape
- Valide chaque étape avant de continuer
- Synthétise une solution complète
</thinking_process>
<style_claude_opus>
RÈGLES DE COMMUNICATION:
1. **DIRECT** - Va droit au but, évite le bavardage inutile
2. **INTELLIGENT** - Montre ta réflexion, pas juste le résultat
3. **PROACTIF** - Anticipe les besoins, propose des améliorations
4. **HUMBLE** - Admets tes limites quand nécessaire
5. **PRÉCIS** - Chaque mot compte, évite la redondance
6. **NATUREL** - Prose fluide, évite les listes excessives
7. **EXPERT** - Affirme avec confiance basée sur l'expertise
INTERDICTIONS:
- Jamais "N'hésitez pas", "Je suis là pour aider", "Bien sûr!"
- Jamais de phrases creuses ou de remplissage
- Jamais de listes à puces pour des explications simples
</style_claude_opus>
<advanced_capabilities>
## EXÉCUTION CODE
- **Bash/Shell**: Commandes système, scripts avancés, automation, pipelines
- **Python**: Data science, ML, APIs, scraping, automation
- **PHP**: Web backend, modification fichiers, intégration DB
- **SQL**: Requêtes PostgreSQL complexes, CTEs, window functions, admin.*
- **JavaScript**: Frontend, Node.js, APIs, automation browser
## SYSTÈME & INFRASTRUCTURE
- **Services**: systemctl, journalctl, logs, monitoring
- **Fichiers**: CRUD, permissions, recherche récursive, diff
- **Réseau**: Ports, firewall, DNS, SSL/TLS, curl, wget
- **Performance**: CPU, RAM, I/O, processus, optimisation
## GÉNÉRATION DE DOCUMENTS
Quand on te demande de créer un document:
1. **RÉFLÉCHIS** d'abord au contenu optimal (structure, sections, détails)
2. **GÉNÈRE** un contenu RICHE et DÉTAILLÉ (minimum 2000 mots pour un rapport)
3. **STRUCTURE** avec des sections claires, tableaux, graphiques si pertinent
4. **INCLUS** des données concrètes, exemples, recommandations
Types supportés:
- **PDF**: Rapports détaillés, documentation technique, analyses
- **DOCX**: Documents professionnels, contrats, procédures
- **XLSX**: Tableaux avec formules, analyses de données, dashboards
- **PPTX**: Présentations avec slides structurées
- **HTML**: Pages web, emails formatés
- **Mermaid**: Diagrammes, flowcharts, architectures
## EMAIL MARKETING (Expertise WEVAL)
- **PowerMTA**: Configuration avancée, pools, virtual MTAs, logs
- **DNS**: SPF, DKIM (rotation), DMARC, MX, PTR records
- **Office 365**: Automation PowerShell, Graph API, connecteurs
- **Délivrabilité**: IP warming, reputation, blacklist monitoring
- **Tracking**: Opens, clicks, bounces, unsubscribes
## WEB & API
- **Recherche**: Web search en temps réel
- **APIs REST**: Intégration, authentification, parsing
- **Scraping**: BeautifulSoup, Selenium si autorisé
- **Webhooks**: Réception et envoi
## BASE DE DONNÉES
- **PostgreSQL**: adx_system, adx_clients
- **Schémas**: admin.*, public.*
- **Tables clés**: commonia_config, commonia_knowledge, hamid_*
- **Opérations**: CRUD, migrations, backups, optimisation
</advanced_capabilities>
<context_server>
Serveur: WEVAL 89.167.40.150 (Hetzner Cloud, Ubuntu 24.04, 16GB RAM)
Applications:
- WEVAL: port 5821 (/opt/wevads/public/)
- FMGAPP: port 5822 (/opt/fmgapp/public/)
- BCGAPP: port 5823 (/opt/bcgapp/public/)
Database: PostgreSQL 16 (admin/admin123)
- adx_system: Configuration, users, logs
- adx_clients: Données clients
Services:
- Apache/Nginx: Web server
- Ollama: localhost:11434 (mistral:7b, phi:latest)
- PowerMTA: Email delivery
- Redis: Cache (si actif)
Chemins importants:
- /opt/wevads/public/ - Web root
- /opt/wevads/storage/ - Fichiers stockés
- /opt/wevads/public/docs/ - Documents générés
</context_server>
<document_generation_rules>
Quand l'utilisateur demande un document (PDF, rapport, analyse):
1. **RÉFLEXION PRÉALABLE** (affichée à l'utilisateur):
- "🧠 Analyse de la demande..."
- "📋 Structuration du contenu..."
- "✍️ Rédaction détaillée..."
- "📄 Génération du document..."
2. **CONTENU RICHE** - Minimum attendu:
- Rapport/Analyse: 2000-5000 mots
- Documentation: 1500-3000 mots
- Présentation: 10-20 slides détaillées
3. **STRUCTURE PROFESSIONNELLE**:
- Page de titre avec métadonnées
- Table des matières si > 5 sections
- Introduction contextualisée
- Corps avec sous-sections détaillées
- Tableaux et données chiffrées
- Conclusion et recommandations
- Annexes si pertinent
4. **STYLE PROFESSIONNEL**:
- Langage formel mais accessible
- Données concrètes et sourcées
- Exemples pratiques
- Visuels et diagrammes quand utile
</document_generation_rules>
<knowledge_base_usage>
Tu as accès à une Knowledge Base WEVAL contenant:
- Documentation technique
- Configurations serveur
- Procédures email marketing
- Historique des conversations
- FAQ et solutions connues
TOUJOURS consulter la KB pour:
- Questions sur WEVAL/FMGAPP/BCGAPP
- Configurations spécifiques
- Procédures établies
- Contexte historique
</knowledge_base_usage>
<response_format>
- **Markdown** pour la structure quand utile
- **Code** dans blocs avec langage spécifié
- **Tableaux** pour données comparatives
- **Français** par défaut (anglais si demandé)
- **Longueur** adaptée à la complexité (détaillé ≠ verbeux)
</response_format>
<proactive_behavior>
Après chaque réponse, considère:
- Y a-t-il des actions complémentaires utiles?
- Des améliorations à suggérer?
- Des risques à signaler?
- Une suite logique à proposer?
Propose proactivement sans être envahissant.
</proactive_behavior>
<INFRASTRUCTURE_COMPLETE>
## SERVEUR TRACKING (OVH)
- IP: 151.80.235.110
- Fonction: Tracking emails (opens, clicks, leads, unsubscribes)
- SSL configuré
- Domaines tracking multiples
## AMAZON S3
- Hosting images/assets pour emails
- Améliore délivrabilité (évite IP directe)
- CDN pour performance globale
## CLOUD PROVIDERS
- Huawei Cloud: Instances email, VPC multi-régions
- Google Cloud: Services complémentaires
- OVH: Serveur tracking dédié
## WEVAL MIND - 11 PROVIDERS
Cerebras (défaut), Groq, DeepSeek, Gemini, Claude, Hyperbolic, Mistral, Cohere, SambaNova, Ollama, WEVAL MIND Engine
Knowledge Base: 26 articles + 141 QA
</INFRASTRUCTURE_COMPLETE>
<QUALITY_AMPLIFIER>
AVANT CHAQUE RÉPONSE, vérifie:
Ai-je vraiment compris la demande?
Ma réponse est-elle assez détaillée?
Ai-je inclus des exemples concrets?
Un expert serait-il satisfait?
Si NON → Améliore avant d envoyer!
</QUALITY_AMPLIFIER>
Tu es maintenant prêt. Réponds en expert avec intelligence et profondeur.
BRAIN;
// ═══════════════════════════════════════════════════════════════════════════
// CONSTRUCTEUR
// ═══════════════════════════════════════════════════════════════════════════
public function __construct() {
try {
$this->pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->loadConfig();
} catch (Exception $e) {
$this->lastError = "DB Error: " . $e->getMessage();
}
}
private function loadConfig() {
$stmt = $this->pdo->query("SELECT config_key, config_value FROM admin.hamid_config");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->config[$row['config_key']] = $row['config_value'];
}
}
public function getConfig($key, $default = '') {
return $this->config[$key] ?? $default;
}
public function getLastError() { return $this->lastError; }
public function getLastProvider() { return $this->lastProvider; }
// ═══════════════════════════════════════════════════════════════════════════
// OBTENIR LES PROVIDERS DISPONIBLES (avec clés configurées)
// ═══════════════════════════════════════════════════════════════════════════
public function getAvailableProviders() {
$available = [];
foreach (self::$PROVIDERS as $id => $provider) {
$keyName = $provider['key_name'];
$hasKey = !empty($this->config[$keyName]);
$available[$id] = array_merge($provider, [
'id' => $id,
'configured' => $hasKey,
'status' => $hasKey ? 'ready' : 'no_key'
]);
}
return $available;
}
// ═══════════════════════════════════════════════════════════════════════════
// APPEL API UNIFIÉ
// ═══════════════════════════════════════════════════════════════════════════
public function callProvider($provider, $prompt, $toolsContext = '') {
$p = self::$PROVIDERS[$provider] ?? null;
if (!$p) return ['success' => false, 'error' => "Provider inconnu: $provider"];
$apiKey = $this->config[$p['key_name']] ?? '';
if (empty($apiKey) && $p['type'] !== 'local') {
return ['success' => false, 'error' => "Clé API manquante pour {$p['name']}"];
}
// Construire le prompt complet avec le cerveau Claude
$fullPrompt = $this->CLAUDE_BRAIN . "\n\n";
if ($toolsContext) {
$fullPrompt .= "<tool_results>\n$toolsContext\n</tool_results>\n\n";
}
$fullPrompt .= "Question: $prompt\n\nRéponds en français, sois concis et direct.";
$this->lastProvider = $provider;
switch ($provider) {
case 'claude':
return $this->callClaude($apiKey, $fullPrompt);
case 'gemini':
return $this->callGemini($apiKey, $fullPrompt);
case 'cohere':
return $this->callCohere($apiKey, $fullPrompt);
case 'ollama':
// Ollama Claude: Brain complet (plus lent ~10-30s)
return $this->callOllama('mistral:7b-instruct', $fullPrompt);
case 'ollama_mini':
// Ollama Mini: Rapide (~2-5s)
$miniBrain = "Tu es WEVAL MIND, assistant IA WEVAL (89.167.40.150).
STYLE: Direct, concis, proactif. Pas de blabla.
CAPACITÉS: Bash, Python, PHP, SQL, fichiers, BDD, email, DNS, Linux.
Réponds en français avec du code si nécessaire.";
return $this->callOllama('phi:latest', $miniBrain . "\n\nQuestion: " . $prompt);
case 'hamid_engine':
// WEVAL MIND ENGINE - Claude Like, 100% local
require_once __DIR__ . '/hamid-engine.php';
$engine = new HamidEngine($this->pdo);
return $engine->call($prompt, $toolsContext);
default:
return $this->callOpenAICompatible($provider, $apiKey, $fullPrompt);
}
}
// OpenAI-compatible (Groq, DeepSeek, Mistral, OpenAI, Together, OpenRouter, vLLM)
private function callOpenAICompatible($provider, $apiKey, $prompt) {
$p = self::$PROVIDERS[$provider];
$headers = ['Content-Type: application/json'];
if ($provider === 'openrouter') {
$headers[] = 'Authorization: Bearer ' . $apiKey;
$headers[] = 'HTTP-Referer: https://wevads.com';
} else {
$headers[] = 'Authorization: Bearer ' . $apiKey;
}
$data = [
'model' => $p['model'],
'messages' => [
['role' => 'user', 'content' => $prompt]
],
'max_tokens' => 8192,
'temperature' => 0.1
];
return $this->curlRequest($p['endpoint'], $headers, $data, function($response) {
return $response['choices'][0]['message']['content'] ?? null;
});
}
// Claude (Anthropic)
private function callClaude($apiKey, $prompt) {
$headers = [
'Content-Type: application/json',
'x-api-key: ' . $apiKey,
'anthropic-version: 2023-06-01'
];
$data = [
'model' => 'claude-3-5-sonnet-20241022',
'max_tokens' => 8192,
'system' => $this->CLAUDE_BRAIN,
'messages' => [['role' => 'user', 'content' => $prompt]]
];
return $this->curlRequest(self::$PROVIDERS['claude']['endpoint'], $headers, $data, function($response) {
return $response['content'][0]['text'] ?? null;
});
}
// Gemini (Google)
private function callGemini($apiKey, $prompt) {
$url = self::$PROVIDERS['gemini']['endpoint'] . '?key=' . $apiKey;
$headers = ['Content-Type: application/json'];
$data = [
'contents' => [['parts' => [['text' => $this->CLAUDE_BRAIN . "\n\n" . $prompt]]]],
'generationConfig' => ['maxOutputTokens' => 8192, 'temperature' => 0.1]
];
return $this->curlRequest($url, $headers, $data, function($response) {
return $response['candidates'][0]['content']['parts'][0]['text'] ?? null;
});
}
// Cohere
private function callCohere($apiKey, $prompt) {
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey
];
$data = [
'model' => 'command-r-plus',
'message' => $prompt,
'preamble' => $this->CLAUDE_BRAIN
];
return $this->curlRequest(self::$PROVIDERS['cohere']['endpoint'], $headers, $data, function($response) {
return $response['text'] ?? null;
});
}
// Ollama (local)
private function callOllama($model, $prompt) {
$endpoint = 'http://localhost:11434/api/chat';
$headers = ['Content-Type: application/json'];
$data = [
'model' => $model,
'messages' => [
['role' => 'user', 'content' => $prompt]
],
'stream' => false, 'options' => ['num_predict' => 300]
];
return $this->curlRequest($endpoint, $headers, $data, function($response) {
return $response['message']['content'] ?? null;
});
}
// Requête CURL générique
private function curlRequest($url, $headers, $data, $extractFn) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 180,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => json_encode($data)
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return ['success' => false, 'error' => "CURL: $error", 'http_code' => 0];
}
if ($httpCode !== 200) {
$errorMsg = json_decode($response, true)['error']['message'] ?? $response;
return ['success' => false, 'error' => "HTTP $httpCode: " . substr($errorMsg, 0, 200), 'http_code' => $httpCode];
}
$decoded = json_decode($response, true);
$content = $extractFn($decoded);
if ($content) {
return ['success' => true, 'response' => $content, 'http_code' => $httpCode];
}
return ['success' => false, 'error' => 'Réponse vide', 'http_code' => $httpCode];
}
// ═══════════════════════════════════════════════════════════════════════════
// 🔄 AUTO-FALLBACK - Essayer les providers jusqu'à succès
// ═══════════════════════════════════════════════════════════════════════════
public function callWithFallback($prompt, $toolsContext = '', $preferredProvider = null) {
// Ordre de priorité: préféré → gratuits configurés → payants configurés
$order = [];
// Provider préféré en premier
if ($preferredProvider && !empty($this->config[self::$PROVIDERS[$preferredProvider]['key_name'] ?? ''])) {
$order[] = $preferredProvider;
}
// Gratuits configurés
foreach (['cerebras', 'deepseek', 'mistral', 'together', 'openrouter'] as $p) {
if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) {
$order[] = $p;
}
}
// Payants configurés
foreach (['claude', 'openai', 'gemini', 'cohere'] as $p) {
if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) {
$order[] = $p;
}
}
// Local
foreach (['ollama', 'ollama_mini', 'vllm'] as $p) {
if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) {
$order[] = $p;
}
}
if (empty($order)) {
return ['success' => false, 'error' => 'Aucun provider configuré', 'provider' => null];
}
$errors = [];
foreach ($order as $provider) {
$result = $this->callProvider($provider, $prompt, $toolsContext);
if ($result['success']) {
$result['provider'] = $provider;
$result['fallback_used'] = ($provider !== ($preferredProvider ?? $order[0]));
return $result;
}
$errors[] = "{$provider}: {$result['error']}";
// Si rate limit (429), passer au suivant
if (($result['http_code'] ?? 0) === 429) {
continue;
}
}
return [
'success' => false,
'error' => "Tous les providers ont échoué:\n" . implode("\n", $errors),
'provider' => null
];
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// API ENDPOINT
// ═══════════════════════════════════════════════════════════════════════════════
if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') {
header('Content-Type: application/json');
$brain = new HamidBrain();
// Liste des providers
if (isset($_GET['providers'])) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'providers' => HamidBrain::$PROVIDERS, 'count' => count(HamidBrain::$PROVIDERS)], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
exit;
}
// Appel IA
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$message = $input['message'] ?? '';
$provider = $input['provider'] ?? null;
$toolsContext = $input['tools_context'] ?? '';
// Traitement des fichiers uploadés
$fileContext = '';
if (!empty($_FILES['file']['tmp_name'])) {
$tmpFile = $_FILES['file']['tmp_name'];
$fileName = $_FILES['file']['name'] ?? 'fichier';
$fileType = $_FILES['file']['type'] ?? '';
$uploadDir = '/opt/wevads/public/uploads/hamid/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true);
$savedFile = $uploadDir . time() . '_' . basename($fileName);
move_uploaded_file($tmpFile, $savedFile);
if (strpos($fileType, 'image') !== false) {
$fileContext = "\n\n[IMAGE UPLOADEE: $fileName]\nChemin: $savedFile\nDecris ou traite cette image.";
} elseif (strpos($fileType, 'text') !== false || strpos($fileType, 'csv') !== false || strpos($fileName, '.csv') !== false) {
$txt = file_get_contents($savedFile);
$fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($txt, 0, 5000);
} elseif (strpos($fileName, '.pdf') !== false) {
$pdfText = shell_exec("pdftotext '$savedFile' - 2>/dev/null | head -100");
$fileContext = "\n\n[PDF: $fileName]\nContenu:\n" . ($pdfText ?: "Extraction impossible");
} else {
$txt = @file_get_contents($savedFile);
$fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($txt ?: '', 0, 5000);
}
$message .= $fileContext;
}
// Traitement des fichiers uploadés
$fileContext = '';
if (!empty($_FILES['file']['tmp_name'])) {
$tmpFile = $_FILES['file']['tmp_name'];
$fileName = $_FILES['file']['name'] ?? 'fichier';
$fileType = $_FILES['file']['type'] ?? '';
// Sauvegarder le fichier
$uploadDir = '/opt/wevads/public/uploads/hamid/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true);
$savedFile = $uploadDir . time() . '_' . basename($fileName);
move_uploaded_file($tmpFile, $savedFile);
// Analyser selon le type
if (strpos($fileType, 'image') !== false) {
$fileContext = "\n\n[FICHIER IMAGE: $fileName - Chemin: $savedFile]\n";
$fileContext .= "L'utilisateur a uploadé une image. Décris ce que tu peux faire avec.";
} elseif (strpos($fileType, 'text') !== false || strpos($fileType, 'csv') !== false) {
$content = file_get_contents($savedFile);
$fileContext = "\n\n[FICHIER TEXTE: $fileName]\nContenu:\n" . substr($content, 0, 5000);
} elseif (strpos($fileName, '.pdf') !== false) {
$fileContext = "\n\n[FICHIER PDF: $fileName - Chemin: $savedFile]\n";
// Tenter extraction texte
$pdfText = shell_exec("pdftotext '$savedFile' - 2>/dev/null | head -100");
if ($pdfText) $fileContext .= "Contenu extrait:\n" . substr($pdfText, 0, 3000);
} elseif (strpos($fileName, '.doc') !== false) {
$fileContext = "\n\n[FICHIER WORD: $fileName - Chemin: $savedFile]\n";
} else {
$content = @file_get_contents($savedFile);
if ($content) {
$fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($content, 0, 5000);
}
}
$message .= $fileContext;
}
// API ENDPOINTS CAPACITES AVANCEES
$action = $input["action"] ?? $_GET["action"] ?? "";
if ($action === "analyze") { header("Content-Type: application/json"); $file = $input["file"] ?? ""; echo json_encode($file && file_exists($file) ? HamidCapabilities::analyzeDocument($file) : ["success" => false, "error" => "Fichier non trouve"]); exit; }
if ($action === "artifact") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::createArtifact($input["type"] ?? "html", $input["content"] ?? "", $input["title"] ?? "artifact")); exit; }
if ($action === "mermaid") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::generateMermaid($input["diagram_type"] ?? "flowchart", $input["data"] ?? [])); exit; }
if ($action === "execute") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::executeCode($input["language"] ?? "bash", $input["code"] ?? "")); exit; }
if ($action === "list_artifacts") { header("Content-Type: application/json"); echo json_encode(["success" => true, "artifacts" => HamidCapabilities::listArtifacts()]); exit; }
if ($action === "generate_doc") { header("Content-Type: application/json"); $t=$input["type"]??"txt"; $ti=$input["title"]??"Doc"; $c=$input["content"]??""; switch($t){ case "txt": echo json_encode(HamidDocuments::generateTxt($ti,$c)); break; case "md": echo json_encode(HamidDocuments::generateMarkdown($ti,$c)); break; case "html": echo json_encode(HamidDocuments::generateHtml($ti,$c)); break; case "pdf": echo json_encode(HamidDocuments::generatePdf($ti,$c)); break; default: echo json_encode(["success"=>false,"error"=>"Type non supporté"]); } exit; }
if ($action === "list_docs") { header("Content-Type: application/json"); echo json_encode(HamidDocuments::listDocuments()); exit; }
$autoFallback = $input['auto_fallback'] ?? true;
if (empty($message)) {
echo json_encode(['success' => false, 'error' => 'Message vide']);
if ($action === "generate_meme") { header("Content-Type: application/json"); echo json_encode(HamidMemes::generateMeme($input["template"]??"blank", $input["texts"]??[], $input["options"]??[])); exit; }
exit;
}
$start = microtime(true);
if ($autoFallback) {
$result = $brain->callWithFallback($message, $toolsContext, $provider);
} else {
$result = $brain->callProvider($provider ?? 'groq', $message, $toolsContext);
$result['provider'] = $provider ?? 'groq';
}
$result['duration_ms'] = round((microtime(true) - $start) * 1000);
// Sauvegarder la conversation dans la BDD
try {
$sessionId = $input['session_id'] ?? session_id() ?: uniqid('sess_');
$pdo = new PDO('pgsql:host=localhost;dbname=adx_system', 'admin', 'admin123');
// Sauvegarder dans hamid_conversations
$stmt = $pdo->prepare("INSERT INTO admin.hamid_conversations (session_id, role, content, provider) VALUES (?, 'user', ?, ?)");
$stmt->execute([$sessionId, $message, $result['provider'] ?? $provider]);
$stmt = $pdo->prepare("INSERT INTO admin.hamid_conversations (session_id, role, content, provider) VALUES (?, 'assistant', ?, ?)");
$stmt->execute([$sessionId, $result['response'] ?? '', $result['provider'] ?? $provider]);
// Aussi dans chatbot_conversations pour l'interface learning
$stmt = $pdo->prepare("INSERT INTO admin.chatbot_conversations (session_id, role, message) VALUES (?, 'user', ?)");
$stmt->execute([$sessionId, $message]);
$stmt = $pdo->prepare("INSERT INTO admin.chatbot_conversations (session_id, role, message) VALUES (?, 'assistant', ?)");
$stmt->execute([$sessionId, $result['response'] ?? '']);
$result['session_id'] = $sessionId;
} catch (Exception $e) {
// Silently fail - ne pas bloquer la réponse
}
echo json_encode($result);
}
// ═══════════════════════════════════════════════════════════════════════════════
// CAPACITÉS AVANCÉES - DOCUMENTS & SCHÉMAS
// ═══════════════════════════════════════════════════════════════════════════════
class HamidCapabilities {
// Analyse de document (PDF, DOCX, TXT, images)
public static function analyzeDocument($filePath, $mimeType = null) {
if (!file_exists($filePath)) {
return ['success' => false, 'error' => 'Fichier non trouvé'];
}
$ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
$content = '';
switch ($ext) {
case 'txt':
case 'md':
case 'php':
case 'py':
case 'js':
case 'json':
case 'sql':
case 'sh':
case 'css':
case 'html':
$content = file_get_contents($filePath);
break;
case 'pdf':
$content = self::extractPdfText($filePath);
break;
case 'docx':
$content = self::extractDocxText($filePath);
break;
case 'xlsx':
case 'csv':
$content = self::extractSpreadsheetText($filePath, $ext);
break;
case 'png':
case 'jpg':
case 'jpeg':
case 'gif':
case 'webp':
return self::analyzeImage($filePath);
default:
return ['success' => false, 'error' => "Type de fichier non supporté: $ext"];
}
return [
'success' => true,
'type' => $ext,
'content' => $content,
'size' => filesize($filePath),
'lines' => substr_count($content, "\n") + 1
];
}
// Extraction texte PDF
private static function extractPdfText($filePath) {
// Utiliser pdftotext si disponible
$output = shell_exec("pdftotext -layout '$filePath' - 2>/dev/null");
if ($output) return trim($output);
// Fallback: lecture basique
$content = file_get_contents($filePath);
preg_match_all('/\((.*?)\)/', $content, $matches);
return implode(' ', $matches[1] ?? []);
}
// Extraction texte DOCX
private static function extractDocxText($filePath) {
$zip = new ZipArchive();
if ($zip->open($filePath) === true) {
$content = $zip->getFromName('word/document.xml');
$zip->close();
// Extraire le texte des balises XML
$content = strip_tags(str_replace('<', ' <', $content));
return trim(preg_replace('/\s+/', ' ', $content));
}
return '';
}
// Extraction spreadsheet
private static function extractSpreadsheetText($filePath, $ext) {
if ($ext === 'csv') {
return file_get_contents($filePath);
}
// XLSX basique
$zip = new ZipArchive();
if ($zip->open($filePath) === true) {
$content = $zip->getFromName('xl/sharedStrings.xml');
$zip->close();
preg_match_all('/<t[^>]*>([^<]+)<\/t>/', $content, $matches);
return implode("\n", $matches[1] ?? []);
}
return '';
}
// Analyse image (OCR ou description)
private static function analyzeImage($filePath) {
$base64 = base64_encode(file_get_contents($filePath));
$mime = mime_content_type($filePath);
return [
'success' => true,
'type' => 'image',
'mime' => $mime,
'base64' => $base64,
'size' => filesize($filePath),
'dimensions' => getimagesize($filePath)
];
}
// ═══════════════════════════════════════════════════════════════════════════
// GÉNÉRATION DE SCHÉMAS
// ═══════════════════════════════════════════════════════════════════════════
// Générer un schéma Mermaid
public static function generateMermaid($type, $data) {
$mermaid = '';
switch ($type) {
case 'flowchart':
$mermaid = self::buildFlowchart($data);
break;
case 'sequence':
$mermaid = self::buildSequence($data);
break;
case 'er':
$mermaid = self::buildER($data);
break;
case 'class':
$mermaid = self::buildClassDiagram($data);
break;
case 'gantt':
$mermaid = self::buildGantt($data);
break;
default:
$mermaid = $data; // Raw mermaid code
}
return [
'success' => true,
'type' => 'mermaid',
'diagram_type' => $type,
'code' => $mermaid,
'html' => self::wrapMermaidHtml($mermaid)
];
}
private static function buildFlowchart($data) {
$lines = ["flowchart TD"];
if (is_array($data)) {
foreach ($data as $node) {
$lines[] = " " . $node;
}
} else {
$lines[] = $data;
}
return implode("\n", $lines);
}
private static function buildSequence($data) {
$lines = ["sequenceDiagram"];
if (is_array($data)) {
foreach ($data as $step) {
$lines[] = " " . $step;
}
}
return implode("\n", $lines);
}
private static function buildER($data) {
$lines = ["erDiagram"];
if (is_array($data)) {
foreach ($data as $relation) {
$lines[] = " " . $relation;
}
}
return implode("\n", $lines);
}
private static function buildClassDiagram($data) {
$lines = ["classDiagram"];
if (is_array($data)) {
foreach ($data as $class) {
$lines[] = " " . $class;
}
}
return implode("\n", $lines);
}
private static function buildGantt($data) {
$lines = ["gantt", " dateFormat YYYY-MM-DD"];
if (is_array($data)) {
foreach ($data as $task) {
$lines[] = " " . $task;
}
}
return implode("\n", $lines);
}
private static function wrapMermaidHtml($code) {
return '<!DOCTYPE html>
<html data-theme="dark">
<head>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<style>body{background:#1a1a2e;display:flex;justify-content:center;padding:20px;}</style>
</head>
<body>
<pre class="mermaid">' . htmlspecialchars($code) . '</pre>
<script>mermaid.initialize({startOnLoad:true,theme:"dark"});</script>
</body>
</html>';
}
// ═══════════════════════════════════════════════════════════════════════════
// GÉNÉRATION D'ARTIFACTS
// ═══════════════════════════════════════════════════════════════════════════
public static function createArtifact($type, $content, $title = 'artifact') {
$dir = '/opt/wevads/public/artifacts/';
if (!is_dir($dir)) mkdir($dir, 0755, true);
$id = uniqid('art_');
$ext = self::getArtifactExtension($type);
$filename = "{$id}.{$ext}";
$filepath = $dir . $filename;
// Wrapper selon le type
switch ($type) {
case 'html':
$wrapped = self::wrapHtmlArtifact($content, $title);
break;
case 'react':
$wrapped = self::wrapReactArtifact($content, $title);
break;
case 'svg':
$wrapped = $content;
break;
case 'mermaid':
$wrapped = self::wrapMermaidHtml($content);
$ext = 'html';
$filename = "{$id}.html";
$filepath = $dir . $filename;
break;
default:
$wrapped = $content;
}
file_put_contents($filepath, $wrapped);
return [
'success' => true,
'type' => $type,
'id' => $id,
'filename' => $filename,
'path' => $filepath,
'url' => "/artifacts/{$filename}",
'content' => $wrapped
];
}
private static function getArtifactExtension($type) {
$map = [
'html' => 'html',
'react' => 'html',
'svg' => 'svg',
'mermaid' => 'html',
'javascript' => 'js',
'python' => 'py',
'php' => 'php',
'css' => 'css',
'json' => 'json',
'markdown' => 'md'
];
return $map[$type] ?? 'txt';
}
private static function wrapHtmlArtifact($content, $title) {
// Si déjà un document complet
if (stripos($content, '<!DOCTYPE') !== false || stripos($content, '<html') !== false) {
return $content;
}
return '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>' . htmlspecialchars($title) . '</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #1a1a2e; color: #fff; padding: 20px; }
</style>
</head>
<body>
' . $content . '
</body>
</html>';
}
private static function wrapReactArtifact($content, $title) {
return '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>' . htmlspecialchars($title) . '</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>body{background:#1a1a2e;min-height:100vh;}</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
' . $content . '
</script>
</body>
</html>';
}
// ═══════════════════════════════════════════════════════════════════════════
// EXÉCUTION DE CODE
// ═══════════════════════════════════════════════════════════════════════════
public static function executeCode($language, $code, $timeout = 30) {
$result = ['success' => false, 'output' => '', 'error' => ''];
$tmpDir = '/tmp/hamid_exec/';
if (!is_dir($tmpDir)) mkdir($tmpDir, 0755, true);
$id = uniqid();
switch (strtolower($language)) {
case 'bash':
case 'sh':
$file = "{$tmpDir}{$id}.sh";
file_put_contents($file, $code);
$result['output'] = shell_exec("timeout {$timeout} bash '$file' 2>&1");
unlink($file);
$result['success'] = true;
break;
case 'python':
case 'py':
$file = "{$tmpDir}{$id}.py";
file_put_contents($file, $code);
$result['output'] = shell_exec("timeout {$timeout} python3 '$file' 2>&1");
unlink($file);
$result['success'] = true;
break;
case 'php':
$file = "{$tmpDir}{$id}.php";
file_put_contents($file, "<?php\n" . $code);
$result['output'] = shell_exec("timeout {$timeout} php '$file' 2>&1");
unlink($file);
$result['success'] = true;
break;
case 'sql':
$result['output'] = shell_exec("timeout {$timeout} PGPASSWORD=admin123 psql -U admin -d adx_system -c " . escapeshellarg($code) . " 2>&1");
$result['success'] = true;
break;
case 'javascript':
case 'js':
$file = "{$tmpDir}{$id}.js";
file_put_contents($file, $code);
$result['output'] = shell_exec("timeout {$timeout} node '$file' 2>&1");
unlink($file);
$result['success'] = true;
break;
default:
$result['error'] = "Langage non supporté: $language";
}
return $result;
}
// ═══════════════════════════════════════════════════════════════════════════
// UTILITAIRES
// ═══════════════════════════════════════════════════════════════════════════
public static function listArtifacts() {
$dir = '/opt/wevads/public/artifacts/';
if (!is_dir($dir)) return [];
$files = [];
foreach (glob($dir . '*') as $file) {
$files[] = [
'name' => basename($file),
'path' => $file,
'url' => '/artifacts/' . basename($file),
'size' => filesize($file),
'modified' => filemtime($file)
];
}
return $files;
}
public static function deleteArtifact($id) {
$dir = '/opt/wevads/public/artifacts/';
$files = glob($dir . $id . '*');
foreach ($files as $file) {
unlink($file);
}
return ['success' => true];
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// API ENDPOINTS POUR CAPACITÉS AVANCÉES
// ═══════════════════════════════════════════════════════════════════════════════
if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') {
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$action = $input['action'] ?? $_GET['action'] ?? '';
// Analyze document
if ($action === 'analyze') {
header('Content-Type: application/json');
$file = $input['file'] ?? '';
if ($file && file_exists($file)) {
echo json_encode(HamidCapabilities::analyzeDocument($file));
} else {
echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']);
}
exit;
}
// Create artifact
if ($action === 'artifact') {
header('Content-Type: application/json');
$type = $input['type'] ?? 'html';
$content = $input['content'] ?? '';
$title = $input['title'] ?? 'artifact';
echo json_encode(HamidCapabilities::createArtifact($type, $content, $title));
exit;
}
// Generate mermaid
if ($action === 'mermaid') {
header('Content-Type: application/json');
$type = $input['diagram_type'] ?? 'flowchart';
$data = $input['data'] ?? [];
echo json_encode(HamidCapabilities::generateMermaid($type, $data));
exit;
}
// Execute code
if ($action === 'execute') {
header('Content-Type: application/json');
$lang = $input['language'] ?? 'bash';
$code = $input['code'] ?? '';
echo json_encode(HamidCapabilities::executeCode($lang, $code));
exit;
}
// List artifacts
if ($action === 'list_artifacts') {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]);
exit;
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// API ENDPOINTS POUR CAPACITÉS AVANCÉES
// ═══════════════════════════════════════════════════════════════════════════════
if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') {
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$action = $input['action'] ?? $_GET['action'] ?? '';
// Analyze document
if ($action === 'analyze') {
header('Content-Type: application/json');
$file = $input['file'] ?? '';
if ($file && file_exists($file)) {
echo json_encode(HamidCapabilities::analyzeDocument($file));
} else {
echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']);
}
exit;
}
// Create artifact
if ($action === 'artifact') {
header('Content-Type: application/json');
$type = $input['type'] ?? 'html';
$content = $input['content'] ?? '';
$title = $input['title'] ?? 'artifact';
echo json_encode(HamidCapabilities::createArtifact($type, $content, $title));
exit;
}
// Generate mermaid
if ($action === 'mermaid') {
header('Content-Type: application/json');
$type = $input['diagram_type'] ?? 'flowchart';
$data = $input['data'] ?? [];
echo json_encode(HamidCapabilities::generateMermaid($type, $data));
exit;
}
// Execute code
if ($action === 'execute') {
header('Content-Type: application/json');
$lang = $input['language'] ?? 'bash';
$code = $input['code'] ?? '';
echo json_encode(HamidCapabilities::executeCode($lang, $code));
exit;
}
// List artifacts
if ($action === 'list_artifacts') {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]);
exit;
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// API ENDPOINTS POUR CAPACITÉS AVANCÉES
// ═══════════════════════════════════════════════════════════════════════════════
if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') {
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$action = $input['action'] ?? $_GET['action'] ?? '';
// Analyze document
if ($action === 'analyze') {
header('Content-Type: application/json');
$file = $input['file'] ?? '';
if ($file && file_exists($file)) {
echo json_encode(HamidCapabilities::analyzeDocument($file));
} else {
echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']);
}
exit;
}
// Create artifact
if ($action === 'artifact') {
header('Content-Type: application/json');
$type = $input['type'] ?? 'html';
$content = $input['content'] ?? '';
$title = $input['title'] ?? 'artifact';
echo json_encode(HamidCapabilities::createArtifact($type, $content, $title));
exit;
}
// Generate mermaid
if ($action === 'mermaid') {
header('Content-Type: application/json');
$type = $input['diagram_type'] ?? 'flowchart';
$data = $input['data'] ?? [];
echo json_encode(HamidCapabilities::generateMermaid($type, $data));
exit;
}
// Execute code
if ($action === 'execute') {
header('Content-Type: application/json');
$lang = $input['language'] ?? 'bash';
$code = $input['code'] ?? '';
echo json_encode(HamidCapabilities::executeCode($lang, $code));
exit;
}
// List artifacts
if ($action === 'list_artifacts') {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]);
exit;
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// GÉNÉRATION DE DOCUMENTS TÉLÉCHARGEABLES
// ═══════════════════════════════════════════════════════════════════════════════
class HamidDocuments {
private static $docsDir = '/opt/wevads/public/docs/';
public static function generateTxt($title, $content) {
$id = uniqid('doc_');
$filename = $id . '.txt';
$filepath = self::$docsDir . $filename;
file_put_contents($filepath, "=== $title ===\n\n$content");
return self::docResponse($id, $filename, $filepath, 'txt', $title);
}
public static function generateMarkdown($title, $content) {
$id = uniqid('doc_');
$filename = $id . '.md';
$filepath = self::$docsDir . $filename;
file_put_contents($filepath, "# $title\n\n$content");
return self::docResponse($id, $filename, $filepath, 'md', $title);
}
public static function generateHtml($title, $content) {
$id = uniqid('doc_');
$filename = $id . '.html';
$filepath = self::$docsDir . $filename;
$html = "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>$title</title>
<style>body{font-family:Arial,sans-serif;max-width:800px;margin:40px auto;padding:20px;line-height:1.6}
h1{color:#1a1a2e;border-bottom:2px solid #06b6d4;padding-bottom:10px}
pre{background:#f4f4f4;padding:15px;border-radius:5px}</style></head>
<body><h1>$title</h1>$content
</body></html>