= 2 ) { $scene = trim( $parts[0] ); $caption = trim( $parts[1] ); // Strip surrounding quotes from caption — the LLM wraps it in quotes. $caption = trim( $caption, '"\'' ); return array( 'scene' => $scene, 'caption' => $caption, ); } // No blank-line separator found — treat entire response as scene. return array( 'scene' => trim( $raw ), 'caption' => '', ); } /** * Extract the first paragraph from HTML content. * * Removes all tags and captures the text up to the first double-newline * or 200 characters, whichever comes first. * * @param string $html HTML content. * @return string Plain text of the first paragraph. */ public static function extract_first_paragraph( string $html ): string { $text = wp_strip_all_tags( $html ); $paras = preg_split( '/\n\n+/', $text ); $para = isset( $paras[0] ) ? trim( $paras[0] ) : ''; if ( strlen( $para ) > 200 ) { $para = substr( $para, 0, 200 ) . '...'; } return $para; } /** * Rule-based fallback when LLM rewriting is unavailable. * * Kept deliberately simple — this only runs if OpenRouter is down. * * @param string $title Main heading / topic. * @param string $supporting_text Additional context. * @return array{scene: string, caption: string} Scene for image gen, caption for HTML. */ public static function synthesize_visual_concepts_fallback( string $title, string $supporting_text ): array { // Fallback produces a simple comic concept when the LLM is unavailable. $scene = sprintf( 'A cartoon scientist in a lab coat looking bewildered while examining something related to: %s.', $title ); return array( 'scene' => trim( $scene ), 'caption' => 'Science is full of surprises.', ); } }