From 4740c49f2a6e0e029bc61d078143bfc626dad179 Mon Sep 17 00:00:00 2001 From: Patrizio Bekerle Date: Fri, 14 Jun 2024 19:40:12 +0200 Subject: [PATCH] #3037 add: reloading of OpenAI UI, custom API key handling, hook documentation, example script additions, changelog entry and settings information Signed-off-by: Patrizio Bekerle --- CHANGELOG.md | 9 + .../examples/custom-openai-backends.qml | 17 +- src/dialogs/settingsdialog.cpp | 2 + src/dialogs/settingsdialog.ui | 13 + src/languages/QOwnNotes_en.ts | 735 +++++++++--------- src/mainwindow.cpp | 20 +- src/services/openaiservice.cpp | 26 +- src/services/openaiservice.h | 3 +- webpage/src/scripting/hooks.md | 42 + 9 files changed, 475 insertions(+), 392 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40979a0cc5..4a9314671b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # QOwnNotes Changelog +## 24.6.2 +- A new scripting hook `openAiBackendsHook` was added, that is called when the OpenAI + service config is reloaded (for [#3037](https://github.com/pbek/QOwnNotes/issues/3037)) + - For example this is also done when the script engine is reloaded + - You can use it to provide config for custom OpenAI backends, like your own OpenAI API compatible LLMs + - Please take a look at the + [openAiBackendsHook documentation](https://www.qownnotes.org/scripting/hooks.html#openaibackendshook) + for more information + ## 24.6.1 - When using the `Insert` key in the note text edit to toggle overwrite mode, it now will be made sure that no modifier key is pressed (for [#3038](https://github.com/pbek/QOwnNotes/issues/3038)) diff --git a/docs/scripting/examples/custom-openai-backends.qml b/docs/scripting/examples/custom-openai-backends.qml index 6889d74859..95145003e6 100644 --- a/docs/scripting/examples/custom-openai-backends.qml +++ b/docs/scripting/examples/custom-openai-backends.qml @@ -5,11 +5,15 @@ import QOwnNotesTypes 1.0 * This script provides custom OpenAI backends */ Script { + /** + * This function is called when the OpenAI service config is reloaded + * It returns a list of objects with config parameters for new OpenAI backends + */ function openAiBackendsHook() { - const result = [ + return [ { "id": "my-custom-ai", - "name": "My Custom AI12", + "name": "My Custom AI", "baseUrl": "http://localhost:5000", "apiKey": "kDFJkjk3asdm", "models": ["gpt-3.5-turbo", "gpt-4.0-turbo"], @@ -20,9 +24,14 @@ Script { "baseUrl": "http://localhost:5001", "apiKey": "lOikf7eNdb9", "models": ["gpt-3.5-turbo2", "gpt-4.0-turbo2"], + }, + { + "id": "custom-groq", + "name": "Custom Groq", + "baseUrl": "https://api.groq.com/openai/v1/chat/completions", + "apiKey": "gsk_Kfj477MosEC5LwKN2nrSyw4Yj4Zt44KsLn7AM5M4KQGUu87xqgX", + "models": ["llama3-70b-8192"], } ]; - - return result; } } diff --git a/src/dialogs/settingsdialog.cpp b/src/dialogs/settingsdialog.cpp index 4386ffc6cb..8f63d1ef0a 100644 --- a/src/dialogs/settingsdialog.cpp +++ b/src/dialogs/settingsdialog.cpp @@ -303,6 +303,8 @@ SettingsDialog::SettingsDialog(int page, QWidget *parent) "https://www.qownnotes.org/getting-started/command-line-snippet-manager.html")); ui->commandSnippetsNoteNameLabel->hide(); ui->commandSnippetsNoteNameLineEdit->hide(); + ui->openAiScriptingLabel->setText(ui->openAiScriptingLabel->text().arg( + "https://www.qownnotes.org/scripting/hooks.html#openaibackendshook")); #ifndef Q_OS_LINUX ui->systemIconThemeCheckBox->setHidden(true); diff --git a/src/dialogs/settingsdialog.ui b/src/dialogs/settingsdialog.ui index 7b6d62e7f3..84b0c426d6 100644 --- a/src/dialogs/settingsdialog.ui +++ b/src/dialogs/settingsdialog.ui @@ -6958,6 +6958,19 @@ Just test yourself if you get sync conflicts and set a higher value if so. + + + + You can use the scripting hook <a href="%1">openAiBackendsHook</a> to add more OpenAI API compatible backends. + + + true + + + true + + + diff --git a/src/languages/QOwnNotes_en.ts b/src/languages/QOwnNotes_en.ts index 73332015ba..32a08d0afc 100644 --- a/src/languages/QOwnNotes_en.ts +++ b/src/languages/QOwnNotes_en.ts @@ -2048,7 +2048,7 @@ - + Navigation @@ -2059,7 +2059,7 @@ - + Add a tag to the current note @@ -2170,7 +2170,7 @@ - + Select &all notes @@ -2220,7 +2220,7 @@ - + Add a tag to the selected notes @@ -2316,7 +2316,7 @@ - + Workspaces @@ -2624,7 +2624,7 @@ - + Remove current workspace @@ -2692,7 +2692,7 @@ - + Open note in different window @@ -2713,7 +2713,7 @@ - + Show note git versions @@ -2796,7 +2796,7 @@ - + Automatically detect @@ -2887,7 +2887,7 @@ - + Copy absolute path of note @@ -3061,22 +3061,22 @@ - + Note was removed externally! - + Current note was removed outside of this application! Restore current note? - - - - - + + + + + &Cancel @@ -3088,47 +3088,47 @@ Restore current note? - + new version %1 available - + Abort - + Loading notes… - + Removed duplicate conflicted database: %1 - + Could not remove duplicate conflicted database: %1 - + Removed merged conflicted database: %1 - + Could not remove merged conflicted database: %1 - + Delete conflicted database copies - + Removed %n conflicted database copies @@ -3136,62 +3136,62 @@ Restore current note? - + Please select the folder where your notes will get stored - + No folder was selected - + You have to select your ownCloud notes folder to make this software work! - + &Retry - + &Exit - + Remove current note - + Remove current note: <strong>%1</strong>? - + Please enter the <strong>password</strong> of this encrypted note. - + Note can't be decrypted! - + It seems that your password is not valid! - + Remove selected notes - + Remove <strong>%n</strong> selected note(s)? If the trash is enabled on your ownCloud server you should be able to restore them from there. @@ -3205,12 +3205,12 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Remove selected tags - + Remove <strong>%n</strong> selected tag(s)? No notes will be removed in this process. @@ -3218,13 +3218,13 @@ If the trash is enabled on your ownCloud server you should be able to restore th - - + + Move selected notes - + Move %n selected note(s) to <strong>%2</strong>? Move one selected note to <strong>%2</strong>? @@ -3232,13 +3232,13 @@ If the trash is enabled on your ownCloud server you should be able to restore th - - + + Copy selected notes - + Copy %n selected note(s) to <strong>%2</strong>? Copy one selected note to <strong>%2</strong>? @@ -3246,13 +3246,13 @@ If the trash is enabled on your ownCloud server you should be able to restore th - - + + Done - + %n note(s) were copied to <strong>%2</strong>. One note was copied to <strong>%2</strong>. @@ -3260,12 +3260,12 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Tag selected notes - + Tag %n selected note(s) with <strong>%2</strong>? @@ -3273,37 +3273,37 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Restart application - + You may need to restart the application to let the changes take effect. - + Restart - + PDF files - + Todo lists disabled! - + You have disabled the todo lists.<br />Please check your <strong>Todo</strong> configuration in the settings! - + Found <strong>%n</strong> occurrence(s) of any term of <strong>%1</strong> @@ -3311,79 +3311,79 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Note folders - + Note versions are currently loaded from your ownCloud server - + Trashed notes are currently loaded from your ownCloud server - + Inserted text as text attachment file - + Your note will be decrypted and stored as plain text again. Keep in mind that the unencrypted note will possibly be synced to your server and sensitive text may be exposed!<br />Do you want to decrypt your note? - + Markdown files - + Export attached files - + Do you also want to export media files and attachments of the note? Files may be overwritten in the destination folder! - + Bookmarked note position at slot %1 - + Jumped to bookmark position at slot %1 - - + + Inserting image - - + + Done inserting image - + Inserting attachment - + Done inserting attachment - + Copied %n note(s) to %1 @@ -3391,7 +3391,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Failed to copy %n note(s) (most likely already existing) @@ -3399,156 +3399,156 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Saving temporary image - + Nextcloud Deck support disabled! - + Nextcloud Deck support is not enabled or the settings are invalid.<br />Please check your <strong>Nextcloud</strong> configuration in the settings! - + Note path '%1' was copied to the clipboard - + AI backends - + AI models - + AI backend selector - + AI model selector - - + + Temporary file can't be opened - + Downloading %1 - + Reset font size to %1 pt Will be shown after the font size is reset by 'Reset note text size' - + Remove tag '%1' from the current note - + Remove tag '%1' from the selected notes - + Rename tag - + Assign color - + Disable color - + &Move tags to… - + Move to the root to move a tag to the current tag in the tag context menu - + The scripting engine was reloaded - + HTML files - + Jump to the note's subfolder - + Open selected notes in tabs - + A script update was found! - + Script updates - + Updates to your scripts were found in the script repository! Do you want to update them? - + No script updates were found - + Toggle note stickiness - + Close other note tabs - - + + Rename note - + Skipped copying of %n note(s) (no Markdown or text file or not readable) @@ -3556,100 +3556,100 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Paste &HTML as Markdown - + Show all notes (%1) - + Show all notes tagged with '%1' (%2) - + Allows you to rename the filename of the note - + &Move notes to… - + &Copy notes to… - + Move notes to subfolder… - + Copy notes to subfolder… - + &Tag selected notes with… - + &Remove tag from selected notes… - + Name: - + Note renaming not enabled! - + Create new workspace - - + + Workspace name: - + full full workspace - + minimal minimal workspace - + Remove the current workspace? - + Rename workspace - + %n chars characters @@ -3658,52 +3658,52 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Disallow all note editing - + Note editing disabled - + Note editing is currently disabled, do you want to allow it again? - + Select text files to import - + Importing: %1 - + Note headline '%1' was copied to the clipboard - + Leave full-screen mode - + Custom editor width - + Characters: - + %n notes selected @@ -3712,7 +3712,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Allow all note editing @@ -3722,12 +3722,12 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Remove tag from selected notes - + Remove tag <strong>%1</strong> from %n selected note(s)? @@ -3735,7 +3735,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Tag <strong>%1</strong> was removed from %n note(s) @@ -3743,120 +3743,120 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Current notes folder: - + Set the notes folder. Current notes folder: - + Print note - + Letter - + Portrait - + Landscape - + Orientation - + Orientation: - + Export current note as PDF - + You have not selected any todo lists.<br />Please check your <strong>Todo</strong> configuration in the settings! - + Open QOwnNotes - - - + + + New note - + Recent notes - + Show todo lists - + Recent tasks - + Quit - - + + Note folder - - + + Copy to note folder - - + + Move to note folder - - + + Copy to this subfolder - - + + Move to this subfolder - + Move %n selected note(s) to note subfolder <strong>%2</strong>? @@ -3864,13 +3864,13 @@ If the trash is enabled on your ownCloud server you should be able to restore th - - + + Cancel - + %n note(s) were moved to note subfolder "%2" @@ -3878,7 +3878,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Copy %n selected note(s) to note subfolder <strong>%2</strong>? @@ -3886,7 +3886,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + %n note(s) were copied to note subfolder "%2" @@ -3894,103 +3894,103 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Open note in external editor - + Show note in file manager - + If you want to rename your note you have to enable the option to allow the note filename to be different from the headline. - + Create a new folder - + Folder name: - + show all untagged notes (%1) - + Untagged notes - + Export current note as HTML file - + Page size - + quit toolbar - + Page size: - + QOwnNotes will track anonymous usage data, that helps to decide what parts of QOwnNotes to improve next and to find and fix bugs. You can disable that behaviour in the settings. - + &Ok - + &Remove notes - + Your tasks are being loaded from your server - + Current note was modified externally - - + + Stored current note to disk - + Note was modified externally: %1 - + Notes directory was modified externally - + Stored %n note(s) to disk @@ -3998,203 +3998,203 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + All notes - + &Add tag - + Tag could not be created! - + Move to this tag - + Tag this - + Cannot move tag '%1' to this tag - + Moved tag '%1' to new tag - + &Remove tags - + No selected todo lists! - + Action not found! - + Could not find menu action <code>%1</code>! Did you spell it correctly? - + Subfolders - + Tags - + Note search - + Note list - + Note edit - + Note tags - + Note preview - + Log - + Scripting - + formatting toolbar - + inserting toolbar - + encryption toolbar - + AI toolbar - + window toolbar - + custom action toolbar - + Workspace selector - + Show %1 panel - + Show %1 - + Leave distraction free mode - + Switch to note folder - + Toolbar could not be loaded without name - + Overwriting external changes of: %1 - + Loading external changes from: %1 - - + + Current note could not be stored to disk - + Read-only - + Note editing is disabled, click to enable - + Line numbers - + Click here to see what has changed and to be able to update to the latest version - + Proceed with automatic deletion of <strong>%n</strong> conflicted database copies that may block your ownCloud sync process? @@ -4202,7 +4202,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + %n note(s) were tagged with "%2" @@ -4210,7 +4210,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Found <strong>%n</strong> occurrence(s) of <strong>%1</strong> @@ -4218,57 +4218,57 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + Note headline - + Paste as &text file attachment - + Downloading images finished - - - - - + + + + + Open &settings - - + + leave - + Please enter your <strong>password</strong> to encrypt the note.<br />Keep in mind that you have to <strong>remember</strong> your password to read the content of the note<br /> and that you can <strong>only</strong> do that <strong>in QOwnNotes</strong>! - + Decrypt note and store it as plain text - + &Decrypt - + <br />You will be able to edit your encrypted note. - + Export current note as Markdown file @@ -4431,27 +4431,27 @@ If the trash is enabled on your ownCloud server you should be able to restore th NoteFilePathLabel - + Relative path of note, right-click to open context menu - + Absolute path of note, right-click to open context menu - + Copy absolute path of note - + Copy absolute path of note subfolder - + Copy absolute path of note folder @@ -4555,7 +4555,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th OpenAiCompleter - + Timeout, while waiting for the AI response @@ -4563,7 +4563,7 @@ If the trash is enabled on your ownCloud server you should be able to restore th OpenAiService - + AI system is disabled. Please enable it in the main menu or the AI toolbar. @@ -4940,17 +4940,17 @@ If the trash is enabled on your ownCloud server you should be able to restore th - + New connection - + Login flow succeeded - + Username and password were set successfully! @@ -5692,7 +5692,7 @@ Do you want to install it anyway? - + unknown @@ -6038,10 +6038,10 @@ Just test yourself if you get sync conflicts and set a higher value if so. - - - - + + + + Database @@ -6062,7 +6062,7 @@ Just test yourself if you get sync conflicts and set a higher value if so. - + Clear app data and exit @@ -6654,20 +6654,20 @@ Just test yourself if you get sync conflicts and set a higher value if so. - + Reset message boxes - - + + Import settings - + Export settings @@ -7037,6 +7037,11 @@ Just test yourself if you get sync conflicts and set a higher value if so.Create OpenAI API key + + + You can use the scripting hook <a href="%1">openAiBackendsHook</a> to add more OpenAI API compatible backends. + + Groq API key: @@ -7534,7 +7539,7 @@ Just test yourself if you get sync conflicts and set a higher value if so. - + Search script repository @@ -7960,8 +7965,8 @@ Just test yourself if you get sync conflicts and set a higher value if so. - - + + Debug information @@ -7976,54 +7981,54 @@ Just test yourself if you get sync conflicts and set a higher value if so. - + hostname of proxy server - + username for proxy server - + password for proxy server - + HTTP(S) proxy - + SOCKS5 proxy - + notes path <b>%1</b> found on server - + Automatic (needs restart) - + Shortcut already assigned - + The connection was made successfully! Server version: %1 QOwnNotesAPI version: %2 - + There was an error connecting to the ownCloud Server! You also need to have the QOwnNotesAPI app installed and enabled! @@ -8031,153 +8036,153 @@ Connection error message: - + The Database was reinitialized. Please restart the application now! - + Please don't use this in the issue tracker, copy the debug information text directly into the issue. - + Markdown files - + Disable usage tracking - + Anonymous usage data helps to decide what parts of QOwnNotes to improve next and to find and fix bugs.<br />Please disable it only if you really can't live with it.<br /><br />Really disable usage tracking? - + new folder - + Remove note folder - + Remove the current note folder <strong>%1</strong>? - + Please select the folder where your notes will get stored to - + Loading folders from server - + No more folders were found in the current folder - + Loading folders in '%1' from server - + Take a look at the <a href="%1">Scripting documentation</a> to get started fast. - + If you need access to a certain functionality in QOwnNotes please open an issue on the <a href="%1"> QOwnNotes issue page</a>. - + Check for script updates - + Add local script - + Add an existing, local script - + Please enter a new note file extension: - + Markdown file - + Plain text file - + Remove note file extension - - + + INI files - + Do you really want to import settings? Your current settings will get removed and not every setting may get restored, like the note folder settings and which scripts you were using. You also will need to adjust some settings, especially across platforms, but your notes will stay intact! - + The application will be restarted after the import. - + The debug information was copied to the clipboard. - + The integrity of the disk database is valid. - + The integrity of the disk database is not valid! - + Board Id: %1 - + Stack Id: %1 - + Find a script in the script repository @@ -8192,132 +8197,132 @@ Connection error message: - - + + Undefined shortcut - - + + Assign a new shortcut - - + + Reset to default shortcut - + Clear shortcut - + The shortcut <strong>%1</strong> is already assigned to <strong>%2</strong>! Do you want to jump to the shortcut? - + Remove script - + Remove the current script <strong>%1</strong>? - + QML files - + Please select your QML file - + Open repository - + Your script seems to be valid - + There were script errors: %1 - + File extension - + Do you really want to remove the note file extension <strong>%1</strong>? You will not see files with this extension in the note list any more! - + Calendar cache emptied - + Your calendar cache was emptied. - + Reset toolbars and exit - + Do you really want to reset all toolbars? The application will be closed in the process, the default toolbars will be restored when you start it again. - + Reset and &exit - + Log file cleared - + The log file <strong>%1</strong> was cleared. - + Executable files - + All files - + Please select the path of your git executable - + Do you really want to reset the overrides of all message boxes? @@ -8332,86 +8337,86 @@ Connection error message: - + enabled - + disabled - + Portable mode is currently: - + In portable mode - + the internal sqlite database and the settings will be stored inside a <code>Data</code> folder at the binary's location - + the settings will be stored in an ini file - + the note folders, script paths and path to an external editor will be automatically stored relative to the <code>Data</code> folder so that the correct note folders, scripts and external editor will be loaded regardless where your QOwnNotes installation is currently located - + It will be activated if you run QOwnNotes with the parameter <code>--portable</code>. - + Save debug information - + Do you really want to clear all settings, remove the database and exit QOwnNotes? Your notes will stay intact! - + Clear and &exit - - - + + + &Cancel - + You will find a <code>QOwnNotesPortable.bat</code> in your release path to start QOwnNotes in portable mode. - + Do you really want to clear the local database? This will also remove your configured note folders and your cached todo items! - + Clear &database - + Select editor application diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b59c400751..4199d139a7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -9117,13 +9117,12 @@ void MainWindow::on_actionReload_scripting_engine_triggered() { } void MainWindow::reloadOpenAiControls() { - generateAiBackendComboBox(); - generateAiModelComboBox(); - - // TODO: Enable if method can be executed multiple times - // generateAiModelMainMenu(); + OpenAiService::deleteInstance(); + generateAiBackendComboBox(); + generateAiModelComboBox(); + generateAiModelMainMenu(); - aiModelMainMenuSetCurrentItem(); + aiModelMainMenuSetCurrentItem(); } /** @@ -10393,9 +10392,7 @@ void MainWindow::generateAiBackendComboBox() { */ void MainWindow::generateAiModelMainMenu() { QMap backendNames = OpenAiService::instance()->getBackendNames(); - // TODO: Clear the menu, groupd and events before adding new items -// _aiModelGroup->clear(); - _aiModelGroup->setExclusive(true); + ui->menuAI_model->clear(); for (const auto &backendId : backendNames.keys()) { const QString &backendName = backendNames.value(backendId); @@ -10418,8 +10415,6 @@ void MainWindow::generateAiModelMainMenu() { // Add the submenu to the main menu ui->menuAI_model->addMenu(modelSubMenu); } - - connect(_aiModelGroup, &QActionGroup::triggered, this, &MainWindow::onAiModelGroupChanged); } void MainWindow::aiModelMainMenuSetCurrentItem() { @@ -12028,7 +12023,8 @@ void MainWindow::buildAiToolbarAndActions() { aiModelWidgetAction->setText(tr("AI model selector")); _aiToolbar->addAction(aiModelWidgetAction); - // TODO: Enable if we use reloadOpenAiControls() + _aiModelGroup->setExclusive(true); + connect(_aiModelGroup, &QActionGroup::triggered, this, &MainWindow::onAiModelGroupChanged); generateAiModelMainMenu(); aiModelMainMenuSetCurrentItem(); } diff --git a/src/services/openaiservice.cpp b/src/services/openaiservice.cpp index b276fe1852..1f5189062e 100644 --- a/src/services/openaiservice.cpp +++ b/src/services/openaiservice.cpp @@ -75,25 +75,33 @@ void OpenAiService::deleteInstance() { } void OpenAiService::initializeBackends() { + _backendModels.clear(); _backendModels[QStringLiteral("openai")] = QStringList{"gpt-4o", "gpt-4-turbo", "gpt-3.5-turbo", "gpt-4"}; _backendModels[QStringLiteral("groq")] = QStringList{"llama3-70b-8192", "llama3-8b-8192", "llama2-70b-4096", "mixtral-8x7b-32768", "gemma-7b-it"}; + _backendApiBaseUrls.clear(); _backendApiBaseUrls[QStringLiteral("openai")] = QStringLiteral("https://api.openai.com/v1/chat/completions"); _backendApiBaseUrls[QStringLiteral("groq")] = QStringLiteral("https://api.groq.com/openai/v1/chat/completions"); + _backendApiKeys.clear(); + QSettings settings; + _backendApiKeys[QStringLiteral("groq")] = CryptoService::instance()->decryptToString( + settings.value(getApiKeySettingsKeyForBackend(QStringLiteral("groq"))).toString());; + _backendApiKeys[QStringLiteral("openai")] = CryptoService::instance()->decryptToString( + settings.value(getApiKeySettingsKeyForBackend(QStringLiteral("openai"))).toString());; + + _backendNames.clear(); _backendNames[QStringLiteral("groq")] = QStringLiteral("Groq"); _backendNames[QStringLiteral("openai")] = QStringLiteral("OpenAI"); - // TODO: Implement script hook for https://github.com/pbek/QOwnNotes/issues/3037 - // id, name, baseUrl, apiKey, models const QList backends = ScriptingService::instance()->callOpenAiBackendsHook(); - qDebug() << __func__ << " - 'backends': " << backends; - qDebug() << __func__ << " - 'backends count': " << backends.count(); +// qDebug() << __func__ << " - 'backends': " << backends; +// qDebug() << __func__ << " - 'backends count': " << backends.count(); foreach (const QVariantMap& backend, backends) { const QString id = backend["id"].toString(); @@ -108,9 +116,9 @@ void OpenAiService::initializeBackends() { continue; } - // TODO: Take care of apiKey too _backendNames[id] = name; _backendApiBaseUrls[id] = baseUrl; + _backendApiKeys[id] = apiKey; _backendModels[id] = models; } } @@ -132,9 +140,7 @@ QString OpenAiService::getApiBaseUrlForCurrentBackend() { } QString OpenAiService::getApiKeyForCurrentBackend() { - QSettings settings; - return CryptoService::instance()->decryptToString( - settings.value(getCurrentApiKeySettingsKey()).toString()); + return _backendApiKeys.value(getBackendId()); } QStringList OpenAiService::getModelsForBackend(const QString& backendId) { @@ -225,8 +231,8 @@ QString OpenAiService::getCurrentModelSettingsKey() { QStringLiteral("currentModel"); } -QString OpenAiService::getCurrentApiKeySettingsKey() { - return QStringLiteral("ai/") + getBackendId() + QStringLiteral("/") + QStringLiteral("apiKey"); +QString OpenAiService::getApiKeySettingsKeyForBackend(const QString& backendId) { + return QStringLiteral("ai/") + backendId + QStringLiteral("/") + QStringLiteral("apiKey"); } bool OpenAiService::setEnabled(bool enabled) { diff --git a/src/services/openaiservice.h b/src/services/openaiservice.h index f5a6ebf0d1..5687784518 100644 --- a/src/services/openaiservice.h +++ b/src/services/openaiservice.h @@ -67,6 +67,7 @@ class OpenAiService : public QObject { private: QMap _backendModels; QMap _backendApiBaseUrls; + QMap _backendApiKeys; QMap _backendNames; void initializeBackends(); static OpenAiService* createInstance(QObject* parent); @@ -74,7 +75,7 @@ class OpenAiService : public QObject { QString _modelId; OpenAiCompleter* _completer = nullptr; QString getCurrentModelSettingsKey(); - QString getCurrentApiKeySettingsKey(); + static QString getApiKeySettingsKeyForBackend(const QString& backendId); void initializeCompleter(QObject* parent); QString getApiBaseUrlForCurrentBackend(); QString getApiKeyForCurrentBackend(); diff --git a/webpage/src/scripting/hooks.md b/webpage/src/scripting/hooks.md index 2bdb25a00e..5a066f7ab1 100644 --- a/webpage/src/scripting/hooks.md +++ b/webpage/src/scripting/hooks.md @@ -455,3 +455,45 @@ function workspaceSwitchedHook(oldUuid, newUuid); You may want to take a look at the example [websocket-raw-data-new-note.qml](https://github.com/pbek/QOwnNotes/blob/main/docs/scripting/examples/workspaces.qml). + +openAiBackendsHook +------------------ + +This hook is called, when the OpenAI service config is reloaded. For example this is also +done when the script engine is reloaded. + +You can use it to provide config for custom OpenAI backends, like your own OpenAI API compatible LLMs. + +### Method call and parameters +```js +/** + * This function is called when the OpenAI service config is reloaded + * It returns a list of objects with config parameters for new OpenAI backends + */ +function openAiBackendsHook() { + return [ + { + "id": "my-custom-ai", + "name": "My Custom AI", + "baseUrl": "http://localhost:5000", + "apiKey": "kDFJkjk3asdm", + "models": ["gpt-3.5-turbo", "gpt-4.0-turbo"], + }, + { + "id": "my-custom-ai2", + "name": "My Custom AI 2", + "baseUrl": "http://localhost:5001", + "apiKey": "lOikf7eNdb9", + "models": ["gpt-3.5-turbo2", "gpt-4.0-turbo2"], + }, + ]; +} +``` + +::: tip +You can use [Registering script settings variables](./methods-and-objects.md#registering-script-settings-variables) +to store the OpenAI backend settings in the script settings. +::: + +You may want to take a look at the example +[custom-openai-backends.qml](https://github.com/pbek/QOwnNotes/blob/main/docs/scripting/examples/custom-openai-backends.qml).