// NEU: einheitliche Key-Quelle private static function get_api_key() { return defined('OPENAI_API_KEY') ? constant('OPENAI_API_KEY') : ''; } /** * Erstellt einen Batch-Request für die ausgewählten Themen (OpenAI Batch API) * https://api.openai.com/v1/batches, completion_window=24h */ public static function start_batch_processing($selected_themes) { $api_key = self::get_api_key(); if (empty($api_key)) { error_log('CW AI Batch: API Key fehlt (OPENAI_API_KEY)!'); return false; } if (empty($selected_themes) || !is_array($selected_themes)) { error_log('CW AI Batch: Keine Themen übergeben'); return false; } // Schritt 1: JSONL-Datei erstellen (ein Request pro Zeile) $jsonl_content = ""; $ts = time(); foreach ($selected_themes as $index => $theme) { $theme = trim((string)$theme); if ($theme === '') continue; $request = [ 'custom_id' => 'trend_' . $ts . '_' . $index, 'method' => 'POST', 'url' => '/v1/chat/completions', 'body' => [ 'model' => 'gpt-4o', 'messages' => [ [ 'role' => 'system', 'content' => 'Du bist ein professioneller Redakteur für eine Lokalzeitung im Altkreis Burgdorf. Schreibe interessante, gut strukturierte Artikel mit WordPress Gutenberg-Blöcken.' ], [ 'role' => 'user', 'content' => "Schreibe einen interessanten Artikel für die Rubrik 'Tipps & Infos' zum Thema: '$theme'. Anforderungen: - Beziehe den 'Altkreis Burgdorf' oder 'Region Hannover' (besser) dezent mit ein (lokaler Bezug) - Nutze WordPress Gutenberg-Blöcke (, ) - Struktur: Einleitung, 2-3 Zwischenüberschriften mit Inhalt, Fazit - Länge: ca. 400-600 Wörter - Stil: informativ, leicht lesbar, ansprechend WICHTIG: - Erste Zeile: Nur der Titel (ohne Formatierung, ohne '#') - Ab zweiter Zeile: Der vollständige Artikel-Content mit Gutenberg-Blöcken Beispiel-Format: Dein packender Titel hier
Einleitungstext...
" ] ], 'temperature' => 0.7, 'max_tokens' => 3000 ] ]; $jsonl_content .= json_encode($request, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"; } if (trim($jsonl_content) === '') { error_log('CW AI Batch: JSONL leer (keine gültigen Themen)'); return false; } // Schritt 2: Datei hochladen (purpose=batch) $upload_response = self::upload_batch_file($jsonl_content, $api_key); if (!$upload_response || !isset($upload_response['id'])) { error_log('CW AI Batch: Datei-Upload fehlgeschlagen. Response: ' . print_r($upload_response, true)); return false; } $file_id = $upload_response['id']; error_log('CW AI Batch: Datei hochgeladen - ID: ' . $file_id); // Schritt 3: Batch starten (24h = günstiger, asynchron) $batch_response = wp_remote_post('https://api.openai.com/v1/batches', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json' ], 'body' => json_encode([ 'input_file_id' => $file_id, 'endpoint' => '/v1/chat/completions', 'completion_window' => '24h' ]), 'timeout' => 30 ]); if (is_wp_error($batch_response)) { error_log('CW AI Batch Error: ' . $batch_response->get_error_message()); return false; } $raw = wp_remote_retrieve_body($batch_response); $batch_data = json_decode($raw, true); error_log('CW AI Batch Response: ' . $raw); if (!empty($batch_data['id'])) { $batches = get_option(self::$batch_option, []); $batches[] = [ 'id' => $batch_data['id'], 'created' => time(), 'count' => count($selected_themes), 'file_id' => $file_id ]; update_option(self::$batch_option, $batches); error_log('CW AI Batch: Batch-Job ' . $batch_data['id'] . ' gestartet'); return true; } error_log('CW AI Batch: Keine Batch-ID erhalten'); return false; } /** * Cron-Job: Prüft ob Batches fertig sind und postet sie */ public static function check_batches() { $batches = get_option(self::$batch_option, []); if (empty($batches)) return; $api_key = self::get_api_key(); if (empty($api_key)) { error_log('CW AI Batch: API Key fehlt (OPENAI_API_KEY)!'); return; } $category_id = get_cat_ID('Tipps & Infos'); if (!$category_id) { error_log('CW AI Batch: Kategorie "Tipps & Infos" nicht gefunden'); } foreach ($batches as $key => $batch_info) { $batch_id = $batch_info['id']; $response = wp_remote_get("https://api.openai.com/v1/batches/{$batch_id}", [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key ], 'timeout' => 30 ]); if (is_wp_error($response)) { error_log('CW AI Batch Check Error: ' . $response->get_error_message()); continue; } $batch_raw = wp_remote_retrieve_body($response); $batch_data = json_decode($batch_raw, true); $status = $batch_data['status'] ?? 'unknown'; if ($status === 'completed') { error_log('CW AI Batch: Batch ' . $batch_id . ' ist fertig'); if (!empty($batch_data['output_file_id'])) { $file_id = $batch_data['output_file_id']; $file_response = wp_remote_get("https://api.openai.com/v1/files/{$file_id}/content", [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key ], 'timeout' => 30 ]); if (is_wp_error($file_response)) { error_log('CW AI Batch: Fehler beim Laden der Output-Datei: ' . $file_response->get_error_message()); } else { $results_raw = wp_remote_retrieve_body($file_response); $lines = explode("\n", trim($results_raw)); $day_offset = 1; foreach ($lines as $line) { if ($line === '') continue; $result = json_decode($line, true); $full_text = $result['response']['body']['choices'][0]['message']['content'] ?? ''; if ($full_text === '') { error_log('CW AI Batch: Leerer Content in Ergebniszeile übersprungen'); continue; } $parts = explode("\n", $full_text, 2); $title = trim(str_replace(['#', '*', '**'], '', $parts[0])); $content = isset($parts[1]) ? trim($parts[1]) : ''; if ($title === '' || $content === '') { error_log('CW AI Batch: Leerer Titel oder Content übersprungen'); continue; } $post_date = date('Y-m-d H:i:s', strtotime("+$day_offset day 08:00:00")); $post_id = wp_insert_post([ 'post_title' => $title, 'post_content' => $content, 'post_status' => 'future', 'post_date' => $post_date, 'post_category' => $category_id ? [$category_id] : [], 'post_author' => 1 ]); if ($post_id) { error_log("CW AI Batch: Artikel '$title' geplant für $post_date (ID: $post_id)"); } else { error_log("CW AI Batch: Fehler beim Erstellen des Artikels '$title'"); } $day_offset++; } } } else { error_log('CW AI Batch: completed, aber keine output_file_id gefunden'); } unset($batches[$key]); } elseif ($status === 'failed' || $status === 'expired' || $status === 'cancelled') { error_log("CW AI Batch: Batch $batch_id fehlgeschlagen - Status: $status"); unset($batches[$key]); } else { error_log("CW AI Batch: Batch $batch_id läuft noch - Status: $status"); } } update_option(self::$batch_option, array_values($batches)); }