fix puzzle generation failure stage

This commit is contained in:
kdletters
2026-05-28 15:13:20 +08:00
parent 771b0411a3
commit 2cd2b9704b
4 changed files with 56 additions and 13 deletions

View File

@@ -918,6 +918,14 @@
- 验证:运行 `npm run test -- src\services\assetReadUrlService.test.ts src\hooks\useResolvedAssetReadUrl.test.tsx src\components\puzzle-result\PuzzleResultView.test.tsx`,再触发一次真实生成确认 Network 中先请求 `/api/assets/read-url`,图片 `src` 为未追加 `_v` 的签名 URL。
- 关联:`src/services/assetReadUrlService.ts``src/components/ResolvedAssetImage.tsx``docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md`
## 拼图图片生成失败后不要停在 ImageRefining
- 现象:拼图图片生成失败后,会话仍停留在 `PuzzleAgentStage::ImageRefining`,用户从作品架或生成页恢复时容易被当成生成中/精修中状态,重试入口和失败承接不清晰。
- 原因:`mark_puzzle_draft_generation_failed_tx` 只把 `PuzzleResultDraft.generation_status` 标成 `failed`,但 session stage 仍沿用旧的 `row.stage`;如果失败前已进入 `ImageRefining`,失败回写不会把会话带回结果草稿态。
- 处理:失败回写后按失败草稿重新解析 session stage已发布保持 `Published`,仍满足发布门禁则为 `ReadyToPublish`,否则回到 `DraftReady`;前端生成页文案用“拼图图片生成进度 / 重新生成图片”,避免把失败态误导成还在生成整份草稿。
- 验证:运行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml``npm run check:encoding`,以及拼图生成页恢复相关 `RpgEntryFlowShell.agent.interaction.test.tsx` 定向用例。
- 关联:`server-rs/crates/spacetime-module/src/puzzle.rs``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
## 本地短信登录页签突然消失
- 现象:登录弹窗只剩密码登录,短信登录页签看起来像被删掉,但 `LoginScreen` 中手机号验证码表单仍存在。

View File

@@ -1042,6 +1042,7 @@ fn mark_puzzle_draft_generation_failed_tx(
))
}
};
let next_stage = resolve_failed_puzzle_agent_stage(row.stage, &draft);
upsert_puzzle_draft_work_profile(
ctx,
&row.session_id,
@@ -1059,7 +1060,7 @@ fn mark_puzzle_draft_generation_failed_tx(
seed_text: row.seed_text.clone(),
current_turn: row.current_turn,
progress_percent: row.progress_percent.max(88),
stage: row.stage,
stage: next_stage,
anchor_pack_json: row.anchor_pack_json.clone(),
draft_json: Some(serialize_json(&draft)),
last_assistant_reply: Some(input.error_message),
@@ -1078,6 +1079,21 @@ fn mark_puzzle_draft_generation_failed_tx(
)
}
fn resolve_failed_puzzle_agent_stage(
current_stage: PuzzleAgentStage,
draft: &PuzzleResultDraft,
) -> PuzzleAgentStage {
if current_stage == PuzzleAgentStage::Published {
return PuzzleAgentStage::Published;
}
if build_result_preview(draft, Some("陶泥儿主")).publish_ready {
PuzzleAgentStage::ReadyToPublish
} else {
PuzzleAgentStage::DraftReady
}
}
fn save_puzzle_form_draft_tx(
ctx: &TxContext,
input: PuzzleFormDraftSaveInput,
@@ -3862,6 +3878,25 @@ mod tests {
assert_eq!(draft.work_title, "我的猫街合集");
}
#[test]
fn failed_generation_returns_result_draft_stage_instead_of_refining() {
let anchor_pack = infer_anchor_pack("画面描述:一只猫在雨夜灯牌下回头。", None);
let draft = compile_result_draft_from_seed(
&anchor_pack,
&[],
Some("画面描述:一只猫在雨夜灯牌下回头。"),
);
assert_eq!(
resolve_failed_puzzle_agent_stage(PuzzleAgentStage::ImageRefining, &draft),
PuzzleAgentStage::DraftReady
);
assert_eq!(
resolve_failed_puzzle_agent_stage(PuzzleAgentStage::Published, &draft),
PuzzleAgentStage::Published
);
}
#[test]
fn puzzle_recommendation_score_prefers_same_author_weight() {
let left = PuzzleWorkProfile {

View File

@@ -16653,11 +16653,11 @@ export function PlatformEntryFlowShellImpl({
onInterrupt={undefined}
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="重新生成草稿"
retryLabel="重新生成图片"
settingTitle="当前拼图信息"
settingDescription={null}
progressTitle="拼图草稿生成进度"
activeBadgeLabel="草稿生成中"
progressTitle="拼图图片生成进度"
activeBadgeLabel="图片生成中"
idleBadgeLabel="等待返回工作区"
hideBatchModule
/>

View File

@@ -4273,7 +4273,7 @@ test('running puzzle form generation creates a new puzzle draft on same template
);
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
@@ -4309,7 +4309,7 @@ test('running puzzle form generation creates a new puzzle draft on same template
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
await user.click(screen.getByRole('button', { name: '返回创作中心' }));
@@ -4389,7 +4389,7 @@ test('running puzzle draft opens generation progress from draft tab', async () =
);
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
@@ -4403,7 +4403,7 @@ test('running puzzle draft opens generation progress from draft tab', async () =
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
expect(screen.queryByText('拼图结果页')).toBeNull();
@@ -5390,7 +5390,7 @@ test('embedded puzzle form recovers when compile request times out after backend
});
expect(screen.queryByText('执行拼图操作失败。')).toBeNull();
expect(screen.queryByText('请求超时90000ms')).toBeNull();
expect(screen.queryByText('拼图草稿生成进度')).toBeNull();
expect(screen.queryByText('拼图图片生成进度')).toBeNull();
expect(startLocalPuzzleRun).toHaveBeenCalledTimes(1);
});
@@ -7416,13 +7416,13 @@ test('persisted generating puzzle draft opens generation progress after refresh'
});
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
expect(
Number(
screen
.getByRole('progressbar', { name: '拼图草稿生成进度' })
.getByRole('progressbar', { name: '拼图图片生成进度' })
.getAttribute('aria-valuenow'),
),
).toBe(0);
@@ -7481,7 +7481,7 @@ test('persisted generating puzzle draft keeps session polling on the same sessio
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
@@ -7529,7 +7529,7 @@ test('puzzle compile timeout shows failure dialog when reread session is still g
expect(within(dialog).getByRole('button', { name: '复制报错' })).toBeTruthy();
expect(
await screen.findByRole('progressbar', {
name: '拼图草稿生成进度',
name: '拼图图片生成进度',
}),
).toBeTruthy();
});