fix: attach images immediately + upgrade image prompts to v2
Two fixes: 1. Image attachment: moved set_post_thumbnail() and Image B post meta into generate_and_attach_images() so they persist immediately after each image generates. Previously the caller set them after both images completed — if the process timed out (common with GPT-5 Image at ~30s/image), the featured image was never attached and Image B was never attempted. 2. Image prompts: replaced FLUX.1-optimized rewriter system prompt and 90s infomercial style suffix with prompts optimized for Gemini Flash Image and GPT-5 Image. New style: premium scientific lifestyle photography with golds/teals color grading. Includes one-time migration to update stored style suffix. Also logs when Image B is skipped due to missing source data (previously silent), helping diagnose why some posts only get one image. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,6 +138,15 @@ class PRAutoBlogger_Image_Pipeline {
|
||||
$image_a_result = $this->generate_image_a( $post_id, $article_data );
|
||||
if ( ! is_wp_error( $image_a_result ) && isset( $image_a_result['attachment_id'] ) ) {
|
||||
$result['image_a_id'] = $image_a_result['attachment_id'];
|
||||
|
||||
// Set featured image immediately so it persists even if the
|
||||
// process times out before Image B finishes or before the
|
||||
// caller gets to handle the return value.
|
||||
set_post_thumbnail( $post_id, $image_a_result['attachment_id'] );
|
||||
PRAutoBlogger_Logger::instance()->info(
|
||||
sprintf( 'Set featured image (attachment %d) for post %d', $image_a_result['attachment_id'], $post_id ),
|
||||
'image_pipeline'
|
||||
);
|
||||
} else {
|
||||
$result['errors'][] = is_wp_error( $image_a_result )
|
||||
? $image_a_result->get_error_message()
|
||||
@@ -152,6 +161,14 @@ class PRAutoBlogger_Image_Pipeline {
|
||||
$image_b_result = $this->generate_image_b( $post_id, $source_data );
|
||||
if ( ! is_wp_error( $image_b_result ) && isset( $image_b_result['attachment_id'] ) ) {
|
||||
$result['image_b_id'] = $image_b_result['attachment_id'];
|
||||
|
||||
// Store Image B reference immediately for the same
|
||||
// timeout-resilience reason as Image A above.
|
||||
update_post_meta( $post_id, '_prautoblogger_image_b_id', $image_b_result['attachment_id'] );
|
||||
PRAutoBlogger_Logger::instance()->info(
|
||||
sprintf( 'Stored Image B (attachment %d) for post %d', $image_b_result['attachment_id'], $post_id ),
|
||||
'image_pipeline'
|
||||
);
|
||||
} else {
|
||||
$result['errors'][] = is_wp_error( $image_b_result )
|
||||
? $image_b_result->get_error_message()
|
||||
@@ -160,6 +177,11 @@ class PRAutoBlogger_Image_Pipeline {
|
||||
if ( ! is_wp_error( $image_b_result ) ) {
|
||||
$result['cost_usd'] += $image_b_result['cost_usd'] ?? 0.0;
|
||||
}
|
||||
} else {
|
||||
PRAutoBlogger_Logger::instance()->info(
|
||||
sprintf( 'Image B skipped for post %d: no source data available.', $post_id ),
|
||||
'image_pipeline'
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -28,17 +28,22 @@ class PRAutoBlogger_Image_Prompt_Builder {
|
||||
* code review, not an admin-panel click.
|
||||
*/
|
||||
private const REWRITER_SYSTEM_PROMPT = <<<'PROMPT'
|
||||
You are an image-prompt specialist for FLUX.1, a text-to-image model.
|
||||
You are an image-prompt specialist for premium AI image models (Gemini Flash Image, GPT-5 Image).
|
||||
|
||||
Given an article title and summary, output ONE short paragraph (2-4 sentences, under 60 words) describing a concrete visual scene that would make a compelling featured image for the article.
|
||||
Given an article title and summary about peptides, supplements, or biohacking, write ONE vivid scene description (2-3 sentences, under 80 words) for a compelling featured image. Emphasize:
|
||||
- OBJECTS and MATERIALS: lab glassware, peptide vials, molecular structures, syringes, supplement bottles, biometric devices, microscopes, fitness equipment, test tubes
|
||||
- LIGHTING and DEPTH: bright directional studio lighting, selective focus, rich warm/cool color contrasts
|
||||
- COMPOSITION: dynamic framing with clear focal point, professional product photography perspective, sense of scale and precision
|
||||
- MOOD: scientific credibility paired with aspirational wellness — premium feel, approachable, engaging
|
||||
|
||||
Rules:
|
||||
- Describe OBJECTS, SETTING, LIGHTING, COMPOSITION, and MOOD — not abstract concepts.
|
||||
- Never include text, words, labels, logos, or watermarks in the scene.
|
||||
- Never describe people's faces in detail (FLUX.1 struggles with faces). Use silhouettes, hands, or over-the-shoulder framings instead.
|
||||
- Focus on the article's core SUBJECT as a physical thing: lab equipment, supplements, syringes, molecules, gym settings, packaging, etc.
|
||||
- Do NOT include any style direction — that is appended separately.
|
||||
- Output ONLY the scene description. No preamble, no explanation, no quotes.
|
||||
Avoid:
|
||||
- Abstract concepts; show concrete objects only
|
||||
- Text, logos, watermarks, or readable labels
|
||||
- Detailed human faces (use hands, torso, silhouettes, or exclude people)
|
||||
- Multiple competing visual elements; keep the subject dominant
|
||||
- Generic stock-photo composition
|
||||
|
||||
Output ONLY the scene description — no preamble, explanation, or quotes. Do NOT include any style direction; that is appended separately.
|
||||
PROMPT;
|
||||
|
||||
/**
|
||||
|
||||
@@ -138,24 +138,12 @@ class PRAutoBlogger_Post_Assembler {
|
||||
$source_data = ( new PRAutoBlogger_Source_Collector() )->get_source_data_for_image( $idea->get_source_ids() );
|
||||
|
||||
try {
|
||||
// The pipeline now sets featured image and Image B meta
|
||||
// internally, immediately after each image generates. This
|
||||
// ensures attachment persists even if the process times out
|
||||
// before this method returns.
|
||||
$result = ( new PRAutoBlogger_Image_Pipeline() )->generate_and_attach_images( $post_id, $post_data, $source_data );
|
||||
|
||||
if ( isset( $result['image_a_id'] ) ) {
|
||||
set_post_thumbnail( $post_id, $result['image_a_id'] );
|
||||
PRAutoBlogger_Logger::instance()->info(
|
||||
sprintf( 'Set featured image (attachment %d) for post %d', $result['image_a_id'], $post_id ),
|
||||
'publisher'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $result['image_b_id'] ) ) {
|
||||
update_post_meta( $post_id, '_prautoblogger_image_b_id', $result['image_b_id'] );
|
||||
PRAutoBlogger_Logger::instance()->info(
|
||||
sprintf( 'Stored Image B (attachment %d) for post %d', $result['image_b_id'], $post_id ),
|
||||
'publisher'
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $result['errors'] ) ) {
|
||||
foreach ( $result['errors'] as $error ) {
|
||||
PRAutoBlogger_Logger::instance()->warning( 'Image warning for post ' . $post_id . ': ' . $error, 'publisher' );
|
||||
|
||||
Reference in New Issue
Block a user