Files
html/api/ambre-tool-3d.php

80 lines
3.4 KiB
PHP

<?php
/**
* ambre-tool-3d.php — 3D scene generator (Three.js standalone HTML)
*/
header('Content-Type: application/json');
/* SESSION_CONTEXT_INJECTED v1 */
require_once __DIR__ . '/ambre-session-context.php';
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, 400);
$prompt = "Expert Three.js r128. Genere une scene 3D interactive pour: \"$topic\"\n\n"
. "Contraintes:\n"
. "- Three.js via CDN https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\n"
. "- OrbitControls via https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js\n"
. "- Fichier HTML UNIQUE complet avec <!DOCTYPE html>\n"
. "- Scene anime (animation loop)\n"
. "- OrbitControls actifs (souris)\n"
. "- Lumiere + ombre realistes\n"
. "- 5-10 objets 3D differents avec geometries/materiaux varies\n"
. "- Background degrade ou skybox\n"
. "- Fog pour profondeur\n"
. "- Resize responsive\n"
. "- Pas de NO_CAPSULE_GEOMETRY (utiliser CylinderGeometry/SphereGeometry)\n"
. "- Code propre et commente\n\n"
. "RETOURNE UNIQUEMENT LE CODE HTML sans backticks ni texte explicatif";
$prompt = wvia_context_for_prompt() . $prompt;
$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' => 6000, 'temperature' => 0.7
]),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 120,
]);
$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);
$html = $data['choices'][0]['message']['content'] ?? '';
$html = preg_replace('/^```(?:html)?\s*\n/', '', $html);
$html = preg_replace('/\n```\s*$/', '', trim($html));
if (stripos($html, '<!DOCTYPE') === false && stripos($html, '<html') === false) {
echo json_encode(['ok'=>false,'error'=>'invalid HTML output','preview'=>substr($html,0,300)]); exit;
}
$filename = 'scene3d-' . substr(md5($topic . microtime(true)), 0, 10) . '.html';
$outpath = '/var/www/html/files/' . $filename;
if (!is_dir('/var/www/html/files')) { mkdir('/var/www/html/files', 0755, true); }
file_put_contents($outpath, $html);
// SESSION LINK DOC
if (isset($outpath) && isset($filename)) {
$__wvia_title = isset($doc) && isset($doc['title']) ? $doc['title'] : (isset($spec) && isset($spec['title']) ? $spec['title'] : (isset($deck) && isset($deck['title']) ? $deck['title'] : (isset($topic) ? $topic : 'Document')));
wvia_link_doc('/files/' . $filename, '3d', $__wvia_title);
if (isset($topic)) wvia_append_turn('user', $topic);
wvia_append_turn('assistant', '[3D generated: ' . ($__wvia_title ?: 'doc') . ']');
}
echo json_encode([
'ok'=>true,
'url'=>'/files/'.$filename,
'preview_url'=>'/files/'.$filename,
'title'=>'Scene 3D - ' . substr($topic, 0, 50),
'topic'=>$topic,
'size'=>filesize($outpath),
'size_kb'=>round(filesize($outpath)/1024, 1),
'lines'=>substr_count($html, "\n"),
]);