-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
391 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
400 + 20 = 420 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
Oops, something went wrong.