From 26531401b0f815a6717001faf1aca53d70f909c0 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 29 Jul 2025 16:38:21 +0700 Subject: [PATCH] ai: allow custom models --- .../quickshell/ii/modules/common/Config.qml | 14 ++++++++ .config/quickshell/ii/services/Ai.qml | 32 +++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/common/Config.qml b/.config/quickshell/ii/modules/common/Config.qml index 1a947f1d5..780676622 100644 --- a/.config/quickshell/ii/modules/common/Config.qml +++ b/.config/quickshell/ii/modules/common/Config.qml @@ -62,6 +62,20 @@ Singleton { property JsonObject ai: JsonObject { property string systemPrompt: "## Style\n- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question\n\n## Presentation\n- Use Markdown features in your response: \n - **Bold** text to **highlight keywords** in your response\n - **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.\n- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!\n- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\nThanks!\n\n## Tools\nMay or may not be available depending on the user's settings. If they're available, follow these guidelines:\n\n### Search\n- When user asks for information that might benefit from up-to-date information, use this to get search access\n\n### Shell configuration\n- Always fetch the config options to see the available keys before setting\n- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it\n" property string tool: "functions" // search, functions, or none + property list extraModels: [ + { + "api_format": "openai", // Most of the time you want "openai". Use "gemini" for Google's models + "description": "This is a custom model. Edit the config to add more! | Anyway, this is DeepSeek R1 Distill LLaMA 70B", + "endpoint": "https://openrouter.ai/api/v1/chat/completions", + "homepage": "https://openrouter.ai/deepseek/deepseek-r1-distill-llama-70b:free", + "icon": "spark-symbolic", + "key_get_link": "https://openrouter.ai/settings/keys", + "key_id": "openrouter", + "model": "deepseek/deepseek-r1-distill-llama-70b:free", + "name": "Custom: DS R1 Dstl. LLaMA 70B", + "requires_key": true + } + ] } property JsonObject appearance: JsonObject { diff --git a/.config/quickshell/ii/services/Ai.qml b/.config/quickshell/ii/services/Ai.qml index d6992850a..7b6013188 100644 --- a/.config/quickshell/ii/services/Ai.qml +++ b/.config/quickshell/ii/services/Ai.qml @@ -61,7 +61,7 @@ Singleton { } function safeModelName(modelName) { - return modelName.replace(/:/g, "_").replace(/\./g, "_") + return modelName.replace(/:/g, "_").replace(/\./g, "_").replace(/ /g, "-").replace(/\//g, "-") } property list defaultPrompts: [] @@ -206,6 +206,19 @@ Singleton { "key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"), "api_format": "gemini", }), + "gemini-2.5-flash-pro": aiModelComponent.createObject(this, { + "name": "Gemini 2.5 Pro", + "icon": "google-gemini-symbolic", + "description": Translation.tr("Online | Google's model\nGoogle's state-of-the-art multipurpose model that excels at coding and complex reasoning tasks."), + "homepage": "https://aistudio.google.com", + "endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent", + "model": "gemini-2.5-pro", + "requires_key": true, + "key_id": "gemini", + "key_get_link": "https://aistudio.google.com/app/apikey", + "key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"), + "api_format": "gemini", + }), "gemini-2.5-flash-lite": aiModelComponent.createObject(this, { "name": "Gemini 2.5 Flash-Lite", "icon": "google-gemini-symbolic", @@ -241,6 +254,17 @@ Singleton { } property ApiStrategy currentApiStrategy: apiStrategies[models[currentModelId]?.api_format || "openai"] + Connections { + target: Config + function onReadyChanged() { + if (!Config.ready) return; + (Config?.options.ai?.extraModels ?? []).forEach(model => { + const safeModelName = root.safeModelName(model["model"]); + root.addModel(safeModelName, model) + }); + } + } + Component.onCompleted: { setModel(currentModelId, false, false); // Do necessary setup for model } @@ -266,6 +290,10 @@ Singleton { return result; } + function addModel(modelName, data) { + root.models[modelName] = aiModelComponent.createObject(this, data); + } + Process { id: getOllamaModels running: true @@ -278,7 +306,7 @@ Singleton { root.modelList = [...root.modelList, ...dataJson]; dataJson.forEach(model => { const safeModelName = root.safeModelName(model); - root.models[safeModelName] = aiModelComponent.createObject(this, { + root.addModel(safeModelName, { "name": guessModelName(model), "icon": guessModelLogo(model), "description": Translation.tr("Local Ollama model | %1").arg(model),