jbilcke-hf HF staff commited on
Commit
9802882
1 Parent(s): 9a8adca

working to add some llama2 step

Browse files
package-lock.json CHANGED
@@ -8,6 +8,7 @@
8
  "name": "video-quest",
9
  "version": "0.0.0",
10
  "dependencies": {
 
11
  "@radix-ui/react-accordion": "^1.1.2",
12
  "@radix-ui/react-avatar": "^1.0.3",
13
  "@radix-ui/react-checkbox": "^1.0.4",
@@ -183,6 +184,14 @@
183
  "react-dom": ">=16.8.0"
184
  }
185
  },
 
 
 
 
 
 
 
 
186
  "node_modules/@humanwhocodes/config-array": {
187
  "version": "0.11.10",
188
  "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
 
8
  "name": "video-quest",
9
  "version": "0.0.0",
10
  "dependencies": {
11
+ "@huggingface/inference": "^2.6.1",
12
  "@radix-ui/react-accordion": "^1.1.2",
13
  "@radix-ui/react-avatar": "^1.0.3",
14
  "@radix-ui/react-checkbox": "^1.0.4",
 
184
  "react-dom": ">=16.8.0"
185
  }
186
  },
187
+ "node_modules/@huggingface/inference": {
188
+ "version": "2.6.1",
189
+ "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-2.6.1.tgz",
190
+ "integrity": "sha512-qFYchgOCPeEkZJKiSr7Kz62QwukJtgkeQCT7Q0SSKUcvHpTQVNJp6i/JrJMR4dBdzQysJ1SZDC0pLBBnnskTag==",
191
+ "engines": {
192
+ "node": ">=18"
193
+ }
194
+ },
195
  "node_modules/@humanwhocodes/config-array": {
196
  "version": "0.11.10",
197
  "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
package.json CHANGED
@@ -9,6 +9,7 @@
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
 
12
  "@radix-ui/react-accordion": "^1.1.2",
13
  "@radix-ui/react-avatar": "^1.0.3",
14
  "@radix-ui/react-checkbox": "^1.0.4",
 
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
+ "@huggingface/inference": "^2.6.1",
13
  "@radix-ui/react-accordion": "^1.1.2",
14
  "@radix-ui/react-avatar": "^1.0.3",
15
  "@radix-ui/react-checkbox": "^1.0.4",
src/app/agents/pirates.ts CHANGED
@@ -34,10 +34,13 @@ const actionnables = [
34
  // "ship's wheel",
35
  // "hat",
36
  // "barrel",
37
- // "cannon",
38
  // "rope",
39
  // "bucket",
 
40
  "parrot",
 
 
41
  // "wooden leg"
42
  ]
43
 
@@ -54,9 +57,8 @@ export const agent: Agent = {
54
  const prompt = [
55
  `screenshot from an adventure videogame`,
56
  `inside the hold of a pirate ship`,
57
- `with a pirate chest in the center`,
58
- `a parrot`,
59
- `and a wooden leg`,
60
  `at sunset`,
61
  `unreal engine`,
62
  ].join(", ")
 
34
  // "ship's wheel",
35
  // "hat",
36
  // "barrel",
37
+ "cannon",
38
  // "rope",
39
  // "bucket",
40
+ "skull",
41
  "parrot",
42
+ "lock",
43
+ "ship",
44
  // "wooden leg"
45
  ]
46
 
 
57
  const prompt = [
58
  `screenshot from an adventure videogame`,
59
  `inside the hold of a pirate ship`,
60
+ `a pirate chest in the center with a large lock`,
61
+ `a parrot on top of it`,
 
62
  `at sunset`,
63
  `unreal engine`,
64
  ].join(", ")
src/app/agents/server.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ "use server"
2
+
3
+ import { HfInference } from "@huggingface/inference"
4
+
5
+ const hfi = new HfInference(process.env.HF_API_TOKEN)
6
+ const hf = hfi.endpoint(`${process.env.HF_INFERENCE_ENDPOINT_URL || ""}`)
7
+
8
+ export async function decideNextSteps(userAction: string) {
9
+ return ""
10
+ }
src/app/main.tsx CHANGED
@@ -13,9 +13,9 @@ import {
13
  } from "@/components/ui/select"
14
 
15
  import { render } from "./render"
16
- import { Agent, AgentType, Scene } from "./agents/types"
17
  import { agents, defaultAgent, getAgent } from "./agents"
18
- import { ImageSegment, RenderedScene } from "./types"
19
 
20
  export default function Main() {
21
  const [isPending, startTransition] = useTransition()
@@ -28,54 +28,59 @@ export default function Main() {
28
  })
29
  const ref = useRef<AgentType>(defaultAgent)
30
 
31
- useEffect(() => {
32
-
33
- const updateView = async () => {
34
- // console.log(`update view..`)
35
-
36
- await startTransition(async () => {
37
-
38
- // console.log(`getting agent..`)
39
- const type = ref?.current
40
- const agent = getAgent(type)
41
-
42
- // console.log(`asking agent to determine things..`)
43
- const scene = agent.simulate()
44
-
45
- // console.log(`rendering scene..`)
46
- const newRendered = await render(
47
- scene.prompt,
48
- scene.actionnables.slice(0, 5) // too many can slow us down it seems
49
- )
50
-
51
- if (type !== ref?.current) {
52
- console.log("agent type changed! reloading scene")
53
- setTimeout(() => { updateView() }, 0)
54
- return
55
- }
56
-
57
-
58
- if (newRendered.assetUrl) {
59
- setRendered(newRendered)
60
- // console.log(`got a new url: ${newUrl}`)
61
- setScene(scene)
62
- setTimeout(() => { updateView()}, 1000)
63
- } else {
64
- // console.log(`going to wait a bit more: ${newUrl}`)
65
- setTimeout(() => { updateView()}, newRendered.error ? 6000 : 3000)
66
- }
67
- })
68
- }
69
-
70
- updateView()
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  }, [])
73
 
 
 
 
 
 
 
 
 
 
 
 
74
  return (
75
  <div className="flex flex-col w-full pt-4">
76
  <div className="flex flex-col space-y-3 px-2">
77
  <div className="flex flex-row items-center space-x-3">
78
- <label className="flex">Select a game:</label>
79
  <Select
80
  defaultValue={defaultAgent}
81
  onValueChange={(value) => {
@@ -97,7 +102,7 @@ export default function Main() {
97
  </SelectContent>
98
  </Select>
99
  </div>
100
- <p>Note: changing the model might take up to 1 minute</p>
101
 
102
  {(scene) ? <div>
103
  <p>Action: {scene.action}</p>
@@ -111,7 +116,7 @@ export default function Main() {
111
  </div>)}
112
  </div>
113
  </div>
114
- <ImageRenderer {...rendered} />
115
  </div>
116
  )
117
  }
 
13
  } from "@/components/ui/select"
14
 
15
  import { render } from "./render"
16
+ import { AgentType, Scene } from "./agents/types"
17
  import { agents, defaultAgent, getAgent } from "./agents"
18
+ import { RenderedScene } from "./types"
19
 
20
  export default function Main() {
21
  const [isPending, startTransition] = useTransition()
 
28
  })
29
  const ref = useRef<AgentType>(defaultAgent)
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ const loadNextScene = async () => {
33
+ // console.log(`update view..`)
34
+
35
+ await startTransition(async () => {
36
+
37
+ // console.log(`getting agent..`)
38
+ const type = ref?.current
39
+ const agent = getAgent(type)
40
+
41
+ // console.log(`asking agent to determine things..`)
42
+ const scene = agent.simulate()
43
+
44
+ // console.log(`rendering scene..`)
45
+ const newRendered = await render(
46
+ scene.prompt,
47
+ scene.actionnables.slice(0, 5) // too many can slow us down it seems
48
+ )
49
+
50
+ if (type !== ref?.current) {
51
+ console.log("agent type changed! reloading scene")
52
+ setTimeout(() => { loadNextScene() }, 0)
53
+ return
54
+ }
55
+
56
+ if (newRendered.assetUrl) {
57
+ setRendered(newRendered)
58
+ // console.log(`got a new url: ${newUrl}`)
59
+ setScene(scene)
60
+ }
61
+ })
62
+ }
63
+
64
+ useEffect(() => {
65
+ loadNextScene()
66
  }, [])
67
 
68
+ const handleUserAction = (action: string) => {
69
+ console.log("user action:", action)
70
+
71
+ // TODO: ask Llama2 what to do about it
72
+ // we need a frame and some actionnables,
73
+ // perhaps even some music or sound effects
74
+
75
+ console.log("we don't know what to do, so we just load the next frame!")
76
+ loadNextScene()
77
+ }
78
+
79
  return (
80
  <div className="flex flex-col w-full pt-4">
81
  <div className="flex flex-col space-y-3 px-2">
82
  <div className="flex flex-row items-center space-x-3">
83
+ <label className="flex">Select a story:</label>
84
  <Select
85
  defaultValue={defaultAgent}
86
  onValueChange={(value) => {
 
102
  </SelectContent>
103
  </Select>
104
  </div>
105
+ <p>Note: it takes about 1 minute to generate a new game panel</p>
106
 
107
  {(scene) ? <div>
108
  <p>Action: {scene.action}</p>
 
116
  </div>)}
117
  </div>
118
  </div>
119
+ <ImageRenderer rendered={rendered} onUserAction={handleUserAction} />
120
  </div>
121
  )
122
  }
src/components/business/image-renderer.tsx CHANGED
@@ -1,73 +1,115 @@
1
- import { useRef } from "react"
2
 
3
  import { ImageSegment, RenderedScene } from "@/app/types"
4
 
5
  export const ImageRenderer = ({
6
- assetUrl = "",
7
- maskBase64 = "",
8
- segments = []
9
- }: RenderedScene) => {
 
 
 
 
 
 
10
  const imgRef = useRef<HTMLImageElement | null>(null)
11
- const canvas = document.createElement('canvas')
12
- const context = canvas.getContext('2d')
13
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  const getPixelColor = (x: number, y: number) => {
15
- console.log("getting pixel color")
16
- if (!context) {
17
  throw new Error("Unable to get context from canvas")
18
  }
19
 
20
- const imgData = context.getImageData(x, y, 1, 1).data
21
 
22
- return `[${imgData[0]},${imgData[1]},${imgData[2]},${imgData[3]/255}]`
 
 
 
23
  }
24
 
25
- const handleMouseDown = (event: React.MouseEvent) => {
26
- const boundingRect = imgRef.current!.getBoundingClientRect()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- const x = event.clientX - boundingRect.left
29
- const y = event.clientY - boundingRect.top
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- if (maskBase64) {
32
- const image = new Image()
33
-
34
- image.onload = function () {
35
- if (context) {
36
- context.drawImage(image, 0, 0)
37
-
38
- const clickedColor = getPixelColor(x, y) as any
39
-
40
- let closestSegment: ImageSegment | null = null
41
-
42
- let minDistance = Infinity
43
-
44
- segments.forEach(segment => {
45
- const segmentColor = segment.color.slice(0,3) // get the RGB part only
46
-
47
- const distance = Math.sqrt(
48
- Math.pow(clickedColor[0] - segmentColor[0], 2) +
49
- Math.pow(clickedColor[1] - segmentColor[1], 2) +
50
- Math.pow(clickedColor[2] - segmentColor[2], 2)
51
- )
52
-
53
- if(distance < minDistance) {
54
- minDistance = distance;
55
- closestSegment = segment;
56
- }
57
- })
58
 
59
- console.log("closestSegment:", closestSegment)
60
- console.log(closestSegment) // Here is the closest matching segment
61
- }
62
- }
63
 
64
- image.src = maskBase64
65
- // image.src = "data:image/png;base64," + maskBase64;
66
- } else {
67
- console.log("No mask available, aborting..")
68
  }
69
- }
70
 
 
 
 
 
 
 
 
 
 
71
 
72
  if (!assetUrl) {
73
  return <div className="flex w-full h-screen items-center justify-center text-center">
@@ -75,14 +117,56 @@ export const ImageRenderer = ({
75
  </div>
76
  }
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  return (
79
  <div className="w-full py-8 px-2">
80
- <img
81
- src={assetUrl}
82
- ref={imgRef}
83
- className="w-full rounded-md overflow-hidden"
84
- onMouseDown={handleMouseDown}
85
- />
 
 
 
 
 
 
 
 
 
 
86
  </div>
87
  )
88
  }
 
1
+ import { useEffect, useRef, useState } from "react"
2
 
3
  import { ImageSegment, RenderedScene } from "@/app/types"
4
 
5
  export const ImageRenderer = ({
6
+ rendered: {
7
+ assetUrl = "",
8
+ maskBase64 = "",
9
+ segments = []
10
+ },
11
+ onUserAction,
12
+ }: {
13
+ rendered: RenderedScene
14
+ onUserAction: (action: string) => void
15
+ }) => {
16
  const imgRef = useRef<HTMLImageElement | null>(null)
17
+ const canvasRef = useRef<HTMLCanvasElement | null>(null)
18
+ const contextRef = useRef<CanvasRenderingContext2D | null>(null)
19
+ const [actionnable, setActionnable] = useState<string>("")
20
+
21
+ useEffect(() => {
22
+ if (maskBase64) {
23
+ console.log("maskBase64:", maskBase64)
24
+ const img = new Image();
25
+ img.onload = function () {
26
+ canvasRef.current = document.createElement('canvas');
27
+ canvasRef.current.width = img.width;
28
+ canvasRef.current.height = img.height;
29
+ contextRef.current = canvasRef.current.getContext('2d');
30
+ contextRef.current!.drawImage(img, 0, 0, img.width, img.height);
31
+ }
32
+ img.src = "data:image/png;base64," + maskBase64;
33
+ } else {
34
+ console.log("error, no maskBase64 detected!")
35
+ }
36
+ }, [maskBase64]);
37
+
38
+
39
  const getPixelColor = (x: number, y: number) => {
40
+ if (!contextRef.current) {
 
41
  throw new Error("Unable to get context from canvas")
42
  }
43
 
44
+ const imgData = contextRef.current.getImageData(x, y, 1, 1).data
45
 
46
+
47
+ const clickedColor = Array.from(imgData.slice(0, 3), value => value / 255);
48
+
49
+ return clickedColor
50
  }
51
 
52
+
53
+ const getSegmentAt = (x: number, y: number): ImageSegment => {
54
+ if (!contextRef.current) throw new Error("Unable to get context from canvas");
55
+ if (!maskBase64) throw new Error("Mask is undefined");
56
+
57
+ let closestSegment: ImageSegment = {
58
+ id: 0,
59
+ box: [],
60
+ color: [],
61
+ label: "",
62
+ score: 0,
63
+ }
64
+
65
+ const clickedColor = getPixelColor(x,y) as any
66
+
67
+ if (`${clickedColor}` === "1,1,1") {
68
+ return closestSegment
69
+ }
70
 
71
+ let minDistance = Infinity;
72
+
73
+ segments.forEach(segment => {
74
+ const segmentColor = segment.color.slice(0,3); // get the RGB part only
75
+
76
+ const distance = Math.sqrt(
77
+ Math.pow(clickedColor[0] - segmentColor[0], 2) +
78
+ Math.pow(clickedColor[1] - segmentColor[1], 2) +
79
+ Math.pow(clickedColor[2] - segmentColor[2], 2)
80
+ );
81
+
82
+ if(distance < minDistance) {
83
+ minDistance = distance;
84
+ closestSegment = segment;
85
+ }
86
+ });
87
+
88
+ return closestSegment;
89
+ }
90
+
91
+ const handleMouseEvent = (event: React.MouseEvent, isClickEvent: boolean = false) => {
92
+ if (!contextRef.current) return; // Return early if mask image has not been loaded yet
93
 
94
+ const boundingRect = imgRef.current!.getBoundingClientRect();
95
+ const x = event.clientX - boundingRect.left;
96
+ const y = event.clientY - boundingRect.top;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ const newSegment = getSegmentAt(x, y)
 
 
 
99
 
100
+ if (actionnable !== newSegment.label) {
101
+ setActionnable(newSegment.label)
 
 
102
  }
 
103
 
104
+ if (!newSegment.label) { return }
105
+
106
+ console.log("actionnable: ", actionnable)
107
+
108
+ if (isClickEvent) {
109
+ console.log("User clicked on " + actionnable);
110
+ // onUserAction(actionnable);
111
+ }
112
+ };
113
 
114
  if (!assetUrl) {
115
  return <div className="flex w-full h-screen items-center justify-center text-center">
 
117
  </div>
118
  }
119
 
120
+ /*
121
+ <img
122
+ src={assetUrl}
123
+ ref={imgRef}
124
+ width="1024px"
125
+ height="512px"
126
+ className={
127
+ [
128
+ "absolute top-0 left-0",
129
+ actionnable ? "cursor-pointer" : ""
130
+ ].join(" ")
131
+ }
132
+ onMouseDown={(event) => handleMouseEvent(event, true)}
133
+ onMouseMove={handleMouseEvent}
134
+ />
135
+
136
+ <img
137
+ src={"data:image/png;base64," + maskBase64}
138
+ ref={imgRef}
139
+ width="1024px"
140
+ height="512px"
141
+ className={
142
+ [
143
+ "absolute top-0 left-0 opacity-30",
144
+ actionnable ? "cursor-pointer" : ""
145
+ ].join(" ")
146
+ }
147
+ onMouseDown={(event) => handleMouseEvent(event, true)}
148
+ onMouseMove={handleMouseEvent}
149
+ />
150
+ */
151
+
152
  return (
153
  <div className="w-full py-8 px-2">
154
+ <div className="relative w-full">
155
+ <img
156
+ src={"data:image/png;base64," + maskBase64}
157
+ ref={imgRef}
158
+ width="1024px"
159
+ height="512px"
160
+ className={
161
+ [
162
+ "absolute top-0 left-0 opacity-30",
163
+ actionnable ? "cursor-pointer" : ""
164
+ ].join(" ")
165
+ }
166
+ onMouseDown={(event) => handleMouseEvent(event, true)}
167
+ onMouseMove={handleMouseEvent}
168
+ />
169
+ </div>
170
  </div>
171
  )
172
  }