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