Files
CodePilot/src/lib/image-ref-store.ts
T
7418andClaude Opus 4.6 d5dd9cfe34 feat: unify reference image data structure, add Nano Banana 2 model
Reference Image 统一重构:
- 新增 ReferenceImage 类型 (src/types/index.ts),统一承载 base64 和 localPath 两种来源
- 重写 image-ref-store.ts:单一 Map<string, ReferenceImage[]> 替代原来的
  imageGenRefStore + lastGeneratedImagePaths 双通路
  - sessionStorage 持久化 last-generated 路径,解决页面刷新后数据丢失
  - buildReferenceImages() 作为唯一的 merge 入口,消除各组件手写拼接逻辑
- ImageGenConfirmation props 从两个 (referenceImagePaths + referenceImagesData)
  合并为单一 referenceImages?: ReferenceImage[]
  - 预览渲染改为单循环,根据 data/localPath 决定 img src,上传图和结果图同时显示
  - API 调用时再拆分回 base64 和路径两个字段,后端无需改动
- StreamingMessage / MessageItem 各自 5 行手动 merge 逻辑替换为一行
  buildReferenceImages() 调用
- ChatView 改用 setLastGeneratedImages() 和 transferPendingToMessage()
  替代直接操作 Map
- MessageInput 改用 setRefImages() / deleteRefImages() 替代直接操作 Map

新增 Gemini 3.1 Flash Image 模型:
- 新增 Nano Banana 2 (gemini-3.1-flash-image-preview) 作为默认图片生成模型
- 模型列表: Nano Banana 2 > Nano Banana Pro > Nano Banana
- 更新 ProviderManager、image-generator.ts、media/generate route 的默认值

其他已有改动一并提交:
- batch image generation 功能文件
- 依赖更新 (package.json / package-lock.json)
- i18n、db schema、AppShell、uploads route 等相关改动

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:55:24 +08:00

124 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Unified reference-image store for image generation.
*
* Keys:
* PENDING_KEY – images uploaded via the input bar, not yet bound to a message
* LAST_GENERATED_KEY – file paths of the most recently generated images (sessionStorage-backed)
* <message-id> – images bound to a specific assistant message
*/
import type { ReferenceImage } from '@/types';
export const PENDING_KEY = '__pending__';
export const LAST_GENERATED_KEY = '__last_generated__';
const store = new Map<string, ReferenceImage[]>();
// ── sessionStorage persistence for last-generated paths ──
const SS_KEY = 'imgref:last_generated';
function loadLastGenerated(): void {
if (typeof window === 'undefined') return;
try {
const raw = sessionStorage.getItem(SS_KEY);
if (raw) {
const arr: ReferenceImage[] = JSON.parse(raw);
if (Array.isArray(arr) && arr.length > 0) {
store.set(LAST_GENERATED_KEY, arr);
}
}
} catch {
// ignore
}
}
// Auto-restore on module load (client only)
loadLastGenerated();
// ── Public helpers ──
/** Set reference images for a given key. */
export function setRefImages(key: string, images: ReferenceImage[]): void {
if (images.length === 0) {
store.delete(key);
} else {
store.set(key, images);
}
}
/** Delete reference images for a given key. */
export function deleteRefImages(key: string): void {
store.delete(key);
}
/** Get reference images for a given key (or undefined). */
export function getRefImages(key: string): ReferenceImage[] | undefined {
return store.get(key);
}
/**
* Transfer pending reference images to a specific message ID.
* Called when a streaming response transitions to a persisted MessageItem.
*/
export function transferPendingToMessage(messageId: string): void {
const pending = store.get(PENDING_KEY);
if (pending) {
store.set(messageId, pending);
store.delete(PENDING_KEY);
}
}
/**
* Store generated image paths and persist to sessionStorage.
* Called when image generation completes.
*/
export function setLastGeneratedImages(paths: string[]): void {
const images: ReferenceImage[] = paths.map(p => ({ mimeType: 'image/png', localPath: p }));
store.set(LAST_GENERATED_KEY, images);
if (typeof window !== 'undefined') {
try {
sessionStorage.setItem(SS_KEY, JSON.stringify(images));
} catch {
// storage full
}
}
}
/**
* Single merge entry-point: build a unified ReferenceImage[] for a given context.
*
* @param key Store key (PENDING_KEY or message.id)
* @param useLastGenerated Whether the LLM requested editing last-generated images
* @param extraPaths Additional file paths from the parsed request (referenceImages field)
*/
export function buildReferenceImages(
key: string,
useLastGenerated: boolean,
extraPaths?: string[],
): ReferenceImage[] {
const result: ReferenceImage[] = [];
// 1. User-uploaded base64 images
const uploaded = store.get(key);
if (uploaded) {
result.push(...uploaded);
}
// 2. Last-generated images (if LLM requested)
if (useLastGenerated) {
const lastGen = store.get(LAST_GENERATED_KEY);
if (lastGen) {
result.push(...lastGen);
}
}
// 3. Extra paths from the parsed request JSON
if (extraPaths && extraPaths.length > 0) {
for (const p of extraPaths) {
result.push({ mimeType: 'image/png', localPath: p });
}
}
return result;
}