From d9d69000e970de3ba0963097ef3c9c227a136f1b Mon Sep 17 00:00:00 2001 From: cneicy Date: Mon, 5 Oct 2026 05:14:27 +0800 Subject: [PATCH] fix: extend image request timeout to 15 minutes --- README.md | 2 +- lib/engine.mjs | 4 ++-- test/engine.test.mjs | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 722f2d0..4584d14 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ git+https://git.crash.work/cneicy/dsh-imagegen.git - API Key:由 DSH 凭据服务保存,不写入插件目录或上述普通配置文件。 - 对话预览:使用 DSH 持久化附件。预览可能被缩小,输出目录里的原图保留服务返回的原始字节。 -使用插件会将提示词和生成参数发送到配置的服务商,并按其规则计费。点击「停止等待」不能保证服务商已经取消生成或计费。 +使用插件会将提示词和生成参数发送到配置的服务商,并按其规则计费。请求最多等待 15 分钟,适用于 `gpt-image-2` 等处理较慢的模型;等待期间仍可手动取消。点击「停止等待」不能保证服务商已经取消生成或计费。 ## 更新与卸载 diff --git a/lib/engine.mjs b/lib/engine.mjs index 2e1b5c2..d2dd62f 100644 --- a/lib/engine.mjs +++ b/lib/engine.mjs @@ -1,6 +1,6 @@ const MAX_BYTES = 64 * 1024 * 1024; const MAX_EDIT_BYTES = 20 * 1024 * 1024; -const TIMEOUT_MS = 180_000; +const TIMEOUT_MS = 15 * 60_000; const QUALITY = new Set(['auto', 'low', 'medium', 'high', 'standard', 'hd']); const BACKGROUND = new Set(['auto', 'transparent', 'opaque']); const OUTPUT_FORMAT = new Set(['png', 'jpeg', 'webp']); @@ -56,7 +56,7 @@ async function operation(signal, work) { if (controller.signal.aborted) throw new Error('Request aborted.'); return await work(controller.signal); } catch (error) { - if (controller.signal.aborted) throw new Error(timedOut ? 'Request timed out after 180 seconds.' : 'Request aborted.'); + if (controller.signal.aborted) throw new Error(timedOut ? `Request timed out after ${TIMEOUT_MS / 1000} seconds.` : 'Request aborted.'); throw error; } finally { clearTimeout(timer); diff --git a/test/engine.test.mjs b/test/engine.test.mjs index ed0882a..48c97f1 100644 --- a/test/engine.test.mjs +++ b/test/engine.test.mjs @@ -256,19 +256,19 @@ test('specified generation options are preserved on the wire', async t => { await generateImages({ baseUrl, apiKey, input: specified }); }); -test('180 second timeout aborts a stalled request', async t => { +test('900 second timeout aborts a stalled request', async t => { const baseUrl = await server(t, () => {}); const original = globalThis.setTimeout; let configuredTimeout; t.mock.method(globalThis, 'setTimeout', (callback, milliseconds, ...args) => { - if (milliseconds === 180_000) { + if (milliseconds === 900_000) { configuredTimeout = milliseconds; return original(callback, 20, ...args); } return original(callback, milliseconds, ...args); }); - await assert.rejects(listModels({ baseUrl, apiKey }), /timed out after 180 seconds/); - assert.equal(configuredTimeout, 180_000); + await assert.rejects(listModels({ baseUrl, apiKey }), /timed out after 900 seconds/); + assert.equal(configuredTimeout, 900_000); }); test('edit response downloads omit auth and retain output validation and bounds', async t => { @@ -327,11 +327,11 @@ test('edits cancel pending API requests, downloads and pre-aborted requests', as assert.equal(count, 2); }); -test('edits share the 180 second operation timeout', async t => { +test('edits share the 900 second operation timeout', async t => { const baseUrl = await server(t, () => {}); const original = globalThis.setTimeout; - t.mock.method(globalThis, 'setTimeout', (callback, milliseconds, ...args) => original(callback, milliseconds === 180_000 ? 20 : milliseconds, ...args)); - await assert.rejects(editImages({ baseUrl, apiKey, input, image: png }), /timed out after 180 seconds/); + t.mock.method(globalThis, 'setTimeout', (callback, milliseconds, ...args) => original(callback, milliseconds === 900_000 ? 20 : milliseconds, ...args)); + await assert.rejects(editImages({ baseUrl, apiKey, input, image: png }), /timed out after 900 seconds/); }); test('pre-aborted signal does not send an API request', async t => {