From fe5a59d7255c894e182c25fdd597280f7b74790f Mon Sep 17 00:00:00 2001 From: GinHa <15201596918@163.com> Date: Mon, 20 Jul 2026 13:48:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE/AI=E7=94=9F=E6=88=90?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video-gen-admin/src/api/index.ts | 10 +- .../src/pages/AdminGenerationAiRecords.tsx | 90 +- video-gen-admin/src/types/index.ts | 4 + ...nify_generation_owners_and_soft_delete_.py | 922 +++++++++++++ video-gen-api/app/api/v1/admin.py | 332 ++--- video-gen-api/app/api/v1/credits.py | 4 +- video-gen-api/app/api/v1/generation.py | 367 ++--- video-gen-api/app/api/v1/generation_ai.py | 56 +- .../app/api/v1/hot_opening_replicate.py | 31 +- video-gen-api/app/api/v1/image_engines.py | 2 +- video-gen-api/app/api/v1/shot_replicate.py | 35 +- video-gen-api/app/api/v1/video_engines.py | 2 +- video-gen-api/app/config.py | 21 +- video-gen-api/app/enums/generation_status.py | 8 +- video-gen-api/app/enums/generation_task.py | 9 + video-gen-api/app/main.py | 11 +- .../app/models/chat_generation_task.py | 8 + .../app/models/chat_generation_task_event.py | 27 +- .../app/models/chat_provider_call_log.py | 21 +- .../app/models/generated_resource.py | 10 +- video-gen-api/app/models/generation_record.py | 44 +- video-gen-api/app/models/image_engine.py | 4 +- video-gen-api/app/models/model_config.py | 4 +- video-gen-api/app/models/video_engine.py | 4 +- video-gen-api/app/schemas/admin.py | 1 + video-gen-api/app/schemas/image_engine.py | 3 +- video-gen-api/app/schemas/video_engine.py | 3 +- video-gen-api/app/services/credits.py | 4 +- .../services/generation/ai/engine_service.py | 4 +- .../generation/ai/image_batch_service.py | 51 +- .../app/services/generation/ai/service.py | 6 +- .../generation/ai/task_create_service.py | 44 +- .../generation/ai/task_group_service.py | 17 +- .../services/generation/billing_service.py | 2 + .../services/generation/download_service.py | 104 +- .../generation/history_delete_service.py | 24 +- .../app/services/generation/log_service.py | 157 ++- .../services/generation/pipeline/__init__.py | 1 + .../generation/pipeline/db_lock_service.py | 84 ++ .../generation/pipeline/enqueue_service.py | 39 + .../pipeline/generation_record_service.py | 59 + .../generation/pipeline/lifecycle_service.py | 149 ++ .../generation/pipeline/owner_service.py | 192 +++ .../pipeline/recovery_repository.py | 148 ++ .../generation/poll_schedule_service.py | 21 +- .../app/services/generation/prompt_service.py | 2 +- .../services/generation/provider_service.py | 31 +- .../services/generation/recovery_service.py | 364 +++-- .../app/services/generation/refund_service.py | 69 +- .../generation/task_factory_service.py | 6 + .../services/hot_opening_replicate_service.py | 281 +++- .../hot_opening_video_prompt_service.py | 5 +- video-gen-api/app/services/image_gen.py | 15 +- video-gen-api/app/services/llm.py | 6 +- .../media_token_usage_snapshot_service.py | 5 + .../module_generation_flow_base_service.py | 29 +- .../app/services/operation_log_service.py | 2 +- .../app/services/redis_registry_service.py | 256 +++- .../services/resource_accounting_service.py | 13 +- .../services/shot_replicate_flow_service.py | 281 +++- .../services/shot_video_analysis_service.py | 2 +- video-gen-api/app/services/video_gen.py | 17 +- video-gen-api/app/services/video_queue.py | 433 ------ .../video_upscale/local_ffmpeg_service.py | 99 +- .../services/video_upscale/media_service.py | 13 +- .../services/video_upscale/owner_service.py | 6 +- .../services/video_upscale/task_service.py | 162 ++- .../app/tasks/generation_create_tasks.py | 783 +++++++---- .../app/tasks/generation_download_tasks.py | 1215 +++++++++-------- .../app/tasks/generation_poll_tasks.py | 884 +++++++----- .../app/tasks/generation_recovery_tasks.py | 193 ++- video-gen-api/app/tasks/video_generation.py | 2 - .../app/tasks/video_upscale_tasks.py | 79 +- 73 files changed, 5819 insertions(+), 2573 deletions(-) create mode 100644 video-gen-api/alembic/versions/e6eac828ff61_unify_generation_owners_and_soft_delete_.py create mode 100644 video-gen-api/app/services/generation/pipeline/__init__.py create mode 100644 video-gen-api/app/services/generation/pipeline/db_lock_service.py create mode 100644 video-gen-api/app/services/generation/pipeline/enqueue_service.py create mode 100644 video-gen-api/app/services/generation/pipeline/generation_record_service.py create mode 100644 video-gen-api/app/services/generation/pipeline/lifecycle_service.py create mode 100644 video-gen-api/app/services/generation/pipeline/owner_service.py create mode 100644 video-gen-api/app/services/generation/pipeline/recovery_repository.py delete mode 100644 video-gen-api/app/services/video_queue.py delete mode 100644 video-gen-api/app/tasks/video_generation.py diff --git a/video-gen-admin/src/api/index.ts b/video-gen-admin/src/api/index.ts index 80412b6a..0de34519 100644 --- a/video-gen-admin/src/api/index.ts +++ b/video-gen-admin/src/api/index.ts @@ -348,8 +348,9 @@ export async function deleteIndustryConfig(id: string): Promise { await api.delete(`/admin/industry-configs/${id}`); } -export async function getVideoEngines(): Promise { - return api.get('/admin/video-engines'); +export async function getVideoEngines(options?: { includeDeleted?: boolean }): Promise { + const query = options?.includeDeleted ? '?include_deleted=true' : ''; + return api.get(`/admin/video-engines${query}`); } export async function saveVideoEngine(engine: any): Promise { @@ -361,8 +362,9 @@ export async function deleteVideoEngine(id: string): Promise { await api.delete(`/admin/video-engines/${id}`); } -export async function getImageEngines(): Promise { - return api.get('/admin/image-engines'); +export async function getImageEngines(options?: { includeDeleted?: boolean }): Promise { + const query = options?.includeDeleted ? '?include_deleted=true' : ''; + return api.get(`/admin/image-engines${query}`); } export async function saveImageEngine(engine: any): Promise { diff --git a/video-gen-admin/src/pages/AdminGenerationAiRecords.tsx b/video-gen-admin/src/pages/AdminGenerationAiRecords.tsx index 5c11a1fe..6b8487b9 100644 --- a/video-gen-admin/src/pages/AdminGenerationAiRecords.tsx +++ b/video-gen-admin/src/pages/AdminGenerationAiRecords.tsx @@ -29,8 +29,13 @@ import { VideoCameraOutlined, } from '@ant-design/icons'; import dayjs from 'dayjs'; -import { getAdminGenerationAiTasks } from '../api'; -import type { GenerationAIMediaReference, GenerationAITaskOut } from '../types'; +import { getAdminGenerationAiTasks, getImageEngines, getVideoEngines } from '../api'; +import type { + GenerationAiImageEngine, + GenerationAIMediaReference, + GenerationAITaskOut, + GenerationAiVideoEngine, +} from '../types'; import { formatDate } from '../utils/formatDate'; import GenerationTaskResourceGrid from '../components/generation/GenerationTaskResourceGrid'; @@ -240,6 +245,9 @@ const AdminGenerationAiRecords: React.FC = () => { const [createdRange, setCreatedRange] = useState([todayStart(), todayEnd()]); const [queryCreatedRange, setQueryCreatedRange] = useState([todayStart(), todayEnd()]); const [reloadKey, setReloadKey] = useState(0); + const [engineListLoading, setEngineListLoading] = useState(false); + const [imageEngines, setImageEngines] = useState([]); + const [videoEngines, setVideoEngines] = useState([]); const [preview, setPreview] = useState(null); const [resourceState, setResourceState] = useState(EMPTY_RESOURCE_STATE); @@ -280,6 +288,64 @@ const AdminGenerationAiRecords: React.FC = () => { load(); }, [load, reloadKey]); + useEffect(() => { + let cancelled = false; + + const loadEngineOptions = async () => { + setEngineListLoading(true); + try { + const [images, videos] = await Promise.all([ + getImageEngines({ includeDeleted: true }), + getVideoEngines({ includeDeleted: true }), + ]); + if (!cancelled) { + setImageEngines(images || []); + setVideoEngines(videos || []); + } + } catch (error: any) { + if (!cancelled) { + message.error(error?.message || '加载模型引擎列表失败'); + } + } finally { + if (!cancelled) setEngineListLoading(false); + } + }; + + void loadEngineOptions(); + return () => { + cancelled = true; + }; + }, []); + + const engineOptions = useMemo(() => { + const toOption = ( + engine: GenerationAiImageEngine | GenerationAiVideoEngine, + type: 'image' | 'video', + ) => { + const deleted = Boolean(engine.deletedAt); + const typeText = type === 'image' ? '图片' : '视频'; + const deletedText = deleted ? '[已删除]' : ''; + const detailText = [engine.name, engine.modelName, engine.provider, engine.id] + .filter(Boolean) + .join(' / '); + const label = `[${typeText}]${deletedText} ${detailText}`; + return { + value: engine.id, + label, + searchText: [engine.id, engine.name, engine.modelName, engine.provider, typeText, deleted ? '已删除' : ''] + .filter(Boolean) + .join(' ') + .toLowerCase(), + }; + }; + + const merged = [ + ...imageEngines.map((engine) => toOption(engine, 'image')), + ...videoEngines.map((engine) => toOption(engine, 'video')), + ]; + return Array.from(new Map(merged.map((option) => [option.value, option])).values()); + }, [imageEngines, videoEngines]); + useEffect(() => { if (!preview) { setResourceState(EMPTY_RESOURCE_STATE); @@ -969,21 +1035,17 @@ const AdminGenerationAiRecords: React.FC = () => {