T1ckbase commited on
Commit
f035308
·
1 Parent(s): c28b31a

Generate multiple images at the same time

Browse files
Files changed (1) hide show
  1. main.ts +90 -39
main.ts CHANGED
@@ -106,52 +106,103 @@ app.post('/v1/images/generations', async (c) => {
106
  },
107
  };
108
 
109
- headers.has('guidance_scale') && (requestBody.parameters.guidance_scale = parseFloat(headers.get('guidance_scale')!));
110
- headers.has('negative_prompt') && (requestBody.parameters.negative_prompt = headers.get('negative_prompt'));
111
- headers.has('num_inference_steps') && (requestBody.parameters.num_inference_steps = parseInt(headers.get('num_inference_steps')!));
112
- headers.has('scheduler') && (requestBody.parameters.scheduler = headers.get('scheduler'));
113
- headers.has('seed') && (requestBody.parameters.seed = parseInt(headers.get('seed')!));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  console.log('new body:', requestBody);
115
 
116
- const response = await fetch(targetUrl, {
117
- method: 'POST',
118
- headers: headers,
119
- body: JSON.stringify(requestBody),
120
- });
121
- if (!response.ok) return response;
122
-
123
- const contentType = response.headers.get('content-type')!;
124
- const imageArrayBuffer = await response.arrayBuffer();
125
- const imageData = new Uint8Array(imageArrayBuffer);
126
-
127
- // Generate a unique ID without the file extension
128
- const fileId = crypto.randomUUID();
129
-
130
- // Store in our in-memory cache instead of writing to disk
131
- imageCache.set(fileId, {
132
- data: imageData,
133
- contentType: contentType,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  });
135
 
136
- const host = headers.get('Host') || c.req.header('Host');
137
- const url = `${host}/tmp/${fileId}`;
 
138
 
139
- console.log(url);
140
- let data: any = {
141
- url,
142
- };
143
- if (params.response_format === 'b64_json') {
144
- data = {
145
- b64_json: encodeBase64(imageArrayBuffer),
146
  };
147
- }
148
-
149
- const responseBody = {
150
- created: Math.floor(Date.now() / 1000),
151
- data: [data],
152
- };
153
 
154
- return c.json(responseBody);
 
 
 
 
155
 
156
  // switch (body.model) {
157
  // case 'flux-dev': {
 
106
  },
107
  };
108
 
109
+ if (headers.has('guidance_scale')) {
110
+ requestBody.parameters.guidance_scale = parseFloat(headers.get('guidance_scale')!);
111
+ headers.delete('guidance_scale');
112
+ }
113
+ if (headers.has('negative_prompt')) {
114
+ requestBody.parameters.negative_prompt = headers.get('negative_prompt');
115
+ headers.delete('negative_prompt');
116
+ }
117
+ if (headers.has('num_inference_steps')) {
118
+ requestBody.parameters.num_inference_steps = parseInt(headers.get('num_inference_steps')!);
119
+ headers.delete('num_inference_steps');
120
+ }
121
+ if (headers.has('scheduler')) {
122
+ requestBody.parameters.scheduler = headers.get('scheduler');
123
+ headers.delete('scheduler');
124
+ }
125
+ if (headers.has('seed')) {
126
+ requestBody.parameters.seed = parseInt(headers.get('seed')!);
127
+ headers.delete('seed');
128
+ }
129
  console.log('new body:', requestBody);
130
 
131
+ // Determine how many images to generate (default to 1)
132
+ const numImages = params.n || 1;
133
+
134
+ // Create an array of promises for parallel execution
135
+ const imagePromises = Array.from({ length: numImages }, async (_, i) => {
136
+ // Clone the request body to avoid race conditions
137
+ const currentRequestBody = structuredClone(requestBody);
138
+
139
+ // If a seed was provided, increment it for each image to ensure variety
140
+ if (currentRequestBody.parameters.seed !== undefined && i > 0) {
141
+ currentRequestBody.parameters.seed += i; // Add index to ensure unique seeds
142
+ }
143
+
144
+ // Create a copy of headers for each request
145
+ const currentHeaders = new Headers(headers);
146
+
147
+ try {
148
+ const response = await fetch(targetUrl, {
149
+ method: 'POST',
150
+ headers: currentHeaders,
151
+ body: JSON.stringify(currentRequestBody),
152
+ });
153
+
154
+ if (!response.ok) {
155
+ throw new Error(`Request failed with status ${response.status}: ${await response.text()}`);
156
+ }
157
+
158
+ const contentType = response.headers.get('content-type')!;
159
+ const imageArrayBuffer = await response.arrayBuffer();
160
+ const imageData = new Uint8Array(imageArrayBuffer);
161
+
162
+ // Generate a unique ID without the file extension
163
+ const fileId = crypto.randomUUID();
164
+
165
+ // Store in our in-memory cache instead of writing to disk
166
+ imageCache.set(fileId, {
167
+ data: imageData,
168
+ contentType: contentType,
169
+ });
170
+
171
+ const host = headers.get('Host') || c.req.header('Host');
172
+ const url = `${host}/tmp/${fileId}`;
173
+
174
+ console.log(`Generated image ${i + 1}/${numImages}: ${url}`);
175
+
176
+ // Create the appropriate data format based on the response_format
177
+ if (params.response_format === 'b64_json') {
178
+ return {
179
+ b64_json: encodeBase64(imageArrayBuffer),
180
+ };
181
+ } else {
182
+ return {
183
+ url,
184
+ };
185
+ }
186
+ } catch (error) {
187
+ console.error(`Error generating image ${i + 1}:`, error);
188
+ throw error;
189
+ }
190
  });
191
 
192
+ try {
193
+ // Wait for all image generation promises to complete
194
+ const imageResults = await Promise.all(imagePromises);
195
 
196
+ const responseBody = {
197
+ created: Math.floor(Date.now() / 1000),
198
+ data: imageResults,
 
 
 
 
199
  };
 
 
 
 
 
 
200
 
201
+ return c.json(responseBody);
202
+ } catch (error) {
203
+ console.error('Error in parallel image generation:', error);
204
+ return c.json({ error: 'Failed to generate one or more images' }, 500);
205
+ }
206
 
207
  // switch (body.model) {
208
  // case 'flux-dev': {