commit cc7498a96a7157242e6678ffa9c7e68146cde96a Author: thecookingsenpai Date: Mon Dec 25 13:25:43 2023 +0100 Initial commit diff --git a/.cleanthat/cleanthat.yaml b/.cleanthat/cleanthat.yaml new file mode 100644 index 0000000..e7435cd --- /dev/null +++ b/.cleanthat/cleanthat.yaml @@ -0,0 +1,23 @@ +syntax_version: "2023-01-09" +meta: + labels: + - "cleanthat" + refs: + protected_patterns: + - "refs/heads/develop" + - "refs/heads/main" + - "refs/heads/master" + full_clean_on_configuration_change: false + can_edit_not_protected_branches: true +source_code: + encoding: "UTF-8" + line_ending: "GIT" +engines: +- engine: "spotless" + skip: false + source_code: {} + steps: + - id: "spotless" + skip: false + parameters: + configuration: "repository:/.cleanthat/spotless.yaml" diff --git a/.cleanthat/spotless.yaml b/.cleanthat/spotless.yaml new file mode 100644 index 0000000..8fa9c0a --- /dev/null +++ b/.cleanthat/spotless.yaml @@ -0,0 +1,26 @@ +syntax_version: "2023-01-09" +encoding: "UTF-8" +git: + core_eol: "native" +line_ending: "GIT_ATTRIBUTES" +formatters: +- format: "json" + steps: + - id: "jackson" + skip: false + parameters: + features: + ORDER_MAP_ENTRIES_BY_KEYS: true + yaml_features: + QUOTE_FIELD_NAMES: false +- format: "markdown" + steps: + - id: "flexmark" + skip: false + parameters: + version: "0.62.2" + - id: "freshmark" + skip: false + parameters: + properties: + k1: "v1" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9cc178a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +node_modules +.env +output.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e8d0a2d --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# AutoGPT GUI + +WARNING: Currently discontinued, feel free to fork and work on this version but don't lean on it for production + +## A graphical user interface to AutoGPT + +![image](https://user-images.githubusercontent.com/67682496/231631881-72ad9cc9-56d7-447c-bbb5-5fa407897f0a.png) + + +### Status + +*Alpha has been tested with simple tasks, remember it will probably contains errors and please open issues about them* + +*NOTE: Currently only continuous mode is supported* + +***Current Version:*** Alpha Version (13 April 2023) + +- [x] Code architecture definition +- [x] All needed elements are in GUI +- [x] Defining the best way to integrate autogpt +- [x] Actual integeration of autogpt +- [x] Alpha Version Release +- [ ] Ability to work in non continuous mode +- [ ] Debug of Alpha (issues are welcomed!) +- [ ] Beta Version Release + +### Usage + + git clone https://github.com/thecookingsenpai/autogpt-gui + cd autogpt-gui + npm install + +Then, place autogpt-gui in your autogpt folder (e.g. AutoGPT/autogpt_gui) + +Finally, in your autogpt folder: + + cd autogpt-gui + npm start + +**Important:** please take a moment to read [autogpt instructions](https://github.com/Torantulino/Auto-GPT#usage) to avoid risks and to learn the meaning of the various options. + +### Credits + +The original AutoGPT is by Torantulino and can be found [HERE](https://github.com/Torantulino/Auto-GPT). + +All the credits included in the original AutoGPT are valid for this project as long as the single components are used. + +This project is by TheCookingSenpai. + +### License + +Distributed under the CC-BY-NC 4.0 License diff --git a/assets/gui.png b/assets/gui.png new file mode 100644 index 0000000..431c622 Binary files /dev/null and b/assets/gui.png differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..56db820 Binary files /dev/null and b/assets/icon.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..9160568 --- /dev/null +++ b/index.html @@ -0,0 +1,66 @@ + + + + + + + + + AutoGPT GUI + + + +

AutoGPT Graphical User Interface

+
AutoGPT created by Torantulino - GUI created by TheCookingSenpai
+
+
+
+

Choose your AI personality (e.g. an AI that can write essays)

+
Your AI is:
+ +
And is named:
+ +
+
+

Define up to 5 goals for your AI

+
+
Goal 1
+ +
Goal 2
+ +
+
+
Goal 3
+ +
Goal 4
+ +
+
+
Goal 5
+ +
+
+
+
+ Contiuous Mode + Debug Mode + Speak Mode + Save output to file +
+
+ + +
+
+
+

Output

+
+
+ +
+ + + + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..07bde1d --- /dev/null +++ b/main.js @@ -0,0 +1,40 @@ +// Modules to control application life and create native browser window +const {app, BrowserWindow, screen} = require('electron') +const path = require('path') +var width; +var height; + +function createWindow () { + let sizes = screen.getPrimaryDisplay().workAreaSize + width = sizes.width + height = sizes.height + // Create the browser window. + const mainWindow = new BrowserWindow({ + icon: path.join(__dirname, 'assets/icon.png'), + width: width, + height: height, + webPreferences: { + // Enabling nodejs + nodeIntegration: true, + contextIsolation: false + } + }) + + // and loading the index.html of the app. + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed +app.on('window-all-closed', function () { + app.quit() +}) \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..890607b --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "electron-quick-start", + "version": "1.0.0", + "description": "A minimal Electron application", + "main": "main.js", + "scripts": { + "start": "electron ." + }, + "repository": "https://github.com/electron/electron-quick-start", + "keywords": [ + "Electron", + "quick", + "start", + "tutorial", + "demo" + ], + "author": "GitHub", + "license": "CC0-1.0", + "devDependencies": { + "electron": "^23.2.1" + } +} diff --git a/script.js b/script.js new file mode 100644 index 0000000..383b27e --- /dev/null +++ b/script.js @@ -0,0 +1,173 @@ +const fs = require('fs'); +const path = require('path') +const { spawn } = require('child_process'); +const { error } = require('console'); +var child_autogpt = null +var first_input = false +let save_output = false + + +// ANCHOR Getting GUI elements needed +// Actions +const cmd_execute = document.getElementById('cmd_execute') +const cmd_stop = document.getElementById('cmd_stop') +// Configurations +const cfg_debug = document.getElementById('cfg_debug') +const cfg_continuous = document.getElementById('cfg_continuous') +const cfg_speak = document.getElementById('cfg_speak') +const cfg_save = document.getElementById('cfg_save') +// Utilities +const util_installDeps = document.getElementById('util_installDeps') +// Zones +const zone_personality = document.getElementById('zone_personality') +const zone_name = document.getElementById('zone_name') +const zone_output = document.getElementById('zone_output') +const zone_error = document.getElementById('zone_error') + +// Variables +var is_running = false + +// NOTE Initial configuration +async function init() { + // Setting up listeners + cmd_execute.addEventListener('click', async () => { + console.log("Execute button clicked") + if (is_running) return // Avoid multiple executions + // Executing autogpt on click on the Go button + console.log('Executing') + zone_output.innerHTML = '' + let args = await get_args_from_gui() + console.log(args) + is_running = true + await execute_autogpt(args) + is_running = false + }); + + cmd_stop.addEventListener('click', async () => { + console.log("Stop button clicked") + if (child_autogpt) { + child_autogpt.kill() + cmd_stop.classList.add('disabled') + zone_output.scrollTop = zone_output.scrollHeight + } + }); +} + +// NOTE Gives back the arguments from the GUI +async function get_args_from_gui() { + // Configuration + let _args = { + name: zone_name.value, + personality: zone_personality.value, + goals: [], + debug: cfg_debug.checked, + continuous: cfg_continuous.checked, + speak: cfg_speak.checked, + save: cfg_save.checked + } + // Fetching goals + for (let i = 1; i <= 5; i++) { + let goal = document.getElementById(`zone_goal_${i}`).value + _args.goals.push(goal) + } + return _args +} + +async function execute_autogpt(args) { + if (!zone_error.classList.contains('hidden')) { + zone_error.classList.add('hidden') + } + zone_error.innerHTML = '' + // Sanity check + if (args.goals[0] == '') { + if (zone_error.classList.contains('hidden')) zone_error.classList.remove('hidden') + zone_error.innerHTML = 'You need to specify at least one goal' + return + } + if (args.personality == '') { + if (zone_error.classList.contains('hidden')) zone_error.classList.remove('hidden') + zone_error.innerHTML = 'You need to specify a personality' + return + } + if (args.name == '') { + args.name = 'Autogpt' + } + // TODO write the settings to ai_settings.yaml + let settings = "ai_goals: \n" + for (let i = 0; i < args.goals.length; i++) { + settings += `- ${args.goals[i]}\n` + } + settings += "ai_name: " + args.name + "\n" + settings += "ai_role: " + args.personality + "\n" + fs.writeFileSync('../ai_settings.yaml', settings) + // Define the arguments + let additionals = [] + if (args.debug) { + additionals.push('--debug') + } + if (args.continuous) { + additionals.push('--continuous') + } + if (args.speak) { + additionals.push('--speak') + } + if (args.save) { + save_output = true + } + // REVIEW Run ../scripts/main.py and redirect all the output to a variable live in the GUI + // Set up the command + let cmd = 'python' + let args_cmd = ['scripts/main.py'] + // Pushing the arguments + args_cmd.push(...additionals) + // Executing + child_autogpt = spawn(cmd, args_cmd, {cwd: path.join(__dirname, '..')}) + if (child_autogpt.pid) { + console.log('Child process started with PID ${child_autogpt.pid}') + cmd_stop.classList.remove('hidden') + } + // INFO Setting up listeners + child_autogpt.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); + if (data.includes('Thinking...')) { + if (zone_output.innerHTML.includes('Thinking...') ){ + data = "." + } + } + // Go to the next line if the last character is thinking + if (data.includes('Thinking...')) { + zone_output.innerHTML += '
' + } + // Try to detect new lines + if (data.includes('\n')) { + zone_output.innerHTML += '
|>|> ' + } + zone_output.innerHTML += data + // Scroll to the bottom + zone_output.scrollTop = zone_output.scrollHeight + // NOTE if specified, save the output to a file + if (save_output) { + fs.appendFileSync(path.join(__dirname, 'output.txt'), data) + } + // NOTE If the first input is required, send a 'y' to the child process to read from ai_settings.yaml + if (data.includes('(y/n)')) { + if (!first_input) { + first_input = true + child_autogpt.stdin.write('y\n') + } + } + }); + child_autogpt.stderr.on('data', (data) => { + console.error(`stderr: ${data}`); + zone_output.innerHTML += '
' + data + '' + }); + child_autogpt.on('close', (code) => { + console.log(`child process exited with code ${code}`); + zone_output.innerHTML += '

child process exited with code ' + code + '

' + cmd_stop.classList.add('hidden') + }); +} + +(async () => { + await init() +}) (); \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..0c43565 --- /dev/null +++ b/styles.css @@ -0,0 +1,212 @@ +/* styles.css */ +body { + background-color: #000000; + color: #02cc53; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 21px; + line-height: 1.42857143; + margin: 0; + align-items: center; + justify-content: center; + text-align: center; +} + +input { + border-radius: 20px; + font-size: 18px; +} + +button { + background-color: #000000; + color: #02cc53; + border: 1px solid #02cc53; + border-radius: 15px; + font-size: 24px; + padding: 10px; + padding-left: 20px; + padding-right: 20px; +} + +button:hover +{ + background-color: #02cc53; + color: #000000; +} +/* Element Styles */ + +.centered { + align-items: center; + text-align: center; +} + +.rounded { + border-radius: 15px; +} + +.card { + border: 1px solid #02cc53; + border-radius: 15px; + padding: 5px; + margin: 25px; + margin-bottom: 10px !important; + box-shadow: 0 0 10px #02cc53; + width: auto; +} + + +.halfcard { + border: 1px solid #000; + border-radius: 15px; + padding: 5px; + box-shadow: 0 0 10px #000; + width: 70%; + margin: auto; +} + + +.oneliner { + white-space: nowrap; + overflow-x: auto; +} + +.sameline { + display: inline-block; + margin-left: 20px; +} + +.wide { + width: 50%; +} + +.output_space { + height: fit-content !important; + border-radius: 5px !important; +} + +.output_text { + border: 1px solid #02cc53 !important; +} + +.hidden { + display: none; +} + +.scrollable { + overflow-y: scroll !important; + height: 75% !important; +} + +.red { + color: #ff0000 !important; +} + +.small { + font-size: 10px !important; +} +/* Animations */ +/* ---------------------------------------------- + * Generated by Animista on 2023-4-11 20:26:10 + * Licensed under FreeBSD License. + * See http://animista.net/license for more info. + * w: http://animista.net, t: @cssanimista + * ---------------------------------------------- */ + +.tilt-top { + -webkit-animation: tilt-in-top-1 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation: tilt-in-top-1 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; +} + +.pop-up { + -webkit-animation: text-pop-up-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation: text-pop-up-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; +} + +.expand { + -webkit-animation: tracking-in-expand 0.7s cubic-bezier(0.215, 0.610, 0.355, 1.000) both 0.5s; + animation: tracking-in-expand 0.7s cubic-bezier(0.215, 0.610, 0.355, 1.000) both 0.5s; +} + +@-webkit-keyframes tracking-in-expand { + 0% { + letter-spacing: -0.5em; + opacity: 0; + } + 40% { + opacity: 0.6; + } + 100% { + opacity: 1; + } + } + @keyframes tracking-in-expand { + 0% { + letter-spacing: -0.5em; + opacity: 0; + } + 40% { + opacity: 0.6; + } + 100% { + opacity: 1; + } + } + + +@-webkit-keyframes text-pop-up-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + text-shadow: none; + } + 100% { + -webkit-transform: translateY(-50px); + transform: translateY(-50px); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + text-shadow: 0 1px 0 #cccccc, 0 2px 0 #cccccc, 0 3px 0 #cccccc, 0 4px 0 #cccccc, 0 5px 0 #cccccc, 0 6px 0 #cccccc, 0 7px 0 #cccccc, 0 8px 0 #cccccc, 0 9px 0 #cccccc, 0 50px 30px rgba(0, 0, 0, 0.3); + } + } + @keyframes text-pop-up-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + text-shadow: none; + } + 100% { + -webkit-transform: translateY(-50px); + transform: translateY(-50px); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + text-shadow: 0 1px 0 #cccccc, 0 2px 0 #cccccc, 0 3px 0 #cccccc, 0 4px 0 #cccccc, 0 5px 0 #cccccc, 0 6px 0 #cccccc, 0 7px 0 #cccccc, 0 8px 0 #cccccc, 0 9px 0 #cccccc, 0 50px 30px rgba(0, 0, 0, 0.3); + } + } + +@-webkit-keyframes tilt-in-top-1 { + 0% { + -webkit-transform: rotateY(30deg) translateY(-300px) skewY(-30deg); + transform: rotateY(30deg) translateY(-300px) skewY(-30deg); + opacity: 0; + } + 100% { + -webkit-transform: rotateY(0deg) translateY(0) skewY(0deg); + transform: rotateY(0deg) translateY(0) skewY(0deg); + opacity: 1; + } + } + @keyframes tilt-in-top-1 { + 0% { + -webkit-transform: rotateY(30deg) translateY(-300px) skewY(-30deg); + transform: rotateY(30deg) translateY(-300px) skewY(-30deg); + opacity: 0; + } + 100% { + -webkit-transform: rotateY(0deg) translateY(0) skewY(0deg); + transform: rotateY(0deg) translateY(0) skewY(0deg); + opacity: 1; + } + } + \ No newline at end of file