diff --git a/src/Services/LLMpool.php b/src/Services/LLMpool.php index ff1991e..f83e3d3 100644 --- a/src/Services/LLMpool.php +++ b/src/Services/LLMpool.php @@ -14,12 +14,14 @@ class LLMpool private FileStorage $storage; private DAIClient $daiClient; private ContentPrompt $promptGenerator; + private Renderer $renderer; public function __construct() { $this->storage = new FileStorage(); $this->daiClient = new DAIClient(); $this->promptGenerator = new ContentPrompt(); + $this->renderer = new Renderer(); } /** @@ -91,12 +93,21 @@ class LLMpool } $projectData['content']['generated'] = $content; + $this->storage->put("projects/{$projectId}.json", $projectData); + + // 5. Render static site + if (!$this->renderer->render($projectId)) { + throw new Exception("Rendering failed."); + } + + // 6. Update Project Status + $projectData = $this->storage->get("projects/{$projectId}.json"); $projectData['status'] = 'ready'; // Transition to ready $projectData['current_step'] = 7; // Automatically ready for preview $projectData['updated_at'] = date('c'); $this->storage->put("projects/{$projectId}.json", $projectData); - // 6. Finish Task (Delete or Archive) + // 7. Finish Task (Delete or Archive) $this->storage->delete($taskPath); error_log("LLMpool: Task $taskFilename processed successfully for project $projectId."); diff --git a/src/Services/Renderer.php b/src/Services/Renderer.php new file mode 100644 index 0000000..fd1829c --- /dev/null +++ b/src/Services/Renderer.php @@ -0,0 +1,69 @@ +storage = new FileStorage(); + $this->exportsPath = realpath(__DIR__ . '/../../exports'); + $this->templatesPath = realpath(__DIR__ . '/../Templates'); + } + + /** + * Renders a complete static website for a project. + */ + public function render(string $projectId): bool + { + $projectData = $this->storage->get("projects/{$projectId}.json"); + if (!$projectData || empty($projectData['content']['generated'])) { + return false; + } + + $projectExportDir = $this->exportsPath . DIRECTORY_SEPARATOR . $projectId; + $assetsDir = $projectExportDir . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'css'; + + // 1. Create directory structure + if (!is_dir($assetsDir)) { + mkdir($assetsDir, 0777, true); + } + + // 2. Copy static assets + $siteCssSource = $this->templatesPath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'site.css'; + copy($siteCssSource, $assetsDir . DIRECTORY_SEPARATOR . 'site.css'); + + // 3. Render HTML + $html = $this->renderTemplate('base', [ + 'project' => $projectData, + 'content' => '' + ]); + + // 4. Save to exports + return file_put_contents($projectExportDir . DIRECTORY_SEPARATOR . 'index.html', $html) !== false; + } + + /** + * Internal helper to render a PHP template with variables. + */ + private function renderTemplate(string $templateName, array $vars = []): string + { + $templateFile = $this->templatesPath . DIRECTORY_SEPARATOR . $templateName . '.php'; + if (!file_exists($templateFile)) { + throw new Exception("Template not found: $templateName"); + } + + extract($vars); + ob_start(); + include $templateFile; + return ob_get_clean(); + } +} diff --git a/src/Templates/base.php b/src/Templates/base.php new file mode 100644 index 0000000..5085581 --- /dev/null +++ b/src/Templates/base.php @@ -0,0 +1,87 @@ + + + + + + + + <?= e($seo['title'] ?? $identity['business_name'] ?? 'Môj Web') ?> + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + + diff --git a/src/Templates/css/site.css b/src/Templates/css/site.css new file mode 100644 index 0000000..f636772 --- /dev/null +++ b/src/Templates/css/site.css @@ -0,0 +1,83 @@ +/* Reset & Base Styles */ +:root { + --primary-color: #2563eb; + --text-color: #1f2937; + --bg-color: #ffffff; + --section-padding: 5rem 1.5rem; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + color: var(--text-color); + background-color: var(--bg-color); + line-height: 1.6; +} + +h1, h2, h3 { + line-height: 1.2; + margin-bottom: 1.5rem; +} + +p { + margin-bottom: 1rem; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 1.5rem; +} + +section { + padding: var(--section-padding); +} + +/* Common Components */ +.btn { + display: inline-block; + padding: 0.75rem 1.5rem; + border-radius: 0.375rem; + font-weight: 600; + text-decoration: none; + transition: all 0.2s; + cursor: pointer; +} + +.btn-primary { + background-color: var(--primary-color); + color: white; +} + +.btn-primary:hover { + opacity: 0.9; +} + +/* Header & Nav */ +header { + padding: 1.5rem 0; + border-bottom: 1px solid #e5e7eb; +} + +nav .container { + display: flex; + justify-content: space-between; + align-items: center; +} + +.logo img { + height: 2.5rem; +} + +/* Footer */ +footer { + background-color: #111827; + color: white; + padding: 4rem 0; + margin-top: 2rem; +} diff --git a/tests/test_llmpool.php b/tests/test_llmpool.php deleted file mode 100644 index f82582c..0000000 --- a/tests/test_llmpool.php +++ /dev/null @@ -1,72 +0,0 @@ - $userId, - 'created_at' => date('c'), - 'projects' => [] -]; -$storage->put("users/{$userId}.json", $userData); - -$project = $projectActions->createProject($userId); -$projectId = $project['project_id']; - -// Mock some wizard data -$project['wizard_data'] = [ - 'business_category' => ['group' => 'gastro', 'subcategory' => 'cafe'], - 'identity' => ['business_name' => 'Kaviareň u Robota', 'tagline' => 'Káva s dušou'], - 'services' => ['items' => [['name' => 'Espresso', 'description' => 'Silná káva', 'price_from' => '2']]], - 'smart_answers' => ['terrace' => true] -]; -$storage->put("projects/{$projectId}.json", $project); - -// 2. Create a dummy task -$taskId = 't_test_worker'; -$taskData = [ - 'task_id' => $taskId, - 'project_id' => $projectId, - 'status' => 'queued', - 'attempt_count' => 0, - 'max_attempts' => 3, - 'created_at' => date('c'), - 'wizard_data' => $project['wizard_data'] -]; -$storage->put("llm/{$taskId}.json", $taskData); - -echo "[INFO] Task created: $taskId for project $projectId" . PHP_EOL; - -// 3. Run Worker -$worker = new LLMpool(); -echo "[PROCESS] Running worker for task $taskId.json..." . PHP_EOL; - -// Since we call real AI, it might take time -$success = $worker->processTask($taskId . '.json'); - -if ($success) { - echo "[SUCCESS] Worker finished successfully." . PHP_EOL; - $updatedProject = $storage->get("projects/{$projectId}.json"); - echo "[INFO] Project status: " . $updatedProject['status'] . PHP_EOL; - echo "[INFO] Generated content keys: " . implode(', ', array_keys($updatedProject['content']['generated'])) . PHP_EOL; -} else { - echo "[FAIL] Worker failed to process task." . PHP_EOL; - $task = $storage->get("llm/{$taskId}.json"); - if ($task) { - echo "[DEBUG] Task status: " . $task['status'] . PHP_EOL; - echo "[DEBUG] Last error: " . ($task['last_error'] ?? 'N/A') . PHP_EOL; - } -}