-
Notifications
You must be signed in to change notification settings - Fork 1
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
0 parents
commit 608350a
Showing
17 changed files
with
2,347 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
dist | ||
.DS_Store |
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,7 @@ | ||
Copyright © 2023 Jerry Sievert | ||
|
||
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. |
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,84 @@ | ||
# Dumbar | ||
|
||
![dumbar icon](media/dumbar-icon.png) | ||
|
||
Dumbar is sort of like a smart bar app, but it's ... dumb. | ||
|
||
But seriously, Dumbar is a simple menu bar application that gives you quick access to Ollama and any models you have installed or have created. The goal is to give fast access to LLMs to help you with whatever task you feel you're dumb enough to ask a pseudo-AI for help about. | ||
|
||
![dumbar in action](media/dumbar.png) | ||
|
||
Dumbar uses the [Ollama](https://ollama.ai) API for any queries to an LLM. | ||
|
||
## Requirements | ||
|
||
In order to run Dumbar, you must have [Ollama](https://ollama.ai) installed. As of the writing of this README, only Apple Silicon Macs are supported. | ||
|
||
### Configuration | ||
|
||
There are currently two configuration options for Dumbar: | ||
|
||
- Ollama Host - this is typically `127.0.0.1` or `localhost`, but you have the option to override it if needed. | ||
- Ollama Port - typically Ollama runs on port `11434`, but you can override the port as well. | ||
|
||
### Troubleshooting | ||
|
||
The most common issues are that either Ollama is not running, or you have not yet set up any models for Ollama to use. | ||
|
||
You can run `ollama list` in a terminal, and it should give you a list of models installed: | ||
|
||
```shell | ||
$ ollama list | ||
NAME SIZE MODIFIED | ||
bartender:latest 7.3 GB 5 weeks ago | ||
chef:latest 7.3 GB 10 minutes ago | ||
codellama:7b-instruct 3.8 GB 33 hours ago | ||
codellama:latest 3.8 GB 33 hours ago | ||
llama2:13b 7.3 GB 5 weeks ago | ||
llama2:7b 3.8 GB 12 hours ago | ||
programmer:latest 3.8 GB 5 minutes ago | ||
``` | ||
|
||
### Example Modelfiles | ||
|
||
Dumbar includes some example Modelfiles that you can use to get started: | ||
|
||
- [bartender](examples/bartender.modelfile) - `ollama create bartender -f examples/bartender.modelfile` | ||
- [chef](examples/chef.modelfile) - `ollama create chef -f examples/chef.modelfile` | ||
- [programmer](examples/programmer.modelfile) - `ollama create programmer -f examples/programmer.modelfile` | ||
|
||
Each tries to inject a fairly simple prompt to help guide responses from the LLMs. | ||
|
||
## Building Locally | ||
|
||
Dumbar is an Electron.js app, and requires Node.js in order to run and package. | ||
|
||
### Setting Up | ||
|
||
You will need to install all packages that are required: | ||
|
||
```shell | ||
$ yarn | ||
``` | ||
|
||
### Running | ||
|
||
In order to run locally: | ||
|
||
```shell | ||
$ yarn run app | ||
``` | ||
|
||
This will run Dumbar locally from the checked out source code. | ||
|
||
### Packaging | ||
|
||
```shell | ||
$ yarn run package | ||
``` | ||
|
||
Dumbar uses `electron-builder` to prepare and package the application. If you are not familiar with `electron-builder`, you can read documentation at https://electron.build/ | ||
|
||
When ready to package, you will need to change the `identity` in `build/electron-builder.json` to your own certificate profile, otherwise the package will not be signed. Not being signed is not the end of the world, but other users may have to explicitly allow the installation to take place in their security settings. | ||
|
||
Official Dumbar packages are signed for your convenience. |
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,210 @@ | ||
/* | ||
* Dumbar - a simple menu bar for LLM. | ||
* | ||
* Copyright 2023 Jerry Sievert | ||
* https://github.com/JerrySievert/Dumbar | ||
*/ | ||
|
||
/* Our error message, in case anything goes wrong. */ | ||
const error_message = `<div class="error">Unable to connect to Ollama.<br><br>Is it running?</div>`; | ||
|
||
/* | ||
* read_chunks | ||
* | ||
* Reads streaming data from a reader, returning an iterator. | ||
*/ | ||
const read_chunks = (reader) => { | ||
return { | ||
async *[Symbol.asyncIterator]() { | ||
let readResult = await reader.read(); | ||
while (!readResult.done) { | ||
yield readResult.value; | ||
readResult = await reader.read(); | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
/* | ||
* get_pref | ||
* | ||
* Reads a preference item from localStorage, returning null if it is | ||
* either unset or blank. | ||
*/ | ||
const get_pref = (which) => { | ||
const pref = localStorage.getItem(which); | ||
if (pref == '') { | ||
return null; | ||
} | ||
|
||
return pref; | ||
}; | ||
|
||
/* | ||
* get_models | ||
* | ||
* Retrieve all known models from the Ollama API endpoint. On error, | ||
* write the standard error message into the results. | ||
*/ | ||
const get_models = async () => { | ||
const host = | ||
get_pref('prefs:host') !== null ? get_pref('prefs:host') : '127.0.0.1'; | ||
|
||
const port = get_pref('prefs:port') !== null ? get_pref(prefs.port) : 11434; | ||
const url = `http://${host}:${port}`; | ||
|
||
try { | ||
fetch(`${url}/api/tags`) | ||
.then(async (response) => { | ||
const models = await response.json(); | ||
|
||
const eModel = document.getElementById('model'); | ||
eModel.innerHTML = ''; | ||
|
||
for (let model of models.models) { | ||
const option = document.createElement('option'); | ||
option.text = model.name; | ||
option.value = model.name; | ||
|
||
eModel.add(option); | ||
} | ||
}) | ||
.catch((err) => { | ||
document.getElementById('spinner').classList.add('hidden'); | ||
resultsWindow.innerHTML = error_message; | ||
}); | ||
} catch (err) { | ||
console.log(err); | ||
} | ||
}; | ||
|
||
/* | ||
* query | ||
* | ||
* Read the model and prompt from the UI and make a query, writing the results | ||
* into the results element as they arrive. On error, write the standard error | ||
* message. | ||
*/ | ||
const query = async () => { | ||
const eModel = document.getElementById('model'); | ||
const model = eModel.value; | ||
|
||
const ePrompt = document.getElementById('prompt'); | ||
const prompt = ePrompt.value; | ||
|
||
document.getElementById('spinner').classList.remove('hidden'); | ||
const body = { | ||
model, | ||
prompt | ||
}; | ||
|
||
const resultsWindow = document.getElementById('results'); | ||
resultsWindow.innerText = ''; | ||
|
||
let response; | ||
|
||
const host = get_pref('prefs:host') ? get_pref('prefs.host') : '127.0.0.1'; | ||
const port = get_pref('prefs:port') ? get_pref(prefs.port) : 11434; | ||
const url = `http://${host}:${port}`; | ||
|
||
try { | ||
let utf8decoder = new TextDecoder(); | ||
|
||
fetch(`${url}/api/generate`, { | ||
method: 'post', | ||
body: JSON.stringify(body), | ||
headers: { 'Content-Type': 'application/json' } | ||
}) | ||
.then(async (response) => { | ||
document.getElementById('spinner').classList.add('hidden'); | ||
|
||
const reader = response.body.getReader(); | ||
|
||
for await (const chunk of read_chunks(reader)) { | ||
let str = utf8decoder.decode(chunk.buffer); | ||
let obj = JSON.parse(str); | ||
|
||
if (obj.done) { | ||
return; | ||
} else if (obj.response) { | ||
resultsWindow.innerText += obj.response; | ||
} | ||
} | ||
}) | ||
.catch((err) => { | ||
document.getElementById('spinner').classList.add('hidden'); | ||
resultsWindow.innerHTML = `<div class="error">Unable to connect to Ollama.<br><br>Is it running?</div>`; | ||
}); | ||
} catch (err) { | ||
console.log(err); | ||
} | ||
}; | ||
|
||
/* | ||
* show_preferences | ||
* | ||
* Show the preferences dialog pane, set the current values. | ||
*/ | ||
const show_preferences = () => { | ||
const host = document.getElementById('host'); | ||
host.value = localStorage.getItem('prefs:host'); | ||
|
||
const port = document.getElementById('port'); | ||
port.value = localStorage.getItem('prefs:port'); | ||
|
||
const prefPane = document.getElementById('preferences'); | ||
prefPane.classList.remove('hidden'); | ||
}; | ||
|
||
/* | ||
* prefs_cancel | ||
* | ||
* Cancel out of the preferences pane, setting things back to normal. | ||
*/ | ||
const prefs_cancel = () => { | ||
const host = document.getElementById('host'); | ||
host.value = ''; | ||
|
||
const port = document.getElementById('port'); | ||
port.value = ''; | ||
|
||
const prefPane = document.getElementById('preferences'); | ||
prefPane.classList.add('hidden'); | ||
}; | ||
|
||
/* | ||
* prefs_save | ||
* | ||
* Save the new preferences, then call for the models again from Ollama. | ||
*/ | ||
const prefs_save = () => { | ||
const host = document.getElementById('host'); | ||
localStorage.setItem('prefs:host', host.value); | ||
|
||
const port = document.getElementById('port'); | ||
localStorage.setItem('prefs:port', port.value); | ||
|
||
const prefPane = document.getElementById('preferences'); | ||
prefPane.classList.add('hidden'); | ||
|
||
const resultsWindow = document.getElementById('results'); | ||
resultsWindow.innerText = ''; | ||
|
||
get_models(); | ||
}; | ||
|
||
/* Set up click handlers for all of the buttons. */ | ||
const searchButton = document.getElementById('query'); | ||
searchButton.onclick = query; | ||
|
||
const prefsButton = document.getElementById('prefs'); | ||
prefsButton.onclick = show_preferences; | ||
|
||
const saveButton = document.getElementById('save'); | ||
saveButton.onclick = prefs_save; | ||
|
||
const cancelButton = document.getElementById('cancel'); | ||
cancelButton.onclick = prefs_cancel; | ||
|
||
/* Start off by retrieving the models. */ | ||
get_models(); |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,10 @@ | ||
{ | ||
"appId": "com.legitimatesounding.dumbar", | ||
"mac": { | ||
"category": "public.app-category.reference", | ||
"icon": "./app-icon.png", | ||
"entitlements": "build/entitlements.mac.plist", | ||
"identity": "Jerry Sievert (8W4GSNA7C5)", | ||
"mergeASARs": true | ||
} | ||
} |
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,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>com.apple.security.cs.allow-jit</key> | ||
<true/> | ||
</dict> | ||
</plist> |
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,6 @@ | ||
# Modelfile for creating a drink from a list of ingredients | ||
# Run `ollama create bartender -f ./bartender.modelfile` and then `ollama run bartender` and feed it lists of ingredients to create recipes around. | ||
FROM llama2:13b | ||
SYSTEM """ | ||
The instruction will be a list of ingredients. You should generate a cocktail recipe that can be made with common liquor and mixers. You can also include ingredients that most people will find in their pantry every day. The recipe should be 1 drink and you should include a description of what the cocktail will taste like | ||
""" |
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,6 @@ | ||
# Modelfile for creating a recipe from a list of ingredients | ||
# Run `ollama create chef -f ./chef.modelfile` and then `ollama run chef` and feed it lists of ingredients to create recipes around. | ||
FROM llama2:13b | ||
SYSTEM """ | ||
The instruction will be a list of ingredients. You should generate a food recipe that can be made with common ingredients that can be found in a regular kitchen. You can also include ingredients that most people will find in their pantry every day. The recipe include a description of what the meal will taste like | ||
""" |
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,6 @@ | ||
# Modelfile for a helpful programmer | ||
# Run `ollama create programmer -f ./programmer.modelfile` and then `ollama run programmer` and tell it what you need help with | ||
FROM codellama:7b-instruct | ||
SYSTEM """ | ||
You will be acting as a senior software developer mentoring someone in how to write software. Your responses will consist of source code, be clear, and will contain helpful comments about the code | ||
""" |
Oops, something went wrong.