$model,
'max_tokens' => $max_tokens,
'system' => $system_prompt,
'messages' => [
[ 'role' => 'user', 'content' => $user_prompt ]
]
];
$ch = curl_init( self::$api_url );
curl_setopt_array( $ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . $api_key,
'anthropic-version: 2023-06-01'
],
CURLOPT_POSTFIELDS => json_encode( $payload ),
CURLOPT_TIMEOUT => 60
] );
$response = curl_exec( $ch );
$http_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
curl_close( $ch );
if ( $http_code !== 200 )
{
$error = json_decode( $response, true );
return [ 'status' => 'error', 'message' => $error['error']['message'] ?? 'Błąd API Claude (HTTP ' . $http_code . ')' ];
}
$data = json_decode( $response, true );
$content = '';
if ( !empty( $data['content'] ) )
{
foreach ( $data['content'] as $block )
{
if ( $block['type'] === 'text' )
{
$content .= $block['text'];
}
}
}
$content = trim( $content );
return [ 'status' => 'ok', 'suggestion' => $content ];
}
static private function build_context_text( $context )
{
$lines = [];
$lines[] = 'Nazwa produktu: ' . ( $context['original_name'] ?? '—' );
if ( !empty( $context['current_title'] ) )
$lines[] = 'Obecny tytuł (custom): ' . $context['current_title'];
if ( !empty( $context['current_description'] ) )
$lines[] = 'Obecny opis: ' . $context['current_description'];
if ( !empty( $context['current_category'] ) )
$lines[] = 'Obecna kategoria Google: ' . $context['current_category'];
if ( !empty( $context['offer_id'] ) )
$lines[] = 'ID oferty: ' . $context['offer_id'];
if ( !empty( $context['custom_label_4'] ) )
$lines[] = 'Status produktu: ' . $context['custom_label_4'];
$lines[] = '';
$lines[] = 'Metryki reklamowe (ostatnie 30 dni):';
$lines[] = '- Wyświetlenia: ' . ( $context['impressions_30'] ?? 0 );
$lines[] = '- Kliknięcia: ' . ( $context['clicks_30'] ?? 0 );
$lines[] = '- CTR: ' . ( $context['ctr'] ?? 0 ) . '%';
$lines[] = '- Koszt: ' . ( $context['cost'] ?? 0 ) . ' PLN';
$lines[] = '- Konwersje: ' . ( $context['conversions'] ?? 0 );
$lines[] = '- Wartość konwersji: ' . ( $context['conversions_value'] ?? 0 ) . ' PLN';
$lines[] = '- ROAS: ' . ( $context['roas'] ?? 0 ) . '%';
if ( !empty( $context['page_content'] ) )
{
$lines[] = '';
$lines[] = 'Treść ze strony produktu (użyj tych informacji do stworzenia dokładniejszego opisu):';
$lines[] = $context['page_content'];
}
return implode( "\n", $lines );
}
static public function suggest_title( $context )
{
$context_text = self::build_context_text( $context );
$keyword_planner_text = '';
if ( !empty( $context['keyword_planner_terms'] ) && is_array( $context['keyword_planner_terms'] ) )
{
$keyword_lines = [];
$keyword_lines[] = 'Najpopularniejsze frazy z Google Ads Keyword Planner (na bazie URL produktu, posortowane malejąco po średniej liczbie wyszukiwań):';
foreach ( array_slice( $context['keyword_planner_terms'], 0, 15 ) as $term )
{
$text = trim( (string) ( $term['keyword_text'] ?? '' ) );
if ( $text === '' )
{
continue;
}
$avg_monthly = (int) ( $term['avg_monthly_searches'] ?? 0 );
$keyword_lines[] = '- ' . $text . ' (avg miesięcznie: ' . $avg_monthly . ')';
}
if ( count( $keyword_lines ) > 1 )
{
$keyword_lines[] = 'Użyj tych fraz WYBIÓRCZO i naturalnie (bez upychania słów kluczowych), tylko jeśli pasują do produktu.';
$keyword_planner_text = "\n\n" . implode( "\n", $keyword_lines );
}
}
$prompt = 'Zaproponuj zoptymalizowany tytuł produktu dla Google Merchant Center.
WYMAGANIA:
- Max 150 znaków, najważniejsze info w pierwszych 70 znakach
- Struktura: [Marka jeśli jest w nazwie] [Typ produktu] [Kluczowe cechy z nazwy] [Dla kogo/okazja jeśli wynika z nazwy]
- Pisownia zdaniowa lub tytułowa, naturalny język
- Tytuł musi brzmieć jak wpis w katalogu produktowym
BEZWZGLĘDNY ZAKAZ (odrzucenie przez Google):
- Słowa promocyjne: bestseller, hit, idealny, najlepszy, polecamy, okazja, nowość, TOP
- Wykrzykniki (!), emotikony, symbole dekoracyjne
- WIELKIE LITERY (wyjątek: LED, USB, TV)
- Wezwania do działania, informacje o cenie/dostawie
- Cechy wymyślone — opisuj TYLKO to co wynika z oryginalnej nazwy lub treści strony produktu
- Jeśli podano treść ze strony produktu, wykorzystaj ją do wzbogacenia tytułu o rzeczywiste cechy (marka, materiał, kolor, rozmiar itp.)
' . $context_text . $keyword_planner_text . '
Zwróć TYLKO tytuł, bez cudzysłowów, bez wyjaśnień.';
return self::call_api( self::$system_prompt, $prompt );
}
static public function suggest_description( $context )
{
$context_text = self::build_context_text( $context );
$has_page = !empty( $context['page_content'] );
$keyword_planner_text = '';
if ( !empty( $context['keyword_planner_terms'] ) && is_array( $context['keyword_planner_terms'] ) )
{
$keyword_lines = [];
$keyword_lines[] = 'Najpopularniejsze frazy z Google Ads Keyword Planner (na bazie URL produktu, posortowane malejąco po średniej liczbie wyszukiwań):';
foreach ( array_slice( $context['keyword_planner_terms'], 0, 15 ) as $term )
{
$text = trim( (string) ( $term['keyword_text'] ?? '' ) );
if ( $text === '' )
{
continue;
}
$avg_monthly = (int) ( $term['avg_monthly_searches'] ?? 0 );
$keyword_lines[] = '- ' . $text . ' (avg miesięcznie: ' . $avg_monthly . ')';
}
if ( count( $keyword_lines ) > 1 )
{
$keyword_lines[] = 'W opisie wykorzystuj te frazy naturalnie i wyłącznie gdy realnie pasują do produktu (bez keyword stuffing).';
$keyword_planner_text = "\n\n" . implode( "\n", $keyword_lines );
}
}
$length_guide = $has_page
? '- Napisz rozbudowany, szczegółowy opis: ok. 1000 znaków (800-1200)
- Wykorzystaj szczegóły ze strony produktu: skład zestawu, materiały, wymiary, kolory, przeznaczenie
- Każdy akapit/punkt powinien wnosić NOWĄ informację — NIE powtarzaj tych samych elementów'
: '- Napisz opis o długości ok. 1000 znaków (800-1200) — jeśli brak szczegółów, opisz ogólnie zastosowanie i grupę docelową
- Opisuj TYLKO to co wynika z oryginalnej nazwy — nie wymyślaj konkretnych parametrów';
$prompt = 'Napisz zoptymalizowany opis produktu dla Google Merchant Center.
WYMAGANIA:
' . $length_guide . '
- Najważniejsze info na początku (pierwsze 160 znaków widoczne w wynikach)
- Rzeczowo opisz: co to jest, z czego się składa, do czego służy, dla kogo
- Ton neutralny, informacyjny — jak w specyfikacji produktowej
- Każdy akapit musi zawierać INNĄ informację niż poprzedni — NIGDY nie powtarzaj tych samych elementów
FORMATOWANIE — Google Merchant Center obsługuje podstawowe HTML:
- Używaj
do oddzielania akapitów/sekcji
- Używaj pogrubienia dla kluczowych cech (np. nazwy elementów zestawu, materiał)
- Używaj