Skip to content

Commit

Permalink
docs: new example
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelass committed Mar 31, 2023
1 parent 24c785f commit c7f5d84
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 1 deletion.
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ a try and see where your imagination takes you!
*/
```

Try the interactive [mandebrot-zoom](wtf-moments%2Fmandebrot-zoom)
Try the interactive [mandebrot-zoom](wtf-moments/mandebrot-zoom)

```shell
❯ node generation-005.js -g 5
Expand All @@ -171,6 +171,31 @@ Enter number of iterations (1-1000): 1000

<img src="assets/example-09.png" alt="example-01.png" width="600"/>

Try the interactive [calculator](wtf-moments/calculator)

```shell
❯ node generation-003.js -g 3
Welcome to the CALCULATOR!
Please enter your calculations in the following format: number operator number
Supported operators: +, -, *, /
Example: 2 + 3
To save calculations, type 'save'
To load calculations, type 'load'
To exit, type 'exit'
400 + 20
Result: 420
save
Calculations saved to file!
load
Calculations loaded from file:
400 + 20 = 420
exit
Exiting calculator...
Calculations performed:
400 + 20 = 420

```

## Goal

Our generative process, powered by OpenAI's GPT-3.5 language model, allows you to choose your goal
Expand Down
129 changes: 129 additions & 0 deletions wtf-moments/calculator/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import process from "node:process";
import fs from "node:fs/promises";
import { config } from "dotenv";
import meow from "meow";
import { Configuration, OpenAIApi } from "openai";
import ora from "ora";
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: 5,
},
persona: {
type: "string",
alias: "p",
default: "expert developer, creative, art enthusiast, gamer, visionary",
},
},
});

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}
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"
- VERY IMPORTANT: DO NOT import any new modules or packages
- 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 fx 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: 0.2,
});
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 `generation-${currentGeneration.toString().padStart(3, "0")}.js`;
}
1 change: 1 addition & 0 deletions wtf-moments/calculator/calculations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
400 + 20 = 420
22 changes: 22 additions & 0 deletions wtf-moments/calculator/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 wtf-moments/calculator/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: implement calculator functionality
*/

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

async function output() {
console.log("Welcome to the CALCULATOR!");
console.log("Please enter your calculation in the following format: number operator number");
console.log("Supported operators: +, -, *, /");
console.log("Example: 2 + 3");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("line", (input) => {
const [num1, operator, num2] = input.split(" ");
let result;
switch (operator) {
case "+":
result = Number(num1) + Number(num2);
break;
case "-":
result = Number(num1) - Number(num2);
break;
case "*":
result = Number(num1) * Number(num2);
break;
case "/":
result = Number(num1) / Number(num2);
break;
default:
console.log("Invalid operator");
return;
}
console.log(`Result: ${result}`);
rl.close();
});
}

if (generation < generations) {
try {
await evolve(generation);
} catch (error) {
console.error(error);
}
} else {
await output();
}
69 changes: 69 additions & 0 deletions wtf-moments/calculator/generation-002.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* CHANGELOG:
* Generation 0: implement base script
* Generation 1: implement calculator functionality
* Generation 2: implement support for multiple calculations
*/

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

async function output() {
console.log("Welcome to the CALCULATOR!");
console.log("Please enter your calculations in the following format: number operator number");
console.log("Supported operators: +, -, *, /");
console.log("Example: 2 + 3");
console.log("To exit, type 'exit'");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

let calculations = [];

rl.on("line", (input) => {
if (input === "exit") {
console.log("Exiting calculator...");
rl.close();
return;
}

const [num1, operator, num2] = input.split(" ");
let result;
switch (operator) {
case "+":
result = Number(num1) + Number(num2);
break;
case "-":
result = Number(num1) - Number(num2);
break;
case "*":
result = Number(num1) * Number(num2);
break;
case "/":
result = Number(num1) / Number(num2);
break;
default:
console.log("Invalid operator");
return;
}
calculations.push(`${num1} ${operator} ${num2} = ${result}`);
console.log(`Result: ${result}`);
});

rl.on("close", () => {
console.log("Calculations performed:");
calculations.forEach((calculation) => console.log(calculation));
});
}

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

0 comments on commit c7f5d84

Please sign in to comment.