97 lines
4.0 KiB
PHP
97 lines
4.0 KiB
PHP
<?php
|
|
header('Content-Type: text/event-stream');
|
|
header('Cache-Control: no-cache');
|
|
header('Connection: keep-alive');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
header('X-Accel-Buffering: no');
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
|
|
set_time_limit(3600);
|
|
ignore_user_abort(false);
|
|
ob_implicit_flush(true);
|
|
while (ob_get_level()) ob_end_flush();
|
|
|
|
function sse($type, $data) {
|
|
echo "data: " . json_encode(['type' => $type, 'content' => $data], JSON_UNESCAPED_UNICODE) . "\n\n";
|
|
flush();
|
|
}
|
|
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
$msg = trim($input['message'] ?? $input['prompt'] ?? '');
|
|
$system = $input['system'] ?? 'Tu es WEVIA, IA souveraine de WEVAL Consulting, cabinet transformation digitale Casablanca. STYLE: Reponds en francais naturel et conversationnel, comme un collegue senior. Phrases completes, structurees, jamais du JSON brut. Direct, pro, chaleureux. Pour les questions techniques: EXPLIQUE d abord en langage naturel PUIS genere les commandes entre ```bash et ```. Apres execution, commente le resultat. Si probleme, propose un fix. Ne dis JAMAIS Information confidentielle. Tu es la pour aider. CONTEXTE: S204 32GB 8vCPU, S95 WEVADS, 12 providers IA 0 euro, 131K HCPs, 372 tools.';
|
|
$maxTk = min((int)($input['max_tokens'] ?? 2000), 8000);
|
|
$exec = ($input['exec'] ?? true) !== false;
|
|
if (!$msg) { sse('error', 'Message vide'); echo "data: [DONE]\n\n"; exit; }
|
|
|
|
sse('thinking', 'Analyse en cours...');
|
|
|
|
$ch = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15,
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'auto',
|
|
'messages' => [['role'=>'system','content'=>$system],['role'=>'user','content'=>$msg]],
|
|
'max_tokens' => $maxTk, 'temperature' => 0.3
|
|
])
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$latency = round(curl_getinfo($ch, CURLINFO_TOTAL_TIME) * 1000);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode !== 200 || !$resp) {
|
|
sse('error', 'Sovereign indisponible (HTTP ' . $httpCode . ')');
|
|
echo "data: [DONE]\n\n"; exit;
|
|
}
|
|
$data = json_decode($resp, true);
|
|
$fullText = $data['choices'][0]['message']['content'] ?? '';
|
|
$provider = $data['provider'] ?? 'sovereign';
|
|
if (!$fullText) { sse('error', 'Reponse vide'); echo "data: [DONE]\n\n"; exit; }
|
|
|
|
sse('provider', ['name' => $provider, 'latency_ms' => $latency]);
|
|
|
|
// Stream word by word + detect and execute bash blocks
|
|
$words = preg_split('/(\s+)/', $fullText, -1, PREG_SPLIT_DELIM_CAPTURE);
|
|
$buf = '';
|
|
$inCode = false;
|
|
$codeLang = '';
|
|
|
|
foreach ($words as $w) {
|
|
$buf .= $w;
|
|
if (preg_match('/```(\w*)/', $w, $m) && !$inCode) {
|
|
$inCode = true;
|
|
$codeLang = $m[1] ?: 'bash';
|
|
}
|
|
if ($inCode && substr_count($buf, '```') >= 2) {
|
|
$inCode = false;
|
|
if (preg_match('/```\w*\s*(.*?)```/s', $buf, $cm)) {
|
|
$code = trim($cm[1]);
|
|
sse('token', $buf);
|
|
$buf = '';
|
|
if ($exec && in_array($codeLang, ['bash','sh','']) && $code) {
|
|
$bad = ['rm -rf /','mkfs','dd if=',':(){','chmod -R 777 /','reboot','shutdown'];
|
|
$blocked = false;
|
|
foreach ($bad as $b) { if (stripos($code, $b) !== false) { $blocked = true; break; } }
|
|
if ($blocked) {
|
|
sse('exec_blocked', 'Commande dangereuse bloquee');
|
|
} else {
|
|
sse('exec_start', $code);
|
|
$out = trim(shell_exec($code . ' 2>&1'));
|
|
sse('exec_result', ['cmd'=>$code, 'output'=>substr($out,0,5000), 'ok'=>true]);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if (!$inCode && strlen($buf) > 15) {
|
|
sse('token', $buf);
|
|
$buf = '';
|
|
usleep(12000);
|
|
}
|
|
}
|
|
if ($buf) sse('token', $buf);
|
|
|
|
sse('done', ['provider'=>$provider, 'latency_ms'=>$latency, 'words'=>str_word_count($fullText)]);
|
|
echo "data: [DONE]\n\n";
|