From 27768046dbbe3e031421ed12af37a97cb220b6c4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 7 Apr 2025 21:44:49 +0200 Subject: [PATCH] ai: detect ollama models automatically --- .config/ags/modules/sideleft/apis/chatgpt.js | 2 +- .../ai/show-installed-ollama-models.sh | 16 ++++++ .config/ags/services/gpt.js | 55 ++++++++++++------- 3 files changed, 51 insertions(+), 22 deletions(-) create mode 100755 .config/ags/scripts/ai/show-installed-ollama-models.sh diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index e0db9968d..7801d5588 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -58,7 +58,7 @@ const ProviderSwitcher = () => { }); } let indicatorIcon = Icon({ - icon: GPTService.providers[userOptions.ai.defaultGPTProvider]['logo_name'], + icon: GPTService.providers[GPTService._currentProvider]['logo_name'], className: 'txt-large', setup: (self) => self.hook(GPTService, (self) => { self.icon = GPTService.providers[GPTService.providerID]['logo_name']; diff --git a/.config/ags/scripts/ai/show-installed-ollama-models.sh b/.config/ags/scripts/ai/show-installed-ollama-models.sh new file mode 100755 index 000000000..e56ac766a --- /dev/null +++ b/.config/ags/scripts/ai/show-installed-ollama-models.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Get the list, skip the header, and extract the first column (model names) +model_names=$(ollama list | tail -n +2 | awk '{print $1}') + +# Build a JSON array +json_array="[" +for name in $model_names; do + json_array+="\"$name\"," +done + +# Remove trailing comma and close the array +json_array="${json_array%,}]" + +# Output the JSON array +echo "$json_array" diff --git a/.config/ags/services/gpt.js b/.config/ags/services/gpt.js index 717ee2932..747aada5c 100644 --- a/.config/ags/services/gpt.js +++ b/.config/ags/services/gpt.js @@ -6,6 +6,22 @@ import GLib from 'gi://GLib'; import Soup from 'gi://Soup?version=3.0'; import { fileExists } from '../modules/.miscutils/files.js'; +function guessModelLogo(model) { + if (model.includes("llama")) return "ollama-symbolic"; + if (model.includes("gemma")) return "google-gemini-symbolic"; + if (model.includes("deepseek")) return "deepseek-symbolic"; + return "ollama-symbolic"; +} + +function guessModelName(model) { + const replaced = model.replace(/-/g, ' ').replace(/:/g, ' '); + const words = replaced.split(' '); + words[words.length - 1] = words[words.length - 1].replace(/(\d+)b$/, (_, num) => `${num}B`) + words[words.length - 1] = `[${words[words.length - 1]}]`; // Surround the last word with square brackets + const result = words.join(' '); + return result.charAt(0).toUpperCase() + result.slice(1); // Capitalize the first letter +} + const PROVIDERS = Object.assign({ "ollama_llama_3_2": { "name": "Ollama - Llama 3.2", @@ -17,26 +33,6 @@ const PROVIDERS = Object.assign({ "key_file": "ollama_key.txt", "model": "llama3.2", }, - "ollama_deepseek_r1": { - "name": "Ollama - DeepSeek R1", - "logo_name": "deepseek-symbolic", - "description": getString('That popular Chinese model that thinks thoroughly'), - "base_url": "http://localhost:11434/v1/chat/completions", - "key_get_url": "", - "key_file": "ollama_key.txt", - "requires_key": false, - "model": "deepseek-r1", - }, - "ollama_gemma3": { - "name": "Ollama - Gemma 3", - "logo_name": "google-gemini-symbolic", - "description": getString('Gemma 3 from Google. Runs on a single GPU.'), - "base_url": "http://localhost:11434/v1/chat/completions", - "key_get_url": "", - "key_file": "ollama_key.txt", - "requires_key": false, - "model": "gemma3", - }, "openrouter": { "name": "OpenRouter (Llama-3-70B)", "logo_name": "openrouter-symbolic", @@ -59,6 +55,23 @@ const PROVIDERS = Object.assign({ }, }, userOptions.ai.extraGptModels) +const installedOllamaModels = JSON.parse( + Utils.exec(`${App.configDir}/scripts/ai/show-installed-ollama-models.sh`)) + || []; +installedOllamaModels.forEach(model => { + const providerKey = `ollama_${model}`; // Generate a unique key for each model + PROVIDERS[providerKey] = { + name: `Ollama - ${guessModelName(model)}`, + logo_name: guessModelLogo(model), + description: `Ollama model: ${model}`, + base_url: 'http://localhost:11434/v1/chat/completions', + key_get_url: "", + requires_key: false, + key_file: "ollama_key.txt", + model: `${model}` + }; +}); + // Custom prompt const initMessages = [ @@ -152,7 +165,7 @@ class GPTService extends Service { } _assistantPrompt = true; - _currentProvider = userOptions.ai.defaultGPTProvider; + _currentProvider = PROVIDERS[userOptions.ai.defaultGPTProvider] ? userOptions.ai.defaultGPTProvider : Object.keys(PROVIDERS)[0]; _requestCount = 0; _temperature = userOptions.ai.defaultTemperature; _messages = [];