Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
OPTIMIZATIONS per API: - docx: 4000->2800 tokens timeout 60s - xlsx: 4500->3200 tokens timeout 70s - pptx: 4500->3500 tokens timeout 75s - react: 6000->4500 tokens timeout 90s - 3d: 6000->4500 tokens timeout 90s - dataviz: 7000->5000 tokens timeout 100s - site: 12000->8000 tokens timeout 120s - sql: 2000->1500 tokens timeout 40s - brainstorm: 1200->800 tokens timeout 30s - translate-code: 3500->2500 tokens timeout 60s RETRY HELPER: - wvia_llm_retry_once() avec llama-3.3-70b fallback - Active si curl 503 sovereign - 1 retry max (latency cushion) TESTED LIVE: - DOCX: 38KB 7 sections OK - SQL: PostgreSQL array_agg LIMIT GROUP BY OK - Gallery: 1 doc tracked auto
109 lines
4.0 KiB
PHP
109 lines
4.0 KiB
PHP
<?php
|
|
/**
|
|
* ambre-tool-sql.php — NL → SQL generator
|
|
*/
|
|
header('Content-Type: application/json');
|
|
|
|
/* OPT_V2_RETRY - retry once on 503 with simpler model */
|
|
if (!function_exists('wvia_llm_retry_once')) {
|
|
function wvia_llm_retry_once($payload) {
|
|
$payload['model'] = 'llama-3.3-70b';
|
|
$ch = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_TIMEOUT => 60,
|
|
]);
|
|
$r = curl_exec($ch);
|
|
$c = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
return [$c, $r];
|
|
}
|
|
}
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['ok'=>false,'error'=>'POST only']); exit; }
|
|
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
$query = trim($input['query'] ?? $input['topic'] ?? '');
|
|
$dialect = $input['dialect'] ?? 'postgresql';
|
|
if (strlen($query) < 3) { echo json_encode(['ok'=>false,'error'=>'query too short']); exit; }
|
|
$query = substr($query, 0, 800);
|
|
|
|
$prompt = "Expert SQL $dialect. Traduis la demande en langue naturelle en SQL:\n\n\"$query\"\n\n"
|
|
. "Retourne UNIQUEMENT un JSON:\n"
|
|
. "{\n"
|
|
. " \"sql\": \"SELECT ... FROM ... WHERE ...;\",\n"
|
|
. " \"explanation\": \"Bref explication de ce que fait la requete\",\n"
|
|
. " \"tables_needed\": [\"table1\",\"table2\"],\n"
|
|
. " \"dialect\": \"$dialect\",\n"
|
|
. " \"complexity\": \"simple|medium|complex\",\n"
|
|
. " \"suggested_indexes\": [\"CREATE INDEX ...\"]\n"
|
|
. "}\n\n"
|
|
. "IMPORTANT:\n"
|
|
. "- SQL valide et optimise\n"
|
|
. "- Utiliser jointures appropriees (INNER/LEFT/RIGHT)\n"
|
|
. "- Mettre ORDER BY si sens\n"
|
|
. "- Preciser LIMIT si pertinent\n"
|
|
. "- Si agrecation, utiliser GROUP BY + HAVING\n"
|
|
. "- Explanation en francais\n"
|
|
. "- JSON UNIQUEMENT, aucun texte avant/apres";
|
|
|
|
$ch = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'auto',
|
|
'messages' => [['role'=>'user', 'content'=>$prompt]],
|
|
'max_tokens' => 1500, 'temperature' => 0.3
|
|
]),
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_TIMEOUT => 60,
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($http !== 200) {
|
|
/* OPT_V2_RETRY - try once with simpler model */
|
|
list($http, $resp) = wvia_llm_retry_once([
|
|
'messages' => [['role'=>'user', 'content'=>$prompt]],
|
|
'max_tokens' => 1500,
|
|
'temperature' => 0.6
|
|
]);
|
|
if ($http !== 200) {
|
|
echo json_encode(['ok'=>false,'error'=>"LLM HTTP $http (after retry)"]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$data = json_decode($resp, true);
|
|
$content_raw = $data['choices'][0]['message']['content'] ?? '';
|
|
|
|
// Balanced JSON extract
|
|
if (preg_match('/```(?:json)?\s*\n?(.*?)\n?```/s', $content_raw, $m)) { $content_raw = $m[1]; }
|
|
$jstart = strpos($content_raw, '{');
|
|
if ($jstart !== false) {
|
|
$depth = 0; $jend = -1;
|
|
for ($i = $jstart; $i < strlen($content_raw); $i++) {
|
|
if ($content_raw[$i] === '{') $depth++;
|
|
elseif ($content_raw[$i] === '}') { $depth--; if ($depth === 0) { $jend = $i; break; } }
|
|
}
|
|
if ($jend > $jstart) $content_raw = substr($content_raw, $jstart, $jend - $jstart + 1);
|
|
}
|
|
$result = json_decode($content_raw, true);
|
|
|
|
if (!$result || !isset($result['sql'])) {
|
|
echo json_encode(['ok'=>false,'error'=>'invalid JSON','raw'=>substr($content_raw,0,300)]); exit;
|
|
}
|
|
|
|
echo json_encode([
|
|
'ok' => true,
|
|
'sql' => $result['sql'],
|
|
'explanation' => $result['explanation'] ?? '',
|
|
'tables_needed' => $result['tables_needed'] ?? [],
|
|
'dialect' => $result['dialect'] ?? $dialect,
|
|
'complexity' => $result['complexity'] ?? 'medium',
|
|
'suggested_indexes' => $result['suggested_indexes'] ?? [],
|
|
'result' => $result['sql'], // for inline kind render
|
|
]);
|