Files
laralog/app/Console/Commands/GenerateCovers.php
T
gouki d041622531
Build and Deploy / verify (push) Successful in 10s
Build and Deploy / deploy (push) Successful in 17s
feat: post cover filter + admin AI cover action, restyle page-cache admin
- 抽 CoverGenerator 服务(covers:generate 与后台共用),内部强制同步产出 card 转换
- 文章列表:新增封面状态图标列、「有/无封面/完全无图」筛选、行内「生成封面」AI 操作
- 页面缓存:统计改为原生 StatsOverviewWidget(缓存页数/总大小/命中率/时长),
  缓存明细表重排(表头、悬停、URL 截断、图标删除按钮、空状态)
2026-10-14 23:48:57 +00:00

88 lines
2.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Blog\Services\CoverGenerator;
use App\Models\Post;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* 批量为文章生成 AI 封面(默认只补完全没有任何图片的文章)。
*/
class GenerateCovers extends Command
{
protected $signature = 'covers:generate
{--all : 全部重新生成(默认只处理没有任何封面图的文章)}
{--limit= : 最多处理多少篇}
{--post= : 只处理指定文章 ID,逗号分隔}
{--model= : 图片模型,覆盖 llm_image_model 设置}
{--style= : 附加到提示词的风格描述}
{--dry-run : 只列出将处理的文章,不调用接口}';
protected $description = '用 AI 为文章批量生成封面图(存入 media cover 集合)';
public function handle(CoverGenerator $covers): int
{
if (! $covers->isConfigured()) {
$this->error('LLM 未配置:请先在后台「AI 设置」或 .env 配置 LLM_BASE_URL / LLM_API_KEY');
return self::FAILURE;
}
$model = $covers->model($this->option('model') ?: null);
$style = $this->option('style') ?: null;
$query = Post::query()->published()->orderedForList();
if ($ids = trim((string) $this->option('post'))) {
$query->whereIn('id', array_filter(array_map('intval', explode(',', $ids))));
}
$todo = $query->get()
->filter(fn (Post $post) => $this->option('all') || $post->coverOrFirstImageUrl() === null)
->values();
if ($limit = (int) $this->option('limit')) {
$todo = $todo->take($limit)->values();
}
if ($todo->isEmpty()) {
$this->info('没有需要生成封面的文章。');
return self::SUCCESS;
}
$this->info("待处理 {$todo->count()} 篇,模型 {$model}");
if ($this->option('dry-run')) {
foreach ($todo as $post) {
$this->line("[{$post->id}] {$post->title}");
}
return self::SUCCESS;
}
$ok = 0;
$fail = 0;
foreach ($todo as $post) {
try {
$covers->generateFor($post, $model, $style);
$ok++;
$this->info("✔ [{$post->id}] {$post->title}");
} catch (\Throwable $e) {
$fail++;
$this->warn("✘ [{$post->id}] {$post->title}:{$e->getMessage()}");
Log::warning('covers:generate 失败', ['post_id' => $post->id, 'error' => $e->getMessage()]);
}
}
$this->info("完成:成功 {$ok},失败 {$fail}");
return $ok === 0 && $fail > 0 ? self::FAILURE : self::SUCCESS;
}
}