diff --git a/.env.example b/.env.example index 1e9e3d32..e863ff51 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ RP_PACK_UUID=68a061ba-18fc-4930-a56a-1da78742daa1 RP_MODULE_UUID=ad91326d-3455-4ea2-b12d-9e49591fa1f2 BP_PACK_UUID=eefdf10b-b20b-4580-8515-d6a2c35db762 BP_MODULE_UUID=a684c1d3-ad02-4ddb-9241-cfd132b79621 -GITHUB_ACTION_REPOSITORY=jasonjgardner/minecraft-rtx-rainbow \ No newline at end of file +GITHUB_ACTION_REPOSITORY=jasonjgardner/minecraft-rtx-rainbow +OPENAI_API_KEY= \ No newline at end of file diff --git a/src/functions/chatgpt.ts b/src/functions/chatgpt.ts new file mode 100644 index 00000000..f268a43f --- /dev/null +++ b/src/functions/chatgpt.ts @@ -0,0 +1,66 @@ +import { load } from "https://deno.land/std@0.184.0/dotenv/mod.ts"; +import openai from "npm:openai@^3.2.1"; +import { Image } from "imagescript/mod.ts"; +import type { Axis, WssParams } from "../../typings/types.ts"; +import { convertImage } from "../components/ImagePrinter.ts"; +import assemble from "../components/_assemble.ts"; +import { join } from "path/mod.ts"; + +const { Configuration, OpenAIApi } = openai; + +const env = await load(); +const OPENAI_API_KEY = env.OPENAI_API_KEY || Deno.env.get("OPENAI_API_KEY") || + ""; + +const SYSTEM_PROMPT = "Act as a Minecraft Bedrock add-on creator. " + + "You will be asked to create commands, functions, and structures for a Minecraft Bedrock Edition add-on. " + + "You will provide responses in the form of a Minecraft command. " + + "Reply with the solutions only, no explanations."; +const getRandomPrompt = () => { + const prompts = [ + "Summon a zombie", + "Play a prank on nearby players", + "Teleport a player to a random location", + ]; + + return prompts[Math.floor(Math.random() * prompts.length)]; +}; + +const configuration = new Configuration({ + apiKey: OPENAI_API_KEY, +}); + +const client = new OpenAIApi(configuration); + +export default async function chatgpt( + { parameters, queueCommandRequest }: WssParams, +) { + const prompt = parameters.get("prompt") ?? getRandomPrompt(); + + const completion = await client.createChatCompletion({ + model: "gpt-3.5-turbo", + messages: [ + { role: "system", content: SYSTEM_PROMPT }, + { role: "user", name: "Minecraft", content: prompt }, + ], + temperature: 0.3, + n: 1, + }); + + const completionCommands = + (completion.data.choices[0].message?.content?.split("\n") ?? []).map((c) => + c.replace(/^\//, "").trim() + ).filter((c) => c.length > 0); + + console.group("ChatGPT response"); + console.log(completionCommands); + console.groupEnd(); + + const commands: string[] = []; + + commands.push( + ...completionCommands, + ); + + commands.map((c) => queueCommandRequest(c)); +} diff --git a/src/functions/dalle.ts b/src/functions/dalle.ts new file mode 100644 index 00000000..2908f1d8 --- /dev/null +++ b/src/functions/dalle.ts @@ -0,0 +1,80 @@ +import { load } from "https://deno.land/std@0.184.0/dotenv/mod.ts"; +import openai from "npm:openai@^3.2.1"; +import { Image } from "imagescript/mod.ts"; +import type { Axis, WssParams } from "../../typings/types.ts"; +import { convertImage } from "../components/ImagePrinter.ts"; +import assemble from "../components/_assemble.ts"; +import { join } from "path/mod.ts"; + +const { Configuration, OpenAIApi } = openai; + +const env = await load(); +const OPENAI_API_KEY = env.OPENAI_API_KEY || Deno.env.get("OPENAI_API_KEY") || + ""; + +const outputDir = join(Deno.cwd(), "out"); + +const getRandomPrompt = () => { + const prompts = [ + "A unicorn in space", + "A dog in a hat", + ]; + + return prompts[Math.floor(Math.random() * prompts.length)]; +}; + +const configuration = new Configuration({ + apiKey: OPENAI_API_KEY, +}); +const client = new OpenAIApi(configuration); + +function getBlockLibrary(material: string, exclude?: string[]) { + return assemble(exclude).filter((b) => b.behaviorId.includes(material)); +} + +export default async function dalle( + { parameters, queueCommandRequest, formatPosition }: WssParams, +) { + const axis = parameters.get("axis") ?? "y"; + const material = parameters.get("material") ?? "plastic"; + const exclude = (parameters.get("exclude") ?? "").split(","); + const position = parameters.get("position") ?? "0 0 0"; + const useAbsolutePosition = parameters.get("absolute") === "true"; + const [x, y, z] = position.split(" ").map((v) => parseInt(v, 10)); + const prompt = parameters.get("prompt") ?? getRandomPrompt(); + const response = await client.createImage({ + prompt, + n: 1, + size: "256x256", + }); + + const imageUrl: string = response.data.data[0].url ?? ""; + const imageRes = await fetch(imageUrl); + const imageData = await imageRes.arrayBuffer(); + const decoded = await Image.decode(imageData); + + try { + await Deno.writeFile( + join(outputDir, prompt.trim().replace(/[\s:\/\\#\$\?]+/gi, "-") + ".png"), + new Uint8Array(imageData), + ); + } catch (err) { + console.warn(`Failed saving image from DALL-E: ${err}`); + } + + const resized = decoded.resize(128, 128); + + const commands: string[] = []; + + commands.push( + ...convertImage( + resized, + getBlockLibrary(material, exclude), + [x, y, z], + axis, + useAbsolutePosition === true, + ), + ); + + commands.map((c) => queueCommandRequest(c)); +} diff --git a/src/versions.json b/src/versions.json index e8178b1b..d1be3797 100644 --- a/src/versions.json +++ b/src/versions.json @@ -1,4 +1,4 @@ { - "RP": "2.3.0", - "BP": "2.3.0" + "RP": "2.3.1", + "BP": "2.3.1" }