diff --git a/README.md b/README.md index 26f15d3..f8d5c05 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ To use Internet search you need a [Tavily API key](https://app.tavily.com/home). ## DONE +- [x] OpenAI base URL as settings - [x] DALL-E as tool - [x] Google Gemini API - [x] Prompt anywhere diff --git a/defaults/settings.json b/defaults/settings.json index 88ee697..1d2d79e 100644 --- a/defaults/settings.json +++ b/defaults/settings.json @@ -43,6 +43,7 @@ "engines": { "openai": { "apiKey": "", + "baseURL": "https://api.openai.com/v1", "models": { "chat": [], "image": [] @@ -93,6 +94,7 @@ } }, "ollama": { + "baseURL": "https://api.ollama.com", "models": { "chat": [], "image": [] diff --git a/package-lock.json b/package-lock.json index e413f7d..2946429 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@el3um4s/run-vbs": "^1.1.2", "@excalidraw/markdown-to-text": "^0.1.2", "@google/generative-ai": "^0.11.1", - "@iktakahiro/markdown-it-katex": "^4.0.1", + "@iktakahiro/markdown-it-katex": "^3.0.4", "@mistralai/mistralai": "^0.1.3", "applescript": "^1.0.0", "bootstrap-icons-vue": "^1.11.3", @@ -36,7 +36,7 @@ "openai-speech-stream-player": "^1.0.8", "pdf2json": "^3.1.2", "python-shell": "^5.0.0", - "sweetalert2": "^11.10.7", + "sweetalert2": "^11.6.13", "update-electron-app": "^3.0.0", "uuid": "^9.0.1", "vue": "^3.4.21" @@ -2089,24 +2089,21 @@ "dev": true }, "node_modules/@iktakahiro/markdown-it-katex": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@iktakahiro/markdown-it-katex/-/markdown-it-katex-4.0.1.tgz", - "integrity": "sha512-kGFooO7fIOgY34PSG8ZNVsUlKhhNoqhzW2kq94TNGa8COzh73PO4KsEoPOsQVG1mEAe8tg7GqG0FoVao0aMHaw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@iktakahiro/markdown-it-katex/-/markdown-it-katex-3.0.4.tgz", + "integrity": "sha512-yfxYr9eJ/2coJmju3Rh1TKSOhsnwmBwHgBkDwJ/IgK4qFNzFvMOqIW/I6m3NGwRIVc1NoN528qkwysZDrFDa/Q==", + "license": "MIT", "dependencies": { - "katex": "^0.12.0" + "katex": "^0.9.0" } }, - "node_modules/@iktakahiro/markdown-it-katex/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, "node_modules/@iktakahiro/markdown-it-katex/node_modules/katex": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.12.0.tgz", - "integrity": "sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.9.0.tgz", + "integrity": "sha512-lp3x90LT1tDZBW2tjLheJ98wmRMRjUHwk4QpaswT9bhqoQZ+XA4cPcjcQBxgOQNwaOSt6ZeL/a6GKQ1of3LFxQ==", + "license": "MIT", "dependencies": { - "commander": "^2.19.0" + "match-at": "^0.1.1" }, "bin": { "katex": "cli.js" @@ -7111,17 +7108,18 @@ "peer": true }, "node_modules/electron-winstaller": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.3.0.tgz", - "integrity": "sha512-ml77/OmeeLFFc+dk3YCwPQrl8rthwYcAea6mMZPFq7cGXlpWyRmmT0LY73XdCukPnevguXJFs+4Xu+aGHJwFDA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.3.1.tgz", + "integrity": "sha512-oM8BW3a8NEqG0XW+Vx3xywhk0DyDV4T0jT0zZfWt0IczNT3jHAAvQWBorF8osQDplSsCyXXyxrsrQ8cY0Slb/A==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", - "lodash.template": "^4.2.2", + "lodash": "^4.17.21", "temp": "^0.9.0" }, "engines": { @@ -12587,13 +12585,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", - "dev": true, - "optional": true - }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -12606,27 +12597,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "optional": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "optional": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -12917,6 +12887,11 @@ "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-4.0.0.tgz", "integrity": "sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg==" }, + "node_modules/match-at": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz", + "integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q==" + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -16674,9 +16649,10 @@ } }, "node_modules/sweetalert2": { - "version": "11.10.7", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.7.tgz", - "integrity": "sha512-5Jlzrmaitay6KzU+2+LhYu9q+L4v/dZ8oZyEDH14ep0C/QilCnFLHmqAyD/Lhq/lm5DiwsOs6Tr58iv8k3wyGg==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.11.0.tgz", + "integrity": "sha512-wKCTtoE6lQVDKaJ5FFq+znk/YykJmJlD8RnLZps8C7DyivctCoRlVeeOwnKfgwKS+QJYon7s++3dmNi3/am1tw==", + "license": "MIT", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" diff --git a/package.json b/package.json index 5e982ad..460ca74 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@el3um4s/run-vbs": "^1.1.2", "@excalidraw/markdown-to-text": "^0.1.2", "@google/generative-ai": "^0.11.1", - "@iktakahiro/markdown-it-katex": "^4.0.1", + "@iktakahiro/markdown-it-katex": "^3.0.4", "@mistralai/mistralai": "^0.1.3", "applescript": "^1.0.0", "bootstrap-icons-vue": "^1.11.3", @@ -89,7 +89,7 @@ "openai-speech-stream-player": "^1.0.8", "pdf2json": "^3.1.2", "python-shell": "^5.0.0", - "sweetalert2": "^11.10.7", + "sweetalert2": "^11.6.13", "update-electron-app": "^3.0.0", "uuid": "^9.0.1", "vue": "^3.4.21" diff --git a/src/main/config.ts b/src/main/config.ts index e8d025d..cb4b7f9 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -53,6 +53,9 @@ const buildConfig = (defaults: anyDict, overrides: anyDict): Configuration => { delete config.ollama } + // nullify defaults + nullifyDefaults(config) + // done return config as Configuration @@ -75,6 +78,9 @@ export const loadSettings = (source: App|string): Configuration => { export const saveSettings = (dest: App|string, config: anyDict) => { try { + // nullify defaults + nullifyDefaults(config) + // remove instructions that are the same as the default const settings = JSON.parse(JSON.stringify(config)) for (const instr in settings.instructions) { @@ -90,4 +96,13 @@ export const saveSettings = (dest: App|string, config: anyDict) => { } catch (error) { console.log('Error saving settings data', error) } -} \ No newline at end of file +} + +const nullifyDefaults = (settings: anyDict) => { + if (settings.engines.openai.baseURL == '' || settings.engines.openai.baseURL === defaultSettings.engines.openai.baseURL) { + delete settings.engines.openai.baseURL + } + if (settings.engines.ollama.baseURL == '' || settings.engines.ollama.baseURL === defaultSettings.engines.ollama.baseURL) { + delete settings.engines.ollama.baseURL + } +} diff --git a/src/services/openai.ts b/src/services/openai.ts index e38c521..56b532c 100644 --- a/src/services/openai.ts +++ b/src/services/openai.ts @@ -2,6 +2,7 @@ import { Message } from '../types/index.d' import { LLmCompletionPayload, LlmChunk, LlmCompletionOpts, LlmResponse, LlmStream, LlmToolCall, LlmEventCallback } from '../types/llm.d' import { EngineConfig, Configuration } from '../types/config.d' +import defaults from '../../defaults/settings.json' import LlmEngine from './engine' import OpenAI from 'openai' import { ChatCompletionChunk } from 'openai/resources' @@ -24,6 +25,7 @@ export default class extends LlmEngine { super(config) this.client = new OpenAI({ apiKey: config.engines.openai.apiKey, + baseURL: config.engines.openai.baseURL || defaults.engines.openai.baseURL, dangerouslyAllowBrowser: true }) } @@ -52,8 +54,17 @@ export default class extends LlmEngine { } } + private setBaseURL() { + if (this.client) { + this.client.baseURL = this.config.engines.openai.baseURL || defaults.engines.openai.baseURL + } + } + async complete(thread: Message[], opts: LlmCompletionOpts): Promise { + // set baseURL on client + this.setBaseURL() + // call const model = opts?.model || this.config.engines.openai.model.chat console.log(`[openai] prompting model ${model}`) @@ -71,6 +82,9 @@ export default class extends LlmEngine { async stream(thread: Message[], opts: LlmCompletionOpts): Promise { + // set baseURL on client + this.setBaseURL() + // model: switch to vision if needed this.currentModel = this.selectModel(thread, opts?.model || this.getChatModel()) diff --git a/src/settings/SettingsOpenAI.vue b/src/settings/SettingsOpenAI.vue index 44a10a7..4584be2 100644 --- a/src/settings/SettingsOpenAI.vue +++ b/src/settings/SettingsOpenAI.vue @@ -19,6 +19,10 @@ +
+ + +
@@ -27,15 +31,18 @@ import { ref } from 'vue' import { store } from '../services/store' import { loadOpenAIModels } from '../services/llm' +import defaults from '../../defaults/settings.json' import InputObfuscated from '../components/InputObfuscated.vue' const apiKey = ref(null) +const baseURL = ref(null) const refreshLabel = ref('Refresh') const chat_model = ref(null) const chat_models = ref([]) const load = () => { apiKey.value = store.config.engines.openai?.apiKey || '' + baseURL.value = store.config.engines.openai?.baseURL || '' chat_models.value = store.config.engines.openai?.models?.chat || [] chat_model.value = store.config.engines.openai?.model?.chat || '' } @@ -78,6 +85,7 @@ const onKeyChange = () => { const save = () => { store.config.engines.openai.apiKey = apiKey.value + store.config.engines.openai.baseURL = baseURL.value store.config.engines.openai.model.chat = chat_model.value store.saveSettings() } diff --git a/src/types/config.d.ts b/src/types/config.d.ts index f501bb3..e8ee523 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -52,6 +52,7 @@ interface ShortcutsConfig { interface EngineConfig { apiKey?: string + baseURL?: string models: ModelsConfig model: ModelConfig tts?: TTSConfig