jbilcke-hf HF staff commited on
Commit
719ed9c
1 Parent(s): 726926f

working to add a long-requested feature: panel reload

Browse files
.env CHANGED
@@ -11,6 +11,12 @@ RENDERING_ENGINE="INFERENCE_API"
11
  # - OPENAI
12
  LLM_ENGINE="INFERENCE_API"
13
 
 
 
 
 
 
 
14
  # Set to "true" to create artificial delays and smooth out traffic
15
  NEXT_PUBLIC_ENABLE_RATE_LIMITER="false"
16
 
 
11
  # - OPENAI
12
  LLM_ENGINE="INFERENCE_API"
13
 
14
+ # Not implemented for the Inference API yet - you can submit a PR if you have some ideas
15
+ NEXT_PUBLIC_CAN_UPSCALE="false"
16
+
17
+ # Not implemented for the Inference API yet - you can submit a PR if you have some ideas
18
+ NEXT_PUBLIC_CAN_REDRAW="false"
19
+
20
  # Set to "true" to create artificial delays and smooth out traffic
21
  NEXT_PUBLIC_ENABLE_RATE_LIMITER="false"
22
 
package-lock.json CHANGED
@@ -49,6 +49,7 @@
49
  "react": "18.2.0",
50
  "react-circular-progressbar": "^2.1.0",
51
  "react-dom": "18.2.0",
 
52
  "react-virtualized-auto-sizer": "^1.0.20",
53
  "replicate": "^0.17.0",
54
  "sbd": "^1.0.19",
@@ -7908,6 +7909,14 @@
7908
  "loose-envify": "^1.1.0"
7909
  }
7910
  },
 
 
 
 
 
 
 
 
7911
  "node_modules/react-is": {
7912
  "version": "16.13.1",
7913
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
 
49
  "react": "18.2.0",
50
  "react-circular-progressbar": "^2.1.0",
51
  "react-dom": "18.2.0",
52
+ "react-icons": "^4.11.0",
53
  "react-virtualized-auto-sizer": "^1.0.20",
54
  "replicate": "^0.17.0",
55
  "sbd": "^1.0.19",
 
7909
  "loose-envify": "^1.1.0"
7910
  }
7911
  },
7912
+ "node_modules/react-icons": {
7913
+ "version": "4.11.0",
7914
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz",
7915
+ "integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==",
7916
+ "peerDependencies": {
7917
+ "react": "*"
7918
+ }
7919
+ },
7920
  "node_modules/react-is": {
7921
  "version": "16.13.1",
7922
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
package.json CHANGED
@@ -50,6 +50,7 @@
50
  "react": "18.2.0",
51
  "react-circular-progressbar": "^2.1.0",
52
  "react-dom": "18.2.0",
 
53
  "react-virtualized-auto-sizer": "^1.0.20",
54
  "replicate": "^0.17.0",
55
  "sbd": "^1.0.19",
 
50
  "react": "18.2.0",
51
  "react-circular-progressbar": "^2.1.0",
52
  "react-dom": "18.2.0",
53
+ "react-icons": "^4.11.0",
54
  "react-virtualized-auto-sizer": "^1.0.20",
55
  "replicate": "^0.17.0",
56
  "sbd": "^1.0.19",
src/app/engine/render.ts CHANGED
@@ -136,6 +136,8 @@ export async function newRender({
136
 
137
  // Recommendation: handle errors
138
  if (res.status !== 200) {
 
 
139
  // This will activate the closest `error.js` Error Boundary
140
  throw new Error('Failed to fetch data')
141
  }
 
136
 
137
  // Recommendation: handle errors
138
  if (res.status !== 200) {
139
+ const content = await res.text()
140
+ console.error(content)
141
  // This will activate the closest `error.js` Error Boundary
142
  throw new Error('Failed to fetch data')
143
  }
src/app/interface/bottom-bar/index.tsx CHANGED
@@ -101,11 +101,13 @@ ${uploadUrl
101
  `print:hidden`,
102
  `fixed bottom-2 md:bottom-4 left-2 right-0 md:left-3 md:right-1`,
103
  `flex flex-row`,
104
- `justify-between`
 
105
  )}>
106
  <div className={cn(
107
  `flex flex-row`,
108
  `items-end`,
 
109
  `animation-all duration-300 ease-in-out`,
110
  isGeneratingStory ? `scale-0 opacity-0` : ``,
111
  `space-x-3`,
@@ -115,20 +117,21 @@ ${uploadUrl
115
  </div>
116
  <div className={cn(
117
  `flex flex-row`,
 
118
  `animation-all duration-300 ease-in-out`,
119
  isGeneratingStory ? `scale-0 opacity-0` : ``,
120
  `space-x-3`,
121
  `scale-[0.9]`
122
  )}>
123
  <div>
124
- <Button
125
  onClick={handleUpscale}
126
  disabled={!prompt?.length || remainingImages > 0 || isUpscaling || !Object.values(upscaleQueue).length}
127
  >
128
  {isUpscaling
129
  ? `${allStatus.length - Object.values(upscaleQueue).length}/${allStatus.length} ⌛`
130
  : "Upscale"}
131
- </Button>
132
  </div>
133
  <div>
134
  <Button
@@ -152,7 +155,7 @@ ${uploadUrl
152
  </Button>
153
  </div>
154
  <div>
155
- <Button
156
  onClick={handleShare}
157
  disabled={!prompt?.length}
158
  className="space-x-2"
@@ -162,7 +165,7 @@ ${uploadUrl
162
  <span className="hidden md:inline">Share to community</span>
163
  <span className="inline md:hidden">Share</span>
164
  </div>
165
- </Button>
166
  </div>
167
  </div>
168
  </div>
 
101
  `print:hidden`,
102
  `fixed bottom-2 md:bottom-4 left-2 right-0 md:left-3 md:right-1`,
103
  `flex flex-row`,
104
+ `justify-between`,
105
+ `pointer-events-none`
106
  )}>
107
  <div className={cn(
108
  `flex flex-row`,
109
  `items-end`,
110
+ `pointer-events-auto`,
111
  `animation-all duration-300 ease-in-out`,
112
  isGeneratingStory ? `scale-0 opacity-0` : ``,
113
  `space-x-3`,
 
117
  </div>
118
  <div className={cn(
119
  `flex flex-row`,
120
+ `pointer-events-auto`,
121
  `animation-all duration-300 ease-in-out`,
122
  isGeneratingStory ? `scale-0 opacity-0` : ``,
123
  `space-x-3`,
124
  `scale-[0.9]`
125
  )}>
126
  <div>
127
+ {process.env.NEXT_PUBLIC_CAN_UPSCALE === "true" ? <Button
128
  onClick={handleUpscale}
129
  disabled={!prompt?.length || remainingImages > 0 || isUpscaling || !Object.values(upscaleQueue).length}
130
  >
131
  {isUpscaling
132
  ? `${allStatus.length - Object.values(upscaleQueue).length}/${allStatus.length} ⌛`
133
  : "Upscale"}
134
+ </Button> : null}
135
  </div>
136
  <div>
137
  <Button
 
155
  </Button>
156
  </div>
157
  <div>
158
+ {process.env.NEXT_PUBLIC_ENABLE_COMMUNITY_SHARING === "true" ? <Button
159
  onClick={handleShare}
160
  disabled={!prompt?.length}
161
  className="space-x-2"
 
165
  <span className="hidden md:inline">Share to community</span>
166
  <span className="inline md:hidden">Share</span>
167
  </div>
168
+ </Button> : null}
169
  </div>
170
  </div>
171
  </div>
src/app/interface/panel/index.tsx CHANGED
@@ -1,7 +1,7 @@
1
  "use client"
2
 
3
  import { useEffect, useRef, useState, useTransition } from "react"
4
- // import AutoSizer from "react-virtualized-auto-sizer"
5
 
6
  import { RenderedScene } from "@/types"
7
 
@@ -12,9 +12,6 @@ import { cn } from "@/lib/utils"
12
  import { getInitialRenderedScene } from "@/lib/getInitialRenderedScene"
13
  import { Progress } from "@/app/interface/progress"
14
 
15
- // import { see } from "@/app/engine/caption"
16
- // import { replaceTextInSpeechBubbles } from "@/lib/replaceTextInSpeechBubbles"
17
-
18
  export function Panel({
19
  panel,
20
  className = "",
@@ -28,13 +25,13 @@ export function Panel({
28
  }) {
29
  const panelId = `${panel}`
30
 
 
31
  const ref = useRef<HTMLImageElement>(null)
32
  const font = useStore(state => state.font)
33
  const preset = useStore(state => state.preset)
34
 
35
  const setGeneratingImages = useStore(state => state.setGeneratingImages)
36
 
37
- const [imageWithText, setImageWithText] = useState("")
38
  const panels = useStore(state => state.panels)
39
  const prompt = panels[panel] || ""
40
 
@@ -63,9 +60,8 @@ export function Panel({
63
 
64
  const delay = enableRateLimiter ? (3000 + (1000 * panel)) : 1000
65
 
66
- // since this run in its own loop, we need to use references everywhere
67
- // but perhaps this could be refactored
68
- useEffect(() => {
69
  // console.log("Panel prompt: "+ prompt)
70
  if (!prompt?.length) { return }
71
 
@@ -113,6 +109,12 @@ export function Panel({
113
  }
114
  })
115
  }, enableRateLimiter ? 2000 * panel : 0)
 
 
 
 
 
 
116
  }, [prompt, width, height])
117
 
118
 
@@ -215,27 +217,10 @@ export function Panel({
215
  `print:border-[1.5px] print:shadow-none`,
216
  )
217
 
218
-
219
- /*
220
- text detection (doesn't work)
221
- useEffect(() => {
222
- const fn = async () => {
223
- if (!rendered.assetUrl || !ref.current) {
224
- return
225
- }
226
-
227
- const result = await replaceTextInSpeechBubbles(
228
- rendered.assetUrl,
229
- "Lorem ipsum dolor sit amet, dolor ipsum. Sit amet? Ipsum! Dolor!!!"
230
- )
231
- if (result) {
232
- setImageWithText(result)
233
- }
234
- }
235
- fn()
236
-
237
- }, [rendered.assetUrl, ref.current])
238
- */
239
 
240
  if (prompt && !rendered.assetUrl) {
241
  return (
@@ -254,9 +239,11 @@ export function Panel({
254
  frameClassName,
255
  { "grayscale": preset.color === "grayscale" },
256
  className
257
- )}>
 
 
 
258
  <div className={cn(
259
- ``,
260
  `bg-stone-50`,
261
  `border-stone-800`,
262
  `transition-all duration-200 ease-in-out`,
@@ -296,7 +283,7 @@ export function Panel({
296
  {rendered.assetUrl &&
297
  <img
298
  ref={ref}
299
- src={imageWithText || rendered.assetUrl}
300
  width={width}
301
  height={height}
302
  alt={rendered.alt}
@@ -305,6 +292,26 @@ export function Panel({
305
  // showCaptions ? `-mt-11` : ''
306
  )}
307
  />}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  </div>
309
  )
310
  }
 
1
  "use client"
2
 
3
  import { useEffect, useRef, useState, useTransition } from "react"
4
+ import { RxReload } from "react-icons/rx"
5
 
6
  import { RenderedScene } from "@/types"
7
 
 
12
  import { getInitialRenderedScene } from "@/lib/getInitialRenderedScene"
13
  import { Progress } from "@/app/interface/progress"
14
 
 
 
 
15
  export function Panel({
16
  panel,
17
  className = "",
 
25
  }) {
26
  const panelId = `${panel}`
27
 
28
+ const [mouseOver, setMouseOver] = useState(false)
29
  const ref = useRef<HTMLImageElement>(null)
30
  const font = useStore(state => state.font)
31
  const preset = useStore(state => state.preset)
32
 
33
  const setGeneratingImages = useStore(state => state.setGeneratingImages)
34
 
 
35
  const panels = useStore(state => state.panels)
36
  const prompt = panels[panel] || ""
37
 
 
60
 
61
  const delay = enableRateLimiter ? (3000 + (1000 * panel)) : 1000
62
 
63
+
64
+ const startImageGeneration = ({ prompt, width, height }: { prompt: string, width: number, height: number}) => {
 
65
  // console.log("Panel prompt: "+ prompt)
66
  if (!prompt?.length) { return }
67
 
 
109
  }
110
  })
111
  }, enableRateLimiter ? 2000 * panel : 0)
112
+ }
113
+
114
+ // since this run in its own loop, we need to use references everywhere
115
+ // but perhaps this could be refactored
116
+ useEffect(() => {
117
+ startImageGeneration({ prompt, width, height })
118
  }, [prompt, width, height])
119
 
120
 
 
217
  `print:border-[1.5px] print:shadow-none`,
218
  )
219
 
220
+ const handleReload = () => {
221
+ console.log(`Asked to reload panel ${panelId}`)
222
+ startImageGeneration({ prompt, width, height })
223
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  if (prompt && !rendered.assetUrl) {
226
  return (
 
239
  frameClassName,
240
  { "grayscale": preset.color === "grayscale" },
241
  className
242
+ )}
243
+ onMouseEnter={() => setMouseOver(true)}
244
+ onMouseLeave={() => setMouseOver(false)}
245
+ >
246
  <div className={cn(
 
247
  `bg-stone-50`,
248
  `border-stone-800`,
249
  `transition-all duration-200 ease-in-out`,
 
283
  {rendered.assetUrl &&
284
  <img
285
  ref={ref}
286
+ src={rendered.assetUrl}
287
  width={width}
288
  height={height}
289
  alt={rendered.alt}
 
292
  // showCaptions ? `-mt-11` : ''
293
  )}
294
  />}
295
+ {process.env.NEXT_PUBLIC_CAN_REDRAW === "true" ? <div
296
+ className={cn(`relative -mt-14 ml-4`,)}>
297
+ <div className="flex flex-row">
298
+ <div
299
+ onClick={rendered.status === "completed" ? handleReload : undefined}
300
+ className={cn(
301
+ `bg-stone-100 rounded-lg`,
302
+ `flex flex-row space-x-2 items-center`,
303
+ `py-2 px-3 cursor-pointer`,
304
+ `transition-all duration-200 ease-in-out`,
305
+ rendered.status === "completed" ? "opacity-95" : "opacity-50",
306
+ mouseOver && rendered.assetUrl ? `scale-95 hover:scale-100 hover:opacity-100`: `scale-0`
307
+ )}>
308
+ <RxReload
309
+ className="w-5 h-5"
310
+ />
311
+ <span className="text-base">Redraw</span>
312
+ </div>
313
+ </div>
314
+ </div> : null}
315
  </div>
316
  )
317
  }