forked from 77media/video-flow
项目名批量更新
This commit is contained in:
parent
a6c654d596
commit
ce6a6d84d4
@ -17,7 +17,7 @@ npm run dev
|
||||
## 生产部署
|
||||
|
||||
```shellscript
|
||||
cd video-flow
|
||||
cd video-flow-b
|
||||
./compile.sh
|
||||
|
||||
登入服务器:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
## Video-Flow API 使用指南(方案一:保持现状,统一规范与示例)
|
||||
## video-flow-b API 使用指南(方案一:保持现状,统一规范与示例)
|
||||
|
||||
> 目标:在不改动现有代码结构与签名的前提下,提供清晰的一致性用法、错误处理约定与多场景接入示例。
|
||||
|
||||
@ -54,7 +54,7 @@ await del<ApiResponse<null>>('/user/remove?id=1');
|
||||
import { stream } from '@/api/request';
|
||||
|
||||
await stream<{ type: string; message?: string; progress?: number }>({
|
||||
url: '/api/video-flow/export/ai-clips',
|
||||
url: '/api/video-flow-b/export/ai-clips',
|
||||
method: 'POST',
|
||||
data: { /* your body */ },
|
||||
onMessage: (evt) => {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
/**
|
||||
* 导出API适配器 - 将OpenCut的导出API适配到Video-Flow项目
|
||||
* 文件路径: video-flow/api/export-adapter.ts
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* 导出API适配器 - 将OpenCut的导出API适配到video-flow-b项目
|
||||
* 文件路径: video-flow-b/api/export-adapter.ts
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
@ -39,7 +37,7 @@ interface AIExportRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Video-Flow AI剪辑导出API
|
||||
* video-flow-b AI剪辑导出API
|
||||
* 复用OpenCut项目的 /api/export/ai-clips 逻辑
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
@ -49,11 +47,11 @@ export async function POST(req: NextRequest) {
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
try {
|
||||
console.log('🚀 Video-Flow AI剪辑导出API启动');
|
||||
console.log('🚀 video-flow-b AI剪辑导出API启动');
|
||||
const requestData: AIExportRequest = await req.json();
|
||||
const { clips, subtitles, totalDuration, options } = requestData;
|
||||
|
||||
console.log('=== Video-Flow AI剪辑导出开始 ===');
|
||||
console.log('=== video-flow-b AI剪辑导出开始 ===');
|
||||
console.log('Clips count:', clips.length);
|
||||
console.log('Total duration:', totalDuration, 'seconds');
|
||||
console.log('Quality:', options.quality);
|
||||
@ -64,7 +62,7 @@ export async function POST(req: NextRequest) {
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||
type: 'progress',
|
||||
stage: 'starting',
|
||||
message: '开始Video-Flow AI剪辑导出...',
|
||||
message: '开始video-flow-b AI剪辑导出...',
|
||||
progress: 0,
|
||||
})}\n\n`));
|
||||
} catch (controllerError) {
|
||||
@ -72,7 +70,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
// 创建工作目录
|
||||
workDir = await fs.mkdtemp(join(tmpdir(), 'video-flow-ai-export-'));
|
||||
workDir = await fs.mkdtemp(join(tmpdir(), 'video-flow-b-ai-export-'));
|
||||
console.log('Work directory:', workDir);
|
||||
|
||||
// 执行AI剪辑导出
|
||||
@ -83,14 +81,14 @@ export async function POST(req: NextRequest) {
|
||||
const stats = await fs.stat(outputPath);
|
||||
|
||||
// 提取导出ID
|
||||
const exportId = workDir.split('/').pop()?.replace('video-flow-ai-export-', '') || '';
|
||||
const exportId = workDir.split('/').pop()?.replace('video-flow-b-ai-export-', '') || '';
|
||||
|
||||
console.log('🎉 Video-Flow AI剪辑导出完成:', {
|
||||
console.log('🎉 video-flow-b AI剪辑导出完成:', {
|
||||
outputPath,
|
||||
fileSize: stats.size,
|
||||
exportId,
|
||||
workDir,
|
||||
downloadUrl: `/api/video-flow/export/download/${exportId}`,
|
||||
downloadUrl: `/api/video-flow-b/export/download/${exportId}`,
|
||||
});
|
||||
|
||||
// 🚀 新增:上传到七牛云(复用OpenCut逻辑)
|
||||
@ -110,7 +108,7 @@ export async function POST(req: NextRequest) {
|
||||
// 这里可以调用七牛云上传逻辑
|
||||
// const qiniuResult = await uploadToQiniu(outputPath, exportId);
|
||||
// 暂时使用本地URL
|
||||
qiniuUrl = `/api/video-flow/export/download/${exportId}`;
|
||||
qiniuUrl = `/api/video-flow-b/export/download/${exportId}`;
|
||||
console.log('✅ 视频上传完成:', qiniuUrl);
|
||||
} catch (error) {
|
||||
console.warn('⚠️ 视频上传失败:', error);
|
||||
@ -119,17 +117,17 @@ export async function POST(req: NextRequest) {
|
||||
try {
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||
type: 'completed',
|
||||
downloadUrl: qiniuUrl || `/api/video-flow/export/download/${exportId}`,
|
||||
downloadUrl: qiniuUrl || `/api/video-flow-b/export/download/${exportId}`,
|
||||
fileSize: stats.size,
|
||||
exportId: exportId,
|
||||
message: 'Video-Flow AI剪辑导出完成!'
|
||||
message: 'video-flow-b AI剪辑导出完成!'
|
||||
})}\n\n`));
|
||||
} catch (controllerError) {
|
||||
console.warn('⚠️ 控制器已关闭,无法发送完成通知:', controllerError);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Video-Flow AI剪辑导出失败:', error);
|
||||
console.error('video-flow-b AI剪辑导出失败:', error);
|
||||
try {
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||
type: 'error',
|
||||
@ -154,7 +152,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Video-Flow AI剪辑导出
|
||||
* 执行video-flow-b AI剪辑导出
|
||||
* 复用OpenCut的核心导出逻辑
|
||||
*/
|
||||
async function executeVideoFlowAIExport(
|
||||
@ -189,7 +187,7 @@ async function executeVideoFlowAIExport(
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||
type: 'progress',
|
||||
stage: 'downloading',
|
||||
message: '下载Video-Flow视频片段...',
|
||||
message: '下载video-flow-b视频片段...',
|
||||
progress: 0.2,
|
||||
})}\n\n`));
|
||||
} catch (controllerError) {
|
||||
@ -212,7 +210,7 @@ async function executeVideoFlowAIExport(
|
||||
|
||||
const ffmpegArgs = await buildVideoFlowFFmpegCommand(processedClips, subtitles, totalDuration, options, workDir);
|
||||
|
||||
console.log('=== Video-Flow AI剪辑导出调试信息 ===');
|
||||
console.log('=== video-flow-b AI剪辑导出调试信息 ===');
|
||||
console.log('Processed clips:', processedClips.length);
|
||||
console.log('Total duration:', totalDuration);
|
||||
console.log('FFmpeg合成命令: ffmpeg', ffmpegArgs.join(' '));
|
||||
@ -234,7 +232,7 @@ async function executeVideoFlowAIExport(
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载和处理Video-Flow视频片段
|
||||
* 下载和处理video-flow-b视频片段
|
||||
*/
|
||||
async function downloadAndProcessVideoFlowClips(
|
||||
clips: AIClipData[],
|
||||
@ -297,7 +295,7 @@ async function downloadAndProcessVideoFlowClips(
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建Video-Flow FFmpeg命令
|
||||
* 构建video-flow-b FFmpeg命令
|
||||
*/
|
||||
async function buildVideoFlowFFmpegCommand(
|
||||
processedClips: Array<{ clipPath: string; duration: number; startTime: number }>,
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
/**
|
||||
* Video-Flow AI剪辑导出API路由
|
||||
* 文件路径: video-flow/app/api/export/ai-clips/route.ts
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* video-flow-b AI剪辑导出API路由
|
||||
* 文件路径: video-flow-b/app/api/export/ai-clips/route.ts
|
||||
|
||||
*
|
||||
* 这个API端点专门为Video-Flow项目提供AI剪辑导出功能
|
||||
* 复用OpenCut项目的核心导出逻辑,但适配Video-Flow的数据结构
|
||||
* 这个API端点专门为video-flow-b项目提供AI剪辑导出功能
|
||||
* 复用OpenCut项目的核心导出逻辑,但适配video-flow-b的数据结构
|
||||
*/
|
||||
|
||||
// 直接导出适配器中的POST函数
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
/**
|
||||
* Video-Flow 导出视频下载API
|
||||
* 文件路径: video-flow/app/api/export/download/[exportId]/route.ts
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* video-flow-b 导出视频下载API
|
||||
* 文件路径: video-flow-b/app/api/export/download/[exportId]/route.ts
|
||||
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
@ -24,10 +23,10 @@ export async function GET(
|
||||
);
|
||||
}
|
||||
|
||||
console.log('📥 Video-Flow 导出视频下载请求:', exportId);
|
||||
console.log('📥 video-flow-b 导出视频下载请求:', exportId);
|
||||
|
||||
// 构建文件路径
|
||||
const workDir = join(tmpdir(), `video-flow-ai-export-${exportId}`);
|
||||
const workDir = join(tmpdir(), `video-flow-b-ai-export-${exportId}`);
|
||||
const filePath = join(workDir, 'output.mp4');
|
||||
|
||||
// 检查文件是否存在
|
||||
@ -45,7 +44,7 @@ export async function GET(
|
||||
const fileBuffer = await fs.readFile(filePath);
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
console.log('✅ Video-Flow 导出视频下载成功:', {
|
||||
console.log('✅ video-flow-b 导出视频下载成功:', {
|
||||
exportId,
|
||||
fileSize: stats.size,
|
||||
filePath
|
||||
@ -56,13 +55,13 @@ export async function GET(
|
||||
headers: {
|
||||
'Content-Type': 'video/mp4',
|
||||
'Content-Length': stats.size.toString(),
|
||||
'Content-Disposition': `attachment; filename="video-flow-ai-edited-${exportId}.mp4"`,
|
||||
'Content-Disposition': `attachment; filename="video-flow-b-ai-edited-${exportId}.mp4"`,
|
||||
'Cache-Control': 'public, max-age=3600', // 缓存1小时
|
||||
},
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Video-Flow 导出视频下载失败:', error);
|
||||
console.error('❌ video-flow-b 导出视频下载失败:', error);
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
@ -92,7 +91,7 @@ export async function DELETE(
|
||||
);
|
||||
}
|
||||
|
||||
const workDir = join(tmpdir(), `video-flow-ai-export-${exportId}`);
|
||||
const workDir = join(tmpdir(), `video-flow-b-ai-export-${exportId}`);
|
||||
|
||||
try {
|
||||
await fs.rm(workDir, { recursive: true, force: true });
|
||||
|
||||
101
compile_dev.ps1
101
compile_dev.ps1
@ -1,101 +0,0 @@
|
||||
# Windows PowerShell deployment script
|
||||
|
||||
$BRANCH_NAME = "dev"
|
||||
|
||||
# Project name
|
||||
$PROJECT_NAME = "video-flow-$BRANCH_NAME-frontend"
|
||||
|
||||
# Log file path
|
||||
$LOGFILE = "build_and_copy.log"
|
||||
|
||||
# Record start time
|
||||
$startMessage = "Build process started at $(Get-Date)"
|
||||
$startMessage | Tee-Object -FilePath $LOGFILE
|
||||
|
||||
# Get current branch name
|
||||
$current_branch = git rev-parse --abbrev-ref HEAD
|
||||
|
||||
# Check if on dev branch, working directory is clean, and in sync with remote
|
||||
if ($current_branch -ne $BRANCH_NAME) {
|
||||
Write-Host "Current branch is not dev branch" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if working directory is clean
|
||||
$gitStatus = git status --porcelain
|
||||
if ($gitStatus) {
|
||||
Write-Host "Working directory is not clean" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if local branch is in sync with remote
|
||||
$localHead = git rev-parse HEAD
|
||||
$remoteHead = git rev-parse origin/$BRANCH_NAME
|
||||
if ($localHead -ne $remoteHead) {
|
||||
Write-Host "Local branch is not in sync with remote branch" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check current branch and run corresponding build command
|
||||
if ($current_branch -eq $BRANCH_NAME) {
|
||||
$buildMessage = "On dev branch, building project..."
|
||||
$buildMessage | Tee-Object -FilePath $LOGFILE -Append
|
||||
$PROFILE_ENV = $BRANCH_NAME
|
||||
|
||||
# Install dependencies and build (production mode with development environment variables)
|
||||
yarn install
|
||||
$env:NODE_ENV = "production"
|
||||
npx --yes env-cmd -f .env.development yarn build
|
||||
|
||||
# Prepare dist directory
|
||||
if (Test-Path "dist") {
|
||||
Remove-Item -Path "dist" -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path "dist" -Force | Out-Null
|
||||
|
||||
if (Test-Path ".next\cache") {
|
||||
Remove-Item -Path ".next\cache" -Recurse -Force
|
||||
}
|
||||
|
||||
Copy-Item -Path ".next" -Destination "dist\.next" -Recurse -Force
|
||||
Copy-Item -Path "public" -Destination "dist\public" -Recurse -Force
|
||||
Copy-Item -Path "package.json" -Destination "dist\package.json" -Force
|
||||
Copy-Item -Path "package-lock.json" -Destination "dist\package-lock.json" -Force
|
||||
|
||||
} else {
|
||||
Write-Host "On non-dev branch ($current_branch), exiting" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Create tar package
|
||||
$tarFileName = "$PROJECT_NAME-$PROFILE_ENV.tar.gz"
|
||||
tar -czvf $tarFileName dist
|
||||
|
||||
# Record end time
|
||||
$endMessage = "Build process completed at $(Get-Date)"
|
||||
$endMessage | Tee-Object -FilePath $LOGFILE -Append
|
||||
|
||||
# Upload to nexus
|
||||
$uploadMessage = "upload to nexus at $(Get-Date)"
|
||||
$uploadMessage | Tee-Object -FilePath $LOGFILE -Append
|
||||
|
||||
$nexusUrl = "https://repo.qikongjian.com/repository/frontend-tar-files/$tarFileName"
|
||||
$credentials = 'admin:YZ9Gq6=8\*G|?:,'
|
||||
$encodedCredentials = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($credentials))
|
||||
|
||||
try {
|
||||
Invoke-WebRequest -Uri $nexusUrl -Method Put -InFile $tarFileName -Headers @{
|
||||
Authorization = "Basic $encodedCredentials"
|
||||
}
|
||||
Write-Host "Upload successful" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "Upload failed: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Clean up build files
|
||||
Remove-Item -Path "dist" -Recurse -Force
|
||||
Remove-Item -Path $tarFileName -Force
|
||||
|
||||
Write-Host "Deployment completed" -ForegroundColor Green
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
BRANCH_NAME="dev"
|
||||
|
||||
# 修改项目名称
|
||||
PROJECT_NAME="video-flow-$BRANCH_NAME-frontend"
|
||||
PROJECT_NAME="video-flow-b-$BRANCH_NAME-frontend"
|
||||
|
||||
# 设置日志文件路径
|
||||
LOGFILE="build_and_copy.log"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
BRANCH_NAME="prod"
|
||||
|
||||
# 修改项目名称
|
||||
PROJECT_NAME="video-flow-$BRANCH_NAME-frontend"
|
||||
PROJECT_NAME="video-flow-b-$BRANCH_NAME-frontend"
|
||||
|
||||
# 设置日志文件路径
|
||||
LOGFILE="build_and_copy.log"
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
/**
|
||||
* AI剪辑适配器 - 将OpenCut的AI剪辑逻辑适配到Video-Flow
|
||||
* 文件路径: video-flow/components/pages/work-flow/ai-editing-adapter.ts
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* AI剪辑适配器 - 将OpenCut的AI剪辑逻辑适配到video-flow-b
|
||||
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-adapter.ts
|
||||
|
||||
*/
|
||||
|
||||
// 从OpenCut项目导入的类型定义
|
||||
@ -40,7 +39,7 @@ interface ExportOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Video-Flow项目的任务对象类型
|
||||
* video-flow-b项目的任务对象类型
|
||||
*/
|
||||
interface VideoFlowTaskObject {
|
||||
title: string;
|
||||
@ -61,7 +60,7 @@ interface VideoFlowTaskObject {
|
||||
|
||||
/**
|
||||
* AI剪辑适配器类
|
||||
* 负责将Video-Flow的视频数据转换为OpenCut的AI剪辑格式,并执行自动化剪辑流程
|
||||
* 负责将video-flow-b的视频数据转换为OpenCut的AI剪辑格式,并执行自动化剪辑流程
|
||||
*/
|
||||
export class AIEditingAdapter {
|
||||
private projectId: string;
|
||||
@ -87,12 +86,12 @@ export class AIEditingAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Video-Flow的视频数据转换为AI剪辑计划格式
|
||||
* 将video-flow-b的视频数据转换为AI剪辑计划格式
|
||||
*/
|
||||
private convertToAIEditingPlan(): AIEditingPlan {
|
||||
const clips: AIClipData[] = [];
|
||||
|
||||
// 遍历Video-Flow的视频数据,转换为AI剪辑格式
|
||||
// 遍历video-flow-b的视频数据,转换为AI剪辑格式
|
||||
this.taskObject.videos.data.forEach((video, index) => {
|
||||
if (video.video_status === 1 && video.urls && video.urls.length > 0) {
|
||||
// 只处理生成成功的视频
|
||||
@ -172,7 +171,7 @@ export class AIEditingAdapter {
|
||||
|
||||
this.onProgress?.(90, "剪辑完成,正在生成最终视频...");
|
||||
|
||||
// 第四步:更新Video-Flow项目状态
|
||||
// 第四步:更新video-flow-b项目状态
|
||||
await this.updateVideoFlowProject(finalVideoUrl);
|
||||
|
||||
this.onProgress?.(100, "AI剪辑流程完成!");
|
||||
@ -197,7 +196,7 @@ export class AIEditingAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用Video-Flow的导出API
|
||||
* 调用video-flow-b的导出API
|
||||
* 复用OpenCut项目中的 /api/export/ai-clips 逻辑
|
||||
*/
|
||||
private async callExportAPI(exportRequest: any): Promise<string> {
|
||||
@ -263,12 +262,12 @@ export class AIEditingAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新Video-Flow项目状态
|
||||
* 将AI剪辑结果更新到Video-Flow的数据结构中
|
||||
* 更新video-flow-b项目状态
|
||||
* 将AI剪辑结果更新到video-flow-b的数据结构中
|
||||
*/
|
||||
private async updateVideoFlowProject(finalVideoUrl: string): Promise<void> {
|
||||
try {
|
||||
// 构建任务结果数据,模拟Video-Flow的粗剪接口调用
|
||||
// 构建任务结果数据,模拟video-flow-b的粗剪接口调用
|
||||
const taskResult = {
|
||||
task_result: JSON.stringify({
|
||||
video: finalVideoUrl
|
||||
@ -277,16 +276,16 @@ export class AIEditingAdapter {
|
||||
project_id: this.projectId
|
||||
};
|
||||
|
||||
console.log('🎬 更新Video-Flow项目状态:');
|
||||
console.log('🎬 更新video-flow-b项目状态:');
|
||||
console.log(' - 项目ID:', this.projectId);
|
||||
console.log(' - 最终视频URL:', finalVideoUrl);
|
||||
console.log(' - 任务结果:', taskResult);
|
||||
|
||||
// 这里可以调用Video-Flow的API来更新项目状态
|
||||
// 这里可以调用video-flow-b的API来更新项目状态
|
||||
// 或者直接更新本地状态(取决于具体需求)
|
||||
|
||||
} catch (error) {
|
||||
console.warn("更新Video-Flow项目状态失败:", error);
|
||||
console.warn("更新video-flow-b项目状态失败:", error);
|
||||
// 不抛出错误,避免影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
/**
|
||||
* AI剪辑按钮组件 - Video-Flow集成OpenCut AI剪辑功能
|
||||
* 文件路径: video-flow/components/pages/work-flow/ai-editing-button.tsx
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* AI剪辑按钮组件 - video-flow-b集成OpenCut AI剪辑功能
|
||||
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-button.tsx
|
||||
|
||||
*/
|
||||
|
||||
"use client";
|
||||
@ -25,7 +24,7 @@ import { createAIEditingAdapter, VideoFlowTaskObject, AIEditingAdapter } from '.
|
||||
interface AIEditingButtonProps {
|
||||
/** 项目ID */
|
||||
projectId: string;
|
||||
/** Video-Flow任务对象 */
|
||||
/** video-flow-b任务对象 */
|
||||
taskObject: VideoFlowTaskObject;
|
||||
/** 是否禁用按钮 */
|
||||
disabled?: boolean;
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
/**
|
||||
* AI剪辑iframe组件 - 集成智能剪辑到work-flow页面
|
||||
* 文件路径: video-flow/components/pages/work-flow/ai-editing-iframe.tsx
|
||||
* 作者: 资深全栈开发工程师
|
||||
* 创建时间: 2025-01-08
|
||||
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-iframe.tsx
|
||||
|
||||
*/
|
||||
|
||||
"use client";
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# Video-Flow AI 剪辑集成技术文档
|
||||
# video-flow-b AI 剪辑集成技术文档
|
||||
|
||||
## 📋 项目概述
|
||||
|
||||
本文档详细记录了将 OpenCut 项目的 AI 智能剪辑功能集成到 Video-Flow 工作流系统中的完整技术方案。该集成实现了从剧本生成的视频片段到最终成片的自动化 AI 剪辑流程。
|
||||
本文档详细记录了将 OpenCut 项目的 AI 智能剪辑功能集成到 video-flow-b 工作流系统中的完整技术方案。该集成实现了从剧本生成的视频片段到最终成片的自动化 AI 剪辑流程。
|
||||
|
||||
### 🎯 集成目标
|
||||
|
||||
- **自动化剪辑**: 在 Video-Flow 工作流中实现一键 AI 剪辑功能
|
||||
- **自动化剪辑**: 在 video-flow-b 工作流中实现一键 AI 剪辑功能
|
||||
- **无缝集成**: 复用 OpenCut 的核心 AI 剪辑逻辑,无需重复开发
|
||||
- **流程优化**: 简化从视频片段到最终成片的处理流程
|
||||
- **用户体验**: 提供直观的进度反馈和错误处理机制
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Video-Flow 前端层"
|
||||
subgraph "video-flow-b 前端层"
|
||||
A[work-flow.tsx] --> B[ai-editing-button.tsx]
|
||||
B --> C[ai-editing-adapter.ts]
|
||||
end
|
||||
@ -33,7 +33,7 @@ graph TB
|
||||
G --> H[云存储上传]
|
||||
end
|
||||
|
||||
subgraph "Video-Flow 后端"
|
||||
subgraph "video-flow-b 后端"
|
||||
H --> I[任务状态更新]
|
||||
I --> J[最终成片展示]
|
||||
end
|
||||
@ -75,7 +75,7 @@ classDiagram
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
video-flow/
|
||||
video-flow-b/
|
||||
├── components/pages/work-flow/
|
||||
│ ├── ai-editing-adapter.ts # AI剪辑逻辑适配器
|
||||
│ ├── ai-editing-button.tsx # AI剪辑按钮组件
|
||||
@ -93,7 +93,7 @@ video-flow/
|
||||
|
||||
### 1. AI 剪辑适配器 (`ai-editing-adapter.ts`)
|
||||
|
||||
**职责**: 将 Video-Flow 的数据结构转换为 OpenCut 兼容格式,并管理整个 AI 剪辑流程。
|
||||
**职责**: 将 video-flow-b 的数据结构转换为 OpenCut 兼容格式,并管理整个 AI 剪辑流程。
|
||||
|
||||
**核心功能**:
|
||||
|
||||
@ -116,7 +116,7 @@ class AIEditingAdapter {
|
||||
**数据转换逻辑**:
|
||||
|
||||
```typescript
|
||||
// Video-Flow格式 -> OpenCut AI剪辑格式
|
||||
// video-flow-b格式 -> OpenCut AI剪辑格式
|
||||
{
|
||||
videos: VideoFlowVideoData[]
|
||||
}
|
||||
@ -168,7 +168,7 @@ class AIEditingAdapter {
|
||||
### 1. 触发条件
|
||||
|
||||
```typescript
|
||||
// 当Video-Flow工作流进入video阶段且有视频片段时
|
||||
// 当video-flow-b工作流进入video阶段且有视频片段时
|
||||
if (taskObject.currentStage === "video" && taskObject.videos.data.length > 0) {
|
||||
// 显示AI剪辑按钮
|
||||
showAIEditingButton = true;
|
||||
@ -213,7 +213,7 @@ sequenceDiagram
|
||||
**输入数据结构**:
|
||||
|
||||
```typescript
|
||||
// Video-Flow视频数据
|
||||
// video-flow-b视频数据
|
||||
interface VideoFlowVideoData {
|
||||
id: string;
|
||||
url: string;
|
||||
@ -355,7 +355,7 @@ FFMPEG_PATH=/usr/local/bin/ffmpeg
|
||||
|
||||
```typescript
|
||||
describe("AIEditingAdapter", () => {
|
||||
test("应该正确转换Video-Flow数据格式", () => {
|
||||
test("应该正确转换video-flow-b数据格式", () => {
|
||||
const adapter = new AIEditingAdapter(mockTaskObject);
|
||||
const result = adapter.convertVideoFlowToAIClips();
|
||||
expect(result).toHaveLength(mockTaskObject.videos.data.length);
|
||||
@ -451,7 +451,7 @@ console.log("✅ 处理完成:", finalVideoUrl);
|
||||
## 📚 参考资料
|
||||
|
||||
- [OpenCut 项目文档](../apps/web/README.md)
|
||||
- [Video-Flow 项目文档](./README.md)
|
||||
- [video-flow-b 项目文档](./README.md)
|
||||
- [FFmpeg 官方文档](https://ffmpeg.org/documentation.html)
|
||||
- [Next.js API Routes 文档](https://nextjs.org/docs/api-routes/introduction)
|
||||
- [Server-Sent Events 规范](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
## 📋 概述
|
||||
|
||||
本文档详细记录了 Video-Flow 项目中 Google OAuth2 登录功能的完整实现,包括前端 UI 集成、后端 API 对接、错误处理和安全机制等。
|
||||
本文档详细记录了 video-flow-b 项目中 Google OAuth2 登录功能的完整实现,包括前端 UI 集成、后端 API 对接、错误处理和安全机制等。
|
||||
|
||||
**实现日期:** 2024 年 12 月
|
||||
|
||||
@ -770,4 +770,4 @@ const signInWithGoogleRetry = async (maxRetries = 3) => {
|
||||
|
||||
**最后更新**: 2024 年 12 月 19 日
|
||||
**版本**: v1.0.0
|
||||
**维护者**: Video-Flow 开发团队
|
||||
**维护者**: video-flow-b 开发团队
|
||||
|
||||
@ -118,4 +118,4 @@ if (result.success) {
|
||||
|
||||
文档版本:v4.0
|
||||
更新时间:2025-09-23
|
||||
适用范围:video-flow 前端项目
|
||||
适用范围:video-flow-b 前端项目
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
## 📋 概述
|
||||
|
||||
本文档为Video-Flow视频编辑功能的后端API提供完整的实现规范,包括RESTful API设计、数据结构定义、认证机制、数据库设计等,为后端开发团队提供详细的实现指南。
|
||||
本文档为video-flow-b视频编辑功能的后端API提供完整的实现规范,包括RESTful API设计、数据结构定义、认证机制、数据库设计等,为后端开发团队提供详细的实现指南。
|
||||
|
||||
## 🏗️ 系统架构
|
||||
|
||||
@ -622,4 +622,4 @@ def test_create_edit_point():
|
||||
|
||||
**文档版本**: v1.0.0
|
||||
**最后更新**: 2024-09-19
|
||||
**维护者**: Video-Flow 开发团队
|
||||
**维护者**: video-flow-b 开发团队
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Video-Flow 自动下载功能禁用说明
|
||||
# video-flow-b 自动下载功能禁用说明
|
||||
|
||||
## 📋 修改概述
|
||||
|
||||
根据需求,已将 Video-Flow 工作流中的自动下载视频功能暂时禁用,用户需要手动下载生成的视频。
|
||||
根据需求,已将 video-flow-b 工作流中的自动下载视频功能暂时禁用,用户需要手动下载生成的视频。
|
||||
|
||||
## 🔍 工作流程梳理
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# ⚡ Video-Flow 性能优化快速实施指南
|
||||
# ⚡ video-flow-b 性能优化快速实施指南
|
||||
|
||||
> **紧急修复清单** - 可在1-2天内完成,立即提升50%+性能
|
||||
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@ -91,6 +91,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.17.19",
|
||||
"env-cmd": "^10.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.2"
|
||||
}
|
||||
@ -10247,6 +10248,23 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/env-cmd": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz",
|
||||
"integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^4.0.0",
|
||||
"cross-spawn": "^7.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"env-cmd": "bin/env-cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user