Files
html/api/ambre-tool-pptx.php

103 lines
4.1 KiB
PHP

<?php
/**
* ambre-tool-pptx.php - Premium PowerPoint generation
* Input: JSON {topic}
* Output: JSON {ok, url, slides, title}
*/
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['ok'=>false, 'error'=>'POST only']); exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$topic = trim($input['topic'] ?? '');
if (strlen($topic) < 3) {
echo json_encode(['ok'=>false, 'error'=>'topic too short']); exit;
}
$topic = substr($topic, 0, 500);
$prompt = "Genere une presentation PowerPoint professionnelle sur: \"$topic\"\n\n"
. "Retourne UNIQUEMENT du JSON valide:\n"
. "{\n"
. " \"title\": \"Titre principal\",\n"
. " \"subtitle\": \"Sous-titre\",\n"
. " \"author\": \"WEVAL Consulting\",\n"
. " \"slides\": [\n"
. " {\"type\":\"title\", \"title\":\"Titre\", \"subtitle\":\"...\"},\n"
. " {\"type\":\"content\", \"title\":\"Section 1\", \"bullets\":[\"Point 1\", \"Point 2\"]},\n"
. " {\"type\":\"two_column\", \"title\":\"Comparaison\", \"left\":{\"heading\":\"Avant\", \"items\":[...]}, \"right\":{\"heading\":\"Apres\", \"items\":[...]}},\n"
. " {\"type\":\"stats\", \"title\":\"Chiffres cles\", \"stats\":[{\"value\":\"80%\", \"label\":\"Libelle\"}]},\n"
. " {\"type\":\"table\", \"title\":\"Tableau\", \"headers\":[\"A\",\"B\"], \"rows\":[[\"v1\",\"v2\"]]},\n"
. " {\"type\":\"conclusion\", \"title\":\"Conclusion\", \"text\":\"...\", \"bullets\":[...]}\n"
. " ]\n"
. "}\n\n"
. "IMPORTANT:\n"
. "- 8 a 12 slides au total (commencant par 'title' et finissant par 'conclusion')\n"
. "- Varier les types: content / two_column / stats / table / content\n"
. "- Bullets concis et percutants (10-15 mots chacun)\n"
. "- Stats: 3-4 chiffres avec valeur + libelle court\n"
. "- Francais pro, pas d'info confidentielle WEVAL\n"
. "- JSON valide uniquement";
$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' => 4500, 'temperature' => 0.7
]),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 90,
]);
$resp = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http !== 200) { echo json_encode(['ok'=>false, 'error'=>"LLM HTTP $http"]); exit; }
$data = json_decode($resp, true);
$content_raw = $data['choices'][0]['message']['content'] ?? '';
/* BALANCED_JSON_V2 */
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);
}
$deck = json_decode($content_raw, true);
if (!$deck || !isset($deck['title'])) {
echo json_encode(['ok'=>false, 'error'=>'LLM invalid JSON', 'raw'=>substr($content_raw,0,500)]); exit;
}
$tmpjson = tempnam('/tmp', 'pptx_') . '.json';
file_put_contents($tmpjson, json_encode($deck));
$filename = 'weval-' . substr(md5($topic . microtime(true)), 0, 10) . '.pptx';
$outpath = '/var/www/html/files/' . $filename;
if (!is_dir('/var/www/html/files')) { mkdir('/var/www/html/files', 0755, true); }
$pyScript = '/var/www/html/api/ambre-tool-pptx-render.py';
$cmd = "python3 " . escapeshellarg($pyScript) . " " . escapeshellarg($tmpjson) . " " . escapeshellarg($outpath) . " 2>&1";
$out = shell_exec($cmd);
@unlink($tmpjson);
if (!file_exists($outpath)) {
echo json_encode(['ok'=>false, 'error'=>'pptx render failed', 'py_out'=>substr($out, 0, 500)]); exit;
}
echo json_encode([
'ok' => true,
'url' => '/files/' . $filename,
'title' => $deck['title'],
'slides' => count($deck['slides'] ?? []),
'size' => filesize($outpath),
'size_kb' => round(filesize($outpath)/1024, 1),
]);