Compare commits

...

28 Commits

Author SHA1 Message Date
045f78d50d Add code blocks and resizable window 2024-03-09 17:23:16 -05:00
ee6f775b5b Restructure GUI folder & modify styles.css 2024-03-09 16:19:47 -05:00
bdf5715868 Add stop button 2024-03-09 15:22:44 -05:00
d2470b2dd6 Update GUI styles.css & increase prompt timeout in GUI & CLI 2024-03-09 13:53:26 -05:00
05e5495fad Update README.md 2024-03-09 12:28:19 -05:00
5298482708 Update workflow 2024-03-09 12:02:42 -05:00
113e413167 Update cli.yml and gui.yml 2024-03-09 11:56:46 -05:00
5bc5fb7cad Bump nodejs version in gui.yml & create cli.yml 2024-03-09 11:46:27 -05:00
9a92b47a02 Retry creating gui.yml 2024-03-09 11:32:33 -05:00
81a8f6b9e3 Move gui.yml to .github/workflows 2024-03-09 11:17:46 -05:00
35309ee2d1 Add gui.yml 2024-03-09 11:14:43 -05:00
445eda821d Include timeout function in GUI 2024-03-09 05:56:54 -05:00
437831aea5 Create dropdown box to select which model to use in the GUI on startup 2024-03-09 05:43:40 -05:00
e5419b0108 Update kuzco-cli to allow choice of model on startup & include a timeout function 2024-03-09 04:50:30 -05:00
424a1b5ad1 Update README.md 2024-03-09 03:59:07 -05:00
1a00e34837 Update package.json 2024-03-09 03:33:54 -05:00
2d9f8649a7 Update README.md 2024-03-09 03:26:06 -05:00
16c1d680cb Typing indicator for GUI 2024-03-09 03:20:24 -05:00
0ab585943f Wait for AI response before letting user send another message in GUI 2024-03-09 03:12:19 -05:00
226f4bf409 Update package.json 2024-03-09 02:57:57 -05:00
4bc3b013bb Restart GUI when we get API key 2024-03-09 02:52:10 -05:00
97402a8b1f Add function to alert user if their API key isnt set and open a popup for user to enter their key 2024-03-09 02:42:30 -05:00
61cf0bd49e move kuzco-cli.js 2024-03-09 02:18:37 -05:00
af39ad7094 Restructure project 2024-03-09 02:17:26 -05:00
fd8bba8199 First GUI version 2024-03-09 02:15:01 -05:00
006ce3a7c4 Add LICENSE 2024-03-09 00:56:37 -05:00
6ab6cea5f9 Merge branch 'master' of https://git.deadzone.lol/Wizzard/kuzco-cli.git 2024-03-09 00:52:15 -05:00
6ede8ca8d8 Change file names 2024-03-09 00:52:07 -05:00
17 changed files with 4324 additions and 19 deletions

51
.github/workflows/cli.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: CLI Build
on: [push, pull_request]
jobs:
build-cli:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies (CLI)
run: cd cli && npm install
- name: Install pkg globally
run: npm install -g pkg
- name: Build CLI executables
run: |
cd cli
pkg kuzco-cli.js --targets node18-linux-x64,node18-macos-x64,node18-win-x64
- name: Rename executables
run: |
cd cli
mv kuzco-cli-linux kuzco-cli-linux-x64
mv kuzco-cli-macos kuzco-cli-macos-x64
mv kuzco-cli-win.exe kuzco-cli-win-x64.exe
- name: Upload Linux Executable
uses: actions/upload-artifact@v4
with:
name: kuzco-cli-linux-x64
path: cli/kuzco-cli-linux-x64
- name: Upload macOS Executable
uses: actions/upload-artifact@v4
with:
name: kuzco-cli-macos-x64
path: cli/kuzco-cli-macos-x64
- name: Upload Windows Executable
uses: actions/upload-artifact@v4
with:
name: kuzco-cli-win-x64.exe
path: cli/kuzco-cli-win-x64.exe

75
.github/workflows/gui.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
name: GUI Build
on: [push, pull_request]
jobs:
build-linux-gui:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies (GUI)
run: cd gui && npm install
- name: Build Linux Application
run: cd gui && npm run dist-linux
- name: Archive Linux production build
run: |
cd gui/dist
tar czf linux-unpacked.tar.gz linux-unpacked
- name: Upload Linux AppImage
uses: actions/upload-artifact@v4
with:
name: KuzcoChat-Linux-Appimage
path: gui/dist/*.AppImage
- name: Upload Linux DEB
uses: actions/upload-artifact@v4
with:
name: KuzcoChat-DEB
path: gui/dist/*.deb
- name: Upload Linux Unpacked Archive
uses: actions/upload-artifact@v4
with:
name: KuzcoChat-Linux-Unpacked
path: gui/dist/linux-unpacked.tar.gz
build-windows-gui:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies (GUI)
run: cd gui && npm install
- name: Build Windows Application
run: cd gui && npm run dist-win
- name: Zip Windows production build
run: |
Compress-Archive -Path gui/dist/win-unpacked/* -DestinationPath gui/dist/win-unpacked.zip
- name: Upload Windows Executable
uses: actions/upload-artifact@v4
with:
name: KuzcoChat-Windows-EXE
path: gui/dist/*.exe
- name: Upload Windows Unpacked Archive
uses: actions/upload-artifact@v4
with:
name: KuzcoChat-Windows-Unpacked
path: gui/dist/win-unpacked.zip

6
.gitignore vendored
View File

@@ -1,4 +1,4 @@
node_modules/ node_modules/
main-linux gui/dist/
main-macos *.exe
*.exe

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 bandaholics.cash
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -19,7 +19,7 @@ Welcome to Kuzco CLI, a sleek Node.js-based interface for interacting with Kuzco
1. Clone this repository and navigate into the directory: 1. Clone this repository and navigate into the directory:
```bash ```bash
git clone https://git.deadzone.lol/Wizzard/kuzco-cli.git git clone https://git.deadzone.lol/Wizzard/kuzco-cli.git
cd kuzco-cli cd kuzco-cli/cli
``` ```
2. Install the necessary Node.js dependencies: 2. Install the necessary Node.js dependencies:
@@ -27,6 +27,16 @@ Welcome to Kuzco CLI, a sleek Node.js-based interface for interacting with Kuzco
npm install npm install
``` ```
3. Installing the GUI:
```bash
cd kuzco-cli/gui
```
4. Install the necessary Node.js dependencies:
```bash
npm install
```
### Configuration ### Configuration
On first run, you'll be prompted to enter your API key for accessing Kuzco's network. This is stored securely and ensures your interactions are authenticated. On first run, you'll be prompted to enter your API key for accessing Kuzco's network. This is stored securely and ensures your interactions are authenticated.
@@ -35,17 +45,26 @@ On first run, you'll be prompted to enter your API key for accessing Kuzco's net
Run Kuzco CLI with: Run Kuzco CLI with:
```bash ```bash
node main.js cd kuzco-cli/cli
node kuzco-cli.js
```
Run Kuzco GUI with:
```bash
cd kuzco-cli/gui
electron19 kuzco-gui.js
``` ```
Follow the on-screen prompts to send your AI prompts to the network. Follow the on-screen prompts to send your AI prompts to the network.
## Prebuilt Binaries
You can download prebuilt versions of this application from the [GitHub Actions page](https://github.com/CODJointOps/kuzco-cli/actions).
## Contributing ## Contributing
Your contributions are welcome! Your contributions are welcome!
## License ## License
Kuzco CLI is released under the MIT license. Feel free to use, modify, and distribute it as you see fit. Kuzco CLI is released under the MIT license. Feel free to use, modify, and distribute it as you see fit.
Enjoy harnessing the power of decentralized AI with Kuzco!

View File

@@ -52,9 +52,27 @@ const askQuestion = (query) => {
})); }));
}; };
const fetchWithTimeout = (url, options, timeout = 3000) => {
const timeoutPromise = new Promise((_, reject) => {
const id = setTimeout(() => {
clearTimeout(id);
reject(new Error('Request timed out'));
}, timeout);
});
return Promise.race([
fetch(url, options),
timeoutPromise
]);
};
async function main() { async function main() {
let messages = []; let messages = [];
console.log("Please choose a model: 1 for Mistral, 2 for Llama2");
const modelChoice = prompt('Enter your choice (1 or 2): ');
const model = modelChoice === '2' ? 'llama2' : 'mistral';
while (true) { while (true) {
const user_input = await askQuestion("User: "); const user_input = await askQuestion("User: ");
if (user_input.toLowerCase() === 'exit') { if (user_input.toLowerCase() === 'exit') {
@@ -63,7 +81,7 @@ async function main() {
messages.push({ 'role': 'user', 'content': user_input + '\n' }); messages.push({ 'role': 'user', 'content': user_input + '\n' });
try { try {
const response = await fetch(`${BASE_URL}/chat/completions`, { const response = await fetchWithTimeout(`${BASE_URL}/chat/completions`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${API_KEY}`, 'Authorization': `Bearer ${API_KEY}`,
@@ -71,17 +89,16 @@ async function main() {
}, },
body: JSON.stringify({ body: JSON.stringify({
messages: messages, messages: messages,
model: 'mistral', model: model
stream: false
}) })
}); }, 25000);;
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const data = await response.json(); const data = await response.json();
console.log(`\nKuzco (Mistral):\n\n${data.choices[0].message.content.trim()}\n`); console.log(`\nKuzco (${model}):\n\n${data.choices[0].message.content.trim()}\n`);
} catch (error) { } catch (error) {
console.error(`An error occurred: ${error.message}`); console.error(`An error occurred: ${error.message}`);
} }

View File

@@ -1,11 +1,11 @@
{ {
"name": "kyzco-cli", "name": "kuzco-cli",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "kyzco-cli", "name": "kuzco-cli",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"got": "^14.2.1", "got": "^14.2.1",
@@ -13,7 +13,7 @@
"prompt-sync": "^4.2.0" "prompt-sync": "^4.2.0"
}, },
"bin": { "bin": {
"kyzco-cli": "main.js" "kuzco-cli": "kuzco-cli.js"
} }
}, },
"node_modules/@sindresorhus/is": { "node_modules/@sindresorhus/is": {

View File

@@ -2,10 +2,10 @@
"name": "kuzco-cli", "name": "kuzco-cli",
"version": "1.0.0", "version": "1.0.0",
"description": "A simple cli for kyzco api", "description": "A simple cli for kyzco api",
"main": "main.js", "main": "kuzco-cli.js",
"bin": "main.js", "bin": "kuzco-cli.js",
"scripts": { "scripts": {
"start": "node main.js" "start": "node kuzco-cli.js"
}, },
"pkg": { "pkg": {
"targets": [ "targets": [

222
gui/css/styles.css Normal file
View File

@@ -0,0 +1,222 @@
body {
background-color: #2c3e50;
color: #ecf0f1;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
height: 100vh;
margin: 0;
padding: 20px;
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: #34495e #2c3e50;
}
body, html {
height: 100%;
margin: 0;
}
#app {
display: flex;
flex-direction: column;
height: 100%;
}
#chatHistory {
height: 300px;
flex-grow: 1;
overflow-y: auto;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #34495e;
border-radius: 5px;
}
#sendButton {
padding: 10px 20px;
font-size: 1rem;
color: white;
background-color: #007BFF;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s;
}
#sendButton:hover {
background-color: #0056b3;
}
#sendButton:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
#submitApiKey {
padding: 10px 20px;
font-size: 1rem;
color: white;
background-color: #007BFF;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s;
}
#stopButton {
padding: 10px 20px;
font-size: 1rem;
color: white;
background-color: #c0392b;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s;
}
#stopButton:hover {
background-color: #a93226;
}
#stopButton:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.message {
font-size: 0.9em;
padding: 10px 15px;
margin-bottom: 15px;
padding: 10px;
background-color: #34495e;
border-radius: 5px;
}
.userMessage {
align-self: flex-end;
background-color: #2980b9;
}
.assistantMessage {
align-self: flex-start;
background-color: #16a085;
}
#chatForm {
display: flex;
gap: 10px;
}
#promptInput {
flex-grow: 1;
padding: 10px;
border: 1px solid #34495e;
border-radius: 5px;
color: inherit;
background-color: #2c3e50;
}
#apiKeyInput {
flex-grow: 1;
padding: 10px;
border: 1px solid #34495e;
border-radius: 5px;
color: inherit;
background-color: #2c3e50;
}
#promptInput:focus {
outline: none;
box-shadow: 0 0 0 2px #007BFF;
}
header {
margin-bottom: 20px;
}
header h1 {
font-size: 1.5rem;
text-align: center;
padding: 0.5em;
background: #2980b9;
border-radius: 5px;
}
#sendPrompt {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #2980b9;
color: #ecf0f1;
}
#modelSelectionContainer {
margin-bottom: 20px;
color: #ecf0f1;
}
#chatHistory, #promptInput, #modelSelect {
border: 2px solid #34495e;
}
#modelSelect {
padding: 10px;
border: 1px solid #34495e;
border-radius: 5px;
background-color: #2c3e50;
color: #ecf0f1;
font-family: Arial, sans-serif;
cursor: pointer;
}
#modelSelect:focus {
outline: none;
border-color: #2980b9;
}
label {
color: #ecf0f1;
margin-right: 10px;
}
#modelSelectionContainer {
display: flex;
align-items: center;
justify-content: start;
gap: 10px;
margin-bottom: 10px;
}
pre {
background-color: #333;
color: #f8f8f2;
border: 1px solid #2980b9;
border-left: 3px solid #2980b9;
padding: 10px;
overflow-x: auto;
font-family: 'Courier New', Courier, monospace;
margin: 10px 0;
border-radius: 4px;
white-space: pre-wrap;
}
code {
font-family: 'Courier New', Courier, monospace;
}
::-webkit-scrollbar {
width: 12px;
}
::-webkit-scrollbar-track {
background: #2c3e50;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: #34495e;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #2980b9;
}
@keyframes ellipsis {
0%, 20% {
content: '';
}
40% {
content: '.';
}
60% {
content: '..';
}
80%, 100% {
content: '...';
}
}
.ellipsis::after {
content: '';
animation: ellipsis 2s infinite;
}

32
gui/html/index.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Kuzco Chat</title>
<link rel="stylesheet" href="../css/styles.css">
</head>
<body>
<div id="app">
<header>
<h1>Welcome to Kuzco Chat</h1>
</header>
<div id="modelSelectionContainer">
<label for="modelSelect">Choose AI Model:</label>
<select id="modelSelect">
<option value="mistral">Mistral</option>
<option value="llama2">Llama2</option>
</select>
</div>
<main id="chatHistory" class="chat-history">
</main>
<footer>
<form id="chatForm" class="chat-form">
<input id="promptInput" type="text" placeholder="Enter your prompt" autofocus>
<button id="sendButton">Send</button>
<button id="stopButton" disabled>Stop</button>
</form>
</footer>
</div>
<script src="../js/renderer.js"></script>
</body>
</html>

20
gui/html/prompt.html Normal file
View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Enter API Key</title>
<link rel="stylesheet" href="../css/styles.css">
</head>
<body>
<h1>Enter API Key</h1>
<input type="text" id="apiKeyInput" placeholder="API Key">
<button id="submitApiKey">Submit</button>
<script>
const { ipcRenderer } = require('electron');
document.getElementById('submitApiKey').addEventListener('click', () => {
const apiKey = document.getElementById('apiKeyInput').value;
ipcRenderer.send('submit-api-key', apiKey);
});
</script>
</body>
</html>

92
gui/js/kuzcoCore.js Normal file
View File

@@ -0,0 +1,92 @@
const fs = require('fs');
const path = require('path');
const os = require('os');
const fetch = require('node-fetch');
async function fetchData(url, options = {}) {
const { default: fetch } = await import('node-fetch');
const response = await fetch(url, options);
return response;
}
class KuzcoCore {
constructor() {
this.configPath = path.join(os.homedir(), '.kuzco-cli', 'config.json');
this.API_KEY = this.loadApiKey();
this.controller = new AbortController();
this.isAborted = false;
}
loadApiKey() {
try {
if (fs.existsSync(this.configPath)) {
const configFile = fs.readFileSync(this.configPath);
const config = JSON.parse(configFile);
return config.API_KEY;
} else {
console.log('API Key config file does not exist. Please set up your API Key.');
return '';
}
} catch (error) {
console.error(`An error occurred while reading the API key: ${error.message}`);
return '';
}
}
apiKeyExists() {
return fs.existsSync(this.configPath) && this.API_KEY !== '';
}
abortFetch() {
this.isAborted = true;
this.controller.abort();
}
async sendPrompt(prompt, model) {
console.log("Model received in sendPrompt:", model)
this.controller = new AbortController();
const signal = this.controller.signal;
const timeoutId = setTimeout(() => this.controller.abort(), 25000);
try {
const response = await fetch('https://relay.kuzco.xyz/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
messages: [{ role: 'user', 'content': prompt + '\n' }],
model: model,
stream: false,
}),
signal: signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
const errorMessage = this.isAborted
? 'Request aborted by the user. Please try again.'
: 'Request timed out. Please try again.';
this.isAborted = false;
this.controller = new AbortController();
return error.name === 'AbortError'
? { error: errorMessage }
: { error: error.message };
}
}
}
module.exports = KuzcoCore;

7
gui/js/preload.js Normal file
View File

@@ -0,0 +1,7 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
sendPrompt: (prompt, model) => ipcRenderer.invoke('send-prompt', { prompt, model }),
onApiKeySaved: (callback) => ipcRenderer.on('api-key-saved', callback),
abortPrompt: () => ipcRenderer.send('abort-prompt')
});

99
gui/js/renderer.js Normal file
View File

@@ -0,0 +1,99 @@
function displayMessage(message, sender) {
const chatHistory = document.getElementById('chatHistory');
const messageDiv = document.createElement('div');
messageDiv.classList.add('message');
const parts = message.split('```');
for (let i = 0; i < parts.length; i++) {
if (i % 2 === 0) {
const textPart = document.createElement('span');
textPart.textContent = parts[i];
messageDiv.appendChild(textPart);
} else {
const codeBlock = document.createElement('pre');
const code = document.createElement('code');
code.textContent = parts[i];
codeBlock.appendChild(code);
messageDiv.appendChild(codeBlock);
}
}
if (sender === 'user') {
messageDiv.classList.add('userMessage');
} else {
messageDiv.classList.add('assistantMessage');
}
chatHistory.appendChild(messageDiv);
chatHistory.scrollTop = chatHistory.scrollHeight;
}
document.addEventListener('DOMContentLoaded', () => {
const chatForm = document.getElementById('chatForm');
const promptInput = document.getElementById('promptInput');
const modelSelect = document.getElementById('modelSelect');
const sendButton = document.getElementById('sendButton');
const stopButton = document.getElementById('stopButton');
const modelSelectionContainer = document.getElementById('modelSelectionContainer');
if (chatForm && promptInput && modelSelect) {
chatForm.addEventListener('submit', async (event) => {
event.preventDefault();
const userInput = promptInput.value;
const selectedModel = modelSelect.value;
promptInput.value = '';
modelSelectionContainer.style.display = 'none';
sendButton.disabled = true;
promptInput.disabled = true;
stopButton.disabled = false;
displayMessage(userInput, 'user');
const typingIndicator = displayTypingIndicator();
try {
const response = await window.electronAPI.sendPrompt(userInput, selectedModel);
if (response.error) {
throw new Error(response.error);
}
const assistantMessage = response.choices[0].message.content.trim();
displayMessage(assistantMessage, 'assistant');
} catch (error) {
console.error(`Error sending prompt: ${error.message}`);
displayMessage(`Error: ${error.message}`, 'assistant');
} finally {
typingIndicator.remove();
sendButton.disabled = false;
promptInput.disabled = false;
promptInput.focus();
stopButton.disabled = true;
}
});
} else {
console.error('chatForm or promptInput elements not found!');
}
});
document.getElementById('stopButton').addEventListener('click', () => {
window.electronAPI.abortPrompt();
document.getElementById('stopButton').disabled = true;
});
function displayTypingIndicator() {
const chatHistory = document.getElementById('chatHistory');
const typingIndicator = document.createElement('div');
typingIndicator.classList.add('message', 'assistantMessage', 'ellipsis');
typingIndicator.textContent = 'Processing';
chatHistory.appendChild(typingIndicator);
chatHistory.scrollTop = chatHistory.scrollHeight;
return typingIndicator;
}
document.addEventListener('keydown', (e) => {
if (e.key === 'F11') {
e.preventDefault();
ipcRenderer.send('toggle-fullscreen');
}
});

82
gui/kuzco-gui.js Normal file
View File

@@ -0,0 +1,82 @@
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const fs = require('fs');
const path = require('path');
const os = require('os');
const KuzcoCore = require('./js/kuzcoCore');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'js/preload.js'),
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
},
});
mainWindow.loadFile('html/index.html');
if (!kuzcoCore.apiKeyExists()) {
promptForApiKey(mainWindow);
}
}
ipcMain.on('submit-api-key', (event, apiKey) => {
const configDir = path.join(os.homedir(), '.kuzco-cli');
const configPath = path.join(configDir, 'config.json');
if (!fs.existsSync(configDir)){
fs.mkdirSync(configDir, { recursive: true });
}
fs.writeFileSync(configPath, JSON.stringify({ API_KEY: apiKey }, null, 2), 'utf8');
event.reply('api-key-saved');
app.relaunch();
app.quit();
});
let inputWindow;
function promptForApiKey() {
inputWindow = new BrowserWindow({
width: 300,
height: 300,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
});
inputWindow.loadFile('html/prompt.html');
inputWindow.on('closed', () => {
inputWindow = null;
});
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
const kuzcoCore = new KuzcoCore();
ipcMain.handle('send-prompt', async (event, { prompt, model }) => {
console.log("Received model in main process:", model);
return await kuzcoCore.sendPrompt(prompt, model);
});
ipcMain.on('abort-prompt', () => {
kuzcoCore.abortFetch();
});

3506
gui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

62
gui/package.json Normal file
View File

@@ -0,0 +1,62 @@
{
"name": "kuzco-gui",
"version": "0.0.1",
"description": "Simple gui for kuzco api",
"author": "Wizzard <Wizzard@deadzone.lol>",
"main": "kuzco-gui.js",
"homepage": "https://git.deadzone.lol/Wizzard/kuzco-cli",
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist-linux": "electron-builder --linux",
"dist-mac": "electron-builder --mac",
"dist-win": "electron-builder --win",
"dist-all": "electron-builder -mwl"
},
"build": {
"appId": "com.codjointops.kuzco",
"productName": "KuzcoChat",
"directories": {
"output": "dist"
},
"files": [
"**/*",
"css/**/*",
"js/**/*",
"html/**/*",
"!**/*.ts",
"!*.code-workspace",
"!**/*.js.map",
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}",
"!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
"!**/node_modules/*.d.ts",
"!**/node_modules/.bin",
"!**/*.{o,hprof,orig,pyc,pyo,rbc}",
"!**/._*",
"!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,__pycache__,thumbs.db,.db,desktop.ini}"
],
"win": {
"target": [
"nsis",
"portable"
]
},
"mac": {
"target": "dmg",
"category": "public.app-category.utilities"
},
"linux": {
"target": [
"AppImage",
"deb"
]
}
},
"devDependencies": {
"electron": "latest",
"electron-builder": "^22.0.0"
},
"dependencies": {
"node-fetch": "^2.7.0"
}
}