lh 1 месяц назад
Родитель
Сommit
afeb227ce3

+ 122 - 0
app/Console/Commands/BackfillVideoTokensCommand.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\MpGenerateVideoTask;
+use App\Services\PointsService;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+
+class BackfillVideoTokensCommand extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'points:backfill-video-tokens
+                            {--dry-run : 只统计将回填的记录数,不实际更新}
+                            {--limit= : 最多处理记录数(默认全部)}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '回填视频积分明细缺失的 token(历史 bug:扣费时读取到未同步的 result_json 导致 tokens_consumed=0)';
+
+    /**
+     * Execute the console command.
+     *
+     * @param PointsService $pointsService
+     * @return int
+     */
+    public function handle(PointsService $pointsService)
+    {
+        $dryRun = (bool)$this->option('dry-run');
+        $limit = (int)$this->option('limit');
+        if ($limit < 0) {
+            $limit = 0;
+        }
+
+        $query = DB::table('mp_user_points_details as d')
+            ->leftJoin('mp_generate_video_tasks as t', 't.id', '=', 'd.task_id')
+            ->where('d.type', 'video')
+            ->where('d.points_consumed', '>', 0)
+            ->where('d.tokens_consumed', 0)
+            ->select('d.id', 'd.task_id', 't.api_type', 't.result_json');
+
+        $total = (clone $query)->count();
+        $this->info("待回填明细总数: {$total}" . ($dryRun ? '(dry-run 模式,不更新)' : ''));
+        if ($total <= 0) {
+            return 0;
+        }
+        if ($limit > 0) {
+            $query->limit($limit);
+            $this->info("本次最多处理: {$limit} 条");
+        }
+
+        $updated = 0;
+        $skipped = 0;
+        $notFound = 0;
+
+        $rows = $query->get();
+        $bar = $this->output->createProgressBar($rows->count());
+        $bar->start();
+
+        foreach ($rows as $row) {
+            $bar->advance();
+
+            if (!$row->task_id || $row->result_json === null) {
+                $skipped++;
+                continue;
+            }
+
+            $task = new MpGenerateVideoTask();
+            $task->api_type = (string)$row->api_type;
+            $task->result_json = $row->result_json;
+
+            try {
+                $tokens = $pointsService->getVideoTokensConsumed($task);
+            } catch (\Throwable $e) {
+                dLog('points')->warning('视频 token 回填解析异常', [
+                    'detail_id' => $row->id,
+                    'task_id'   => $row->task_id,
+                    'error'     => $e->getMessage(),
+                ]);
+                $skipped++;
+                continue;
+            }
+
+            if ($tokens <= 0) {
+                $skipped++;
+                continue;
+            }
+
+            if (!$dryRun) {
+                DB::table('mp_user_points_details')
+                    ->where('id', $row->id)
+                    ->update([
+                        'tokens_consumed' => $tokens,
+                        'updated_at'      => date('Y-m-d H:i:s'),
+                    ]);
+            }
+            $updated++;
+        }
+
+        $bar->finish();
+        $this->newLine(2);
+
+        $this->info("可回填: {$updated} 条" . ($dryRun ? '(dry-run 未写入)' : ',已写入'));
+        $this->info("跳过(任务缺失/无 token 数据): {$skipped} 条");
+
+        if ($updated > 0 && !$dryRun) {
+            dLog('points')->info('视频积分明细 token 历史回填完成', [
+                'updated' => $updated,
+                'skipped' => $skipped,
+            ]);
+        }
+
+        return 0;
+    }
+}

+ 2 - 2
app/Http/Controllers/AIGeneration/ImageGenerationController.php

@@ -303,8 +303,8 @@ class ImageGenerationController extends BaseController
         // 1.图片文件最大4.7MB
         // 2.图片分辨率最大: 4096*4096, 最短边不低于320
         // 3.图片长边与短边比例在3以内
-        if ($refImg['size'] > 13 * 1024 * 1024) {
-            Utils::throwError('1003:图片' . $index . '大小不能超过10MB');
+        if ($refImg['size'] > 60 * 1024 * 1024) {
+            Utils::throwError('1003:图片' . $index . '大小不能超过50MB');
         }
         
         $minDimension = min($refImg['width'], $refImg['height']);

+ 28 - 0
app/Services/AIGeneration/AIVideoGenerationService.php

@@ -4020,6 +4020,34 @@ class AIVideoGenerationService
 
         if ($updated) {
             $task->status = MpGenerateVideoTask::STATUS_SUCCESS;
+
+            // 同步内存对象属性,保证后续逻辑(如计费时解析 result_json 中的 token)
+            // 读到最新结果,而不是数据库已更新但内存仍是旧值
+            if (isset($statusInfo['result_json'])) {
+                $task->result_json = is_array($statusInfo['result_json'])
+                    ? $statusInfo['result_json']
+                    : json_decode($statusInfo['result_json'], true);
+            }
+            if (isset($statusInfo['result_url'])) {
+                $task->result_url = $statusInfo['result_url'];
+            }
+            if (isset($statusInfo['compressed_url'])) {
+                $task->compressed_url = $statusInfo['compressed_url'];
+            }
+            if (isset($statusInfo['last_frame_url'])) {
+                $task->last_frame_url = $statusInfo['last_frame_url'];
+            }
+            if (isset($statusInfo['error_message'])) {
+                $task->error_message = $statusInfo['error_message'];
+            }
+            if (isset($statusInfo['extra_params'])) {
+                $task->extra_params = is_array($statusInfo['extra_params'])
+                    ? $statusInfo['extra_params']
+                    : json_decode($statusInfo['extra_params'], true);
+            }
+            if (!$task->completed_at) {
+                $task->completed_at = now();
+            }
         }
 
         return (bool)$updated;