auto-save 2026-05-19 10:51 (~2)
This commit is contained in:
@@ -484,6 +484,19 @@
|
|||||||
"message": "auto-save 2026-05-19 10:40 (+1, ~3)",
|
"message": "auto-save 2026-05-19 10:40 (+1, ~3)",
|
||||||
"hash": "12159ca",
|
"hash": "12159ca",
|
||||||
"files_changed": 4
|
"files_changed": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-19T10:43:58+08:00",
|
||||||
|
"type": "commit",
|
||||||
|
"message": "feat: add upload replicate mode",
|
||||||
|
"hash": "a9b1250",
|
||||||
|
"files_changed": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-19T02:50:00Z",
|
||||||
|
"type": "session-heartbeat",
|
||||||
|
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:feat: add upload replicate mode",
|
||||||
|
"files_changed": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,19 @@ export async function generateMock(opts: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readImageBase64(payload: unknown): string {
|
async function imageResponseToDataUrl(payload: unknown): Promise<string> {
|
||||||
const data = payload as { data?: Array<{ b64_json?: string; url?: string }> };
|
const data = payload as { data?: Array<{ b64_json?: string; url?: string }> };
|
||||||
const first = data.data?.[0];
|
const first = data.data?.[0];
|
||||||
if (!first) throw new Error('GPT image response missing data');
|
if (!first) throw new Error('GPT image response missing data');
|
||||||
if (first.b64_json) return first.b64_json;
|
if (first.b64_json) return `data:image/png;base64,${first.b64_json}`;
|
||||||
throw new Error('GPT image response missing b64_json');
|
if (first.url) {
|
||||||
|
const res = await fetch(first.url);
|
||||||
|
if (!res.ok) throw new Error(`GPT image URL fetch ${res.status}: ${await res.text()}`);
|
||||||
|
const type = res.headers.get('content-type')?.split(';')[0] || 'image/png';
|
||||||
|
const buf = Buffer.from(await res.arrayBuffer());
|
||||||
|
return `data:${type};base64,${buf.toString('base64')}`;
|
||||||
|
}
|
||||||
|
throw new Error('GPT image response missing b64_json or url');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateGptImages(opts: {
|
export async function generateGptImages(opts: {
|
||||||
@@ -77,14 +84,13 @@ export async function generateGptImages(opts: {
|
|||||||
prompt: `${opts.prompt}${refHint}`,
|
prompt: `${opts.prompt}${refHint}`,
|
||||||
n: 1,
|
n: 1,
|
||||||
size: '1024x1024',
|
size: '1024x1024',
|
||||||
response_format: 'b64_json',
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error(`GPT image ${res.status}: ${await res.text()}`);
|
if (!res.ok) throw new Error(`GPT image ${res.status}: ${await res.text()}`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return {
|
return {
|
||||||
id: `img_${opts.sessionId}_${i}`,
|
id: `img_${opts.sessionId}_${i}`,
|
||||||
url: `data:image/png;base64,${readImageBase64(data)}`,
|
url: await imageResponseToDataUrl(data),
|
||||||
prompt: opts.prompt,
|
prompt: opts.prompt,
|
||||||
status: 'pending' as const,
|
status: 'pending' as const,
|
||||||
meta: { provider: 'gpt', model: GPT_IMAGE_MODEL, index: i },
|
meta: { provider: 'gpt', model: GPT_IMAGE_MODEL, index: i },
|
||||||
@@ -94,14 +100,6 @@ export async function generateGptImages(opts: {
|
|||||||
return Promise.all(calls);
|
return Promise.all(calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readEditImageBase64(payload: unknown): string {
|
|
||||||
return readImageBase64(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dataUrlFromImageResponse(payload: unknown): string {
|
|
||||||
return `data:image/png;base64,${readEditImageBase64(payload)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readResponseText(data: {
|
function readResponseText(data: {
|
||||||
output_text?: string;
|
output_text?: string;
|
||||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||||
@@ -136,7 +134,6 @@ export async function generateGptImageEdit(opts: {
|
|||||||
form.set('model', process.env.GPT_IMAGE_EDIT_MODEL || GPT_IMAGE_MODEL);
|
form.set('model', process.env.GPT_IMAGE_EDIT_MODEL || GPT_IMAGE_MODEL);
|
||||||
form.set('prompt', opts.prompt);
|
form.set('prompt', opts.prompt);
|
||||||
form.set('size', opts.size || '1024x1024');
|
form.set('size', opts.size || '1024x1024');
|
||||||
form.set('response_format', 'b64_json');
|
|
||||||
const imageBytes = source.buf.buffer.slice(source.buf.byteOffset, source.buf.byteOffset + source.buf.byteLength) as ArrayBuffer;
|
const imageBytes = source.buf.buffer.slice(source.buf.byteOffset, source.buf.byteOffset + source.buf.byteLength) as ArrayBuffer;
|
||||||
form.set('image', new Blob([imageBytes], { type: source.type }), source.filename);
|
form.set('image', new Blob([imageBytes], { type: source.type }), source.filename);
|
||||||
|
|
||||||
@@ -149,7 +146,7 @@ export async function generateGptImageEdit(opts: {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return {
|
return {
|
||||||
id: `img_${opts.sessionId}_edit`,
|
id: `img_${opts.sessionId}_edit`,
|
||||||
url: dataUrlFromImageResponse(data),
|
url: await imageResponseToDataUrl(data),
|
||||||
prompt: opts.prompt,
|
prompt: opts.prompt,
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
meta: { provider: 'gpt', model: process.env.GPT_IMAGE_EDIT_MODEL || GPT_IMAGE_MODEL, edit: true },
|
meta: { provider: 'gpt', model: process.env.GPT_IMAGE_EDIT_MODEL || GPT_IMAGE_MODEL, edit: true },
|
||||||
|
|||||||
Reference in New Issue
Block a user