Initial commit

This commit is contained in:
thecookingsenpai 2023-12-25 13:25:43 +01:00
commit cc7498a96a
11 changed files with 618 additions and 0 deletions

23
.cleanthat/cleanthat.yaml Normal file
View File

@ -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"

26
.cleanthat/spotless.yaml Normal file
View File

@ -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"

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
package-lock.json
node_modules
.env
output.txt

52
README.md Normal file
View File

@ -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

BIN
assets/gui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

66
index.html Normal file
View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
<link href="./styles.css" rel="stylesheet">
<title>AutoGPT GUI</title>
</head>
<body>
<h3 class="centered expand">AutoGPT Graphical User Interface</h3>
<h5 class="small centered expand">AutoGPT created by Torantulino - GUI created by TheCookingSenpai</h5>
<div class="centered">
<div class="card tilt-top" id="settings">
<div class="oneliner">
<h4>Choose your AI personality (e.g. an AI that can write essays)</h4>
<h5 class="sameline">Your AI is: </h5>
<input class="sameline wide" type="text" id="zone_personality">
<h5 class="sameline"> And is named: </h5>
<input class="sameline" type="text" id="zone_name">
</div>
<div class="halfcard">
<h4>Define up to 5 goals for your AI</h4>
<div class="oneliner">
<h5 class="sameline">Goal 1</h5>
<input class="sameline" type="text" id="zone_goal_1">
<h5 class="sameline">Goal 2</h5>
<input class="sameline" type="text" id="zone_goal_2">
</div>
<div class="oneliner">
<h5 class="sameline">Goal 3</h5>
<input class="sameline" type="text" id="zone_goal_3">
<h5 class="sameline">Goal 4</h5>
<input class="sameline" type="text" id="zone_goal_4">
</div>
<div class="oneliner">
<h5 class="sameline">Goal 5</h5>
<input class="sameline" type="text" id="zone_goal_5">
</div>
</div>
<br>
<div class="oneliner">
<input class="sameline" type="checkbox" id="cfg_continuous" unchecked>Contiuous Mode</input>
<input class="sameline" type="checkbox" id="cfg_debug" unchecked>Debug Mode</input>
<input class="sameline" type="checkbox" id="cfg_speak" unchecked>Speak Mode</input>
<input class="sameline" type="checkbox" id="cfg_save" unchecked>Save output to file</input>
</div>
<br>
<div class="hidden red" id="zone_error"></div>
<button class="centered" id="cmd_execute">Go!</button>
<br>
</div>
<div class="output_space card tilt-top" id="output">
<h4>Output</h4>
<div class="output_space scrollable output_text" id="zone_output"></div>
</div>
<button class="centered hidden" id="cmd_stop">Stop</button>
</div>
<!-- You can also require other files to run in this process -->
<script src="./script.js"></script>
</body>
</html>

40
main.js Normal file
View File

@ -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()
})

22
package.json Normal file
View File

@ -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"
}
}

173
script.js Normal file
View File

@ -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 += '<br>'
}
// Try to detect new lines
if (data.includes('\n')) {
zone_output.innerHTML += '<br>|>|> '
}
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 += '<br><span class"red">' + data + '</span>'
});
child_autogpt.on('close', (code) => {
console.log(`child process exited with code ${code}`);
zone_output.innerHTML += '<br><p class"red">child process exited with code ' + code + '</p>'
cmd_stop.classList.add('hidden')
});
}
(async () => {
await init()
}) ();

212
styles.css Normal file
View File

@ -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;
}
}