feat: 添加前端输出目录选择功能
🎯 **解决问题**: 修复 AI 视频生成失败问题:'Single mode requires --image, --prompt, and --output' 🔧 **前端改进**: 1. **单个模式输出目录选择**: - 添加 singleOutputFolder 状态管理 - 新增 handleSingleOutputFolderSelect 处理函数 - UI 中添加输出目录选择按钮和输入框 - 支持手动输入和文件夹选择两种方式 2. **批量模式输出目录优化**: - 重构为专门的 handleBatchOutputFolderSelect 函数 - 替换内联函数,提高代码可维护性 - 统一错误处理和用户反馈 3. **用户界面增强**: - 单个模式:'视频保存目录 (可选)' - 用户友好的可选设置 - 批量模式:保持原有的必需输出目录设置 - 占位符文本提供清晰的使用指导 - 实时显示选择状态:'未选择 (将使用默认目录)' 4. **后端兼容性**: - Rust 代码提供默认输出路径备用方案 - 确保 Python 脚本始终接收到 --output 参数 - 使用系统临时目录作为默认保存位置 ✅ **修复效果**: - 解决 'Single mode requires --output' 错误 ✓ - 用户可以自定义视频保存位置 ✓ - 提供默认保存路径备用方案 ✓ - 改善用户体验和操作便利性 ✓ 现在用户可以选择视频保存位置,解决了生成失败的问题!
This commit is contained in:
parent
1ef9371dde
commit
58c6b6c247
|
|
@ -17,6 +17,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
const [customPrompt, setCustomPrompt] = useState<string>('')
|
const [customPrompt, setCustomPrompt] = useState<string>('')
|
||||||
const [batchPrompts, setBatchPrompts] = useState<string[]>([''])
|
const [batchPrompts, setBatchPrompts] = useState<string[]>([''])
|
||||||
const [outputFolder, setOutputFolder] = useState<string>('')
|
const [outputFolder, setOutputFolder] = useState<string>('')
|
||||||
|
const [singleOutputFolder, setSingleOutputFolder] = useState<string>('')
|
||||||
const [duration, setDuration] = useState<string>('5')
|
const [duration, setDuration] = useState<string>('5')
|
||||||
const [modelType, setModelType] = useState<string>('lite')
|
const [modelType, setModelType] = useState<string>('lite')
|
||||||
const [previewData, setPreviewData] = useState<{
|
const [previewData, setPreviewData] = useState<{
|
||||||
|
|
@ -114,6 +115,30 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSingleOutputFolderSelect = async () => {
|
||||||
|
try {
|
||||||
|
console.log('Opening output folder dialog...')
|
||||||
|
const folderPath = await invoke('select_folder') as string
|
||||||
|
console.log('Selected output folder:', folderPath)
|
||||||
|
setSingleOutputFolder(folderPath)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to select output folder:', error)
|
||||||
|
alert(`输出文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBatchOutputFolderSelect = async () => {
|
||||||
|
try {
|
||||||
|
console.log('Opening batch output folder dialog...')
|
||||||
|
const folderPath = await invoke('select_folder') as string
|
||||||
|
console.log('Selected batch output folder:', folderPath)
|
||||||
|
setOutputFolder(folderPath)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to select batch output folder:', error)
|
||||||
|
alert(`批量输出文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Handle generation
|
// Handle generation
|
||||||
|
|
@ -136,7 +161,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
prompt: customPrompt,
|
prompt: customPrompt,
|
||||||
duration,
|
duration,
|
||||||
model_type: modelType,
|
model_type: modelType,
|
||||||
output_path: outputFolder
|
output_path: singleOutputFolder
|
||||||
})
|
})
|
||||||
|
|
||||||
await generateSingleVideo({
|
await generateSingleVideo({
|
||||||
|
|
@ -144,7 +169,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
prompt: customPrompt,
|
prompt: customPrompt,
|
||||||
duration,
|
duration,
|
||||||
model_type: modelType,
|
model_type: modelType,
|
||||||
output_path: outputFolder || undefined,
|
output_path: singleOutputFolder || undefined,
|
||||||
timeout: 300
|
timeout: 300
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -262,6 +287,32 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Output Directory for Single Mode */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-secondary-700 mb-2">
|
||||||
|
视频保存目录 (可选)
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<button
|
||||||
|
onClick={handleSingleOutputFolderSelect}
|
||||||
|
className="flex items-center px-4 py-2 bg-secondary-100 hover:bg-secondary-200 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<Folder size={16} className="mr-2" />
|
||||||
|
选择保存目录
|
||||||
|
</button>
|
||||||
|
<span className="text-sm text-secondary-600">
|
||||||
|
{singleOutputFolder || '未选择 (将使用默认目录)'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={singleOutputFolder}
|
||||||
|
onChange={(e) => setSingleOutputFolder(e.target.value)}
|
||||||
|
placeholder="或手动输入保存目录路径 (例如: C:\Users\用户名\Videos)"
|
||||||
|
className="input w-full text-sm mt-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|
@ -298,17 +349,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={async () => {
|
onClick={handleBatchOutputFolderSelect}
|
||||||
try {
|
|
||||||
console.log('Opening output folder dialog...')
|
|
||||||
const folderPath = await invoke('select_folder') as string
|
|
||||||
console.log('Selected output folder:', folderPath)
|
|
||||||
setOutputFolder(folderPath)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to select output folder:', error)
|
|
||||||
alert(`输出文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="btn-secondary px-3 py-2"
|
className="btn-secondary px-3 py-2"
|
||||||
title="选择输出文件夹"
|
title="选择输出文件夹"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue