feat: 生成前同步片段到后端clips表
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 31s
CI/CD Pipeline / Frontend Lint (push) Failing after 30s
CI/CD Pipeline / Unit Tests (push) Successful in 1m47s
CI/CD Pipeline / Integration Tests (push) Successful in 1m24s
CI Build & Deploy Pipeline / Production Browser E2E (push) Failing after 1492h26m21s
CI Build & Deploy Pipeline / Deploy Production (push) Failing after 1492h26m23s
CI Build & Deploy Pipeline / Build Production Web Image (push) Failing after 1492h26m27s
CI Build & Deploy Pipeline / Build Production API Image (push) Failing after 1492h26m29s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Failing after 1492h26m37s
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Failing after 1492h26m33s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Failing after 1492h26m39s
CI Build & Deploy Pipeline / Staging E2E Tests (push) Failing after 1492h26m33s
CI Build & Deploy Pipeline / Build Staging API Image (push) Failing after 1492h26m39s
CI Build & Deploy Pipeline / Build Production Worker Image (push) Failing after 1492h58m12s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 1492h58m22s

- 编辑器新增 syncClipsToBackend 函数
- 生成前自动将本地片段同步到后端 clips 表
- 并发控制 3 个请求,删除旧片段后批量重建
- 同步失败不阻塞生成(后端有模板兜底)
- 对接后端 PR#389 clips API
This commit is contained in:
2026-07-16 11:03:09 +08:00
parent 7e2f35d4dd
commit 87e739d42f
@@ -38,6 +38,11 @@ import {
getGenerationStatus,
getGenerationTaskResults,
cancelGenerationTask,
getEditPlanClips,
createEditPlanClip,
batchDeleteEditPlanClips,
type EditPlanClip,
type CreateEditPlanClipRequest,
} from "@/api/editPlans";
import { useUndoRedo } from "./hooks/useUndoRedo";
import type {
@@ -931,10 +936,62 @@ const EditingPlanner: React.FC = () => {
}
};
/**
* 将本地编辑的片段同步到后端 clips 表
* 策略:先删除后端所有片段,再批量创建(简单可靠,生成前使用)
*/
const syncClipsToBackend = async (planId: string): Promise<void> => {
if (clips.length === 0) return;
// 1. 获取后端现有片段 ID
try {
const existing = await getEditPlanClips(planId, { limit: 500 });
if (existing.items.length > 0) {
await batchDeleteEditPlanClips(
planId,
existing.items.map((c) => c.id),
);
}
} catch (err) {
console.warn("[获取后端片段失败,跳过删除]", err);
}
// 2. 批量创建新片段(并发 3 个)
const clipDataList: CreateEditPlanClipRequest[] = clips.map((c, i) => ({
clip_type: c.type === "voice" ? "voiceover" : "main",
order: i,
asset_id: c.media_asset_id || "",
text_content: c.script_text || "",
start_time: 0,
duration: c.duration,
transition_effect: c.transition?.type || "cut",
transition_duration: c.transition?.duration || 0,
playback_speed: c.speed?.rate || 1.0,
config: {
tts_config: c.tts_config || null,
trim_config: c.trim_config || null,
template_segment_id: c.template_segment_id || null,
},
}));
// 并发控制:最多同时 3 个请求
const results: EditPlanClip[] = [];
const concurrency = 3;
for (let i = 0; i < clipDataList.length; i += concurrency) {
const batch = clipDataList.slice(i, i + concurrency);
const batchResults = await Promise.all(
batch.map((data) => createEditPlanClip(planId, data)),
);
results.push(...batchResults);
}
console.log(`[片段同步] 创建了 ${results.length} 个片段`);
};
/**
* 剪辑计划生成
* 1. 有 planId → 更新计划配置 + 触发生成
* 2. 无 planId(从模板库直接进入)→ 先创建计划 + 触发生成
* 1. 有 planId → 更新计划配置 + 同步片段 + 触发生成
* 2. 无 planId(从模板库直接进入)→ 先创建计划 + 同步片段 + 触发生成
* 3. 触发生成后轮询状态,完成后获取视频结果
*/
const handleGoToGenerate = async () => {
@@ -991,6 +1048,14 @@ const EditingPlanner: React.FC = () => {
window.history.replaceState(null, "", `?${params.toString()}`);
}
// 同步片段到后端 clips 表(生成前必须同步,后端生成从 clips 表读)
try {
await syncClipsToBackend(planId);
} catch (syncErr) {
console.warn("[片段同步失败]", syncErr);
// 同步失败不阻塞生成,后端有模板兜底
}
// 触发生成
const genRes = await generateEditPlan(planId);
setGenTotalClips(genRes.clip_count);