diff --git a/app/Blog/Services/CoverGenerator.php b/app/Blog/Services/CoverGenerator.php index a218582..d4853bf 100644 --- a/app/Blog/Services/CoverGenerator.php +++ b/app/Blog/Services/CoverGenerator.php @@ -35,16 +35,13 @@ class CoverGenerator // 站点无常驻 queue worker:同步产出 card 转换,避免缩略图永远卡在队列里。 config(['media-library.queue_conversions_by_default' => false]); - $response = Http::timeout(120) - ->withToken($this->llm->apiKey()) - ->post($this->llm->baseUrl().'/image_generation', [ - 'model' => $this->model($model), - 'prompt' => $this->buildPrompt($post, $style), - 'aspect_ratio' => '16:9', - 'response_format' => 'url', - 'n' => 1, - 'prompt_optimizer' => true, - ]); + $response = $this->requestImage($this->buildPrompt($post, $style), $model); + + // 标题触发内容审核(input new_sensitive):退化为不含标题的通用提示词重试一次。 + if (str_contains((string) $response->body(), 'sensitive') + && ! is_string($response->json('data.image_urls.0'))) { + $response = $this->requestImage($this->neutralPrompt($style), $model); + } if ($response->failed()) { throw new \RuntimeException('HTTP '.$response->status().':'.Str::limit($response->body(), 200)); @@ -91,4 +88,29 @@ class CoverGenerator return implode('。', $parts); } + + /** + * 不含标题/摘要的通用封面提示词(标题触发审核时的兜底)。 + */ + public function neutralPrompt(?string $style = null): string + { + $style = trim((string) ($style + ?: blog_setting('cover_prompt_style', '扁平插画风格,色调柔和,构图简洁'))); + + return "博客文章封面配图。{$style}。画面中不要出现任何文字"; + } + + private function requestImage(string $prompt, ?string $model = null): \Illuminate\Http\Client\Response + { + return Http::timeout(120) + ->withToken($this->llm->apiKey()) + ->post($this->llm->baseUrl().'/image_generation', [ + 'model' => $this->model($model), + 'prompt' => $prompt, + 'aspect_ratio' => '16:9', + 'response_format' => 'url', + 'n' => 1, + 'prompt_optimizer' => true, + ]); + } }