Skip to content

Commit

Permalink
docs: add todo-app and html canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelass committed Apr 1, 2023
1 parent cd4794c commit 07f49ee
Show file tree
Hide file tree
Showing 24 changed files with 2,912 additions and 0 deletions.
140 changes: 140 additions & 0 deletions examples/html-canvas/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import process from "node:process";
import fs from "node:fs/promises";
import path from "node:path";
import { config } from "dotenv";
import meow from "meow";
import { Configuration, OpenAIApi } from "openai";
import ora from "ora";
import pkg from "./package.json" assert { type: "json" };

config();

const { flags } = meow("", {
importMeta: import.meta,
flags: {
goal: {
type: "string",
alias: "G",
default:
"mandelbrot algorithm that outputs ascii to the console in a 90 columns * 30 rows grid",
},
generations: {
type: "number",
alias: "g",
default: 1,
},
persona: {
type: "string",
alias: "p",
default: "expert node.js developer, creative",
},
temperature: {
type: "number",
alias: "t",
default: 0.2,
},
},
});

const spinner = ora("Working");

const configuration = new Configuration({
apiKey: process.env.OPENAI_SECRET,
});

export const openai = new OpenAIApi(configuration);

const instructions = `
Extend the code but the RULES can NEVER be changed and must be respected AT ALL TIMES.
The code should INCREASE in logic and COMPLEXITY.
It is utterly important that ALL RULES are respected fully. NEVER break RULES
There are EXCEPTIONS which have a higher weight than RULES
There is a GOAL, it must be completed
GOAL: ${flags.goal}
AVAILABLE NPM PACKAGES: ${Object.entries(pkg.dependencies)
.map(([name, version]) => `${name}@${version}`)
.join(", ")}
RULES:
- Pay special attention TO ALL UPPERCASE words
- Pay attention to the GOAL and EXTEND it
- KEEP the existing code, only ADD new code or improve the code you added since "Generation 0"
- increment the generation constant ONCE per generation
- Keep track of changes in the CHANGELOG
- DO NOT use Browser APIs (Node.js only)
- DO NOT use 3d party libraries
- Use Node.js and module syntax (with imports)
- NEVER use "require"
- NEVER explain anything
- VERY IMPORTANT: output the javaScript only (this is the most important rule, the entire answer has to be valid javascript)
`;

const persona = `programmer with the following characteristics: ${flags.persona}`;

export const generations = flags.generations;
const maxTries = 3;
let tries = 0;

export async function evolve(generation, history = [], error) {
if (tries > maxTries) {
spinner.fail("Maximum retries reached");
return;
}
const nextGeneration = generation + 1;
tries++;

try {
const filename = buildFilename(generation);
const code = await fs.readFile(filename, "utf-8");
spinner.start(`Working (${generation})`);
history.push({
role: "user",
content: error
? `
An error occurred: ${error}
in this code:
${code}
Please fix it.
RULES:
- VERY IMPORTANT: output the javaScript only (this is the most important rule, the entire answer has to be valid javascript)
`
: code,
});
const completion = await openai.createChatCompletion({
// model: "gpt-4",
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: `You are a: ${persona} extend or fix my code based on these instructions: ${instructions}`,
},
...history,
],
max_tokens: 2000,
temperature: flags.temperature,
});
spinner.stop();
const { content } = completion.data.choices[0].message;
const nextFilename = buildFilename(nextGeneration);
await fs.writeFile(nextFilename, content);
spinner.text = `Generation ${nextGeneration} created`;
spinner.text = `Spawning ${nextFilename}`;
await import(`./${nextFilename}`);
} catch (error) {
const message = (error.response?.message ?? error.message ?? "unknown error").trim();
spinner.fail(message);
// The AI might increment too often
if (message.startsWith("ENOENT") && generation > 1) {
await evolve(generation - 1);
} else {
spinner.text = `Generation ${nextGeneration} failed`;
await evolve(generation, history, error);
}
}
}

export function buildFilename(currentGeneration) {
return path.join(".", `generation-${currentGeneration.toString().padStart(3, "0")}.js`);
}
22 changes: 22 additions & 0 deletions examples/html-canvas/generation-000.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* CHANGELOG:
* Generation 0: implement base script
*/

import { generations, evolve } from "./base.js";
import readline from "readline";
const generation = 0;

async function output() {
console.log(" 0-0 ");
}

if (generation < generations) {
try {
await evolve(generation);
} catch (error) {
console.error(error);
}
} else {
await output();
}
53 changes: 53 additions & 0 deletions examples/html-canvas/generation-001.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* CHANGELOG:
* Generation 0: implement base script
* Generation 1: add code to create index.html and script.js files
*/

import { generations, evolve } from "./base.js";
import readline from "readline";
import fs from "fs";

const generation = 1;

async function output() {
const indexHtmlContent = `
<!DOCTYPE html>
<html>
<head>
<title>Canvas Experiment</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="./script.js"></script>
</body>
</html>
`;

const scriptJsContent = `
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
// Draw a rectangle
context.fillStyle = "red";
context.fillRect(10, 10, 100, 100);
`;

// Create index.html file
fs.writeFileSync("./index.html", indexHtmlContent);

// Create script.js file
fs.writeFileSync("./script.js", scriptJsContent);

console.log("Files created successfully!");
}

if (generation < generations) {
try {
await evolve(generation);
} catch (error) {
console.error(error);
}
} else {
await output();
}
83 changes: 83 additions & 0 deletions examples/html-canvas/generation-002.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* CHANGELOG:
* Generation 0: implement base script
* Generation 1: add code to create index.html and script.js files
* Generation 2: add code to draw a flower on the canvas
*/

import { generations, evolve } from "./base.js";
import readline from "readline";
import fs from "fs";

const generation = 2;

async function output() {
const indexHtmlContent = `
<!DOCTYPE html>
<html>
<head>
<title>Canvas Experiment</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="./script.js"></script>
</body>
</html>
`;

const scriptJsContent = `
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
// Draw a flower
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 100;
// Draw petals
context.beginPath();
context.moveTo(centerX, centerY - radius);
context.bezierCurveTo(
centerX + radius / 2,
centerY - radius / 2,
centerX + radius / 2,
centerY + radius / 2,
centerX,
centerY + radius
);
context.bezierCurveTo(
centerX - radius / 2,
centerY + radius / 2,
centerX - radius / 2,
centerY - radius / 2,
centerX,
centerY - radius
);
context.fillStyle = "yellow";
context.fill();
// Draw center
context.beginPath();
context.arc(centerX, centerY, radius / 5, 0, 2 * Math.PI);
context.fillStyle = "orange";
context.fill();
`;

// Create index.html file
fs.writeFileSync("./index.html", indexHtmlContent);

// Create script.js file
fs.writeFileSync("./script.js", scriptJsContent);

console.log("Files created successfully!");
}

if (generation < generations) {
try {
await evolve(generation);
} catch (error) {
console.error(error);
}
} else {
await output();
}
Loading

0 comments on commit 07f49ee

Please sign in to comment.