Files
html/api/wevia-multi-ai.php
2026-04-16 02:28:32 +02:00

112 lines
4.8 KiB
PHP

<?php
// WEVIA Multi-AI API — Route vers le meilleur provider disponible
// Ollama local (qwen3:4b, gemma4:e4b) + cascade externe quand dispo
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
$input = json_decode(file_get_contents("php://input"), true);
$message = $input['message'] ?? $_GET['q'] ?? '';
$mode = $input['mode'] ?? 'auto'; // auto, local, creative, deep, code
$model = $input['model'] ?? 'auto';
if (!$message) {
echo json_encode([
'service' => 'WEVIA Multi-AI',
'providers' => [
'ollama_qwen3' => ['status' => 'UP', 'model' => 'weval-brain-v3', 'speed' => 'fast', 'cost' => '0€'],
'ollama_gemma4' => ['status' => 'UP', 'model' => 'gemma4:e4b', 'speed' => 'fast', 'cost' => '0€'],
'deepseek_web' => ['status' => 'pending', 'model' => 'DeepSeek-V3', 'cost' => '0€', 'unlimited' => true],
'claude' => ['status' => 'key_needed', 'model' => 'claude-sonnet-4'],
'mistral' => ['status' => 'key_needed', 'model' => 'mistral-small'],
],
'modes' => ['auto','local','creative','deep','code'],
], JSON_PRETTY_PRINT);
exit;
}
$secrets = [];
foreach (file('/etc/weval/secrets.env', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) as $l) {
if (empty(trim($l)) || $l[0] === '#') continue;
$p = strpos($l, '='); if ($p) $secrets[trim(substr($l, 0, $p))] = trim(substr($l, $p+1), " \t\"'");
}
// Model selection by mode
$models = [
'auto' => 'weval-brain-v3',
'creative' => 'gemma4:e4b',
'deep' => 'weval-brain-v3',
'code' => 'weval-brain-v3',
'local' => 'weval-brain-v3',
];
$system_prompts = [
'auto' => 'Tu es WEVIA Engine, IA souveraine de WEVAL Consulting. Réponds de façon précise et utile.',
'creative' => 'Tu es WEVIA Creative Engine. Écris avec style, créativité et profondeur. Français soutenu.',
'deep' => 'Tu es WEVIA DeepThink. Raisonne étape par étape. Analyse. Synthétise. Conclus.',
'code' => 'Tu es WEVCODE. Code COMPLET et FONCTIONNEL. Python/PHP/JS/SQL/Bash. Tests inclus.',
];
$selected_model = $model !== 'auto' ? $model : ($models[$mode] ?? 'weval-brain-v3');
$system = $system_prompts[$mode] ?? $system_prompts['auto'];
// Try providers in order
$providers = [
['name' => 'Ollama', 'url' => 'http://127.0.0.1:11434/v1/chat/completions', 'key' => 'ollama', 'model' => $selected_model],
];
// Add external providers if keys exist
if (!empty($secrets['ANTHROPIC_KEY'])) {
$providers[] = ['name' => 'Claude', 'url' => 'https://api.anthropic.com/v1/messages', 'key' => $secrets['ANTHROPIC_KEY'], 'model' => 'claude-sonnet-4-20250514', 'format' => 'anthropic'];
}
if (!empty($secrets['MISTRAL_KEY'])) {
$providers[] = ['name' => 'Mistral', 'url' => 'https://api.mistral.ai/v1/chat/completions', 'key' => $secrets['MISTRAL_KEY'], 'model' => 'mistral-small-latest'];
}
$t0 = microtime(true);
foreach ($providers as $prov) {
$ch = curl_init($prov['url']);
$headers = ['Content-Type: application/json'];
if (($prov['format'] ?? '') === 'anthropic') {
$headers[] = 'x-api-key: ' . $prov['key'];
$headers[] = 'anthropic-version: 2023-06-01';
$body = json_encode(['model' => $prov['model'], 'max_tokens' => 2000, 'system' => $system, 'messages' => [['role' => 'user', 'content' => $message]]]);
} else {
if ($prov['key'] !== 'ollama') $headers[] = 'Authorization: Bearer ' . $prov['key'];
$body = json_encode(['model' => $prov['model'], 'messages' => [['role' => 'system', 'content' => $system], ['role' => 'user', 'content' => $message]], 'max_tokens' => 2000, 'temperature' => 0.7]);
}
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => false]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code === 200 && $resp) {
$data = json_decode($resp, true);
$content = '';
if (($prov['format'] ?? '') === 'anthropic') {
$content = $data['content'][0]['text'] ?? '';
} else {
$content = $data['choices'][0]['message']['content'] ?? '';
}
if (!empty($content)) {
echo json_encode([
'content' => $content,
'provider' => $prov['name'],
'model' => $prov['model'],
'mode' => $mode,
'latency_ms' => round((microtime(true) - $t0) * 1000),
'cost' => 0,
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
}
}
}
echo json_encode(['error' => 'All providers failed', 'tried' => count($providers)]);