Spaces:
Runtime error
Runtime error
Commit
·
8fb2ec4
1
Parent(s):
6896326
debugging..
Browse files- src/app/games/dungeon.ts +1 -1
- src/app/main.tsx +12 -29
- src/app/predict.ts +2 -0
- src/app/prompts.ts +83 -0
- src/components/business/image-renderer.tsx +31 -2
- src/components/misc/progress.tsx +57 -0
src/app/games/dungeon.ts
CHANGED
@@ -51,7 +51,7 @@ export const game: Game = {
|
|
51 |
initialActionnables,
|
52 |
getScenePrompt: (situation?: string) => [
|
53 |
`screenshot from an adventure videogame`,
|
54 |
-
|
55 |
situation || initialSituation,
|
56 |
`medieval`,
|
57 |
`unreal engine`,
|
|
|
51 |
initialActionnables,
|
52 |
getScenePrompt: (situation?: string) => [
|
53 |
`screenshot from an adventure videogame`,
|
54 |
+
// `first-person footage`,
|
55 |
situation || initialSituation,
|
56 |
`medieval`,
|
57 |
`unreal engine`,
|
src/app/main.tsx
CHANGED
@@ -18,6 +18,7 @@ import { RenderedScene } from "./types"
|
|
18 |
import { predict } from "./predict"
|
19 |
import { GameType } from "./games/types"
|
20 |
import { defaultGame, games, getGame } from "./games"
|
|
|
21 |
|
22 |
export default function Main() {
|
23 |
const [isPending, startTransition] = useTransition()
|
@@ -80,56 +81,42 @@ export default function Main() {
|
|
80 |
|
81 |
const handleUserAction = async (actionnable: string) => {
|
82 |
console.log("user actionnable:", actionnable)
|
83 |
-
|
|
|
|
|
84 |
// TODO: ask Llama2 what to do about it
|
85 |
// we need a frame and some actionnables,
|
86 |
// perhaps even some music or sound effects
|
87 |
|
88 |
await startTransition(async () => {
|
89 |
-
|
90 |
-
setLoading(true)
|
91 |
|
92 |
const game = getGame(ref.current)
|
93 |
-
const initialPrompt = [...game.getScenePrompt()].join(", ")
|
94 |
|
95 |
-
const
|
96 |
-
|
97 |
-
|
98 |
|
99 |
try {
|
100 |
-
const basePrompt = [
|
101 |
-
`QUESTION: You are the AI game master of a role video game.`,
|
102 |
-
initialPrompt !== currentPrompt ? `The initial scene of the game was this: "${initialPrompt}".` : '',
|
103 |
-
`The player is currently in this scene: "${currentPrompt}".`,
|
104 |
-
`The player has just clicked on "${actionnable}".`
|
105 |
-
]
|
106 |
|
107 |
console.log("ask the LLM to invent next steps..")
|
108 |
|
109 |
-
const rawSituation = await predict(
|
110 |
-
...basePrompt,
|
111 |
-
`Please describe the new 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).\nANSWER:`
|
112 |
-
].join(" "))
|
113 |
|
114 |
console.log(`rawSituation: `, rawSituation)
|
115 |
|
116 |
if (!rawSituation) {
|
117 |
throw new Error("failed to generate the situation")
|
118 |
}
|
119 |
-
const newSituation = `${rawSituation
|
120 |
if (!newSituation) {
|
121 |
throw new Error("failed to parse the situation")
|
122 |
}
|
123 |
|
124 |
console.log(`newSituation: `, newSituation)
|
125 |
|
126 |
-
const rawActionnables = await predict(
|
127 |
-
...basePrompt,
|
128 |
-
`Here are the 4 most important objects visible in this scene, that the user can click on. The list is in JSON (list of strings). You must list basic name of things (eg. "parrot", "chest", "spaceship", "glass", "door", "person", "window", "light", "knob", "button" etc..) \nJSON = [`
|
129 |
-
].join(" "))
|
130 |
console.log(`rawActionnables: `, rawActionnables)
|
131 |
|
132 |
-
|
133 |
if (!rawActionnables) {
|
134 |
throw new Error("failed to generate the actionnables")
|
135 |
}
|
@@ -152,17 +139,13 @@ export default function Main() {
|
|
152 |
|
153 |
console.log(`newActionnables: `, newActionnables)
|
154 |
|
155 |
-
|
156 |
-
const rawDialogue = await predict([
|
157 |
-
...basePrompt,
|
158 |
-
`As a game master, what should you say next? (Only reply with 2 sentences, please).\nANSWER:`
|
159 |
-
].join(" "))
|
160 |
console.log(`rawDialogue: `, rawDialogue)
|
161 |
|
162 |
if (!rawDialogue) {
|
163 |
throw new Error("failed to generate the dialogue")
|
164 |
}
|
165 |
-
const newDialogue = `${rawDialogue
|
166 |
if (!newDialogue) {
|
167 |
throw new Error("failed to parse the dialogue")
|
168 |
}
|
|
|
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()
|
|
|
81 |
|
82 |
const handleUserAction = async (actionnable: string) => {
|
83 |
console.log("user actionnable:", actionnable)
|
84 |
+
|
85 |
+
setLoading(true)
|
86 |
+
|
87 |
// TODO: ask Llama2 what to do about it
|
88 |
// we need a frame and some actionnables,
|
89 |
// perhaps even some music or sound effects
|
90 |
|
91 |
await startTransition(async () => {
|
|
|
|
|
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 |
}
|
|
|
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 |
}
|
src/app/predict.ts
CHANGED
@@ -24,6 +24,7 @@ export async function predict(inputs: string) {
|
|
24 |
if (
|
25 |
instructions.includes("</s>") ||
|
26 |
instructions.includes("<s>") ||
|
|
|
27 |
instructions.includes("<|end|>") ||
|
28 |
instructions.includes("<|assistant|>")
|
29 |
) {
|
@@ -40,6 +41,7 @@ export async function predict(inputs: string) {
|
|
40 |
.replaceAll("<|end|>", "")
|
41 |
.replaceAll("<s>", "")
|
42 |
.replaceAll("</s>", "")
|
|
|
43 |
.replaceAll("<|assistant|>", "")
|
44 |
.replaceAll('""', '"')
|
45 |
)
|
|
|
24 |
if (
|
25 |
instructions.includes("</s>") ||
|
26 |
instructions.includes("<s>") ||
|
27 |
+
instructions.includes("</SYS>") ||
|
28 |
instructions.includes("<|end|>") ||
|
29 |
instructions.includes("<|assistant|>")
|
30 |
) {
|
|
|
41 |
.replaceAll("<|end|>", "")
|
42 |
.replaceAll("<s>", "")
|
43 |
.replaceAll("</s>", "")
|
44 |
+
.replaceAll("</SYS>", "")
|
45 |
.replaceAll("<|assistant|>", "")
|
46 |
.replaceAll('""', '"')
|
47 |
)
|
src/app/prompts.ts
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Game } from "./games/types"
|
2 |
+
|
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 = [
|
13 |
+
`[PROMPT] Player is currently in "${currentPrompt}". Player clicked on the "${actionnable}".`
|
14 |
+
]
|
15 |
+
|
16 |
+
const baseSituationPromptIfWeHaveHistory = initialPrompt !== currentPrompt
|
17 |
+
? ` 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.
|
18 |
+
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}".`
|
19 |
+
: ""
|
20 |
+
|
21 |
+
const situationSystemPrompt = [
|
22 |
+
`[INST] <<SYS>>
|
23 |
+
You are the AI game master of a role video game.${baseSituationPromptIfWeHaveHistory}
|
24 |
+
You are going to receive new information about the current whereabouts of the player.
|
25 |
+
Please describe 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).
|
26 |
+
<</SYS>>`,
|
27 |
+
]
|
28 |
+
|
29 |
+
const situationPrompt = [
|
30 |
+
...situationSystemPrompt,
|
31 |
+
...userSituationPrompt,
|
32 |
+
].join(" ")
|
33 |
+
|
34 |
+
const actionnablesSystemPrompt = [
|
35 |
+
`[INST] <<SYS>>
|
36 |
+
You are an API endpoint that can return a list of objects thare are in a scene.
|
37 |
+
You must list basic name of things (eg. "parrot", "chest", "spaceship", "glass", "door", "person", "window", "light", "knob", "button" <etc styleName=""></etc>
|
38 |
+
The answer must be a JSON array, ie. a list of quoted strings.
|
39 |
+
<</SYS>>`,
|
40 |
+
]
|
41 |
+
|
42 |
+
const actionnablesPrompt = [
|
43 |
+
...actionnablesSystemPrompt,
|
44 |
+
currentPrompt
|
45 |
+
].join(" ")
|
46 |
+
|
47 |
+
const baseDialoguePromptIfWeHaveHistory = initialPrompt !== currentPrompt
|
48 |
+
? `for your information, the initial game panel and scene was: "${initialPrompt}".`
|
49 |
+
: ""
|
50 |
+
|
51 |
+
const dialogueSystemPrompt = [
|
52 |
+
`[INST] <<SYS>>
|
53 |
+
You are the AI game master of a role video game.
|
54 |
+
You are going to receive new information about the current whereabouts and action of the player.
|
55 |
+
${baseDialoguePromptIfWeHaveHistory}
|
56 |
+
You must imagine a funny response to speak in reaction to what the player did, like in some old point and click video games.
|
57 |
+
Please limit yourself to only a 1 or 2 sentences, please.
|
58 |
+
<</SYS>>`
|
59 |
+
]
|
60 |
+
|
61 |
+
const dialoguePrompt = [
|
62 |
+
...dialogueSystemPrompt,
|
63 |
+
...userSituationPrompt,
|
64 |
+
].join(" ")
|
65 |
+
|
66 |
+
const prompts = {
|
67 |
+
initialPrompt,
|
68 |
+
currentPrompt,
|
69 |
+
userSituationPrompt,
|
70 |
+
baseSituationPromptIfWeHaveHistory,
|
71 |
+
situationSystemPrompt,
|
72 |
+
situationPrompt,
|
73 |
+
actionnablesSystemPrompt,
|
74 |
+
actionnablesPrompt,
|
75 |
+
baseDialoguePromptIfWeHaveHistory,
|
76 |
+
dialogueSystemPrompt,
|
77 |
+
dialoguePrompt,
|
78 |
+
}
|
79 |
+
|
80 |
+
return prompts
|
81 |
+
}
|
82 |
+
|
83 |
+
|
src/components/business/image-renderer.tsx
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
import { useEffect, useRef, useState } from "react"
|
2 |
|
3 |
import { ImageSegment, RenderedScene } from "@/app/types"
|
|
|
4 |
|
5 |
export const ImageRenderer = ({
|
6 |
rendered: {
|
@@ -21,6 +22,7 @@ export const ImageRenderer = ({
|
|
21 |
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
22 |
const contextRef = useRef<CanvasRenderingContext2D | null>(null)
|
23 |
const [actionnable, setActionnable] = useState<string>("")
|
|
|
24 |
|
25 |
useEffect(() => {
|
26 |
if (maskBase64) {
|
@@ -86,7 +88,7 @@ export const ImageRenderer = ({
|
|
86 |
if(distance < minDistance) {
|
87 |
minDistance = distance;
|
88 |
closestSegment = segment;
|
89 |
-
console.log(`${distance} -> ${segment.label}: score = ${segment.score}`)
|
90 |
}
|
91 |
});
|
92 |
|
@@ -127,9 +129,36 @@ export const ImageRenderer = ({
|
|
127 |
}
|
128 |
};
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
if (!assetUrl) {
|
131 |
return <div className="flex w-full h-screen items-center justify-center text-center">
|
132 |
-
<
|
|
|
|
|
|
|
133 |
</div>
|
134 |
}
|
135 |
|
|
|
1 |
import { useEffect, useRef, useState } from "react"
|
2 |
|
3 |
import { ImageSegment, RenderedScene } from "@/app/types"
|
4 |
+
import { ProgressBar } from "../misc/progress"
|
5 |
|
6 |
export const ImageRenderer = ({
|
7 |
rendered: {
|
|
|
22 |
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
23 |
const contextRef = useRef<CanvasRenderingContext2D | null>(null)
|
24 |
const [actionnable, setActionnable] = useState<string>("")
|
25 |
+
const [progressPercent, setProcessPercent] = useState(0)
|
26 |
|
27 |
useEffect(() => {
|
28 |
if (maskBase64) {
|
|
|
88 |
if(distance < minDistance) {
|
89 |
minDistance = distance;
|
90 |
closestSegment = segment;
|
91 |
+
// console.log(`${distance} -> ${segment.label}: score = ${segment.score}`)
|
92 |
}
|
93 |
});
|
94 |
|
|
|
129 |
}
|
130 |
};
|
131 |
|
132 |
+
useEffect(() => {
|
133 |
+
let progress = 0
|
134 |
+
|
135 |
+
// note: when everything is fine, it takes about 45 seconds to render a new scene
|
136 |
+
|
137 |
+
const computeProgress = async () => {
|
138 |
+
console.log("'computing progress")
|
139 |
+
if (!isLoading && assetUrl) {
|
140 |
+
console.log("Finished loading!")
|
141 |
+
setProcessPercent(100)
|
142 |
+
return
|
143 |
+
}
|
144 |
+
|
145 |
+
console.log("still loading..")
|
146 |
+
|
147 |
+
setTimeout(() => {
|
148 |
+
setProcessPercent(progress++)
|
149 |
+
}, 1000)
|
150 |
+
|
151 |
+
}
|
152 |
+
|
153 |
+
computeProgress()
|
154 |
+
}, [isLoading, assetUrl])
|
155 |
+
|
156 |
if (!assetUrl) {
|
157 |
return <div className="flex w-full h-screen items-center justify-center text-center">
|
158 |
+
<ProgressBar
|
159 |
+
text="⌛"
|
160 |
+
progressPercentage={progressPercent}
|
161 |
+
/>
|
162 |
</div>
|
163 |
}
|
164 |
|
src/components/misc/progress.tsx
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import { CircularProgressbar } from "react-circular-progressbar"
|
4 |
+
import "react-circular-progressbar/dist/styles.css"
|
5 |
+
|
6 |
+
export function ProgressBar ({
|
7 |
+
className,
|
8 |
+
progressPercentage,
|
9 |
+
text
|
10 |
+
}: {
|
11 |
+
className?: string
|
12 |
+
progressPercentage?: number
|
13 |
+
text?: string
|
14 |
+
}) {
|
15 |
+
return (
|
16 |
+
<div className={className}>
|
17 |
+
<CircularProgressbar
|
18 |
+
// doc: https://www.npmjs.com/package/react-circular-progressbar
|
19 |
+
|
20 |
+
value={progressPercentage || 0}
|
21 |
+
|
22 |
+
// Text to display inside progressbar. Default: ''.
|
23 |
+
text={text || ""}
|
24 |
+
|
25 |
+
// Width of circular line relative to total width of component, a value from 0-100. Default: 8.
|
26 |
+
strokeWidth={8}
|
27 |
+
|
28 |
+
/*
|
29 |
+
// As a convenience, you can use buildStyles to configure the most common style changes:
|
30 |
+
|
31 |
+
styles={buildStyles({
|
32 |
+
// Rotation of path and trail, in number of turns (0-1)
|
33 |
+
rotation: 0.25,
|
34 |
+
|
35 |
+
// Whether to use rounded or flat corners on the ends - can use 'butt' or 'round'
|
36 |
+
strokeLinecap: 'butt',
|
37 |
+
|
38 |
+
// Text size
|
39 |
+
textSize: '16px',
|
40 |
+
|
41 |
+
// How long animation takes to go from one percentage to another, in seconds
|
42 |
+
pathTransitionDuration: 0.5,
|
43 |
+
|
44 |
+
// Can specify path transition in more detail, or remove it entirely
|
45 |
+
// pathTransition: 'none',
|
46 |
+
|
47 |
+
// Colors
|
48 |
+
pathColor: `rgba(62, 152, 199, ${percentage / 100})`,
|
49 |
+
textColor: '#f88',
|
50 |
+
trailColor: '#d6d6d6',
|
51 |
+
backgroundColor: '#3e98c7',
|
52 |
+
})}
|
53 |
+
*/
|
54 |
+
/>
|
55 |
+
</div>
|
56 |
+
)
|
57 |
+
}
|