From 89f596ea64b625028f70c42f89d02826fda6ffef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=94=E9=A6=99=E4=B8=B8=E5=AD=90?= <15518898337@163.com> Date: Fri, 5 Jun 2026 14:51:22 +0800 Subject: [PATCH] fix(jump-hop): extend creation timeout --- ...玩法创作】平å°å…¥å£ä¸ŽçŽ©æ³•é“¾è·¯-2026-05-15.md | 3 +- src/services/jump-hop/jumpHopClient.test.ts | 39 +++++++++++++++++++ src/services/jump-hop/jumpHopClient.ts | 4 ++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/services/jump-hop/jumpHopClient.test.ts diff --git a/docs/ã€çŽ©æ³•åˆ›ä½œã€‘å¹³å°å…¥å£ä¸ŽçŽ©æ³•é“¾è·¯-2026-05-15.md b/docs/ã€çŽ©æ³•åˆ›ä½œã€‘å¹³å°å…¥å£ä¸ŽçŽ©æ³•é“¾è·¯-2026-05-15.md index 47791407..f0973a34 100644 --- a/docs/ã€çŽ©æ³•åˆ›ä½œã€‘å¹³å°å…¥å£ä¸ŽçŽ©æ³•é“¾è·¯-2026-05-15.md +++ b/docs/ã€çŽ©æ³•åˆ›ä½œã€‘å¹³å°å…¥å£ä¸ŽçŽ©æ³•é“¾è·¯-2026-05-15.md @@ -149,7 +149,8 @@ RPG / 拼图等è¿è¡Œæ€å­˜æ¡£ä»ä»¥ `/api/profile/save-archives` çš„åŽç«¯åˆ— 3. 地å—åªè°ƒç”¨ä¸€æ¬¡ image2,输出一张 `5行*5列`ã€`1:1`ã€å•一纯洋红 `#FF00FF` key 背景的主题地å—图集;跳一跳地å—常包å«è‰åœ°ã€èбã€é›ªã€ç™½çŸ³å’Œäº‘朵,åŽç«¯é€æ˜ŽåŒ–必须使用跳一跳专用洋红 key,ä¸å¯ç”¨è¿‘ç™½åº•æ‰£é™¤ï¼Œä¹Ÿä¸æ¸…ç†éžè¾¹ç¼˜è¿žé€šçš„ key 色åƒç´ ï¼Œé¿å…把绿色或白色主体误扣;åŽå¤„ç†å¿…须对边缘连通 key 色åšå®¹å·®æ¸…ç†ã€åŽ»å½©è¾¹ defringe 和底部残影清ç†ï¼Œä¸»ä½“图ä¸å¾—自带洋红阴影ã€ç´«è‰²åº•è¾¹ã€ç²‰è‰²è„è¾¹ã€å½©è‰²å…‰æ™•或å‘光底边,è¿è¡Œæ€é˜´å½±ç»Ÿä¸€ç”± DOM 绘制;地å—造型æç¤ºè¯è¦æ±‚以主题物体本身外轮廓为准,å…许苹果近似圆形ã€é¦™è•‰è¿‘ä¼¼é•¿æ¡æˆ–长方形ã€è¥¿ç“œè¿‘似扇形等自然差异,åªç»Ÿä¸€å•格规格ã€å®‰å…¨ç•™ç™½ã€æ­£é¢30度视角和 2D/2.5D 手绘风格包装;所有地å—ç´ æå¿…é¡»ä¿æŒç»Ÿä¸€æ­£é¢30度视角,相机ä½äºŽç‰©ä½“æ­£å‰æ–¹ç•¥é«˜ä½ç½®ã€é•œå¤´å‘下约30度,必须看到清晰正é¢ã€ä¾§å£ã€ä¸‹æ²¿ã€æ˜Žæ˜¾è‡ªèº«åŽšåº¦å’Œå°‘é‡ä¸Šè¡¨é¢ï¼Œä¸»ä½“æ­£é¢æˆ–ä¾§å£å¯è§é¢ç§¯å¿…须接近或大于顶é¢é¢ç§¯ï¼Œé¡¶é¢åªèƒ½ä½œä¸ºè¾…助å¯è§é¢ï¼›æ°´æžœä¸»é¢˜éœ€è¦æ˜Žç¡®è¦æ±‚橙瓣看到橙皮正é¢å¤–ä¾§å’Œæžœè‚‰åŽšåº¦ã€æ¤°å­çœ‹åˆ°å£³çš„æ­£é¢ä¾§å£å’Œåˆ‡å£åŽšåº¦ã€æµ†æžœä¸èƒ½åªæ˜¯ä»Žä¸Šå¾€ä¸‹çœ‹çš„圆形çƒé¡¶ï¼›é¿å…生æˆçº¯ä¿¯è§†ã€æ­£ä¸Šæ–¹ä¿¯æ‹ã€é¸Ÿçž°åœ°å›¾å—ã€å¹³é“ºä¿¯æ‹ã€åœ†å½¢é¡¶è§†å›¾æˆ–æ‰å¹³å›¾æ ‡ï¼›ä¸»é¢˜ç‰©ä½“本身必须是唯一å¯è½è„šä½“,åªèƒ½ç”¨è‡ªèº«åˆ‡é¢ã€è¾¹ç¼˜åŽšåº¦ã€èŠ±ç“£å±‚æˆ–æžœçš®è¾¹è¡¨çŽ°æ‰¿é‡ï¼Œç¦æ­¢åœ¨ä¸»é¢˜ç‰©ä½“下方é¢å¤–垫石å°ã€åœŸå¢©ã€æœ¨æ¿ã€åœ†å°ã€æ‰˜ç›˜ã€å²›å±¿åº•座或通用地æ¿ï¼›å‰ç«¯å’ŒåŽç«¯é»˜è®¤ `tilePrompt` 都必须使用“正é¢30度视角主题物体图集,物体本身作为跳跃è½ç‚¹â€çš„å£å¾„,ä¸å†æäº¤â€œå¹³å°ç´ æ / è·³å° / åœ°å— / 地砖â€ç­‰ä¼šæŠŠæ¨¡åž‹æ‹‰å›žé€šç”¨å¹³å°é€ åž‹çš„è¯ï¼ŒåŽç«¯ç”Ÿæˆå‰ä¹Ÿä¼šæ¸…æ´—æ—§è‰ç¨¿é—留的这些è¯ï¼› 4. èƒŒæ™¯åº•å›¾åŒæ ·ç”± image2 生æˆï¼Œå¤ç”¨çŽ°æœ‰ `coverComposite` / `coverImageSrc` 作为è¿è¡Œæ€èƒŒæ™¯è¯»å†™å­—段,OSS æ§½ä½å›ºå®šä¸º `background/image.png`ï¼Œä¸æ–°å¢ž SpacetimeDB 字段;æç¤ºè¯å¿…须严格以用户主题关键è¯ä¸ºèƒŒæ™¯ä¸»é¢˜ï¼Œç»“构以左å³ä¸¤ä¾§æ°›å›´ä¸ºä¸»ï¼Œä¸­å¤®çºµè½´ 1/2 åŒºåŸŸä¿æŒå°‘元素ã€ç®€æ´ã€å¯è¯»ä¸”有纵深感,两侧å…许更强立体层次和行进感;背景åªä½œä¸ºåº•å›¾ï¼Œç¦æ­¢ç”Ÿæˆè·³æ¿ã€åœ°å—ã€è½è„šç‰©ã€è§’色ã€UIã€æ–‡å­—ã€è·¯å¾„箭头或海报排版; 5. åŽç«¯æŒ‰ä»Žä¸Šåˆ°ä¸‹ã€ä»Žå·¦åˆ°å³å‡åŒ€åˆ‡åˆ†ä¸º `tile-01` 到 `tile-25` çš„é€æ˜Ž PNG,æ¯ä¸ªåˆ‡ç‰‡å¿…须使用唯一 slot/path æŒä¹…化,ä¸èƒ½æŒ‰é‡å¤çš„ `tileType` å¤ç”¨æ§½ä½ï¼› -6. 结果页åªå±•示陶泥儿 logo 逿˜Žè§’色预览ã€åœ°å—æ± é¢„è§ˆå’Œé¦–å± 3 地å—预览;ä¸å†æä¾›æ—§è§’è‰²å›¾ç”Ÿæˆæ§½ã€‚ +6. 结果页åªå±•示陶泥儿 logo 逿˜Žè§’色预览ã€åœ°å—æ± é¢„è§ˆå’Œé¦–å± 3 地å—预览;ä¸å†æä¾›æ—§è§’è‰²å›¾ç”Ÿæˆæ§½ï¼› +7. å‰ç«¯è·³ä¸€è·³åˆ›ä½œ client 的创建会è¯ä¸Žæ‰§è¡Œç”ŸæˆåŠ¨ä½œè¯·æ±‚éƒ½å¿…é¡»ä½¿ç”¨ 20 分钟等待窗å£ï¼Œé¿å…背景底图ã€åœ°å—图集ã€åˆ‡ç‰‡ã€æŠ å›¾å’Œ OSS 写入ä»åœ¨åŽç«¯æ‰§è¡Œæ—¶è¢«å…±åˆ›ä¼šè¯é»˜è®¤ 15 秒超时中断。 è¿è¡Œæ€è§„则真相必须沉到 `module-jump-hop`,å‰ç«¯åªåšæ‹–æ‹½è“„åŠ›ã€è§’色ä½ç§»ã€æŠ•影和è½åœ°åé¦ˆã€‚å¤±è´¥ã€æˆåŠŸè·³è·ƒæ¬¡æ•°ã€æ¸¸æˆæ—¶é•¿å†»ç»“ã€è¿è¡Œæ€å¿«ç…§å’Œå‘布作å“状æ€ä»¥åŽç«¯ä¸ºå‡†ã€‚v1 ä¸ä¿ç•™å…¬å¼€ combo / perfect / 通关语义,旧 `score` 兼容映射为æˆåŠŸè·³è·ƒæ¬¡æ•°ã€‚å…¬å¼€åˆ—è¡¨åº”èµ° `jump_hop_gallery_card_view` 订阅缓存,ä¸è¦æ¯æ¬¡ HTTP 请求调用 procedure 组装全é‡åˆ—表。 diff --git a/src/services/jump-hop/jumpHopClient.test.ts b/src/services/jump-hop/jumpHopClient.test.ts new file mode 100644 index 00000000..7f284fc0 --- /dev/null +++ b/src/services/jump-hop/jumpHopClient.test.ts @@ -0,0 +1,39 @@ +import { beforeEach, expect, test, vi } from 'vitest'; + +const requestJsonMock = vi.hoisted(() => vi.fn()); + +const { createCreationAgentClientMock } = vi.hoisted(() => ({ + createCreationAgentClientMock: vi.fn(), +})); + +vi.mock('../creation-agent', () => ({ + createCreationAgentClient: createCreationAgentClientMock, +})); + +vi.mock('../apiClient', () => ({ + requestJson: requestJsonMock, +})); + +beforeEach(() => { + vi.resetModules(); + createCreationAgentClientMock.mockReset(); + createCreationAgentClientMock.mockReturnValue({ + createSession: vi.fn(), + getSession: vi.fn(), + sendMessage: vi.fn(), + streamMessage: vi.fn(), + executeAction: vi.fn(), + }); + requestJsonMock.mockReset(); +}); + +test('jump hop creation keeps image2 generation requests alive long enough', async () => { + await import('./jumpHopClient'); + + expect(createCreationAgentClientMock).toHaveBeenCalledWith( + expect.objectContaining({ + createSessionTimeoutMs: 20 * 60 * 1000, + executeActionTimeoutMs: 20 * 60 * 1000, + }), + ); +}); diff --git a/src/services/jump-hop/jumpHopClient.ts b/src/services/jump-hop/jumpHopClient.ts index 779c415a..aeea825e 100644 --- a/src/services/jump-hop/jumpHopClient.ts +++ b/src/services/jump-hop/jumpHopClient.ts @@ -31,6 +31,8 @@ import { const JUMP_HOP_API_BASE = '/api/creation/jump-hop/sessions'; const JUMP_HOP_WORKS_API_BASE = '/api/creation/jump-hop/works'; const JUMP_HOP_RUNTIME_API_BASE = '/api/runtime/jump-hop'; +// 中文注释:跳一跳创作会等待背景图ã€25 格图集ã€åˆ‡ç‰‡å’Œ OSS 写入,ä¸èƒ½æ²¿ç”¨å…±åˆ›ä¼šè¯é»˜è®¤ 15 秒超时。 +const JUMP_HOP_GENERATION_TIMEOUT_MS = 20 * 60 * 1000; const JUMP_HOP_RUNTIME_READ_RETRY: ApiRetryOptions = { maxRetries: 1, baseDelayMs: 120, @@ -87,6 +89,8 @@ const jumpHopCreationClient = createCreationAgentClient< streamIncomplete: 'è·³ä¸€è·³å…±åˆ›æ¶ˆæ¯æµå¼ç»“æžœä¸å®Œæ•´', executeAction: '执行跳一跳共创æ“作失败', }, + createSessionTimeoutMs: JUMP_HOP_GENERATION_TIMEOUT_MS, + executeActionTimeoutMs: JUMP_HOP_GENERATION_TIMEOUT_MS, }); type FlattenedJumpHopWorkProfileResponse = Omit<