update:1.优化灵感模式重试功能
This commit is contained in:
@@ -61,6 +61,7 @@ const Inspiration: React.FC = () => {
|
|||||||
|
|
||||||
// 新增:保存生成数据,用于重试
|
// 新增:保存生成数据,用于重试
|
||||||
const [generationData, setGenerationData] = useState<WizardData | null>(null);
|
const [generationData, setGenerationData] = useState<WizardData | null>(null);
|
||||||
|
// 保存世界观生成结果,用于后续步骤
|
||||||
const [worldBuildingResult, setWorldBuildingResult] = useState<any>(null);
|
const [worldBuildingResult, setWorldBuildingResult] = useState<any>(null);
|
||||||
|
|
||||||
// 滚动容器引用
|
// 滚动容器引用
|
||||||
@@ -364,13 +365,14 @@ const Inspiration: React.FC = () => {
|
|||||||
},
|
},
|
||||||
onResult: (result) => {
|
onResult: (result) => {
|
||||||
setProjectId(result.project_id);
|
setProjectId(result.project_id);
|
||||||
setWorldBuildingResult(result); // 保存结果用于重试
|
setWorldBuildingResult(result); // 保存世界观结果
|
||||||
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'completed' }));
|
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'completed' }));
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('世界观生成失败:', error);
|
console.error('世界观生成失败:', error);
|
||||||
setErrorDetails(`世界观生成失败: ${error}`);
|
setErrorDetails(`世界观生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'error' }));
|
||||||
|
setLoading(false); // 确保错误时解除加载状态
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
@@ -385,7 +387,7 @@ const Inspiration: React.FC = () => {
|
|||||||
|
|
||||||
const createdProjectId = worldResult.project_id;
|
const createdProjectId = worldResult.project_id;
|
||||||
setProjectId(createdProjectId);
|
setProjectId(createdProjectId);
|
||||||
setWorldBuildingResult(worldResult);
|
setWorldBuildingResult(worldResult); // 保存世界观结果
|
||||||
|
|
||||||
// 步骤2: 生成角色
|
// 步骤2: 生成角色
|
||||||
setGenerationSteps(prev => ({ ...prev, characters: 'processing' }));
|
setGenerationSteps(prev => ({ ...prev, characters: 'processing' }));
|
||||||
@@ -417,6 +419,7 @@ const Inspiration: React.FC = () => {
|
|||||||
console.error('角色生成失败:', error);
|
console.error('角色生成失败:', error);
|
||||||
setErrorDetails(`角色生成失败: ${error}`);
|
setErrorDetails(`角色生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, characters: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, characters: 'error' }));
|
||||||
|
setLoading(false); // 确保错误时解除加载状态
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
@@ -449,6 +452,7 @@ const Inspiration: React.FC = () => {
|
|||||||
console.error('大纲生成失败:', error);
|
console.error('大纲生成失败:', error);
|
||||||
setErrorDetails(`大纲生成失败: ${error}`);
|
setErrorDetails(`大纲生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, outline: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, outline: 'error' }));
|
||||||
|
setLoading(false); // 确保错误时解除加载状态
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
@@ -470,17 +474,46 @@ const Inspiration: React.FC = () => {
|
|||||||
setErrorDetails(errorMsg);
|
setErrorDetails(errorMsg);
|
||||||
message.error('创建项目失败:' + errorMsg);
|
message.error('创建项目失败:' + errorMsg);
|
||||||
// 不重置步骤,保持在generating状态以显示重试按钮
|
// 不重置步骤,保持在generating状态以显示重试按钮
|
||||||
} finally {
|
setLoading(false); // 确保在错误时也设置loading为false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 智能重试:从失败的步骤继续生成
|
||||||
|
const handleSmartRetry = async () => {
|
||||||
|
if (!generationData) {
|
||||||
|
message.warning('缺少生成数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setErrorDetails('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 判断从哪个步骤开始重试
|
||||||
|
if (generationSteps.worldBuilding === 'error') {
|
||||||
|
// 世界观失败,从世界观开始重新生成
|
||||||
|
message.info('从世界观步骤开始重新生成...');
|
||||||
|
await retryFromWorldBuilding();
|
||||||
|
} else if (generationSteps.characters === 'error') {
|
||||||
|
// 角色失败,从角色开始生成
|
||||||
|
message.info('从角色步骤继续生成...');
|
||||||
|
await retryFromCharacters();
|
||||||
|
} else if (generationSteps.outline === 'error') {
|
||||||
|
// 大纲失败,从大纲开始生成
|
||||||
|
message.info('从大纲步骤继续生成...');
|
||||||
|
await retryFromOutline();
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('智能重试失败:', error);
|
||||||
|
message.error('重试失败:' + (error.message || '未知错误'));
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重试世界观生成
|
// 从世界观步骤重新开始
|
||||||
const retryWorldBuilding = async () => {
|
const retryFromWorldBuilding = async () => {
|
||||||
if (!generationData) return;
|
if (!generationData) return;
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
setErrorDetails('');
|
|
||||||
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'processing' }));
|
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'processing' }));
|
||||||
setProgressMessage('重新生成世界观...');
|
setProgressMessage('重新生成世界观...');
|
||||||
|
|
||||||
@@ -505,12 +538,13 @@ const Inspiration: React.FC = () => {
|
|||||||
setProjectId(result.project_id);
|
setProjectId(result.project_id);
|
||||||
setWorldBuildingResult(result);
|
setWorldBuildingResult(result);
|
||||||
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'completed' }));
|
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'completed' }));
|
||||||
message.success('世界观生成成功!');
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('世界观生成失败:', error);
|
console.error('世界观生成失败:', error);
|
||||||
setErrorDetails(`世界观生成失败: ${error}`);
|
setErrorDetails(`世界观生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, worldBuilding: 'error' }));
|
||||||
|
setLoading(false);
|
||||||
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
console.log('世界观重新生成完成');
|
console.log('世界观重新生成完成');
|
||||||
@@ -518,27 +552,25 @@ const Inspiration: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (worldResult?.project_id) {
|
if (!worldResult?.project_id) {
|
||||||
setProjectId(worldResult.project_id);
|
throw new Error('项目创建失败:未获取到项目ID');
|
||||||
setWorldBuildingResult(worldResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 继续生成角色和大纲
|
||||||
|
await continueFromCharacters(worldResult);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('重试世界观生成失败:', error);
|
throw error;
|
||||||
setErrorDetails(error.message || '重试失败');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重试角色生成
|
// 从角色步骤继续
|
||||||
const retryCharacters = async () => {
|
const retryFromCharacters = async () => {
|
||||||
if (!generationData || !projectId || !worldBuildingResult) {
|
if (!generationData || !projectId || !worldBuildingResult) {
|
||||||
message.warning('请先完成世界观生成');
|
message.warning('缺少必要数据,无法从角色步骤继续');
|
||||||
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
setErrorDetails('');
|
|
||||||
setGenerationSteps(prev => ({ ...prev, characters: 'processing' }));
|
setGenerationSteps(prev => ({ ...prev, characters: 'processing' }));
|
||||||
setProgressMessage('重新生成角色...');
|
setProgressMessage('重新生成角色...');
|
||||||
|
|
||||||
@@ -564,35 +596,35 @@ const Inspiration: React.FC = () => {
|
|||||||
onResult: (result) => {
|
onResult: (result) => {
|
||||||
console.log(`成功生成${result.characters?.length || 0}个角色`);
|
console.log(`成功生成${result.characters?.length || 0}个角色`);
|
||||||
setGenerationSteps(prev => ({ ...prev, characters: 'completed' }));
|
setGenerationSteps(prev => ({ ...prev, characters: 'completed' }));
|
||||||
message.success('角色生成成功!');
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('角色生成失败:', error);
|
console.error('角色生成失败:', error);
|
||||||
setErrorDetails(`角色生成失败: ${error}`);
|
setErrorDetails(`角色生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, characters: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, characters: 'error' }));
|
||||||
|
setLoading(false);
|
||||||
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
console.log('角色重新生成完成');
|
console.log('角色重新生成完成');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 继续生成大纲
|
||||||
|
await continueFromOutline();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('重试角色生成失败:', error);
|
throw error;
|
||||||
setErrorDetails(error.message || '重试失败');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重试大纲生成
|
// 从大纲步骤继续
|
||||||
const retryOutline = async () => {
|
const retryFromOutline = async () => {
|
||||||
if (!generationData || !projectId) {
|
if (!generationData || !projectId) {
|
||||||
message.warning('请先完成世界观和角色生成');
|
message.warning('缺少必要数据,无法从大纲步骤继续');
|
||||||
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
setErrorDetails('');
|
|
||||||
setGenerationSteps(prev => ({ ...prev, outline: 'processing' }));
|
setGenerationSteps(prev => ({ ...prev, outline: 'processing' }));
|
||||||
setProgressMessage('重新生成大纲...');
|
setProgressMessage('重新生成大纲...');
|
||||||
|
|
||||||
@@ -612,29 +644,127 @@ const Inspiration: React.FC = () => {
|
|||||||
onResult: () => {
|
onResult: () => {
|
||||||
console.log('大纲生成完成');
|
console.log('大纲生成完成');
|
||||||
setGenerationSteps(prev => ({ ...prev, outline: 'completed' }));
|
setGenerationSteps(prev => ({ ...prev, outline: 'completed' }));
|
||||||
setProgress(100);
|
|
||||||
setProgressMessage('项目创建完成!');
|
|
||||||
setCurrentStep('complete');
|
|
||||||
message.success('大纲生成成功!项目创建完成!');
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('大纲生成失败:', error);
|
console.error('大纲生成失败:', error);
|
||||||
setErrorDetails(`大纲生成失败: ${error}`);
|
setErrorDetails(`大纲生成失败: ${error}`);
|
||||||
setGenerationSteps(prev => ({ ...prev, outline: 'error' }));
|
setGenerationSteps(prev => ({ ...prev, outline: 'error' }));
|
||||||
|
setLoading(false);
|
||||||
|
throw new Error(error);
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
console.log('大纲重新生成完成');
|
console.log('大纲重新生成完成');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error: any) {
|
|
||||||
console.error('重试大纲生成失败:', error);
|
// 全部完成
|
||||||
setErrorDetails(error.message || '重试失败');
|
setProgress(100);
|
||||||
} finally {
|
setProgressMessage('项目创建完成!');
|
||||||
|
setCurrentStep('complete');
|
||||||
|
message.success('项目创建成功!');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
} catch (error: any) {
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 从角色步骤开始的完整流程(世界观成功后调用)
|
||||||
|
const continueFromCharacters = async (worldResult: any) => {
|
||||||
|
if (!generationData || !worldResult?.project_id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 生成角色
|
||||||
|
setGenerationSteps(prev => ({ ...prev, characters: 'processing' }));
|
||||||
|
setProgressMessage('正在生成角色...');
|
||||||
|
|
||||||
|
await wizardStreamApi.generateCharactersStream(
|
||||||
|
{
|
||||||
|
project_id: worldResult.project_id,
|
||||||
|
count: 5,
|
||||||
|
world_context: {
|
||||||
|
time_period: worldResult.time_period || '',
|
||||||
|
location: worldResult.location || '',
|
||||||
|
atmosphere: worldResult.atmosphere || '',
|
||||||
|
rules: worldResult.rules || '',
|
||||||
|
},
|
||||||
|
theme: generationData.theme,
|
||||||
|
genre: generationData.genre.join('、'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onProgress: (msg, prog) => {
|
||||||
|
setProgress(33 + Math.floor(prog / 3));
|
||||||
|
setProgressMessage(msg);
|
||||||
|
},
|
||||||
|
onResult: (result) => {
|
||||||
|
console.log(`成功生成${result.characters?.length || 0}个角色`);
|
||||||
|
setGenerationSteps(prev => ({ ...prev, characters: 'completed' }));
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error('角色生成失败:', error);
|
||||||
|
setErrorDetails(`角色生成失败: ${error}`);
|
||||||
|
setGenerationSteps(prev => ({ ...prev, characters: 'error' }));
|
||||||
|
setLoading(false);
|
||||||
|
throw new Error(error);
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
console.log('角色生成完成');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 生成大纲
|
||||||
|
await continueFromOutline();
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('继续生成失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 从大纲步骤开始的完整流程(角色成功后调用)
|
||||||
|
const continueFromOutline = async () => {
|
||||||
|
if (!generationData || !projectId) return;
|
||||||
|
|
||||||
|
setGenerationSteps(prev => ({ ...prev, outline: 'processing' }));
|
||||||
|
setProgressMessage('正在生成大纲...');
|
||||||
|
|
||||||
|
await wizardStreamApi.generateCompleteOutlineStream(
|
||||||
|
{
|
||||||
|
project_id: projectId,
|
||||||
|
chapter_count: 5,
|
||||||
|
narrative_perspective: generationData.narrative_perspective,
|
||||||
|
target_words: 100000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onProgress: (msg, prog) => {
|
||||||
|
setProgress(66 + Math.floor(prog / 3));
|
||||||
|
setProgressMessage(msg);
|
||||||
|
},
|
||||||
|
onResult: () => {
|
||||||
|
console.log('大纲生成完成');
|
||||||
|
setGenerationSteps(prev => ({ ...prev, outline: 'completed' }));
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error('大纲生成失败:', error);
|
||||||
|
setErrorDetails(`大纲生成失败: ${error}`);
|
||||||
|
setGenerationSteps(prev => ({ ...prev, outline: 'error' }));
|
||||||
|
setLoading(false);
|
||||||
|
throw new Error(error);
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
console.log('大纲生成完成');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 全部完成
|
||||||
|
setProgress(100);
|
||||||
|
setProgressMessage('项目创建完成!');
|
||||||
|
setCurrentStep('complete');
|
||||||
|
message.success('项目创建成功!');
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleConfirmGenres = async () => {
|
const handleConfirmGenres = async () => {
|
||||||
if (selectedOptions.length === 0) {
|
if (selectedOptions.length === 0) {
|
||||||
message.warning('请至少选择一个类型');
|
message.warning('请至少选择一个类型');
|
||||||
@@ -847,10 +977,10 @@ const Inspiration: React.FC = () => {
|
|||||||
|
|
||||||
<Space direction="vertical" size={16} style={{ width: '100%', maxWidth: 400, margin: '0 auto' }}>
|
<Space direction="vertical" size={16} style={{ width: '100%', maxWidth: 400, margin: '0 auto' }}>
|
||||||
{[
|
{[
|
||||||
{ key: 'worldBuilding', label: '生成世界观', step: generationSteps.worldBuilding, retry: retryWorldBuilding },
|
{ key: 'worldBuilding', label: '生成世界观', step: generationSteps.worldBuilding },
|
||||||
{ key: 'characters', label: '生成角色', step: generationSteps.characters, retry: retryCharacters },
|
{ key: 'characters', label: '生成角色', step: generationSteps.characters },
|
||||||
{ key: 'outline', label: '生成大纲', step: generationSteps.outline, retry: retryOutline },
|
{ key: 'outline', label: '生成大纲', step: generationSteps.outline },
|
||||||
].map(({ key, label, step, retry }) => {
|
].map(({ key, label, step }) => {
|
||||||
const status = getStepStatus(step);
|
const status = getStepStatus(step);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -868,23 +998,9 @@ const Inspiration: React.FC = () => {
|
|||||||
<Text style={{ fontSize: 16, fontWeight: step === 'processing' ? 600 : 400 }}>
|
<Text style={{ fontSize: 16, fontWeight: step === 'processing' ? 600 : 400 }}>
|
||||||
{label}
|
{label}
|
||||||
</Text>
|
</Text>
|
||||||
<Space>
|
|
||||||
<span style={{ fontSize: 20, color: status.color }}>
|
<span style={{ fontSize: 20, color: status.color }}>
|
||||||
{status.icon}
|
{status.icon}
|
||||||
</span>
|
</span>
|
||||||
{step === 'error' && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
danger
|
|
||||||
onClick={retry}
|
|
||||||
loading={loading}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
重试
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -898,18 +1014,13 @@ const Inspiration: React.FC = () => {
|
|||||||
{hasError && (
|
{hasError && (
|
||||||
<Space style={{ marginTop: 16 }}>
|
<Space style={{ marginTop: 16 }}>
|
||||||
<Button
|
<Button
|
||||||
|
type="primary"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => {
|
onClick={handleSmartRetry}
|
||||||
setCurrentStep('confirm');
|
loading={loading}
|
||||||
setGenerationSteps({
|
disabled={loading}
|
||||||
worldBuilding: 'pending',
|
|
||||||
characters: 'pending',
|
|
||||||
outline: 'pending'
|
|
||||||
});
|
|
||||||
setErrorDetails('');
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
返回重新配置
|
继续生成
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user