Download web/src/store/image-composer-draft.ts from zlcy/study: direct link, hf CLI and curl.
- Browser
- Download file 5.14 kB
-
https://huggingface.co/spaces/zlcy/study/resolve/main/web/src/store/image-composer-draft.ts
- Command line
-
hf download hf://spaces/zlcy/study/web/src/store/image-composer-draft.ts
-
curl -L -o image-composer-draft.ts https://huggingface.co/spaces/zlcy/study/resolve/main/web/src/store/image-composer-draft.ts
5.14 kB
| "use client"; | |
| import localforage from "localforage"; | |
| import type { StoredReferenceImage } from "@/store/image-conversations"; | |
| export type ImageComposerDraftState = { | |
| prompt: string; | |
| count: string; | |
| size: string; | |
| model: string; | |
| quality: string; | |
| resolution: string; | |
| thirdPartyImageGroupId: string; | |
| memoryEnabled: boolean; | |
| accountPoolStrategy: string; | |
| }; | |
| export type LoadedImageComposerDraft = ImageComposerDraftState & { | |
| referenceImages: StoredReferenceImage[]; | |
| referenceImageFiles: File[]; | |
| }; | |
| type PersistedDraftReference = { | |
| name: string; | |
| type: string; | |
| source?: "upload" | "result"; | |
| blob: Blob; | |
| }; | |
| const DRAFT_STATE_STORAGE_KEY = "chatgpt2api:image_composer_draft_v2"; | |
| const DRAFT_TAB_ID_STORAGE_KEY = "chatgpt2api:image_composer_draft_tab_id"; | |
| const draftReferenceStorage = localforage.createInstance({ | |
| name: "chatgpt2api", | |
| storeName: "image_composer_draft", | |
| }); | |
| const EMPTY_DRAFT_STATE: ImageComposerDraftState = { | |
| prompt: "", | |
| count: "1", | |
| size: "", | |
| model: "gpt-image-2", | |
| quality: "high", | |
| resolution: "", | |
| thirdPartyImageGroupId: "", | |
| memoryEnabled: false, | |
| accountPoolStrategy: "own_first", | |
| }; | |
| function getDraftTabId(): string { | |
| if (typeof window === "undefined") return "server"; | |
| const existing = window.sessionStorage.getItem(DRAFT_TAB_ID_STORAGE_KEY); | |
| if (existing) return existing; | |
| const next = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" | |
| ? crypto.randomUUID() | |
| : `${Date.now()}-${Math.random().toString(36).slice(2)}`; | |
| window.sessionStorage.setItem(DRAFT_TAB_ID_STORAGE_KEY, next); | |
| return next; | |
| } | |
| function draftReferencesKey(): string { | |
| return `references:v2:${getDraftTabId()}`; | |
| } | |
| function normalizeDraftState(value: unknown): ImageComposerDraftState { | |
| const source = value && typeof value === "object" ? value as Partial<ImageComposerDraftState> : {}; | |
| return { | |
| prompt: String(source.prompt || ""), | |
| count: String(source.count || "1"), | |
| size: String(source.size || ""), | |
| model: String(source.model || "gpt-image-2"), | |
| quality: String(source.quality || "high"), | |
| resolution: String(source.resolution || ""), | |
| thirdPartyImageGroupId: String(source.thirdPartyImageGroupId || ""), | |
| memoryEnabled: source.memoryEnabled === true, | |
| accountPoolStrategy: String(source.accountPoolStrategy || "own_first"), | |
| }; | |
| } | |
| export function saveImageComposerDraftState(state: ImageComposerDraftState): void { | |
| if (typeof window === "undefined") return; | |
| try { | |
| window.sessionStorage.setItem(DRAFT_STATE_STORAGE_KEY, JSON.stringify(normalizeDraftState(state))); | |
| } catch { | |
| // Draft persistence is best-effort when browser storage is unavailable. | |
| } | |
| } | |
| export async function saveImageComposerDraftReferences( | |
| images: StoredReferenceImage[], | |
| files: File[], | |
| ): Promise<void> { | |
| const references = images | |
| .map((image, index): PersistedDraftReference | null => { | |
| const file = files[index]; | |
| if (!file) return null; | |
| return { | |
| name: image.name || file.name || `reference-${index + 1}.png`, | |
| type: image.type || file.type || "image/png", | |
| source: image.source === "result" ? "result" : "upload", | |
| blob: file, | |
| }; | |
| }) | |
| .filter((item): item is PersistedDraftReference => Boolean(item)); | |
| if (references.length === 0) { | |
| await draftReferenceStorage.removeItem(draftReferencesKey()); | |
| return; | |
| } | |
| await draftReferenceStorage.setItem(draftReferencesKey(), references); | |
| } | |
| export async function loadImageComposerDraft(): Promise<LoadedImageComposerDraft | null> { | |
| let state = EMPTY_DRAFT_STATE; | |
| let hasStoredState = false; | |
| if (typeof window !== "undefined") { | |
| try { | |
| const raw = window.sessionStorage.getItem(DRAFT_STATE_STORAGE_KEY); | |
| hasStoredState = Boolean(raw); | |
| state = normalizeDraftState(JSON.parse(raw || "{}")); | |
| } catch { | |
| state = EMPTY_DRAFT_STATE; | |
| } | |
| } | |
| let persistedReferences: PersistedDraftReference[] = []; | |
| try { | |
| persistedReferences = | |
| (await draftReferenceStorage.getItem<PersistedDraftReference[]>(draftReferencesKey())) || []; | |
| } catch { | |
| persistedReferences = []; | |
| } | |
| if (!hasStoredState && persistedReferences.length === 0) { | |
| return null; | |
| } | |
| const referenceImageFiles = persistedReferences.map( | |
| (item) => new File([item.blob], item.name || "reference.png", { type: item.type || item.blob.type || "image/png" }), | |
| ); | |
| const referenceImages = persistedReferences.map((item, index): StoredReferenceImage => ({ | |
| name: item.name || referenceImageFiles[index]?.name || "reference.png", | |
| type: item.type || referenceImageFiles[index]?.type || "image/png", | |
| dataUrl: URL.createObjectURL(item.blob), | |
| source: item.source === "result" ? "result" : "upload", | |
| })); | |
| return { ...state, referenceImages, referenceImageFiles }; | |
| } | |
| export async function clearImageComposerDraft(): Promise<void> { | |
| if (typeof window !== "undefined") { | |
| try { | |
| window.sessionStorage.removeItem(DRAFT_STATE_STORAGE_KEY); | |
| } catch { | |
| // Ignore unavailable browser storage. | |
| } | |
| } | |
| await draftReferenceStorage.removeItem(draftReferencesKey()); | |
| } | |