- Create SQL migration for prompt templates used in article and image generation. - Add migration to change publish interval from days to hours in the sites table. - Implement InstallerController to handle installation requests and validation. - Develop FtpService for FTP connections and file uploads. - Create InstallerService to manage the WordPress installation process, including downloading, extracting, and configuring WordPress. - Add index view for the installer with form inputs for FTP, database, and WordPress admin settings. - Implement progress tracking for the installation process with AJAX polling.
105 lines
4.0 KiB
PHP
105 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use App\Core\Config;
|
|
use App\Helpers\Logger;
|
|
|
|
class OpenAIService
|
|
{
|
|
public const DEFAULT_ARTICLE_PROMPT_TEMPLATE = 'Jesteś doświadczonym copywriterem SEO. Pisz artykuły w języku polskim, optymalizowane pod SEO. Artykuł powinien mieć {min_words}-{max_words} słów, zawierać nagłówki H2 i H3, być angażujący i merytoryczny. Formatuj treść w HTML (bez tagów <html>, <body>, <head>). Zwróć odpowiedź WYŁĄCZNIE w formacie JSON: {"title": "tytuł artykułu", "content": "treść HTML artykułu"}';
|
|
|
|
private Client $client;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->client = new Client([
|
|
'base_uri' => 'https://api.openai.com/v1/',
|
|
'timeout' => 120,
|
|
]);
|
|
}
|
|
|
|
public function generateArticle(string $topicName, string $topicDescription, array $existingTitles): ?array
|
|
{
|
|
$apiKey = Config::getDbSetting('openai_api_key', Config::get('OPENAI_API_KEY'));
|
|
$model = Config::getDbSetting('openai_model', Config::get('OPENAI_MODEL', 'gpt-4o'));
|
|
$minWords = Config::getDbSetting('article_min_words', '800');
|
|
$maxWords = Config::getDbSetting('article_max_words', '1200');
|
|
$systemPromptTemplate = Config::getDbSetting('article_generation_prompt', self::DEFAULT_ARTICLE_PROMPT_TEMPLATE);
|
|
|
|
if (!is_string($systemPromptTemplate) || trim($systemPromptTemplate) === '') {
|
|
$systemPromptTemplate = self::DEFAULT_ARTICLE_PROMPT_TEMPLATE;
|
|
}
|
|
|
|
if (empty($apiKey)) {
|
|
Logger::error('OpenAI API key not configured', 'openai');
|
|
return null;
|
|
}
|
|
|
|
$existingList = !empty($existingTitles)
|
|
? implode("\n- ", $existingTitles)
|
|
: '(brak - to pierwszy artykuł z tego tematu)';
|
|
|
|
$systemPrompt = strtr($systemPromptTemplate, [
|
|
'{min_words}' => (string) $minWords,
|
|
'{max_words}' => (string) $maxWords,
|
|
]);
|
|
|
|
$userPrompt = "Napisz artykuł na temat: {$topicName}\n";
|
|
if (!empty($topicDescription)) {
|
|
$userPrompt .= "Wytyczne: {$topicDescription}\n";
|
|
}
|
|
$userPrompt .= "\nWAŻNE - NIE pisz o następujących tematach, bo artykuły o nich już istnieją na stronie:\n- {$existingList}";
|
|
|
|
$fullPrompt = $systemPrompt . "\n\n" . $userPrompt;
|
|
|
|
try {
|
|
$response = $this->client->post('chat/completions', [
|
|
'headers' => [
|
|
'Authorization' => "Bearer {$apiKey}",
|
|
'Content-Type' => 'application/json',
|
|
],
|
|
'json' => [
|
|
'model' => $model,
|
|
'messages' => [
|
|
['role' => 'system', 'content' => $systemPrompt],
|
|
['role' => 'user', 'content' => $userPrompt],
|
|
],
|
|
'temperature' => 0.8,
|
|
'max_tokens' => 4000,
|
|
'response_format' => ['type' => 'json_object'],
|
|
],
|
|
]);
|
|
|
|
$data = json_decode($response->getBody()->getContents(), true);
|
|
$content = $data['choices'][0]['message']['content'] ?? null;
|
|
|
|
if (!$content) {
|
|
Logger::error('Empty response from OpenAI', 'openai');
|
|
return null;
|
|
}
|
|
|
|
$article = json_decode($content, true);
|
|
|
|
if (!isset($article['title']) || !isset($article['content'])) {
|
|
Logger::error('Invalid JSON structure from OpenAI: ' . $content, 'openai');
|
|
return null;
|
|
}
|
|
|
|
Logger::info("Generated article: {$article['title']}", 'openai');
|
|
|
|
return [
|
|
'title' => $article['title'],
|
|
'content' => $article['content'],
|
|
'model' => $model,
|
|
'prompt' => $fullPrompt,
|
|
];
|
|
} catch (GuzzleException $e) {
|
|
Logger::error('OpenAI API error: ' . $e->getMessage(), 'openai');
|
|
return null;
|
|
}
|
|
}
|
|
}
|