237 lines
6.7 KiB
PHP
Executable File
237 lines
6.7 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Composant Sélecteur Multi-IA pour WEVAL MIND
|
|
* À inclure dans les interfaces
|
|
*/
|
|
|
|
require_once __DIR__ . '/hamid-brain.php';
|
|
$brain = new HamidBrain();
|
|
$providers = $brain->getAvailableProviders();
|
|
$defaultProvider = $brain->getConfig('default_provider', 'groq');
|
|
?>
|
|
|
|
<!-- CSS du sélecteur -->
|
|
<style>
|
|
.ai-selector-container {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.ai-selector {
|
|
position: relative;
|
|
min-width: 160px;
|
|
}
|
|
|
|
.ai-selector select {
|
|
appearance: none;
|
|
width: 100%;
|
|
padding: 8px 36px 8px 12px;
|
|
background: var(--bg-input, #3c3c3c);
|
|
border: 1px solid var(--border, #555);
|
|
border-radius: 8px;
|
|
color: var(--text, #fff);
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
outline: none;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.ai-selector select:hover {
|
|
border-color: var(--accent, #0078d4);
|
|
}
|
|
|
|
.ai-selector select:focus {
|
|
border-color: var(--accent, #0078d4);
|
|
box-shadow: 0 0 0 3px rgba(0, 120, 212, 0.2);
|
|
}
|
|
|
|
.ai-selector::after {
|
|
content: '▼';
|
|
position: absolute;
|
|
right: 12px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
font-size: 10px;
|
|
color: var(--text-dim, #888);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.ai-selector select option {
|
|
background: var(--bg-dark, #1e1e1e);
|
|
color: var(--text, #fff);
|
|
padding: 8px;
|
|
}
|
|
|
|
.ai-selector select option:disabled {
|
|
color: var(--text-dim, #666);
|
|
}
|
|
|
|
.ai-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 12px;
|
|
color: var(--text-dim, #888);
|
|
}
|
|
|
|
.ai-status .dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: var(--success, #4caf50);
|
|
}
|
|
|
|
.ai-status .dot.warning { background: var(--warning, #ff9800); }
|
|
.ai-status .dot.error { background: var(--error, #f44336); }
|
|
|
|
.ai-auto-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 12px;
|
|
color: var(--text-dim, #888);
|
|
}
|
|
|
|
.ai-auto-toggle input[type="checkbox"] {
|
|
width: 16px;
|
|
height: 16px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.ai-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 2px 8px;
|
|
border-radius: 10px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.ai-badge.free { background: #1b5e20; color: #a5d6a7; }
|
|
.ai-badge.paid { background: #e65100; color: #ffcc80; }
|
|
</style>
|
|
|
|
<!-- HTML du sélecteur -->
|
|
<div class="ai-selector-container" id="aiSelectorContainer">
|
|
<div class="ai-selector">
|
|
<select id="aiProviderSelect" onchange="onProviderChange(this.value)">
|
|
<optgroup label="🆓 Gratuits">
|
|
<?php foreach ($providers as $id => $p): ?>
|
|
<?php if ($p['free'] && $p['type'] === 'cloud'): ?>
|
|
<option value="<?= $id ?>" <?= $id === $defaultProvider ? 'selected' : '' ?> <?= !$p['configured'] ? 'disabled' : '' ?>>
|
|
<?= $p['icon'] ?> <?= $p['name'] ?> <?= !$p['configured'] ? '(non configuré)' : '' ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</optgroup>
|
|
<optgroup label="💰 Premium">
|
|
<?php foreach ($providers as $id => $p): ?>
|
|
<?php if (!$p['free'] && $p['type'] === 'cloud'): ?>
|
|
<option value="<?= $id ?>" <?= $id === $defaultProvider ? 'selected' : '' ?> <?= !$p['configured'] ? 'disabled' : '' ?>>
|
|
<?= $p['icon'] ?> <?= $p['name'] ?> <?= !$p['configured'] ? '(non configuré)' : '' ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</optgroup>
|
|
<optgroup label="🏠 Local">
|
|
<?php foreach ($providers as $id => $p): ?>
|
|
<?php if ($p['type'] === 'local'): ?>
|
|
<option value="<?= $id ?>" <?= $id === $defaultProvider ? 'selected' : '' ?> <?= !$p['configured'] ? 'disabled' : '' ?>>
|
|
<?= $p['icon'] ?> <?= $p['name'] ?> <?= !$p['configured'] ? '(non configuré)' : '' ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</optgroup>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ai-auto-toggle" title="Si le provider choisi échoue, essayer automatiquement les autres">
|
|
<input type="checkbox" id="aiAutoFallback" checked>
|
|
<label for="aiAutoFallback">Auto-fallback</label>
|
|
</div>
|
|
|
|
<div class="ai-status" id="aiStatus">
|
|
<span class="dot"></span>
|
|
<span id="aiStatusText">Prêt</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript -->
|
|
<script>
|
|
const AI_PROVIDERS = <?= json_encode($providers) ?>;
|
|
let currentProvider = '<?= $defaultProvider ?>';
|
|
let autoFallback = true;
|
|
|
|
function onProviderChange(provider) {
|
|
currentProvider = provider;
|
|
const p = AI_PROVIDERS[provider];
|
|
updateAIStatus('ready', `${p.icon} ${p.name}`);
|
|
console.log('Provider changé:', provider);
|
|
}
|
|
|
|
function updateAIStatus(status, text) {
|
|
const dot = document.querySelector('#aiStatus .dot');
|
|
const statusText = document.getElementById('aiStatusText');
|
|
|
|
dot.className = 'dot';
|
|
if (status === 'loading') {
|
|
dot.classList.add('warning');
|
|
statusText.textContent = text || 'Chargement...';
|
|
} else if (status === 'error') {
|
|
dot.classList.add('error');
|
|
statusText.textContent = text || 'Erreur';
|
|
} else {
|
|
statusText.textContent = text || 'Prêt';
|
|
}
|
|
}
|
|
|
|
function getSelectedProvider() {
|
|
return document.getElementById('aiProviderSelect').value;
|
|
}
|
|
|
|
function isAutoFallbackEnabled() {
|
|
return document.getElementById('aiAutoFallback').checked;
|
|
}
|
|
|
|
// API call helper
|
|
async function callHamidBrain(message, toolsContext = '') {
|
|
const provider = getSelectedProvider();
|
|
const autoFb = isAutoFallbackEnabled();
|
|
|
|
updateAIStatus('loading', 'Réflexion...');
|
|
|
|
try {
|
|
const res = await fetch('/hamid-brain.php', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({
|
|
message: message,
|
|
provider: provider,
|
|
tools_context: toolsContext,
|
|
auto_fallback: autoFb
|
|
})
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
const usedProvider = AI_PROVIDERS[data.provider];
|
|
updateAIStatus('ready', `${usedProvider?.icon || '🤖'} ${usedProvider?.name || data.provider}`);
|
|
if (data.fallback_used) {
|
|
console.log('Fallback utilisé:', data.provider);
|
|
}
|
|
} else {
|
|
updateAIStatus('error', 'Erreur');
|
|
}
|
|
|
|
return data;
|
|
} catch (e) {
|
|
updateAIStatus('error', 'Erreur connexion');
|
|
return {success: false, error: e.message};
|
|
}
|
|
}
|
|
</script>
|
|
|