jbilcke-hf HF staff commited on
Commit
f0dc1c3
1 Parent(s): 3f09ee7
package-lock.json CHANGED
@@ -44,7 +44,9 @@
44
  "next": "13.4.10",
45
  "pick": "^0.0.1",
46
  "postcss": "8.4.26",
 
47
  "react": "18.2.0",
 
48
  "react-day-picker": "^8.8.0",
49
  "react-dom": "18.2.0",
50
  "tailwind-merge": "^1.13.2",
@@ -56,6 +58,9 @@
56
  "uuid": "^9.0.0",
57
  "zod": "^3.21.4",
58
  "zustand": "^4.3.9"
 
 
 
59
  }
60
  },
61
  "node_modules/@aashutoshrathi/word-wrap": {
@@ -1494,6 +1499,12 @@
1494
  "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
1495
  "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
1496
  },
 
 
 
 
 
 
1497
  "node_modules/@types/react": {
1498
  "version": "18.2.15",
1499
  "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.15.tgz",
@@ -4824,6 +4835,20 @@
4824
  "node": ">=6"
4825
  }
4826
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4827
  "node_modules/queue-microtask": {
4828
  "version": "1.2.3",
4829
  "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -4854,6 +4879,14 @@
4854
  "node": ">=0.10.0"
4855
  }
4856
  },
 
 
 
 
 
 
 
 
4857
  "node_modules/react-day-picker": {
4858
  "version": "8.8.0",
4859
  "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.8.0.tgz",
 
44
  "next": "13.4.10",
45
  "pick": "^0.0.1",
46
  "postcss": "8.4.26",
47
+ "qs": "^6.11.2",
48
  "react": "18.2.0",
49
+ "react-circular-progressbar": "^2.1.0",
50
  "react-day-picker": "^8.8.0",
51
  "react-dom": "18.2.0",
52
  "tailwind-merge": "^1.13.2",
 
58
  "uuid": "^9.0.0",
59
  "zod": "^3.21.4",
60
  "zustand": "^4.3.9"
61
+ },
62
+ "devDependencies": {
63
+ "@types/qs": "^6.9.7"
64
  }
65
  },
66
  "node_modules/@aashutoshrathi/word-wrap": {
 
1499
  "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
1500
  "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
1501
  },
1502
+ "node_modules/@types/qs": {
1503
+ "version": "6.9.7",
1504
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
1505
+ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
1506
+ "dev": true
1507
+ },
1508
  "node_modules/@types/react": {
1509
  "version": "18.2.15",
1510
  "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.15.tgz",
 
4835
  "node": ">=6"
4836
  }
4837
  },
4838
+ "node_modules/qs": {
4839
+ "version": "6.11.2",
4840
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
4841
+ "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
4842
+ "dependencies": {
4843
+ "side-channel": "^1.0.4"
4844
+ },
4845
+ "engines": {
4846
+ "node": ">=0.6"
4847
+ },
4848
+ "funding": {
4849
+ "url": "https://github.com/sponsors/ljharb"
4850
+ }
4851
+ },
4852
  "node_modules/queue-microtask": {
4853
  "version": "1.2.3",
4854
  "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 
4879
  "node": ">=0.10.0"
4880
  }
4881
  },
4882
+ "node_modules/react-circular-progressbar": {
4883
+ "version": "2.1.0",
4884
+ "resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz",
4885
+ "integrity": "sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==",
4886
+ "peerDependencies": {
4887
+ "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
4888
+ }
4889
+ },
4890
  "node_modules/react-day-picker": {
4891
  "version": "8.8.0",
4892
  "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.8.0.tgz",
package.json CHANGED
@@ -45,7 +45,9 @@
45
  "next": "13.4.10",
46
  "pick": "^0.0.1",
47
  "postcss": "8.4.26",
 
48
  "react": "18.2.0",
 
49
  "react-day-picker": "^8.8.0",
50
  "react-dom": "18.2.0",
51
  "tailwind-merge": "^1.13.2",
@@ -57,5 +59,8 @@
57
  "uuid": "^9.0.0",
58
  "zod": "^3.21.4",
59
  "zustand": "^4.3.9"
 
 
 
60
  }
61
  }
 
45
  "next": "13.4.10",
46
  "pick": "^0.0.1",
47
  "postcss": "8.4.26",
48
+ "qs": "^6.11.2",
49
  "react": "18.2.0",
50
+ "react-circular-progressbar": "^2.1.0",
51
  "react-day-picker": "^8.8.0",
52
  "react-dom": "18.2.0",
53
  "tailwind-merge": "^1.13.2",
 
59
  "uuid": "^9.0.0",
60
  "zod": "^3.21.4",
61
  "zustand": "^4.3.9"
62
+ },
63
+ "devDependencies": {
64
+ "@types/qs": "^6.9.7"
65
  }
66
  }
src/app/main.tsx CHANGED
@@ -1,6 +1,7 @@
1
  "use client"
2
 
3
  import { useEffect, useRef, useState, useTransition } from "react"
 
4
 
5
  import { ImageRenderer } from "@/components/business/image-renderer"
6
 
@@ -15,10 +16,11 @@ import {
15
  import { render } from "./render"
16
 
17
  import { RenderedScene } from "./types"
18
- import { predict } from "./predict"
19
  import { GameType } from "./games/types"
20
  import { defaultGame, games, getGame } from "./games"
21
- import { getPrompts } from "./prompts"
 
 
22
 
23
  export default function Main() {
24
  const [isPending, startTransition] = useTransition()
@@ -28,7 +30,9 @@ export default function Main() {
28
  maskBase64: "",
29
  segments:[]
30
  })
31
- const ref = useRef<GameType>(defaultGame)
 
 
32
  const [situation, setSituation] = useState("")
33
  const [scene, setScene] = useState("")
34
  const [dialogue, setDialogue] = useState("")
@@ -92,75 +96,31 @@ export default function Main() {
92
 
93
  const game = getGame(ref.current)
94
 
95
- const prompts = getPrompts(game, situation, actionnable)
96
-
97
- console.log("prompts:", prompts)
98
-
99
  try {
 
 
 
 
 
 
 
100
 
101
- console.log("ask the LLM to invent next steps..")
102
-
103
- const rawSituation = await predict(prompts.situationPrompt)
104
-
105
- console.log(`rawSituation: `, rawSituation)
106
-
107
- if (!rawSituation) {
108
- throw new Error("failed to generate the situation")
109
- }
110
- const newSituation = `${rawSituation || ""}`
111
- if (!newSituation) {
112
- throw new Error("failed to parse the situation")
113
- }
114
-
115
- console.log(`newSituation: `, newSituation)
116
-
117
- const rawActionnables = await predict(prompts.actionnablesPrompt)
118
- console.log(`rawActionnables: `, rawActionnables)
119
-
120
- if (!rawActionnables) {
121
- throw new Error("failed to generate the actionnables")
122
- }
123
-
124
- let newActionnables = []
125
- try {
126
- // we remove all [ or ]
127
- const sanitized = rawActionnables.replaceAll("[", "").replaceAll("]", "")
128
- newActionnables = (JSON.parse(`[${sanitized}]`) as string[]).map(item =>
129
- // clean the words to remove any punctuation
130
- item.replace(/\W/g, '').trim()
131
- )
132
-
133
- if (!newActionnables.length) {
134
- throw new Error("no actionnables")
135
- }
136
- } catch (err) {
137
- throw new Error("failed to parse the actionnables")
138
- }
139
-
140
- console.log(`newActionnables: `, newActionnables)
141
-
142
- const rawDialogue = await predict(prompts.dialoguePrompt)
143
- console.log(`rawDialogue: `, rawDialogue)
144
-
145
- if (!rawDialogue) {
146
- throw new Error("failed to generate the dialogue")
147
- }
148
- const newDialogue = `${rawDialogue || ""}`
149
- if (!newDialogue) {
150
- throw new Error("failed to parse the dialogue")
151
- }
152
- console.log(`newDialogue: `, newDialogue)
153
-
154
 
155
- setDialogue(newDialogue)
156
- setSituation(newSituation)
 
157
 
158
  console.log("loading next scene..")
159
- await loadNextScene(newSituation, newActionnables)
160
 
161
- // todo we could also use useEffect
162
  } catch (err) {
163
- console.error(err)
 
164
  }
165
  })
166
  }
 
1
  "use client"
2
 
3
  import { useEffect, useRef, useState, useTransition } from "react"
4
+ import qs from "qs"
5
 
6
  import { ImageRenderer } from "@/components/business/image-renderer"
7
 
 
16
  import { render } from "./render"
17
 
18
  import { RenderedScene } from "./types"
 
19
  import { GameType } from "./games/types"
20
  import { defaultGame, games, getGame } from "./games"
21
+ import { getBackground } from "@/app/queries/getBackground"
22
+ import { getDialogue } from "@/app/queries/getDialogue"
23
+ import { getActionnables } from "@/app/queries/getActionnables"
24
 
25
  export default function Main() {
26
  const [isPending, startTransition] = useTransition()
 
30
  maskBase64: "",
31
  segments:[]
32
  })
33
+ const urlParams = qs.parse(window.location.search.slice(1))
34
+ console.log("urlParams:", urlParams)
35
+ const ref = useRef<GameType>(`${urlParams?.game as any}` as GameType)
36
  const [situation, setSituation] = useState("")
37
  const [scene, setScene] = useState("")
38
  const [dialogue, setDialogue] = useState("")
 
96
 
97
  const game = getGame(ref.current)
98
 
99
+ let newDialogue = ""
 
 
 
100
  try {
101
+ newDialogue = await getDialogue({ game, situation, actionnable })
102
+ console.log(`newDialogue:`, newDialogue)
103
+ setDialogue(newDialogue)
104
+ } catch (err) {
105
+ console.log(`failed to generate dialogue (but it's only a nice to have, so..)`)
106
+ setDialogue("")
107
+ }
108
 
109
+ try {
110
+ const newActionnables = await getActionnables({ game, situation, actionnable, newDialogue })
111
+ console.log(`newActionnables:`, newActionnables)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ const newBackground = await getBackground({ game, situation, actionnable, newDialogue, newActionnables })
114
+ console.log(`newBackground:`, newBackground)
115
+ setSituation(newBackground)
116
 
117
  console.log("loading next scene..")
118
+ await loadNextScene(newBackground, newActionnables)
119
 
120
+ // todo we could also use useEffect
121
  } catch (err) {
122
+ console.error(`failed to get one of the mandatory entites: ${err}`)
123
+ setLoading(false)
124
  }
125
  })
126
  }
src/app/prompts.ts DELETED
@@ -1,86 +0,0 @@
1
- import { Game } from "./games/types"
2
- import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
-
4
- export const getPrompts = (game: Game, situation: string = "", actionnable: string = "") => {
5
-
6
- const initialPrompt = [...game.getScenePrompt()].join(", ")
7
-
8
- const currentPrompt = situation
9
- ? [...game.getScenePrompt(situation)].join(", ")
10
- : initialPrompt
11
-
12
- const userSituationPrompt = `Player is currently in "${currentPrompt}". Player clicked on the "${actionnable}".`
13
-
14
- const baseSituationPromptIfWeHaveHistory = initialPrompt !== currentPrompt
15
- ? ` You must imagine the most plausible next scene, based on where the player was located before and is now, and also what the player did before and are doing now.
16
- Here is the original scene in which the user was located at first, which will inform you about the general settings to follow (you must respect this): "${initialPrompt}".`
17
- : ""
18
-
19
- const situationPrompt = createLlamaPrompt([
20
- {
21
- role: "system",
22
- content: [
23
- `You are the AI game master of a role video game.`,
24
- baseSituationPromptIfWeHaveHistory,
25
- `You are going to receive new information about the current whereabouts of the player.`,
26
- `Please write a caption for the next plausible scene to display in intricate details: the environment, lights, era, characters, objects, textures, light etc. You must include important objects, that the user can click on (eg. characters, doors, vehicles, useful objects).`
27
- ].filter(item => item).join("\n")
28
- },
29
- {
30
- role: "user",
31
- content: userSituationPrompt
32
- }
33
- ])
34
-
35
- const actionnablesPrompt = createLlamaPrompt([
36
- {
37
- role: "system",
38
- content: [
39
- `You are an API endpoint that can return a list of objects thare are in a scene.`,
40
- `You must list basic name of things (eg. "parrot", "chest", "spaceship", "glass", "door", "person", "window", "light", "knob", "button" etc)`,
41
- `The answer must be a JSON array, ie. a list of quoted strings.`
42
- ].filter(item => item).join("\n")
43
- },
44
- {
45
- role: "user",
46
- content: userSituationPrompt
47
- }
48
- ])
49
-
50
- const baseDialoguePromptIfWeHaveHistory = initialPrompt !== currentPrompt
51
- ? `for your information, the initial game panel and scene was: "${initialPrompt}".`
52
- : ""
53
-
54
- const dialoguePrompt = createLlamaPrompt([
55
- {
56
- role: "system",
57
- content: [
58
- `You are the AI game master of a role video game.`,
59
- `You are going to receive new information about the current whereabouts and action of the player.`,
60
- baseDialoguePromptIfWeHaveHistory,
61
- `You must imagine a funny response to speak in reaction to what the player did, like in some old point and click video games.`,
62
- `Please limit yourself to only a 1 or 2 sentences, please.`,
63
- ].filter(item => item).join("\n")
64
- },
65
- {
66
- role: "user",
67
- content: userSituationPrompt
68
- }
69
- ])
70
-
71
-
72
- const prompts = {
73
- initialPrompt,
74
- currentPrompt,
75
- userSituationPrompt,
76
- baseSituationPromptIfWeHaveHistory,
77
- situationPrompt,
78
- actionnablesPrompt,
79
- baseDialoguePromptIfWeHaveHistory,
80
- dialoguePrompt,
81
- }
82
-
83
- return prompts
84
- }
85
-
86
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app/queries/getActionnables.ts ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+ import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
+ import { parseJsonList } from "@/lib/parseJsonList"
4
+
5
+ import { getBase } from "./getBase"
6
+ import { predict } from "./predict"
7
+
8
+ export const getActionnables = async ({
9
+ game,
10
+ situation = "",
11
+ actionnable = "",
12
+ newDialogue = "",
13
+ // newActionnables = [],
14
+ }: {
15
+ game: Game;
16
+ situation: string;
17
+ actionnable: string;
18
+ newDialogue: string;
19
+ // newActionnables: string[];
20
+ }) => {
21
+
22
+ const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable)
23
+
24
+ const basePrompt = initialPrompt !== currentPrompt
25
+ ? `Here is some context information about the initial scene: ${initialPrompt}`
26
+ : ""
27
+
28
+ const prompt = createLlamaPrompt([
29
+ {
30
+ role: "system",
31
+ content: [
32
+ `You are an API endpoint that can return a list of objects visible in the background image of a role playing game.`,
33
+ basePrompt,
34
+ `You must list basic name of characters or visible objects (eg. "parrot", "chest", "spaceship", "glass", "door", "person", "window", "light", "knob", "button" etc) but don't list any word from abstract concepts (ig. don't say things like "secret", "danger", "next move" etc)`,
35
+ `The answer must be a JSON array, ie. a list of quoted strings.`
36
+ ].filter(item => item).join("\n")
37
+ },
38
+ {
39
+ role: "user",
40
+ content: userSituationPrompt
41
+ }
42
+ ])
43
+
44
+ let rawStringOutput = ""
45
+
46
+ try {
47
+ rawStringOutput = await predict(prompt)
48
+ } catch (err) {
49
+ console.log(`prediction of the actionnables failed, trying again..`)
50
+ try {
51
+ rawStringOutput = await predict(prompt)
52
+ } catch (err) {
53
+ console.error(`prediction of the actionnables failed again!`)
54
+ throw new Error(`failed to generate the actionnables ${err}`)
55
+ }
56
+ }
57
+
58
+ let result = []
59
+
60
+ try {
61
+ result = parseJsonList(rawStringOutput)
62
+
63
+ if (!result.length) {
64
+ throw new Error("no actionnables")
65
+ }
66
+ } catch (err) {
67
+ console.log("failed to find a valid JSON! attempting method 2..")
68
+
69
+ try {
70
+ const sanitized = rawStringOutput.replaceAll("[", "").replaceAll("]", "")
71
+ result = (JSON.parse(`[${sanitized}]`) as string[]).map(item =>
72
+ // clean the words to remove any punctuation
73
+ item.replace(/\W/g, '').trim()
74
+ )
75
+
76
+ if (!result.length) {
77
+ throw new Error("no actionnables")
78
+ }
79
+ } catch (err) {
80
+ console.log("failed to repair and recover a valid JSON!")
81
+ throw new Error("failed to parse the actionnables")
82
+ }
83
+ }
84
+
85
+ return result
86
+ }
src/app/queries/getBackground.ts ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+ import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
+
4
+ import { getBase } from "./getBase"
5
+ import { predict } from "./predict"
6
+
7
+ export const getBackground = async ({
8
+ game,
9
+ situation = "",
10
+ actionnable = "",
11
+ newDialogue = "",
12
+ newActionnables = [],
13
+ }: {
14
+ game: Game;
15
+ situation: string;
16
+ actionnable: string;
17
+ newDialogue: string;
18
+ newActionnables: string[];
19
+ }) => {
20
+
21
+ const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable)
22
+
23
+ const basePrompt = initialPrompt !== currentPrompt
24
+ ? `You must imagine the most plausible next scene, based on where the player was located before and is now, and also what the player did before and are doing now.
25
+ Here is the original scene in which the user was located at first, which will inform you about the general settings to follow (you must respect this): "${initialPrompt}".`
26
+ : ""
27
+
28
+ const prompt = createLlamaPrompt([
29
+ {
30
+ role: "system",
31
+ content: [
32
+ `You are the AI game master of a role video game.`,
33
+ basePrompt,
34
+ `You are going to receive new information about the current whereabouts of the player.`,
35
+ `Please write a caption for the next plausible scene to display in intricate details: the environment, lights, era, characters, objects, textures, light etc.`,
36
+ `You must include important objects, that the user can click on (eg. characters, doors, vehicles, useful objects).`,
37
+ `Be straight to the point, and do not say things like "As the player clicks on.." or "the scene shifts to" (the best is not not mention the player at all)`
38
+ ].filter(item => item).join("\n")
39
+ },
40
+ {
41
+ role: "user",
42
+ content: userSituationPrompt
43
+ }
44
+ ])
45
+
46
+
47
+ let result = ""
48
+ try {
49
+ result = await predict(prompt)
50
+ } catch (err) {
51
+ console.log(`prediction of the background failed, trying again..`)
52
+ try {
53
+ result = await predict(prompt)
54
+ } catch (err) {
55
+ console.error(`prediction of the background failed again!`)
56
+ throw new Error(`failed to generate the background ${err}`)
57
+ }
58
+ }
59
+
60
+ return result
61
+ }
src/app/queries/getBase.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+
3
+ export const getBase = (game: Game, situation: string = "", actionnable: string = "") => {
4
+ const initialPrompt = [...game.getScenePrompt()].join(", ")
5
+
6
+ const currentPrompt = situation
7
+ ? [...game.getScenePrompt(situation)].join(", ")
8
+ : initialPrompt
9
+
10
+ const userSituationPrompt = `Player is currently in "${currentPrompt}". Player clicked on the "${actionnable}".`
11
+
12
+ return { initialPrompt, currentPrompt, userSituationPrompt }
13
+ }
src/app/queries/getDialogue.ts ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+ import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
+
4
+ import { getBase } from "./getBase"
5
+ import { predict } from "./predict"
6
+
7
+
8
+ export const getDialogue = async ({
9
+ game,
10
+ situation = "",
11
+ actionnable = "",
12
+ // newDialogue = "",
13
+ // newActionnables = [],
14
+ }: {
15
+ game: Game;
16
+ situation: string;
17
+ actionnable: string;
18
+ // newDialogue: string;
19
+ // newActionnables: string[];
20
+ }) => {
21
+
22
+ const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable)
23
+
24
+ /*
25
+ const basePrompt = initialPrompt !== currentPrompt
26
+ ? `for your information, the initial game panel and scene was: ${initialPrompt}`
27
+ : ""
28
+ */
29
+
30
+ const basePrompt = initialPrompt !== currentPrompt
31
+ ? ` You must imagine the most plausible next dialogue line from the game master, based on where the player was located before and is now, and also what the player did before and are doing now.
32
+ Here is the original scene in which the user was located at first, which will inform you about the general settings to follow (you must respect this): "${initialPrompt}".`
33
+ : ""
34
+
35
+ const prompt = createLlamaPrompt([
36
+ {
37
+ role: "system",
38
+ content: [
39
+ `You are the AI game master of a role video game.`,
40
+ `You are going to receive new information about the current whereabouts and action of the player.`,
41
+ basePrompt,
42
+ `You must imagine a funny response to speak in reaction to what the player did, like in some old point and click video games.`,
43
+ `Please limit yourself to only a 1 or 2 sentences, please.`,
44
+ ].filter(item => item).join("\n")
45
+ },
46
+ {
47
+ role: "user",
48
+ content: userSituationPrompt
49
+ }
50
+ ])
51
+
52
+
53
+ let result = ""
54
+ try {
55
+ result = await predict(prompt)
56
+ } catch (err) {
57
+ console.log(`prediction of the dialogue failed, trying again..`)
58
+ try {
59
+ result = await predict(prompt)
60
+ } catch (err) {
61
+ console.error(`prediction of the dialogue failed again!`)
62
+ throw new Error(`failed to generate the dialogue ${err}`)
63
+ }
64
+ }
65
+
66
+ return result
67
+ }
src/app/queries/getMusicTrack.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+ import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
+
4
+ import { getBase } from "./getBase"
5
+ import { predict } from "./predict"
6
+
7
+ export const getMusicTrack = async ({
8
+ game,
9
+ situation = "",
10
+ actionnable = "",
11
+ newDialogue = "",
12
+ newActionnables = [],
13
+ }: {
14
+ game: Game;
15
+ situation: string;
16
+ actionnable: string;
17
+ newDialogue: string;
18
+ newActionnables: string[];
19
+ }) => {
20
+ return ""
21
+ }
src/app/queries/getSoundTrack.ts ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Game } from "@/app/games/types"
2
+ import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
3
+
4
+ import { getBase } from "./getBase"
5
+ import { predict } from "./predict"
6
+
7
+ export const getSoundTrack = async ({
8
+ game,
9
+ situation = "",
10
+ actionnable = "",
11
+ newDialogue = "",
12
+ newActionnables = [],
13
+ }: {
14
+ game: Game;
15
+ situation: string;
16
+ actionnable: string;
17
+ newDialogue: string;
18
+ newActionnables: string[];
19
+ }) => {
20
+
21
+ return ""
22
+ }
src/app/{predict.ts → queries/predict.ts} RENAMED
@@ -7,6 +7,8 @@ const hf = hfi.endpoint(`${process.env.HF_INFERENCE_ENDPOINT_URL || ""}`)
7
 
8
  export async function predict(inputs: string) {
9
 
 
 
10
  let instructions = ""
11
  try {
12
  for await (const output of hf.textGenerationStream({
 
7
 
8
  export async function predict(inputs: string) {
9
 
10
+ console.log(`predict: `, inputs)
11
+
12
  let instructions = ""
13
  try {
14
  for await (const output of hf.textGenerationStream({
src/components/business/image-renderer.tsx CHANGED
@@ -33,7 +33,9 @@ export const ImageRenderer = ({
33
  canvasRef.current = document.createElement('canvas');
34
  canvasRef.current.width = img.width;
35
  canvasRef.current.height = img.height;
36
- contextRef.current = canvasRef.current.getContext('2d');
 
 
37
  contextRef.current!.drawImage(img, 0, 0, img.width, img.height);
38
  }
39
  img.src = "data:image/png;base64," + maskBase64;
@@ -104,6 +106,14 @@ export const ImageRenderer = ({
104
  return false
105
  }
106
 
 
 
 
 
 
 
 
 
107
  const boundingRect = imgRef.current!.getBoundingClientRect();
108
  const x = event.clientX - boundingRect.left;
109
  const y = event.clientY - boundingRect.top;
@@ -112,10 +122,12 @@ export const ImageRenderer = ({
112
 
113
  if (actionnable !== newSegment.label) {
114
  if (newSegment.label) {
115
- console.log(`User is hovering "${newSegment.label}"`);
116
  } else {
117
- console.log(`Nothing in the area`);
118
  }
 
 
119
  setActionnable(newSegment.label)
120
  }
121
 
@@ -126,7 +138,11 @@ export const ImageRenderer = ({
126
  console.log("User clicked on " + newSegment.label)
127
  onUserAction(actionnable)
128
  } else {
129
- onUserHover(actionnable)
 
 
 
 
130
  }
131
  };
132
 
@@ -142,9 +158,9 @@ export const ImageRenderer = ({
142
  return
143
  }
144
 
145
- console.log("still loading..")
146
 
147
- console.log("updating progress")
148
  progress = progress + 1
149
  setProcessPercent(progress)
150
 
 
33
  canvasRef.current = document.createElement('canvas');
34
  canvasRef.current.width = img.width;
35
  canvasRef.current.height = img.height;
36
+ contextRef.current = canvasRef.current.getContext('2d', {
37
+ willReadFrequently: true
38
+ });
39
  contextRef.current!.drawImage(img, 0, 0, img.width, img.height);
40
  }
41
  img.src = "data:image/png;base64," + maskBase64;
 
106
  return false
107
  }
108
 
109
+ // sometimes we generate an image, but the segmentation fails
110
+ // so if we click anywhere bug there are no segments,
111
+ // we inform the rest of the app by passing nothing
112
+ if (isClickEvent && segments.length == 0) {
113
+ onUserAction("nothing, to trigger a scene reload")
114
+ return
115
+ }
116
+
117
  const boundingRect = imgRef.current!.getBoundingClientRect();
118
  const x = event.clientX - boundingRect.left;
119
  const y = event.clientY - boundingRect.top;
 
122
 
123
  if (actionnable !== newSegment.label) {
124
  if (newSegment.label) {
125
+ console.log(`User is hovering "${newSegment.label}"`)
126
  } else {
127
+ console.log(`Nothing in the area`)
128
  }
129
+
130
+ // update the actionnable immediately, so we can show the hand / finger cursor pointer
131
  setActionnable(newSegment.label)
132
  }
133
 
 
138
  console.log("User clicked on " + newSegment.label)
139
  onUserAction(actionnable)
140
  } else {
141
+ // only trigger hover events if there are segments,
142
+ // otherwise it's best to stay silent
143
+ if (segments.length) {
144
+ onUserHover(actionnable)
145
+ }
146
  }
147
  };
148
 
 
158
  return
159
  }
160
 
161
+ // console.log("still loading..")
162
 
163
+ // console.log("updating progress")
164
  progress = progress + 1
165
  setProcessPercent(progress)
166
 
src/lib/parseJsonList.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function parseJsonList(content: string): string[] {
2
+ // Extract JSON array from the content
3
+ const start = content.indexOf("[");
4
+ const end = content.lastIndexOf("]");
5
+ const jsonContent = content.slice(start, end + 1);
6
+
7
+ // Parse as JSON into array of strings
8
+ let objects: string[] = [];
9
+
10
+ objects = JSON.parse(jsonContent);
11
+
12
+ return objects;
13
+ }