BennyKok commited on
Commit
d822271
·
1 Parent(s): 531e782

feat: enable batch generation

Browse files
bun.lockb CHANGED
Binary files a/bun.lockb and b/bun.lockb differ
 
src/app/page.tsx CHANGED
@@ -27,6 +27,7 @@ import {
27
  import { Separator } from "@/components/ui/separator";
28
 
29
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
 
30
 
31
  export default function Page() {
32
  return (
@@ -53,27 +54,8 @@ export default function Page() {
53
 
54
  function Txt2img() {
55
  const [prompt, setPrompt] = useState("");
56
- const [image, setImage] = useState("");
57
  const [loading, setLoading] = useState(false);
58
- const [runId, setRunId] = useState("");
59
- const [status, setStatus] = useState<string>();
60
-
61
- // Polling in frontend to check for the
62
- useEffect(() => {
63
- if (!runId) return;
64
- const interval = setInterval(() => {
65
- checkStatus(runId).then((res) => {
66
- if (res) setStatus(res.status);
67
- if (res && res.status === "success") {
68
- console.log(res.outputs[0]?.data);
69
- setImage(res.outputs[0]?.data?.images[0].url);
70
- setLoading(false);
71
- clearInterval(interval);
72
- }
73
- });
74
- }, 2000);
75
- return () => clearInterval(interval);
76
- }, [runId]);
77
 
78
  return (
79
  <Card className="w-full max-w-[600px]">
@@ -90,20 +72,27 @@ function Txt2img() {
90
  <form
91
  className="grid w-full items-center gap-1.5"
92
  onSubmit={(e) => {
93
- if (loading) return;
94
-
95
  e.preventDefault();
 
 
96
  setLoading(true);
97
- generate(prompt).then((res) => {
98
- console.log(res);
99
- if (!res) {
100
- setStatus("error");
101
- setLoading(false);
102
- return;
103
- }
104
- setRunId(res.run_id);
 
 
 
 
 
 
 
 
105
  });
106
- setStatus("preparing");
107
  }}
108
  >
109
  <Label htmlFor="picture">Image prompt</Label>
@@ -117,21 +106,10 @@ function Txt2img() {
117
  Generate {loading && <LoadingIcon />}
118
  </Button>
119
 
120
- <div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
121
- {!loading && image && (
122
- <img
123
- className="w-full h-full object-contain"
124
- src={image}
125
- alt="Generated image"
126
- >
127
- </img>
128
- )}
129
- {!image && status && (
130
- <div className="absolute top-0 left-0 w-full h-full flex items-center justify-center gap-2">
131
- {status} <LoadingIcon />
132
- </div>
133
- )}
134
- {loading && <Skeleton className="w-full h-full" />}
135
  </div>
136
  </form>
137
  </CardContent>
@@ -226,22 +204,7 @@ function Img2img() {
226
  Generate {loading && <LoadingIcon />}
227
  </Button>
228
 
229
- <div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
230
- {!loading && image && (
231
- <img
232
- className="w-full h-full object-contain"
233
- src={image}
234
- alt="Generated image"
235
- >
236
- </img>
237
- )}
238
- {!image && status && (
239
- <div className="absolute top-0 left-0 w-full h-full flex items-center justify-center gap-2">
240
- {status} <LoadingIcon />
241
- </div>
242
- )}
243
- {loading && <Skeleton className="w-full h-full" />}
244
- </div>
245
  </form>
246
  </CardContent>
247
  </Card>
@@ -250,28 +213,23 @@ function Img2img() {
250
 
251
  const poses = {
252
  arms_on_hips: {
253
- url:
254
- "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(1).png",
255
  name: "Arms on Hips",
256
  },
257
  waving: {
258
- url:
259
- "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(2).png",
260
  name: "Waving",
261
  },
262
  legs_together_sideways: {
263
- url:
264
- "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(3).png",
265
  name: "Legs together, body at an angle",
266
  },
267
  excited_jump: {
268
- url:
269
- "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(4).png",
270
  name: "excited jump",
271
  },
272
  pointing_to_the_stars: {
273
- url:
274
- "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(5).png",
275
  name: "Pointing to the stars",
276
  },
277
  };
@@ -328,7 +286,7 @@ function OpenposeToImage() {
328
  e.preventDefault();
329
  setLoading(true);
330
  generate_img_with_controlnet(poseImageUrl, prompt).then((res) => {
331
- console.log('here', res);
332
  if (!res) {
333
  setStatus("error");
334
  setLoading(false);
@@ -372,7 +330,7 @@ function OpenposeToImage() {
372
  Generate {loading && <LoadingIcon />}
373
  </Button>
374
 
375
- <div className="flex gap-4">
376
  <div className="w-full rounded-lg relative">
377
  {/* Pose Image */}
378
  {poseLoading && (
@@ -386,30 +344,16 @@ function OpenposeToImage() {
386
  src={poseImageUrl}
387
  alt="Selected pose"
388
  onLoad={() => setPoseLoading(false)}
389
- >
390
- </img>
391
  )}
392
  </div>
393
- <Separator
394
  orientation="vertical"
395
  className="border-gray-200"
396
  decorative
397
- />
398
- <div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
399
- {!loading && image && (
400
- <img
401
- className="w-full h-full object-contain"
402
- src={image}
403
- alt="Generated image"
404
- >
405
- </img>
406
- )}
407
- {!image && status && (
408
- <div className="absolute top-0 left-0 w-full h-full flex items-center justify-center gap-2">
409
- {status} <LoadingIcon />
410
- </div>
411
- )}
412
- {loading && <Skeleton className="w-full h-full" />}
413
  </div>
414
  </div>
415
  </form>
 
27
  import { Separator } from "@/components/ui/separator";
28
 
29
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
30
+ import { ImageGenerationResult } from "@/components/ImageGenerationResult";
31
 
32
  export default function Page() {
33
  return (
 
54
 
55
  function Txt2img() {
56
  const [prompt, setPrompt] = useState("");
 
57
  const [loading, setLoading] = useState(false);
58
+ const [runIds, setRunIds] = useState<string[]>([]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  return (
61
  <Card className="w-full max-w-[600px]">
 
72
  <form
73
  className="grid w-full items-center gap-1.5"
74
  onSubmit={(e) => {
 
 
75
  e.preventDefault();
76
+
77
+ if (loading) return;
78
  setLoading(true);
79
+
80
+ const promises = Array(4).fill(null).map(() => {
81
+ return generate(prompt)
82
+ .then((res) => {
83
+ if (res) {
84
+ setRunIds((ids) => [...ids, res.run_id]);
85
+ }
86
+ return res;
87
+ })
88
+ .catch((error) => {
89
+ console.error(error);
90
+ });
91
+ });
92
+
93
+ Promise.all(promises).finally(() => {
94
+ setLoading(false);
95
  });
 
96
  }}
97
  >
98
  <Label htmlFor="picture">Image prompt</Label>
 
106
  Generate {loading && <LoadingIcon />}
107
  </Button>
108
 
109
+ <div className="grid grid-cols-2 gap-4">
110
+ {runIds.map((runId, index) => (
111
+ <ImageGenerationResult key={index} runId={runId} />
112
+ ))}
 
 
 
 
 
 
 
 
 
 
 
113
  </div>
114
  </form>
115
  </CardContent>
 
204
  Generate {loading && <LoadingIcon />}
205
  </Button>
206
 
207
+ {runId && <ImageGenerationResult key={runId} runId={runId} className="aspect-square"/>}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  </form>
209
  </CardContent>
210
  </Card>
 
213
 
214
  const poses = {
215
  arms_on_hips: {
216
+ url: "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(1).png",
 
217
  name: "Arms on Hips",
218
  },
219
  waving: {
220
+ url: "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(2).png",
 
221
  name: "Waving",
222
  },
223
  legs_together_sideways: {
224
+ url: "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(3).png",
 
225
  name: "Legs together, body at an angle",
226
  },
227
  excited_jump: {
228
+ url: "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(4).png",
 
229
  name: "excited jump",
230
  },
231
  pointing_to_the_stars: {
232
+ url: "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose%20(5).png",
 
233
  name: "Pointing to the stars",
234
  },
235
  };
 
286
  e.preventDefault();
287
  setLoading(true);
288
  generate_img_with_controlnet(poseImageUrl, prompt).then((res) => {
289
+ console.log("here", res);
290
  if (!res) {
291
  setStatus("error");
292
  setLoading(false);
 
330
  Generate {loading && <LoadingIcon />}
331
  </Button>
332
 
333
+ <div className="grid grid-cols-2 gap-4">
334
  <div className="w-full rounded-lg relative">
335
  {/* Pose Image */}
336
  {poseLoading && (
 
344
  src={poseImageUrl}
345
  alt="Selected pose"
346
  onLoad={() => setPoseLoading(false)}
347
+ ></img>
 
348
  )}
349
  </div>
350
+ {/* <Separator
351
  orientation="vertical"
352
  className="border-gray-200"
353
  decorative
354
+ /> */}
355
+ <div className="w-full h-full">
356
+ {runId && <ImageGenerationResult key={runId} runId={runId} className="aspect-[768/1152]"/>}
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  </div>
358
  </div>
359
  </form>
src/components/ImageGenerationResult.tsx CHANGED
@@ -1,10 +1,14 @@
1
  "use client";
2
  import { LoadingIcon } from "@/components/LoadingIcon";
3
  import { Skeleton } from "@/components/ui/skeleton";
 
4
  import { checkStatus } from "@/server/generate";
5
  import { useEffect, useState } from "react";
6
 
7
- export function ImageGenerationResult({ runId }: { runId: string; }) {
 
 
 
8
  const [image, setImage] = useState("");
9
  const [status, setStatus] = useState<string>("preparing");
10
  const [loading, setLoading] = useState(true);
@@ -27,7 +31,7 @@ export function ImageGenerationResult({ runId }: { runId: string; }) {
27
  }, [runId]);
28
 
29
  return (
30
- <div className="border border-gray-200 w-full square w-full rounded-lg relative">
31
  {!loading && image && (
32
  <img
33
  className="w-full h-full object-contain"
 
1
  "use client";
2
  import { LoadingIcon } from "@/components/LoadingIcon";
3
  import { Skeleton } from "@/components/ui/skeleton";
4
+ import { cn } from "@/lib/utils";
5
  import { checkStatus } from "@/server/generate";
6
  import { useEffect, useState } from "react";
7
 
8
+ export function ImageGenerationResult({
9
+ runId,
10
+ className
11
+ }: { runId: string } & React.ComponentProps<"div">) {
12
  const [image, setImage] = useState("");
13
  const [status, setStatus] = useState<string>("preparing");
14
  const [loading, setLoading] = useState(true);
 
31
  }, [runId]);
32
 
33
  return (
34
+ <div className={cn("border border-gray-200 w-full aspect-[512/768] rounded-lg relative", className)}>
35
  {!loading && image && (
36
  <img
37
  className="w-full h-full object-contain"