forked from op7418/CodePilot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseImageGen.ts
More file actions
108 lines (93 loc) · 3.06 KB
/
useImageGen.ts
File metadata and controls
108 lines (93 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
'use client';
import { createContext, useContext, useState, useCallback, useRef } from 'react';
export interface ImageGenResult {
id: string;
text?: string;
images: Array<{ data: string; mimeType: string; localPath?: string }>;
}
export interface ImageGenState {
enabled: boolean;
generating: boolean;
}
export interface ImageGenContextValue {
state: ImageGenState;
setEnabled: (v: boolean) => void;
generate: (prompt: string, aspectRatio: string, imageSize: string, referenceImages?: File[]) => Promise<ImageGenResult | null>;
lastResult: ImageGenResult | null;
}
export const ImageGenContext = createContext<ImageGenContextValue | null>(null);
export function useImageGen(): ImageGenContextValue {
const ctx = useContext(ImageGenContext);
if (!ctx) {
throw new Error('useImageGen must be used within an ImageGenProvider');
}
return ctx;
}
export function useImageGenState(): ImageGenContextValue {
const [enabled, setEnabled] = useState(false);
const [generating, setGenerating] = useState(false);
const [lastResult, setLastResult] = useState<ImageGenResult | null>(null);
const abortRef = useRef<AbortController | null>(null);
const generate = useCallback(async (prompt: string, aspectRatio: string, imageSize: string, referenceImages?: File[]): Promise<ImageGenResult | null> => {
if (abortRef.current) {
abortRef.current.abort();
}
const controller = new AbortController();
abortRef.current = controller;
setGenerating(true);
try {
const body: Record<string, unknown> = {
prompt,
aspectRatio,
imageSize,
};
if (referenceImages && referenceImages.length > 0) {
const refImagesData: Array<{ data: string; mimeType: string; name: string }> = [];
for (const file of referenceImages) {
const buffer = await file.arrayBuffer();
const base64 = btoa(
new Uint8Array(buffer).reduce((data, byte) => data + String.fromCharCode(byte), '')
);
refImagesData.push({
data: base64,
mimeType: file.type,
name: file.name,
});
}
body.referenceImages = refImagesData;
}
const res = await fetch('/api/media/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
signal: controller.signal,
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: 'Generation failed' }));
throw new Error(err.error || 'Generation failed');
}
const data = await res.json();
const result: ImageGenResult = {
id: data.id,
text: data.text,
images: data.images || [],
};
setLastResult(result);
return result;
} catch (err) {
if ((err as Error).name === 'AbortError') {
return null;
}
throw err;
} finally {
setGenerating(false);
abortRef.current = null;
}
}, []);
return {
state: { enabled, generating },
setEnabled,
generate,
lastResult,
};
}