689 lines
45 KiB
PHP
Executable File
689 lines
45 KiB
PHP
Executable File
<?php
|
||
// Connexion DB
|
||
try {
|
||
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
|
||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||
} catch (Exception $e) {
|
||
$pdo = null;
|
||
}
|
||
|
||
// Charger les configs
|
||
$config = [];
|
||
$providers = [];
|
||
if ($pdo) {
|
||
try {
|
||
$stmt = $pdo->query("SELECT config_key, config_value FROM admin.commonia_config");
|
||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||
$config[$row['config_key']] = $row['config_value'];
|
||
}
|
||
} catch (Exception $e) {}
|
||
|
||
// Compter KB
|
||
try {
|
||
$kbCount = $pdo->query("SELECT COUNT(*) FROM admin.commonia_knowledge")->fetchColumn();
|
||
} catch (Exception $e) { $kbCount = 0; }
|
||
}
|
||
|
||
// Liste des providers avec leur status
|
||
$providerList = [
|
||
'cerebras' => ['name' => 'Cerebras', 'icon' => '🧠', 'key' => 'cerebras_api_key', 'desc' => 'Llama 70B • Ultra rapide', 'type' => 'free'],
|
||
'groq' => ['name' => 'Groq', 'icon' => '🚀', 'key' => 'groq_api_key', 'desc' => 'Llama 70B • 100k/jour', 'type' => 'limited'],
|
||
'deepseek' => ['name' => 'DeepSeek', 'icon' => '🔮', 'key' => 'deepseek_api_key', 'desc' => 'DeepSeek-V3 • Intelligent', 'type' => 'free'],
|
||
'gemini' => ['name' => 'Gemini', 'icon' => '💎', 'key' => 'gemini_api_key', 'desc' => 'Google • 60 req/min', 'type' => 'limited'],
|
||
'mistral' => ['name' => 'Mistral', 'icon' => '🇫🇷', 'key' => 'mistral_api_key', 'desc' => 'Mistral Large • Français', 'type' => 'free'],
|
||
'cohere' => ['name' => 'Cohere', 'icon' => '🔶', 'key' => 'cohere_api_key', 'desc' => 'Command-R+ • RAG', 'type' => 'free'],
|
||
'hyperbolic' => ['name' => 'Hyperbolic', 'icon' => '🌀', 'key' => 'hyperbolic_api_key', 'desc' => 'Llama 70B • Gratuit', 'type' => 'free'],
|
||
'sambanova' => ['name' => 'SambaNova', 'icon' => '🚀', 'key' => 'sambanova_api_key', 'desc' => 'Llama 405B • Gratuit', 'type' => 'free'],
|
||
'claude' => ['name' => 'Claude', 'icon' => '🧠', 'key' => 'anthropic_api_key', 'desc' => 'Claude 3.5 • Premium', 'type' => 'paid'],
|
||
'chatgpt' => ['name' => 'ChatGPT', 'icon' => '🤖', 'key' => 'openai_api_key', 'desc' => 'OpenAI GPT-4', 'type' => 'paid', 'url' => 'https://platform.openai.com/api-keys'],
|
||
'copilot' => ['name' => 'Copilot', 'icon' => '🐙', 'key' => 'copilot_api_key', 'desc' => 'GitHub', 'type' => 'paid', 'url' => 'https://github.com/settings/copilot'],
|
||
'ollama' => ['name' => 'Ollama', 'icon' => '🦙', 'key' => '', 'desc' => 'Mistral 7B • Local', 'type' => 'local'],
|
||
'ollama_mini' => ['name' => 'Ollama Mini', 'icon' => '⚡', 'key' => '', 'desc' => 'Phi 3B • Local rapide', 'type' => 'local'],
|
||
];
|
||
|
||
// Compter providers actifs
|
||
$activeProviders = 0;
|
||
foreach ($providerList as $id => $p) {
|
||
if ($p['type'] === 'local' || !empty($config[$p['key']])) {
|
||
$activeProviders++;
|
||
}
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>WEVAL MIND System - Monitoring</title>
|
||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||
<style>
|
||
:root { --bg: #0f172a; --card: #1e293b; --border: #334155; --text: #e2e8f0; --muted: #94a3b8; --accent: #06b6d4; --green: #10b981; --red: #ef4444; --yellow: #f59e0b; --purple: #8b5cf6; }
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; }
|
||
|
||
.header { background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 100%); padding: 1.5rem 2rem; border-bottom: 1px solid var(--border); }
|
||
.header-content { max-width: 1400px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; }
|
||
.header-left { display: flex; align-items: center; gap: 1rem; }
|
||
.logo { font-size: 2rem; }
|
||
.title { font-size: 1.5rem; font-weight: 700; color: var(--accent); }
|
||
.subtitle { color: var(--muted); font-size: 0.85rem; }
|
||
.header-stats { display: flex; gap: 1.5rem; }
|
||
.stat-box { text-align: center; padding: 0.5rem 1rem; background: rgba(255,255,255,0.05); border-radius: 8px; }
|
||
.stat-value { font-size: 1.5rem; font-weight: 700; color: var(--green); }
|
||
.stat-label { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; }
|
||
.header-actions { display: flex; gap: 0.5rem; }
|
||
.btn { padding: 0.6rem 1rem; border-radius: 8px; border: none; cursor: pointer; font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; transition: all 0.2s; }
|
||
.btn-primary { background: var(--accent); color: white; }
|
||
.btn-primary:hover { background: #0891b2; }
|
||
.btn-outline { background: transparent; border: 1px solid var(--border); color: var(--text); }
|
||
.btn-outline:hover { border-color: var(--accent); color: var(--accent); }
|
||
.btn-danger { background: var(--red); color: white; }
|
||
.btn-success { background: var(--green); color: white; }
|
||
|
||
.main { max-width: 1400px; margin: 0 auto; padding: 1.5rem; }
|
||
|
||
.grid { display: grid; gap: 1.5rem; }
|
||
.grid-2 { grid-template-columns: repeat(2, 1fr); }
|
||
.grid-3 { grid-template-columns: repeat(3, 1fr); }
|
||
.grid-4 { grid-template-columns: repeat(4, 1fr); }
|
||
@media (max-width: 1200px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 768px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }
|
||
|
||
.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 1.25rem; }
|
||
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
|
||
.card-title { font-size: 1rem; font-weight: 600; display: flex; align-items: center; gap: 0.5rem; }
|
||
.card-badge { font-size: 0.7rem; padding: 0.25rem 0.5rem; border-radius: 4px; background: var(--accent); color: white; }
|
||
|
||
.status-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
|
||
.status-dot.green { background: var(--green); box-shadow: 0 0 8px var(--green); }
|
||
.status-dot.red { background: var(--red); box-shadow: 0 0 8px var(--red); }
|
||
.status-dot.yellow { background: var(--yellow); box-shadow: 0 0 8px var(--yellow); }
|
||
|
||
.service-list { display: flex; flex-direction: column; gap: 0.5rem; }
|
||
.service-item { display: flex; align-items: center; justify-content: space-between; padding: 0.6rem 0.75rem; background: rgba(255,255,255,0.03); border-radius: 6px; }
|
||
.service-name { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; }
|
||
.service-actions { display: flex; gap: 0.25rem; }
|
||
.service-btn { padding: 0.25rem 0.5rem; font-size: 0.7rem; border-radius: 4px; border: none; cursor: pointer; }
|
||
.service-btn.restart { background: var(--yellow); color: #000; }
|
||
.service-btn.stop { background: var(--red); color: #fff; }
|
||
|
||
.provider-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
|
||
.provider-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.6rem; background: rgba(255,255,255,0.03); border-radius: 8px; border: 1px solid transparent; cursor: pointer; transition: all 0.2s; }
|
||
.provider-item:hover { border-color: var(--accent); }
|
||
.provider-item.active { border-color: var(--green); background: rgba(16,185,129,0.1); }
|
||
.provider-item.inactive { opacity: 0.5; }
|
||
.provider-icon { font-size: 1.25rem; }
|
||
.provider-info { flex: 1; min-width: 0; }
|
||
.provider-name { font-size: 0.8rem; font-weight: 500; }
|
||
.provider-desc { font-size: 0.65rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||
|
||
.quick-links { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
|
||
.quick-link { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; padding: 1rem; background: rgba(255,255,255,0.03); border-radius: 8px; text-decoration: none; color: var(--text); transition: all 0.2s; border: 1px solid transparent; }
|
||
.quick-link:hover { border-color: var(--accent); background: rgba(6,182,212,0.1); }
|
||
.quick-link i { font-size: 1.5rem; color: var(--accent); }
|
||
.quick-link span { font-size: 0.8rem; }
|
||
|
||
.architecture-diagram { background: rgba(0,0,0,0.3); border-radius: 8px; padding: 1rem; font-family: monospace; font-size: 0.75rem; line-height: 1.6; overflow-x: auto; }
|
||
.architecture-diagram .box { display: inline-block; padding: 0.25rem 0.5rem; border-radius: 4px; margin: 0.1rem; }
|
||
.architecture-diagram .user { background: var(--purple); }
|
||
.architecture-diagram .interface { background: var(--accent); }
|
||
.architecture-diagram .api { background: var(--green); }
|
||
.architecture-diagram .brain { background: var(--yellow); color: #000; }
|
||
.architecture-diagram .provider { background: var(--red); }
|
||
.architecture-diagram .arrow { color: var(--muted); }
|
||
|
||
.modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.9); z-index: 1000; padding: 2rem; overflow-y: auto; }
|
||
.modal.show { display: block; }
|
||
.modal-content { max-width: 1000px; margin: 0 auto; background: var(--card); border-radius: 16px; padding: 2rem; }
|
||
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
|
||
.modal-close { background: none; border: none; color: var(--muted); font-size: 2rem; cursor: pointer; }
|
||
|
||
.log-box { background: #000; border-radius: 8px; padding: 1rem; font-family: monospace; font-size: 0.75rem; max-height: 200px; overflow-y: auto; }
|
||
.log-line { margin-bottom: 0.25rem; }
|
||
.log-line.info { color: var(--accent); }
|
||
.log-line.error { color: var(--red); }
|
||
.log-line.success { color: var(--green); }
|
||
|
||
.progress-bar { height: 8px; background: var(--border); border-radius: 4px; overflow: hidden; }
|
||
.progress-fill { height: 100%; transition: width 0.3s; }
|
||
.progress-fill.green { background: var(--green); }
|
||
.progress-fill.yellow { background: var(--yellow); }
|
||
.progress-fill.red { background: var(--red); }
|
||
|
||
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
||
.pulse { animation: pulse 2s infinite; }
|
||
</style>
|
||
|
||
</head>
|
||
<body>
|
||
<header class="header">
|
||
<div class="header-content">
|
||
<div class="header-left">
|
||
<div class="logo">🧞</div>
|
||
<div>
|
||
<div class="title">WEVAL MIND System</div>
|
||
<div class="subtitle">Monitoring & Administration • 89.167.40.150</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-stats">
|
||
<div class="stat-box">
|
||
<div class="stat-value"><?= $activeProviders ?>/<?= count($providerList) ?></div>
|
||
<div class="stat-label">Providers</div>
|
||
</div>
|
||
<div class="stat-box">
|
||
<div class="stat-value"><?= $kbCount ?></div>
|
||
<div class="stat-label">KB Docs</div>
|
||
</div>
|
||
<div class="stat-box">
|
||
<div class="stat-value" id="cpuLoad">--</div>
|
||
<div class="stat-label">CPU %</div>
|
||
</div>
|
||
<div class="stat-box">
|
||
<div class="stat-value" id="memLoad">--</div>
|
||
<div class="stat-label">RAM %</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-actions">
|
||
<button class="btn btn-outline" onclick="showArchitecture()"><i class="fas fa-sitemap"></i> Architecture</button>
|
||
<button class="btn btn-outline" onclick="showHelp()"><i class="fas fa-question-circle"></i> Aide</button>
|
||
<button class="btn btn-primary" onclick="runHealthCheck()"><i class="fas fa-heartbeat"></i> Health Check</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main">
|
||
<!-- Services System -->
|
||
<div class="grid grid-4" style="margin-bottom:1.5rem">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-server"></i> Services Système</div>
|
||
<button class="btn btn-outline" style="padding:0.25rem 0.5rem;font-size:0.7rem" onclick="refreshServices()"><i class="fas fa-sync"></i></button>
|
||
</div>
|
||
<div class="service-list" id="serviceList">
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-apache"></span> Apache</span><span class="service-actions"><button class="service-btn restart" onclick="restartService('apache2')">↻</button></span></div>
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-postgresql"></span> PostgreSQL</span><span class="service-actions"><button class="service-btn restart" onclick="restartService('postgresql')">↻</button></span></div>
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-redis"></span> Redis</span><span class="service-actions"><button class="service-btn restart" onclick="restartService('redis')">↻</button></span></div>
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-ollama"></span> Ollama</span><span class="service-actions"><button class="service-btn restart" onclick="restartService('ollama')">↻</button></span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-globe"></i> Apps WEVAL</div>
|
||
</div>
|
||
<div class="service-list">
|
||
<div class="service-item"><span class="service-name"><span class="status-dot green"></span> WEVAL :5821</span><a href="/" class="service-btn" style="background:var(--accent);color:#fff">Ouvrir</a></div>
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-fmgapp"></span> FMGAPP :5822</span><a href="http://89.167.40.150:5822" class="service-btn" style="background:var(--accent);color:#fff">Ouvrir</a></div>
|
||
<div class="service-item"><span class="service-name"><span class="status-dot" id="dot-bcgapp"></span> BCGAPP :5823</span><a href="http://89.167.40.150:5823" class="service-btn" style="background:var(--accent);color:#fff">Ouvrir</a></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-chart-line"></i> Ressources</div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;gap:0.75rem">
|
||
<div><div style="display:flex;justify-content:space-between;font-size:0.75rem;margin-bottom:0.25rem"><span>CPU</span><span id="cpuPercent">--%</span></div><div class="progress-bar"><div class="progress-fill green" id="cpuBar" style="width:0%"></div></div></div>
|
||
<div><div style="display:flex;justify-content:space-between;font-size:0.75rem;margin-bottom:0.25rem"><span>RAM</span><span id="memPercent">--%</span></div><div class="progress-bar"><div class="progress-fill green" id="memBar" style="width:0%"></div></div></div>
|
||
<div><div style="display:flex;justify-content:space-between;font-size:0.75rem;margin-bottom:0.25rem"><span>Disque</span><span id="diskPercent">--%</span></div><div class="progress-bar"><div class="progress-fill green" id="diskBar" style="width:0%"></div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-tools"></i> Actions Rapides</div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;gap:0.5rem">
|
||
<button class="btn btn-outline" style="width:100%;justify-content:center" onclick="clearCache()"><i class="fas fa-broom"></i> Vider Cache</button>
|
||
<button class="btn btn-outline" style="width:100%;justify-content:center" onclick="testAllProviders()"><i class="fas fa-flask"></i> Tester Providers</button>
|
||
<button class="btn btn-outline" style="width:100%;justify-content:center" onclick="viewLogs()"><i class="fas fa-file-alt"></i> Voir Logs</button>
|
||
<button class="btn btn-danger" style="width:100%;justify-content:center" onclick="emergencyRestart()"><i class="fas fa-exclamation-triangle"></i> Restart Urgence</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Providers IA -->
|
||
<div class="card" style="margin-bottom:1.5rem">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-brain"></i> Providers IA</div>
|
||
<div style="display:flex;gap:0.5rem">
|
||
<span class="card-badge" style="background:var(--green)"><?= $activeProviders ?> actifs</span>
|
||
<a href="/api-keys.php" class="btn btn-outline" style="padding:0.25rem 0.5rem;font-size:0.7rem"><i class="fas fa-key"></i> Clés API</a> <a href="/widget-admin.php" class="btn btn-outline" style="padding:0.25rem 0.5rem;font-size:0.7rem"><i class="fas fa-cog"></i> Config</a>
|
||
</div>
|
||
</div>
|
||
<div class="provider-grid">
|
||
<?php foreach ($providerList as $id => $p):
|
||
$isActive = ($p['type'] === 'local') || !empty($config[$p['key']]);
|
||
$statusClass = $isActive ? 'active' : 'inactive';
|
||
?>
|
||
<div class="provider-item <?= $statusClass ?>" onclick="testProvider('<?= $id ?>')">
|
||
<span class="status-dot <?= $isActive ? 'green' : 'red' ?>"></span>
|
||
<span class="provider-icon"><?= $p['icon'] ?></span>
|
||
<div class="provider-info">
|
||
<div class="provider-name"><?= $p['name'] ?></div>
|
||
<div class="provider-desc"><?= $p['desc'] ?></div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Interfaces & Liens -->
|
||
<div class="grid grid-2">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-desktop"></i> Interfaces WEVAL MIND</div>
|
||
</div>
|
||
<div class="quick-links">
|
||
<a href="/hamid-fullscreen.php" class="quick-link"><i class="fas fa-comments"></i><span>Chat</span></a>
|
||
<a href="/hamid-code/" class="quick-link"><i class="fas fa-code"></i><span>IDE Code</span></a>
|
||
<a href="/cli/" class="quick-link"><i class="fas fa-terminal"></i><span>CLI Agent</span></a>
|
||
<a href="/" class="quick-link"><i class="fas fa-robot"></i><span>Widget</span></a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title"><i class="fas fa-cogs"></i> Administration</div>
|
||
</div>
|
||
<div class="quick-links">
|
||
<a href="/widget-admin.php" class="quick-link"><i class="fas fa-sliders-h"></i><span>Config IA</span></a>
|
||
<a href="/widget-admin.php#kb" class="quick-link"><i class="fas fa-book"></i><span>Knowledge Base</span></a>
|
||
<a href="/commonia/commonia-brain.php?providers" class="quick-link"><i class="fas fa-plug"></i><span>API Status</span></a>
|
||
<a href="/adminer.php" class="quick-link"><i class="fas fa-database"></i><span>Database</span></a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- Modal Architecture -->
|
||
<div class="modal" id="architectureModal">
|
||
<div class="modal-content" style="max-width:1100px">
|
||
<div class="modal-header">
|
||
<h2 style="color:var(--accent)"><i class="fas fa-sitemap"></i> Architecture WEVAL MIND System</h2>
|
||
<button class="modal-close" onclick="hideModal('architectureModal')">×</button>
|
||
</div>
|
||
<div class="architecture-diagram">
|
||
<pre style="color:var(--text);margin:0">
|
||
|
||
🧞 WEVAL MIND SYSTEM │
|
||
89.167.40.150 (Hetzner) │
|
||
|
||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||
│ 💬 Chat │ │ 💻 IDE Code │ │ 🖥️ CLI Agent │ │ 🧞 Widget │
|
||
│ Fullscreen │ │ VS Code-like │ │ Terminal │ │ Dashboard │
|
||
│ :5821/ │ │ :5821/ │ │ :5821/cli/ │ │ :5821/ │
|
||
│ hamid-full.. │ │ hamid-code/ │ │ │ │ │
|
||
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
||
│ │ │ │
|
||
└────────────────────┴────────────────────┴────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────┐
|
||
│ 📡 /hamid-api.php │
|
||
│ Point d'entrée unifié │
|
||
│ • Reçoit message+provider│
|
||
│ • Charge KB si activé │
|
||
│ • Détecte génération docs│
|
||
└─────────────┬───────────────┘
|
||
│
|
||
┌─────────────────────┼─────────────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
|
||
│ 📚 Knowledge Base │ │ 🧠 commonia-brain │ │ 🛠️ ia-tools.php │
|
||
│ PostgreSQL │ │ Cerveau Multi-IA │ │ Génération docs │
|
||
│ admin.commonia_ │ │ • System prompt │ │ • PDF, PPTX │
|
||
│ knowledge (141) │ │ • Auto-fallback │ │ • XLSX, DOCX │
|
||
└───────────────────┘ │ • Routing │ │ • QR Code │
|
||
└─────────┬─────────┘ └───────────────────┘
|
||
│
|
||
┌────────────────────────────────┼────────────────────────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌───────────────┐ ┌───────────────┐
|
||
☁️ CLOUD APIs │ │ 🦙 LOCAL │ │ 💾 DATABASE │
|
||
├───────────────┤ ├───────────────┤
|
||
🧠 Cerebras │ │ Ollama:11434 │ │ PostgreSQL │
|
||
🚀 Groq │ │ • mistral:7b │ │ • adx_system │
|
||
🔮 DeepSeek │ │ • phi:latest │ │ • adx_clients │
|
||
🇫🇷 Mistral │ └───────────────┘ │ │
|
||
🌀 Hyperbolic │ │ Tables: │
|
||
🔶 Cohere │ │ • commonia_ │
|
||
💎 Gemini │ │ config │
|
||
🧠 Claude │ │ • commonia_ │
|
||
🚀 SambaNova │ │ knowledge │
|
||
└───────────────┘
|
||
|
||
🔄 FLUX DE DONNÉES │
|
||
|
||
1. User → Interface (Chat/Code/CLI/Widget) │
|
||
2. Interface → POST /hamid-api.php (message + provider) │
|
||
3. API → Charge Knowledge Base (141 docs) si provider != ollama_mini │
|
||
4. API → Détecte si génération document (PDF/PPTX/etc) → ia-tools.php │
|
||
5. API → Sinon appelle commonia-brain.php avec message + contexte KB │
|
||
6. Brain → Construit prompt avec CLAUDE_BRAIN (system prompt) │
|
||
7. Brain → Appelle provider sélectionné (ou fallback si erreur) │
|
||
8. Brain → Retourne réponse JSON {success, response, provider, duration_ms, kb_used} │
|
||
9. Interface → Affiche réponse avec tags [PROVIDER • XXXms • 📚 KB] │
|
||
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Aide -->
|
||
<div class="modal" id="helpModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2 style="color:var(--accent)"><i class="fas fa-question-circle"></i> Guide Complet WEVAL MIND</h2>
|
||
<button class="modal-close" onclick="hideModal('helpModal')">×</button>
|
||
</div>
|
||
<div style="display:grid;gap:1.5rem">
|
||
<div>
|
||
<h3 style="color:var(--green);margin-bottom:0.75rem">✅ PROVIDERS GRATUITS ILLIMITÉS</h3>
|
||
<table style="width:100%;border-collapse:collapse;font-size:0.85rem">
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🧠 <b>Cerebras</b></td><td>Llama 3.3 70B</td><td style="color:var(--green)">⚡⚡⚡ 8000 tok/s</td><td>Le meilleur choix général</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🔮 <b>DeepSeek</b></td><td>DeepSeek-V3</td><td style="color:var(--accent)">⚡ Intelligent</td><td>Idéal pour le code</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🇫🇷 <b>Mistral</b></td><td>Mistral Large</td><td style="color:var(--accent)">⚡ Rapide</td><td>Excellent en français</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🌀 <b>Hyperbolic</b></td><td>Llama 70B</td><td style="color:var(--accent)">⚡ Rapide</td><td>Bon raisonnement</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🔶 <b>Cohere</b></td><td>Command-R+</td><td style="color:var(--accent)">⚡ Rapide</td><td>Spécialisé RAG/recherche</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🦙 <b>Ollama</b></td><td>Mistral 7B</td><td style="color:var(--yellow)">~10s Local</td><td>100% privé, hors-ligne</td></tr>
|
||
<tr><td style="padding:0.5rem">⚡ <b>Ollama Mini</b></td><td>Phi 3B</td><td style="color:var(--green)">~2s Local</td><td>Tests rapides</td></tr>
|
||
</table>
|
||
</div>
|
||
<div>
|
||
<h3 style="color:var(--yellow);margin-bottom:0.75rem">⚠️ PROVIDERS LIMITÉS</h3>
|
||
<table style="width:100%;border-collapse:collapse;font-size:0.85rem">
|
||
<tr style="border-bottom:1px solid var(--border)"><td style="padding:0.5rem">🚀 <b>Groq</b></td><td>Llama 70B</td><td>100k tokens/jour</td></tr>
|
||
<tr><td style="padding:0.5rem">💎 <b>Gemini</b></td><td>Gemini 1.5</td><td>60 req/min</td></tr>
|
||
</table>
|
||
</div>
|
||
<div>
|
||
<h3 style="color:var(--red);margin-bottom:0.75rem">💰 PROVIDERS PAYANTS</h3>
|
||
<table style="width:100%;border-collapse:collapse;font-size:0.85rem">
|
||
<tr><td style="padding:0.5rem">🧠 <b>Claude</b></td><td>Claude Sonnet 4</td><td>Le plus intelligent</td></tr>
|
||
</table>
|
||
</div>
|
||
<div>
|
||
<h3 style="color:var(--accent);margin-bottom:0.75rem">🎯 RECOMMANDATIONS PAR INTERFACE</h3>
|
||
<ul style="margin:0;padding-left:1.5rem;line-height:2">
|
||
<li><b>Chat Fullscreen</b> → 🧠 Cerebras ou 🇫🇷 Mistral (conversation fluide)</li>
|
||
<li><b>IDE Code</b> → 🔮 DeepSeek ou 🧠 Claude (analyse de code)</li>
|
||
<li><b>CLI Agent</b> → 🧠 Cerebras ou 🔮 DeepSeek (commandes système)</li>
|
||
<li><b>Widget Dashboard</b> → ⚡ Ollama Mini (réponses rapides)</li>
|
||
<li><b>Documents longs</b> → 🧠 Claude ou 🔶 Cohere</li>
|
||
<li><strong>Vision</strong> → 🔴 Claude (analyse d'images)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Logs -->
|
||
<div class="modal" id="logsModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2 style="color:var(--accent)"><i class="fas fa-file-alt"></i> Logs Système</h2>
|
||
<button class="modal-close" onclick="hideModal('logsModal')">×</button>
|
||
</div>
|
||
<div class="log-box" id="logContent">Chargement...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Test Results -->
|
||
<div class="modal" id="testModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2 style="color:var(--accent)"><i class="fas fa-flask"></i> Test des Providers</h2>
|
||
<button class="modal-close" onclick="hideModal('testModal')">×</button>
|
||
</div>
|
||
<div id="testResults">Lancement des tests...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Refresh services status
|
||
async function refreshServices() {
|
||
try {
|
||
const res = await fetch('/cli/api.php?action=scan');
|
||
const data = await res.json();
|
||
if (data.success) {
|
||
const s = data.scan;
|
||
// Services
|
||
for (const [name, status] of Object.entries(s.services)) {
|
||
const dot = document.getElementById('dot-' + name);
|
||
if (dot) {
|
||
dot.className = 'status-dot ' + (status === 'active' ? 'green' : 'red');
|
||
}
|
||
}
|
||
// Resources
|
||
const cpu = Math.min(Math.round(s.load[0] * 25), 100);
|
||
document.getElementById('cpuLoad').textContent = cpu + '%';
|
||
document.getElementById('cpuPercent').textContent = cpu + '%';
|
||
document.getElementById('cpuBar').style.width = cpu + '%';
|
||
document.getElementById('cpuBar').className = 'progress-fill ' + (cpu > 80 ? 'red' : cpu > 60 ? 'yellow' : 'green');
|
||
|
||
if (s.memory.percent) {
|
||
document.getElementById('memLoad').textContent = s.memory.percent + '%';
|
||
document.getElementById('memPercent').textContent = s.memory.percent + '%';
|
||
document.getElementById('memBar').style.width = s.memory.percent + '%';
|
||
}
|
||
if (s.disk.percent) {
|
||
document.getElementById('diskPercent').textContent = s.disk.percent + '%';
|
||
document.getElementById('diskBar').style.width = s.disk.percent + '%';
|
||
}
|
||
}
|
||
} catch (e) { console.error(e); }
|
||
}
|
||
|
||
function showModal(id) { document.getElementById(id).classList.add('show'); }
|
||
function hideModal(id) { document.getElementById(id).classList.remove('show'); }
|
||
function showArchitecture() { showModal('architectureModal'); }
|
||
function showHelp() { showModal('helpModal'); }
|
||
|
||
async function testProvider(provider) {
|
||
showModal('testModal');
|
||
document.getElementById('testResults').innerHTML = '<div style="color:var(--accent)">Test de ' + provider + '...</div>';
|
||
try {
|
||
const fd = new FormData();
|
||
fd.append('message', 'Réponds juste "OK" en un mot');
|
||
fd.append('provider', provider);
|
||
const start = Date.now();
|
||
const res = await fetch('/hamid-api.php', { method: 'POST', body: fd });
|
||
const data = await res.json();
|
||
const duration = Date.now() - start;
|
||
if (data.success) {
|
||
document.getElementById('testResults').innerHTML = '<div class="log-line success">✅ ' + provider.toUpperCase() + ' fonctionne!</div><div>Réponse: ' + data.response.substring(0, 100) + '</div><div>Temps: ' + duration + 'ms</div>';
|
||
} else {
|
||
document.getElementById('testResults').innerHTML = '<div class="log-line error">❌ Erreur: ' + (data.error || 'Inconnu') + '</div>';
|
||
}
|
||
} catch (e) {
|
||
document.getElementById('testResults').innerHTML = '<div class="log-line error">❌ Erreur: ' + e.message + '</div>';
|
||
}
|
||
}
|
||
|
||
async function testAllProviders() {
|
||
showModal('testModal');
|
||
const providers = ['cerebras', 'groq', 'deepseek', 'gemini', 'mistral', 'cohere', 'hyperbolic', 'ollama', 'claude'];
|
||
let html = '<div style="display:grid;gap:0.5rem">';
|
||
document.getElementById('testResults').innerHTML = html + '<div>Test en cours...</div></div>';
|
||
|
||
for (const p of providers) {
|
||
try {
|
||
const fd = new FormData();
|
||
fd.append('message', 'OK');
|
||
fd.append('provider', p);
|
||
const start = Date.now();
|
||
const res = await fetch('/hamid-api.php', { method: 'POST', body: fd });
|
||
const data = await res.json();
|
||
const duration = Date.now() - start;
|
||
html += data.success
|
||
? '<div class="log-line success">✅ ' + p + ' - ' + duration + 'ms</div>'
|
||
: '<div class="log-line error">❌ ' + p + ' - ' + (data.error || 'Erreur').substring(0, 50) + '</div>';
|
||
} catch (e) {
|
||
html += '<div class="log-line error">❌ ' + p + ' - ' + e.message + '</div>';
|
||
}
|
||
document.getElementById('testResults').innerHTML = html + '</div>';
|
||
}
|
||
}
|
||
|
||
async function viewLogs() {
|
||
showModal('logsModal');
|
||
try {
|
||
const res = await fetch('/cli/api.php?action=logs&log=wevads&lines=50');
|
||
const data = await res.json();
|
||
if (data.success) {
|
||
document.getElementById('logContent').innerHTML = data.content.split('\n').map(l => '<div class="log-line">' + l + '</div>').join('');
|
||
}
|
||
} catch (e) {
|
||
document.getElementById('logContent').innerHTML = '<div class="log-line error">Erreur: ' + e.message + '</div>';
|
||
}
|
||
}
|
||
|
||
async function restartService(service) {
|
||
if (!confirm('Redémarrer ' + service + '?')) return;
|
||
try {
|
||
const res = await fetch('/cli/api.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||
body: 'action=exec&command=systemctl restart ' + service
|
||
});
|
||
alert('Service ' + service + ' redémarré');
|
||
refreshServices();
|
||
} catch (e) { alert('Erreur: ' + e.message); }
|
||
}
|
||
|
||
function clearCache() {
|
||
alert('Cache vidé!');
|
||
}
|
||
|
||
function emergencyRestart() {
|
||
if (!confirm('⚠️ ATTENTION: Redémarrer tous les services IA?\n\nCela va interrompre toutes les requêtes en cours.')) return;
|
||
alert('Restart en cours...');
|
||
}
|
||
|
||
function runHealthCheck() {
|
||
testAllProviders();
|
||
}
|
||
|
||
// Init
|
||
refreshServices();
|
||
setInterval(refreshServices, 30000);
|
||
</script>
|
||
|
||
<div id="guideModal" class="modal" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);z-index:1000;overflow-y:auto">
|
||
<div style="max-width:900px;margin:50px auto;background:#1a1a2e;border-radius:15px;padding:30px;color:#fff">
|
||
<button onclick="document.getElementById('guideModal').style.display='none'" style="float:right;background:#ff4757;border:none;color:#fff;padding:10px 15px;border-radius:5px;cursor:pointer">✕ Fermer</button>
|
||
<h2>🤖 Guide Complet WEVAL MIND</h2>
|
||
|
||
<h3>✅ PROVIDERS GRATUITS ILLIMITÉS</h3>
|
||
<table style="width:100%;border-collapse:collapse;margin:10px 0">
|
||
<tr style="background:#2d3436"><th style="padding:10px;text-align:left">Provider</th><th>Modèle</th><th>Vitesse</th><th>Force</th><th>KB Max</th></tr>
|
||
<tr style="background:#0a0a15"><td>🔶 <b>Cerebras</b></td><td>Llama 3.3 70B</td><td>⚡⚡⚡ 8000 tok/s</td><td>Meilleur choix général</td><td>12 × 1000</td></tr>
|
||
<tr style="background:#12121f"><td>🔮 <b>DeepSeek</b></td><td>DeepSeek-V3</td><td>⚡ Intelligent</td><td>Idéal pour le code</td><td>15 × 1200</td></tr>
|
||
<tr style="background:#0a0a15"><td>🇫🇷 <b>Mistral</b></td><td>Mistral Large</td><td>⚡ Rapide</td><td>Excellent en français</td><td>12 × 1000</td></tr>
|
||
<tr style="background:#12121f"><td>🔶 <b>Cohere</b></td><td>Command-R+</td><td>⚡ Rapide</td><td>Spécialisé RAG/recherche</td><td>10 × 800</td></tr>
|
||
<tr style="background:#0a0a15"><td>🦙 <b>Ollama</b></td><td>Mistral 7B</td><td>~15s Local</td><td>100% privé, hors-ligne</td><td>10 × 800</td></tr>
|
||
<tr style="background:#12121f"><td>⚡ <b>Ollama Mini</b></td><td>TinyLlama 1B</td><td>~3s Local</td><td>Tests rapides</td><td>3 × 300</td></tr>
|
||
</table>
|
||
|
||
<h3>⚠️ PROVIDERS LIMITÉS</h3>
|
||
<table style="width:100%;border-collapse:collapse;margin:10px 0">
|
||
<tr style="background:#2d3436"><th style="padding:10px;text-align:left">Provider</th><th>Limite</th><th>Reset</th></tr>
|
||
<tr style="background:#0a0a15"><td>⚡ Groq</td><td>100k tokens/jour</td><td>Minuit UTC</td></tr>
|
||
<tr style="background:#12121f"><td>💎 Gemini</td><td>60 req/min</td><td>Par minute</td></tr>
|
||
<tr style="background:#0a0a15"><td>🚀 SambaNova</td><td>Variable</td><td>Quotidien</td></tr>
|
||
</table>
|
||
|
||
<h3>💰 PROVIDERS PAYANTS</h3>
|
||
<table style="width:100%;border-collapse:collapse;margin:10px 0">
|
||
<tr style="background:#2d3436"><th style="padding:10px;text-align:left">Provider</th><th>Modèle</th><th>Force</th><th>KB Max</th></tr>
|
||
<tr style="background:#0a0a15"><td>🧠 <b>Claude</b></td><td>Claude Sonnet 4</td><td>Le plus intelligent + Vision 👁️</td><td>20 × 1500</td></tr>
|
||
<tr style="background:#12121f"><td>💚 ChatGPT</td><td>GPT-4</td><td>Polyvalent</td><td>15 × 1200</td></tr>
|
||
</table>
|
||
|
||
<h3>🎯 RECOMMANDATIONS PAR USAGE</h3>
|
||
<ul style="line-height:2">
|
||
<li><b>💬 Chat rapide</b> → 🔶 Cerebras (ultra-rapide)</li>
|
||
<li><b>💻 Analyse de code</b> → 🔮 DeepSeek ou 🧠 Claude</li>
|
||
<li><b>📝 Documents longs</b> → 🧠 Claude (20 KB, 8192 tokens)</li>
|
||
<li><b>🇫🇷 Français</b> → 🇫🇷 Mistral</li>
|
||
<li><b>👁️ Analyse d'images</b> → 🧠 Claude (seul avec vision)</li>
|
||
<li><b>🔒 Confidentialité</b> → 🦙 Ollama (100% local)</li>
|
||
<li><b>⚡ Tests rapides</b> → ⚡ Ollama Mini</li>
|
||
</ul>
|
||
|
||
<h3>⚙️ PARAMÈTRES KB DYNAMIQUES</h3>
|
||
<p>Le nombre de résultats KB s'adapte automatiquement au provider :</p>
|
||
<table style="width:100%;border-collapse:collapse;margin:10px 0">
|
||
<tr style="background:#2d3436"><th style="padding:10px">Provider</th><th>Résultats</th><th>Chars/résultat</th><th>Total max</th></tr>
|
||
<tr style="background:#0a0a15"><td>Claude</td><td>20</td><td>1500</td><td>30 000 chars</td></tr>
|
||
<tr style="background:#12121f"><td>DeepSeek/Gemini</td><td>15</td><td>1200</td><td>18 000 chars</td></tr>
|
||
<tr style="background:#0a0a15"><td>Cerebras/Mistral</td><td>12</td><td>1000</td><td>12 000 chars</td></tr>
|
||
<tr style="background:#12121f"><td>Groq</td><td>10</td><td>800</td><td>8 000 chars</td></tr>
|
||
<tr style="background:#0a0a15"><td>Ollama Mini</td><td>3</td><td>300</td><td>900 chars</td></tr>
|
||
</table>
|
||
|
||
<h3>🔧 DÉPANNAGE RAPIDE</h3>
|
||
<div style="display:flex;flex-wrap:wrap;gap:10px;margin:15px 0">
|
||
<button onclick="restartProvider('ollama')" style="background:#3498db;border:none;color:#fff;padding:10px 20px;border-radius:5px;cursor:pointer">🔄 Restart Ollama</button>
|
||
<button onclick="restartProvider('apache')" style="background:#e67e22;border:none;color:#fff;padding:10px 20px;border-radius:5px;cursor:pointer">🔄 Restart Apache</button>
|
||
<button onclick="testAllProviders()" style="background:#27ae60;border:none;color:#fff;padding:10px 20px;border-radius:5px;cursor:pointer">🧪 Tester Tous</button>
|
||
<button onclick="clearCache()" style="background:#9b59b6;border:none;color:#fff;padding:10px 20px;border-radius:5px;cursor:pointer">🗑️ Vider Cache</button>
|
||
</div>
|
||
|
||
<h3>❌ MESSAGES D'ERREUR</h3>
|
||
<table style="width:100%;border-collapse:collapse;margin:10px 0">
|
||
<tr style="background:#2d3436"><th style="padding:10px">Erreur</th><th>Signification</th><th>Solution</th></tr>
|
||
<tr style="background:#0a0a15"><td>❌ Plus de crédits</td><td>Quota épuisé</td><td>Changer de provider</td></tr>
|
||
<tr style="background:#12121f"><td>⏳ Limite atteinte</td><td>Rate limit</td><td>Attendre ou changer</td></tr>
|
||
<tr style="background:#0a0a15"><td>🔑 Clé invalide</td><td>API key incorrecte</td><td>Vérifier Config IA</td></tr>
|
||
<tr style="background:#12121f"><td>📦 Message trop long</td><td>Contexte KB trop grand</td><td>Utiliser Claude</td></tr>
|
||
<tr style="background:#0a0a15"><td>🔧 Indisponible</td><td>Serveur down</td><td>Réessayer plus tard</td></tr>
|
||
</table>
|
||
|
||
<h3>📊 STATUT ACTUEL</h3>
|
||
<div id="providerStatus" style="background:#0a0a15;padding:15px;border-radius:10px;margin:10px 0">
|
||
Cliquez sur "🧪 Tester Tous" pour voir le statut en temps réel.
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function restartProvider(service) {
|
||
if(confirm("Redémarrer " + service + " ?")) {
|
||
fetch("ia-api.php?action=restart&service=" + service)
|
||
.then(r => r.json())
|
||
.then(d => alert(d.message || "Redémarré!"))
|
||
.catch(e => alert("Erreur: " + e));
|
||
}
|
||
}
|
||
function testAllProviders() {
|
||
document.getElementById("providerStatus").innerHTML = "⏳ Test en cours...";
|
||
fetch("ia-api.php?action=test_providers")
|
||
.then(r => r.json())
|
||
.then(d => {
|
||
let html = "<table style='width:100%'>";
|
||
for(let p in d) {
|
||
let status = d[p].ok ? "✅" : "❌";
|
||
let time = d[p].time ? d[p].time + "ms" : d[p].error;
|
||
html += "<tr><td>" + p + "</td><td>" + status + "</td><td>" + time + "</td></tr>";
|
||
}
|
||
html += "</table>";
|
||
document.getElementById("providerStatus").innerHTML = html;
|
||
})
|
||
.catch(e => document.getElementById("providerStatus").innerHTML = "Erreur: " + e);
|
||
}
|
||
function clearCache() {
|
||
fetch("ia-api.php?action=clear_cache")
|
||
.then(r => r.json())
|
||
.then(d => alert(d.message || "Cache vidé!"))
|
||
.catch(e => alert("Erreur: " + e));
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|