Files
mxivideo/src/services/tauri.ts
root 96e166725b feat: 集成 AI 视频生成功能到 MixVideo V2
🎬 主要功能:
-  完整的 AI 视频生成模块 (Python)
-  图片转视频 API 集成 (字节跳动 Seedance)
-  云存储支持 (腾讯云 COS)
-  单张图片和批量处理模式
-  现代化 React 界面组件
-  Tauri 桥接通信

🛠️ 技术实现:
- Python 模块:VideoGenerator, CloudStorage, APIClient
- Rust 命令:generate_ai_video, batch_generate_ai_videos
- React 组件:AIVideoGenerator, AIVideoPage
- 状态管理:useAIVideoStore (Zustand)
- 路由集成:/ai-video 页面

�� 新增文件:
- python_core/ai_video/ - AI 视频生成核心模块
- src/components/AIVideoGenerator.tsx - 主要 UI 组件
- src/pages/AIVideoPage.tsx - AI 视频生成页面
- src/stores/useAIVideoStore.ts - 状态管理

🎯 功能特性:
- 支持 Lite (720p) 和 Pro (1080p) 模型
- 可配置视频时长 (5秒/10秒)
- 实时进度跟踪和任务管理
- 批量处理多张图片
- 云存储自动上传下载
- 错误处理和重试机制

🔗 界面集成:
- 侧边栏导航添加 'AI 视频' 入口
- 首页快速操作卡片
- 完整的用户引导和帮助文档

这是从原始 Tkinter GUI 到现代 Web 应用的完整迁移!
2025-07-10 10:43:40 +08:00

406 lines
8.7 KiB
TypeScript

/**
* Tauri API Service
* Handles communication between frontend and Tauri backend
*/
import { invoke } from '@tauri-apps/api/core'
// Types for video processing
export interface VideoProcessRequest {
input_path: string
output_path: string
operation: string
parameters: Record<string, any>
}
export interface AudioAnalysisRequest {
file_path: string
analysis_type: string
}
export interface AIVideoRequest {
image_path: string
prompt: string
duration: string
model_type: string
output_path?: string
timeout?: number
}
export interface BatchAIVideoRequest {
image_folder: string
prompts: string[]
output_folder: string
duration: string
model_type: string
timeout?: number
}
export interface ProjectInfo {
id: string
name: string
path: string
created_at: string
modified_at: string
video_tracks: VideoTrack[]
audio_tracks: AudioTrack[]
timeline: {
duration: number
zoom: number
position: number
}
}
export interface VideoTrack {
id: string
name: string
file_path: string
start_time: number
duration: number
}
export interface AudioTrack {
id: string
name: string
file_path: string
start_time: number
duration: number
volume: number
}
// Tauri command wrappers
export class TauriService {
/**
* Test connection to backend
*/
static async greet(name: string): Promise<string> {
try {
return await invoke('greet', { name })
} catch (error) {
console.error('Failed to greet:', error)
throw error
}
}
/**
* Process video with specified operation
*/
static async processVideo(request: VideoProcessRequest): Promise<any> {
try {
const result = await invoke('process_video', { request })
return JSON.parse(result as string)
} catch (error) {
console.error('Failed to process video:', error)
throw error
}
}
/**
* Analyze audio file
*/
static async analyzeAudio(request: AudioAnalysisRequest): Promise<any> {
try {
const result = await invoke('analyze_audio', { request })
return JSON.parse(result as string)
} catch (error) {
console.error('Failed to analyze audio:', error)
throw error
}
}
/**
* Get project information
*/
static async getProjectInfo(projectPath: string): Promise<ProjectInfo> {
try {
return await invoke('get_project_info', { projectPath })
} catch (error) {
console.error('Failed to get project info:', error)
throw error
}
}
/**
* Save project
*/
static async saveProject(projectInfo: ProjectInfo): Promise<string> {
try {
return await invoke('save_project', { projectInfo })
} catch (error) {
console.error('Failed to save project:', error)
throw error
}
}
/**
* Load project
*/
static async loadProject(projectPath: string): Promise<ProjectInfo> {
try {
return await invoke('load_project', { projectPath })
} catch (error) {
console.error('Failed to load project:', error)
throw error
}
}
}
// Video processing operations
export class VideoService {
/**
* Trim video to specified duration
*/
static async trimVideo(
inputPath: string,
outputPath: string,
startTime: number,
endTime: number
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'trim',
parameters: { start_time: startTime, end_time: endTime }
})
}
/**
* Resize video to specified dimensions
*/
static async resizeVideo(
inputPath: string,
outputPath: string,
width?: number,
height?: number
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'resize',
parameters: { width, height }
})
}
/**
* Crop video to specified region
*/
static async cropVideo(
inputPath: string,
outputPath: string,
x1: number,
y1: number,
x2: number,
y2: number
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'crop',
parameters: { x1, y1, x2, y2 }
})
}
/**
* Adjust video brightness
*/
static async adjustBrightness(
inputPath: string,
outputPath: string,
factor: number
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'adjust_brightness',
parameters: { factor }
})
}
/**
* Adjust video contrast
*/
static async adjustContrast(
inputPath: string,
outputPath: string,
factor: number
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'adjust_contrast',
parameters: { factor }
})
}
/**
* Add text overlay to video
*/
static async addText(
inputPath: string,
outputPath: string,
text: string,
options: {
fontsize?: number
color?: string
position?: [string, string]
duration?: number
} = {}
): Promise<any> {
return TauriService.processVideo({
input_path: inputPath,
output_path: outputPath,
operation: 'add_text',
parameters: { text, ...options }
})
}
/**
* Merge multiple videos
*/
static async mergeVideos(
videoPaths: string[],
outputPath: string
): Promise<any> {
return TauriService.processVideo({
input_path: '', // Not used for merge
output_path: outputPath,
operation: 'merge',
parameters: { video_paths: videoPaths }
})
}
}
// Audio processing operations
export class AudioService {
/**
* Analyze rhythm and beat tracking
*/
static async analyzeRhythm(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'rhythm'
})
}
/**
* Analyze spectral features
*/
static async analyzeSpectral(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'spectral'
})
}
/**
* Analyze tempo
*/
static async analyzeTempo(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'tempo'
})
}
/**
* Analyze pitch
*/
static async analyzePitch(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'pitch'
})
}
/**
* Analyze energy
*/
static async analyzeEnergy(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'energy'
})
}
/**
* Analyze MFCC features
*/
static async analyzeMFCC(filePath: string): Promise<any> {
return TauriService.analyzeAudio({
file_path: filePath,
analysis_type: 'mfcc'
})
}
}
// Project management operations
export class ProjectService {
/**
* Create new project
*/
static async createProject(name: string, description: string = ''): Promise<ProjectInfo> {
// This would typically call a Python script to create the project
// For now, we'll create a basic project structure
const projectInfo: ProjectInfo = {
id: crypto.randomUUID(),
name,
path: `/projects/${name}`,
created_at: new Date().toISOString(),
modified_at: new Date().toISOString(),
video_tracks: [],
audio_tracks: [],
timeline: {
duration: 0,
zoom: 1,
position: 0
}
}
await TauriService.saveProject(projectInfo)
return projectInfo
}
/**
* Load existing project
*/
static async loadProject(projectPath: string): Promise<ProjectInfo> {
return TauriService.loadProject(projectPath)
}
/**
* Save project
*/
static async saveProject(projectInfo: ProjectInfo): Promise<void> {
await TauriService.saveProject(projectInfo)
}
}
// AI Video generation operations
export class AIVideoService {
/**
* Generate video from single image
*/
static async generateVideo(request: AIVideoRequest): Promise<any> {
try {
const result = await invoke('generate_ai_video', { request })
return JSON.parse(result as string)
} catch (error) {
console.error('Failed to generate AI video:', error)
throw error
}
}
/**
* Batch generate videos from multiple images
*/
static async batchGenerateVideos(request: BatchAIVideoRequest): Promise<any> {
try {
const result = await invoke('batch_generate_ai_videos', { request })
return JSON.parse(result as string)
} catch (error) {
console.error('Failed to batch generate AI videos:', error)
throw error
}
}
}