fix puzzle generation failure stage
This commit is contained in:
@@ -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。
|
- 验证:运行 `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`。
|
- 关联:`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` 中手机号验证码表单仍存在。
|
- 现象:登录弹窗只剩密码登录,短信登录页签看起来像被删掉,但 `LoginScreen` 中手机号验证码表单仍存在。
|
||||||
|
|||||||
@@ -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(
|
upsert_puzzle_draft_work_profile(
|
||||||
ctx,
|
ctx,
|
||||||
&row.session_id,
|
&row.session_id,
|
||||||
@@ -1059,7 +1060,7 @@ fn mark_puzzle_draft_generation_failed_tx(
|
|||||||
seed_text: row.seed_text.clone(),
|
seed_text: row.seed_text.clone(),
|
||||||
current_turn: row.current_turn,
|
current_turn: row.current_turn,
|
||||||
progress_percent: row.progress_percent.max(88),
|
progress_percent: row.progress_percent.max(88),
|
||||||
stage: row.stage,
|
stage: next_stage,
|
||||||
anchor_pack_json: row.anchor_pack_json.clone(),
|
anchor_pack_json: row.anchor_pack_json.clone(),
|
||||||
draft_json: Some(serialize_json(&draft)),
|
draft_json: Some(serialize_json(&draft)),
|
||||||
last_assistant_reply: Some(input.error_message),
|
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(
|
fn save_puzzle_form_draft_tx(
|
||||||
ctx: &TxContext,
|
ctx: &TxContext,
|
||||||
input: PuzzleFormDraftSaveInput,
|
input: PuzzleFormDraftSaveInput,
|
||||||
@@ -3862,6 +3878,25 @@ mod tests {
|
|||||||
assert_eq!(draft.work_title, "我的猫街合集");
|
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]
|
#[test]
|
||||||
fn puzzle_recommendation_score_prefers_same_author_weight() {
|
fn puzzle_recommendation_score_prefers_same_author_weight() {
|
||||||
let left = PuzzleWorkProfile {
|
let left = PuzzleWorkProfile {
|
||||||
|
|||||||
@@ -16653,11 +16653,11 @@ export function PlatformEntryFlowShellImpl({
|
|||||||
onInterrupt={undefined}
|
onInterrupt={undefined}
|
||||||
backLabel="返回创作中心"
|
backLabel="返回创作中心"
|
||||||
settingActionLabel={null}
|
settingActionLabel={null}
|
||||||
retryLabel="重新生成草稿"
|
retryLabel="重新生成图片"
|
||||||
settingTitle="当前拼图信息"
|
settingTitle="当前拼图信息"
|
||||||
settingDescription={null}
|
settingDescription={null}
|
||||||
progressTitle="拼图草稿生成进度"
|
progressTitle="拼图图片生成进度"
|
||||||
activeBadgeLabel="草稿生成中"
|
activeBadgeLabel="图片生成中"
|
||||||
idleBadgeLabel="等待返回工作区"
|
idleBadgeLabel="等待返回工作区"
|
||||||
hideBatchModule
|
hideBatchModule
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -4273,7 +4273,7 @@ test('running puzzle form generation creates a new puzzle draft on same template
|
|||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
@@ -4309,7 +4309,7 @@ test('running puzzle form generation creates a new puzzle draft on same template
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
await user.click(screen.getByRole('button', { name: '返回创作中心' }));
|
await user.click(screen.getByRole('button', { name: '返回创作中心' }));
|
||||||
@@ -4389,7 +4389,7 @@ test('running puzzle draft opens generation progress from draft tab', async () =
|
|||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
@@ -4403,7 +4403,7 @@ test('running puzzle draft opens generation progress from draft tab', async () =
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(screen.queryByText('拼图结果页')).toBeNull();
|
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('执行拼图操作失败。')).toBeNull();
|
||||||
expect(screen.queryByText('请求超时:90000ms')).toBeNull();
|
expect(screen.queryByText('请求超时:90000ms')).toBeNull();
|
||||||
expect(screen.queryByText('拼图草稿生成进度')).toBeNull();
|
expect(screen.queryByText('拼图图片生成进度')).toBeNull();
|
||||||
expect(startLocalPuzzleRun).toHaveBeenCalledTimes(1);
|
expect(startLocalPuzzleRun).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -7416,13 +7416,13 @@ test('persisted generating puzzle draft opens generation progress after refresh'
|
|||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(
|
expect(
|
||||||
Number(
|
Number(
|
||||||
screen
|
screen
|
||||||
.getByRole('progressbar', { name: '拼图草稿生成进度' })
|
.getByRole('progressbar', { name: '拼图图片生成进度' })
|
||||||
.getAttribute('aria-valuenow'),
|
.getAttribute('aria-valuenow'),
|
||||||
),
|
),
|
||||||
).toBe(0);
|
).toBe(0);
|
||||||
@@ -7481,7 +7481,7 @@ test('persisted generating puzzle draft keeps session polling on the same sessio
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).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(within(dialog).getByRole('button', { name: '复制报错' })).toBeTruthy();
|
||||||
expect(
|
expect(
|
||||||
await screen.findByRole('progressbar', {
|
await screen.findByRole('progressbar', {
|
||||||
name: '拼图草稿生成进度',
|
name: '拼图图片生成进度',
|
||||||
}),
|
}),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user