Version 0.3.5

- Rework General, Code Completion and Chat Assist pages in settings 
- Add Sharing current open file with model and settings for default behavior for this
- Fixed a bug on WindowsOS where settings were set incorrectly
This commit is contained in:
Petr Mironychev
2024-11-11 01:08:18 +01:00
committed by GitHub
46 changed files with 1609 additions and 701 deletions

View File

@@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
find_package(QtCreator REQUIRED COMPONENTS Core) find_package(QtCreator REQUIRED COMPONENTS Core)
find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED) find_package(Qt6 COMPONENTS Core Gui Quick Widgets Network REQUIRED)
add_subdirectory(llmcore) add_subdirectory(llmcore)
add_subdirectory(settings) add_subdirectory(settings)
@@ -22,11 +22,16 @@ add_qtc_plugin(QodeAssist
QtCreator::Core QtCreator::Core
QtCreator::LanguageClient QtCreator::LanguageClient
QtCreator::TextEditor QtCreator::TextEditor
QtCreator::ProjectExplorer
DEPENDS DEPENDS
Qt::Core
Qt::Gui
Qt::Quick
Qt::Widgets Qt::Widgets
Qt::Network
QtCreator::ExtensionSystem QtCreator::ExtensionSystem
QtCreator::Utils QtCreator::Utils
QtCreator::ProjectExplorer QodeAssistChatViewplugin
SOURCES SOURCES
.github/workflows/build_cmake.yml .github/workflows/build_cmake.yml
.github/workflows/README.md .github/workflows/README.md
@@ -55,6 +60,7 @@ add_qtc_plugin(QodeAssist
core/ChangesManager.h core/ChangesManager.cpp core/ChangesManager.h core/ChangesManager.cpp
chat/ChatOutputPane.h chat/ChatOutputPane.cpp chat/ChatOutputPane.h chat/ChatOutputPane.cpp
chat/NavigationPanel.hpp chat/NavigationPanel.cpp chat/NavigationPanel.hpp chat/NavigationPanel.cpp
ConfigurationManager.hpp ConfigurationManager.cpp
) )
target_link_libraries(QodeAssist PRIVATE QodeAssistChatViewplugin) target_link_libraries(QodeAssist PRIVATE )

155
ConfigurationManager.cpp Normal file
View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ConfigurationManager.hpp"
#include <QTimer>
#include <settings/ButtonAspect.hpp>
#include "QodeAssisttr.h"
namespace QodeAssist {
ConfigurationManager &ConfigurationManager::instance()
{
static ConfigurationManager instance;
return instance;
}
void ConfigurationManager::init()
{
setupConnections();
}
ConfigurationManager::ConfigurationManager(QObject *parent)
: QObject(parent)
, m_generalSettings(Settings::generalSettings())
, m_providersManager(LLMCore::ProvidersManager::instance())
, m_templateManger(LLMCore::PromptTemplateManager::instance())
{}
void ConfigurationManager::setupConnections()
{
using Config = ConfigurationManager;
using Button = ButtonAspect;
connect(&m_generalSettings.ccSelectProvider, &Button::clicked, this, &Config::selectProvider);
connect(&m_generalSettings.caSelectProvider, &Button::clicked, this, &Config::selectProvider);
connect(&m_generalSettings.ccSelectModel, &Button::clicked, this, &Config::selectModel);
connect(&m_generalSettings.caSelectModel, &Button::clicked, this, &Config::selectModel);
connect(&m_generalSettings.ccSelectTemplate, &Button::clicked, this, &Config::selectTemplate);
connect(&m_generalSettings.caSelectTemplate, &Button::clicked, this, &Config::selectTemplate);
connect(&m_generalSettings.ccSetUrl, &Button::clicked, this, &Config::selectUrl);
connect(&m_generalSettings.caSetUrl, &Button::clicked, this, &Config::selectUrl);
}
void ConfigurationManager::selectProvider()
{
const auto providersList = m_providersManager.providersNames();
auto *settingsButton = qobject_cast<ButtonAspect *>(sender());
if (!settingsButton)
return;
auto &targetSettings = (settingsButton == &m_generalSettings.ccSelectProvider)
? m_generalSettings.ccProvider
: m_generalSettings.caProvider;
QTimer::singleShot(0, this, [this, providersList, &targetSettings] {
m_generalSettings.showSelectionDialog(providersList,
targetSettings,
Tr::tr("Select LLM Provider"),
Tr::tr("Providers:"));
});
}
void ConfigurationManager::selectModel()
{
const QString providerName = m_generalSettings.ccProvider.volatileValue();
auto *settingsButton = qobject_cast<ButtonAspect *>(sender());
if (!settingsButton)
return;
const auto providerUrl = (settingsButton == &m_generalSettings.ccSelectModel)
? m_generalSettings.ccUrl.volatileValue()
: m_generalSettings.caUrl.volatileValue();
const auto modelList = m_providersManager.getProviderByName(providerName)
->getInstalledModels(providerUrl);
auto &targetSettings = (settingsButton == &m_generalSettings.ccSelectModel)
? m_generalSettings.ccModel
: m_generalSettings.caModel;
QTimer::singleShot(0, &m_generalSettings, [this, modelList, &targetSettings]() {
m_generalSettings.showSelectionDialog(modelList,
targetSettings,
Tr::tr("Select LLM Model"),
Tr::tr("Models:"));
});
}
void ConfigurationManager::selectTemplate()
{
auto *settingsButton = qobject_cast<ButtonAspect *>(sender());
if (!settingsButton)
return;
const auto templateList = (settingsButton == &m_generalSettings.ccSelectTemplate)
? m_templateManger.fimTemplatesNames()
: m_templateManger.chatTemplatesNames();
auto &targetSettings = (settingsButton == &m_generalSettings.ccSelectTemplate)
? m_generalSettings.ccTemplate
: m_generalSettings.caTemplate;
QTimer::singleShot(0, &m_generalSettings, [this, templateList, &targetSettings]() {
m_generalSettings.showSelectionDialog(templateList,
targetSettings,
Tr::tr("Select Template"),
Tr::tr("Templates:"));
});
}
void ConfigurationManager::selectUrl()
{
QStringList urls;
for (const auto &name : m_providersManager.providersNames()) {
const auto url = m_providersManager.getProviderByName(name)->url();
if (!urls.contains(url))
urls.append(url);
}
auto *settingsButton = qobject_cast<ButtonAspect *>(sender());
if (!settingsButton)
return;
auto &targetSettings = (settingsButton == &m_generalSettings.ccSetUrl)
? m_generalSettings.ccUrl
: m_generalSettings.caUrl;
QTimer::singleShot(0, &m_generalSettings, [this, urls, &targetSettings]() {
m_generalSettings.showSelectionDialog(urls,
targetSettings,
Tr::tr("Select URL"),
Tr::tr("URLs:"));
});
}
} // namespace QodeAssist

58
ConfigurationManager.hpp Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QObject>
#include "llmcore/PromptTemplateManager.hpp"
#include "llmcore/ProvidersManager.hpp"
#include "settings/GeneralSettings.hpp"
namespace QodeAssist {
class ConfigurationManager : public QObject
{
Q_OBJECT
public:
static ConfigurationManager &instance();
void init();
public slots:
void selectProvider();
void selectModel();
void selectTemplate();
void selectUrl();
private:
explicit ConfigurationManager(QObject *parent = nullptr);
~ConfigurationManager() = default;
ConfigurationManager(const ConfigurationManager &) = delete;
ConfigurationManager &operator=(const ConfigurationManager &) = delete;
Settings::GeneralSettings &m_generalSettings;
LLMCore::ProvidersManager &m_providersManager;
LLMCore::PromptTemplateManager &m_templateManger;
void setupConnections();
};
} // namespace QodeAssist

View File

@@ -24,7 +24,7 @@
#include <languageserverprotocol/lsptypes.h> #include <languageserverprotocol/lsptypes.h>
#include "core/ChangesManager.h" #include "core/ChangesManager.h"
#include "settings/ContextSettings.hpp" #include "settings/CodeCompletionSettings.hpp"
const QRegularExpression &getYearRegex() const QRegularExpression &getYearRegex()
{ {
@@ -214,11 +214,11 @@ LLMCore::ContextData DocumentContextReader::prepareContext(int lineNumber, int c
QString DocumentContextReader::getContextBefore(int lineNumber, int cursorPosition) const QString DocumentContextReader::getContextBefore(int lineNumber, int cursorPosition) const
{ {
if (Settings::contextSettings().readFullFile()) { if (Settings::codeCompletionSettings().readFullFile()) {
return readWholeFileBefore(lineNumber, cursorPosition); return readWholeFileBefore(lineNumber, cursorPosition);
} else { } else {
int effectiveStartLine; int effectiveStartLine;
int beforeCursor = Settings::contextSettings().readStringsBeforeCursor(); int beforeCursor = Settings::codeCompletionSettings().readStringsBeforeCursor();
if (m_copyrightInfo.found) { if (m_copyrightInfo.found) {
effectiveStartLine = qMax(m_copyrightInfo.endLine + 1, lineNumber - beforeCursor); effectiveStartLine = qMax(m_copyrightInfo.endLine + 1, lineNumber - beforeCursor);
} else { } else {
@@ -230,11 +230,11 @@ QString DocumentContextReader::getContextBefore(int lineNumber, int cursorPositi
QString DocumentContextReader::getContextAfter(int lineNumber, int cursorPosition) const QString DocumentContextReader::getContextAfter(int lineNumber, int cursorPosition) const
{ {
if (Settings::contextSettings().readFullFile()) { if (Settings::codeCompletionSettings().readFullFile()) {
return readWholeFileAfter(lineNumber, cursorPosition); return readWholeFileAfter(lineNumber, cursorPosition);
} else { } else {
int endLine = qMin(m_document->blockCount() - 1, int endLine = qMin(m_document->blockCount() - 1,
lineNumber + Settings::contextSettings().readStringsAfterCursor()); lineNumber + Settings::codeCompletionSettings().readStringsAfterCursor());
return getContextBetween(lineNumber + 1, endLine, -1); return getContextBetween(lineNumber + 1, endLine, -1);
} }
} }
@@ -243,10 +243,10 @@ QString DocumentContextReader::getInstructions() const
{ {
QString instructions; QString instructions;
if (Settings::contextSettings().useFilePathInContext()) if (Settings::codeCompletionSettings().useFilePathInContext())
instructions += getLanguageAndFileInfo(); instructions += getLanguageAndFileInfo();
if (Settings::contextSettings().useProjectChangesCache()) if (Settings::codeCompletionSettings().useProjectChangesCache())
instructions += ChangesManager::instance().getRecentChangesContext(m_textDocument); instructions += ChangesManager::instance().getRecentChangesContext(m_textDocument);
return instructions; return instructions;

View File

@@ -27,10 +27,10 @@
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include "DocumentContextReader.hpp" #include "DocumentContextReader.hpp"
#include "logger/Logger.hpp"
#include "llmcore/PromptTemplateManager.hpp" #include "llmcore/PromptTemplateManager.hpp"
#include "llmcore/ProvidersManager.hpp" #include "llmcore/ProvidersManager.hpp"
#include "settings/ContextSettings.hpp" #include "logger/Logger.hpp"
#include "settings/CodeCompletionSettings.hpp"
#include "settings/GeneralSettings.hpp" #include "settings/GeneralSettings.hpp"
namespace QodeAssist { namespace QodeAssist {
@@ -147,22 +147,30 @@ void LLMClientInterface::handleExit(const QJsonObject &request)
void LLMClientInterface::handleCompletion(const QJsonObject &request) void LLMClientInterface::handleCompletion(const QJsonObject &request)
{ {
auto updatedContext = prepareContext(request); auto updatedContext = prepareContext(request);
auto &completeSettings = Settings::codeCompletionSettings();
auto providerName = Settings::generalSettings().ccProvider();
auto provider = LLMCore::ProvidersManager::instance().getProviderByName(providerName);
auto templateName = Settings::generalSettings().ccTemplate();
auto promptTemplate = LLMCore::PromptTemplateManager::instance().getFimTemplateByName(
templateName);
LLMCore::LLMConfig config; LLMCore::LLMConfig config;
config.requestType = LLMCore::RequestType::Fim; config.requestType = LLMCore::RequestType::Fim;
config.provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider(); config.provider = provider;
config.promptTemplate = LLMCore::PromptTemplateManager::instance().getCurrentFimTemplate(); config.promptTemplate = promptTemplate;
config.url = QUrl(QString("%1%2").arg(Settings::generalSettings().url(), config.url = QUrl(
Settings::generalSettings().endPoint())); QString("%1%2").arg(Settings::generalSettings().ccUrl(), provider->completionEndpoint()));
config.providerRequest = {{"model", Settings::generalSettings().modelName.value()}, config.providerRequest = {{"model", Settings::generalSettings().ccModel()},
{"stream", true}, {"stream", true},
{"stop", {"stop",
QJsonArray::fromStringList(config.promptTemplate->stopWords())}}; QJsonArray::fromStringList(config.promptTemplate->stopWords())}};
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion(); config.multiLineCompletion = completeSettings.multiLineCompletion();
if (Settings::contextSettings().useSystemPrompt()) if (completeSettings.useSystemPrompt())
config.providerRequest["system"] = Settings::contextSettings().systemPrompt(); config.providerRequest["system"] = completeSettings.systemPrompt();
config.promptTemplate->prepareRequest(config.providerRequest, updatedContext); config.promptTemplate->prepareRequest(config.providerRequest, updatedContext);
config.provider->prepareRequest(config.providerRequest, LLMCore::RequestType::Fim); config.provider->prepareRequest(config.providerRequest, LLMCore::RequestType::Fim);

View File

@@ -1,6 +1,6 @@
{ {
"Name" : "QodeAssist", "Name" : "QodeAssist",
"Version" : "0.3.4", "Version" : "0.3.5",
"CompatVersion" : "${IDE_VERSION_COMPAT}", "CompatVersion" : "${IDE_VERSION_COMPAT}",
"Vendor" : "Petr Mironychev", "Vendor" : "Petr Mironychev",
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd", "Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",

View File

@@ -32,7 +32,7 @@
#include "LLMClientInterface.hpp" #include "LLMClientInterface.hpp"
#include "LLMSuggestion.hpp" #include "LLMSuggestion.hpp"
#include "core/ChangesManager.h" #include "core/ChangesManager.h"
#include "settings/ContextSettings.hpp" #include "settings/CodeCompletionSettings.hpp"
#include "settings/GeneralSettings.hpp" #include "settings/GeneralSettings.hpp"
using namespace LanguageServerProtocol; using namespace LanguageServerProtocol;
@@ -75,7 +75,7 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
this, this,
[this, document](int position, int charsRemoved, int charsAdded) { [this, document](int position, int charsRemoved, int charsAdded) {
Q_UNUSED(charsRemoved) Q_UNUSED(charsRemoved)
if (!Settings::generalSettings().enableAutoComplete()) if (!Settings::codeCompletionSettings().autoCompletion())
return; return;
auto project = ProjectManager::projectForFile(document->filePath()); auto project = ProjectManager::projectForFile(document->filePath());
@@ -86,7 +86,7 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
if (!textEditor || textEditor->document() != document) if (!textEditor || textEditor->document() != document)
return; return;
if (Settings::contextSettings().useProjectChangesCache()) if (Settings::codeCompletionSettings().useProjectChangesCache())
ChangesManager::instance().addChange(document, ChangesManager::instance().addChange(document,
position, position,
charsRemoved, charsRemoved,
@@ -102,12 +102,13 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
m_recentCharCount += charsAdded; m_recentCharCount += charsAdded;
if (m_typingTimer.elapsed() if (m_typingTimer.elapsed()
> Settings::generalSettings().autoCompletionTypingInterval()) { > Settings::codeCompletionSettings().autoCompletionTypingInterval()) {
m_recentCharCount = charsAdded; m_recentCharCount = charsAdded;
m_typingTimer.restart(); m_typingTimer.restart();
} }
if (m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold()) { if (m_recentCharCount
> Settings::codeCompletionSettings().autoCompletionCharThreshold()) {
scheduleRequest(widget); scheduleRequest(widget);
} }
}); });
@@ -154,7 +155,8 @@ void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor)
if (editor if (editor
&& editor->textCursor().position() && editor->textCursor().position()
== m_scheduledRequests[editor]->property("cursorPosition").toInt() == m_scheduledRequests[editor]->property("cursorPosition").toInt()
&& m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold()) && m_recentCharCount
> Settings::codeCompletionSettings().autoCompletionCharThreshold())
requestCompletions(editor); requestCompletions(editor);
}); });
connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() {
@@ -168,7 +170,7 @@ void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor)
} }
it.value()->setProperty("cursorPosition", editor->textCursor().position()); it.value()->setProperty("cursorPosition", editor->textCursor().position());
it.value()->start(Settings::generalSettings().startSuggestionTimer()); it.value()->start(Settings::codeCompletionSettings().startSuggestionTimer());
} }
void QodeAssistClient::handleCompletions(const GetCompletionRequest::Response &response, void QodeAssistClient::handleCompletions(const GetCompletionRequest::Response &response,
TextEditor::TextEditorWidget *editor) TextEditor::TextEditorWidget *editor)

View File

@@ -22,7 +22,7 @@
#include <QtQml> #include <QtQml>
#include <utils/aspects.h> #include <utils/aspects.h>
#include "GeneralSettings.hpp" #include "ChatAssistantSettings.hpp"
namespace QodeAssist::Chat { namespace QodeAssist::Chat {
@@ -30,7 +30,7 @@ ChatModel::ChatModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_totalTokens(0) , m_totalTokens(0)
{ {
auto &settings = Settings::generalSettings(); auto &settings = Settings::chatAssistantSettings();
connect(&settings.chatTokensThreshold, connect(&settings.chatTokensThreshold,
&Utils::BaseAspect::changed, &Utils::BaseAspect::changed,
@@ -183,7 +183,7 @@ int ChatModel::totalTokens() const
int ChatModel::tokensThreshold() const int ChatModel::tokensThreshold() const
{ {
auto &settings = Settings::generalSettings(); auto &settings = Settings::chatAssistantSettings();
return settings.chatTokensThreshold(); return settings.chatTokensThreshold();
} }

View File

@@ -22,6 +22,7 @@
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include "ChatAssistantSettings.hpp"
#include "GeneralSettings.hpp" #include "GeneralSettings.hpp"
namespace QodeAssist::Chat { namespace QodeAssist::Chat {
@@ -33,10 +34,16 @@ ChatRootView::ChatRootView(QQuickItem *parent)
{ {
auto &settings = Settings::generalSettings(); auto &settings = Settings::generalSettings();
connect(&settings.chatModelName, connect(&settings.caModel,
&Utils::BaseAspect::changed, &Utils::BaseAspect::changed,
this, this,
&ChatRootView::currentTemplateChanged); &ChatRootView::currentTemplateChanged);
connect(&Settings::chatAssistantSettings().sharingCurrentFile,
&Utils::BaseAspect::changed,
this,
&ChatRootView::isSharingCurrentFileChanged);
generateColors(); generateColors();
} }
@@ -50,9 +57,9 @@ QColor ChatRootView::backgroundColor() const
return Utils::creatorColor(Utils::Theme::BackgroundColorNormal); return Utils::creatorColor(Utils::Theme::BackgroundColorNormal);
} }
void ChatRootView::sendMessage(const QString &message) const void ChatRootView::sendMessage(const QString &message, bool sharingCurrentFile) const
{ {
m_clientInterface->sendMessage(message); m_clientInterface->sendMessage(message, sharingCurrentFile);
} }
void ChatRootView::copyToClipboard(const QString &text) void ChatRootView::copyToClipboard(const QString &text)
@@ -111,7 +118,7 @@ QColor ChatRootView::generateColor(const QColor &baseColor,
QString ChatRootView::currentTemplate() const QString ChatRootView::currentTemplate() const
{ {
auto &settings = Settings::generalSettings(); auto &settings = Settings::generalSettings();
return settings.chatModelName(); return settings.caModel();
} }
QColor ChatRootView::primaryColor() const QColor ChatRootView::primaryColor() const
@@ -129,4 +136,9 @@ QColor ChatRootView::codeColor() const
return m_codeColor; return m_codeColor;
} }
bool ChatRootView::isSharingCurrentFile() const
{
return Settings::chatAssistantSettings().sharingCurrentFile();
}
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat

View File

@@ -35,6 +35,8 @@ class ChatRootView : public QQuickItem
Q_PROPERTY(QColor primaryColor READ primaryColor CONSTANT FINAL) Q_PROPERTY(QColor primaryColor READ primaryColor CONSTANT FINAL)
Q_PROPERTY(QColor secondaryColor READ secondaryColor CONSTANT FINAL) Q_PROPERTY(QColor secondaryColor READ secondaryColor CONSTANT FINAL)
Q_PROPERTY(QColor codeColor READ codeColor CONSTANT FINAL) Q_PROPERTY(QColor codeColor READ codeColor CONSTANT FINAL)
Q_PROPERTY(bool isSharingCurrentFile READ isSharingCurrentFile NOTIFY
isSharingCurrentFileChanged FINAL)
QML_ELEMENT QML_ELEMENT
public: public:
@@ -49,8 +51,10 @@ public:
QColor codeColor() const; QColor codeColor() const;
bool isSharingCurrentFile() const;
public slots: public slots:
void sendMessage(const QString &message) const; void sendMessage(const QString &message, bool sharingCurrentFile = false) const;
void copyToClipboard(const QString &text); void copyToClipboard(const QString &text);
void cancelRequest(); void cancelRequest();
@@ -58,6 +62,8 @@ signals:
void chatModelChanged(); void chatModelChanged();
void currentTemplateChanged(); void currentTemplateChanged();
void isSharingCurrentFileChanged();
private: private:
void generateColors(); void generateColors();
QColor generateColor(const QColor &baseColor, QColor generateColor(const QColor &baseColor,

View File

@@ -1,3 +1,22 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ChatUtils.h" #include "ChatUtils.h"
#include <QClipboard> #include <QClipboard>

View File

@@ -1,3 +1,22 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include <qobject.h> #include <qobject.h>

View File

@@ -18,16 +18,26 @@
*/ */
#include "ClientInterface.hpp" #include "ClientInterface.hpp"
#include "ContextSettings.hpp"
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QUuid>
#include <texteditor/textdocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/idocument.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include "ChatAssistantSettings.hpp"
#include "GeneralSettings.hpp" #include "GeneralSettings.hpp"
#include "Logger.hpp" #include "Logger.hpp"
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
#include "ProvidersManager.hpp" #include "ProvidersManager.hpp"
#include <QJsonArray>
#include <QJsonDocument>
#include <QUuid>
namespace QodeAssist::Chat { namespace QodeAssist::Chat {
ClientInterface::ClientInterface(ChatModel *chatModel, QObject *parent) ClientInterface::ClientInterface(ChatModel *chatModel, QObject *parent)
@@ -54,42 +64,59 @@ ClientInterface::ClientInterface(ChatModel *chatModel, QObject *parent)
ClientInterface::~ClientInterface() = default; ClientInterface::~ClientInterface() = default;
void ClientInterface::sendMessage(const QString &message) void ClientInterface::sendMessage(const QString &message, bool includeCurrentFile)
{ {
cancelRequest(); cancelRequest();
LOG_MESSAGE("Sending message: " + message); auto &chatAssistantSettings = Settings::chatAssistantSettings();
LOG_MESSAGE("chatProvider " + Settings::generalSettings().chatLlmProviders.stringValue());
LOG_MESSAGE("chatTemplate " + Settings::generalSettings().chatPrompts.stringValue());
auto chatTemplate = LLMCore::PromptTemplateManager::instance().getCurrentChatTemplate(); auto providerName = Settings::generalSettings().caProvider();
auto chatProvider = LLMCore::ProvidersManager::instance().getCurrentChatProvider(); auto provider = LLMCore::ProvidersManager::instance().getProviderByName(providerName);
auto templateName = Settings::generalSettings().caTemplate();
auto promptTemplate = LLMCore::PromptTemplateManager::instance().getChatTemplateByName(
templateName);
LLMCore::ContextData context; LLMCore::ContextData context;
context.prefix = message; context.prefix = message;
context.suffix = ""; context.suffix = "";
if (Settings::contextSettings().useChatSystemPrompt())
context.systemPrompt = Settings::contextSettings().chatSystemPrompt(); QString systemPrompt = chatAssistantSettings.systemPrompt();
if (includeCurrentFile) {
QString fileContext = getCurrentFileContext();
if (!fileContext.isEmpty()) {
context.systemPrompt = QString("%1\n\n%2").arg(systemPrompt, fileContext);
LOG_MESSAGE("Using system prompt with file context");
} else {
context.systemPrompt = systemPrompt;
LOG_MESSAGE("Failed to get file context, using default system prompt");
}
} else {
context.systemPrompt = systemPrompt;
}
QJsonObject providerRequest; QJsonObject providerRequest;
providerRequest["model"] = Settings::generalSettings().chatModelName(); providerRequest["model"] = Settings::generalSettings().caModel();
providerRequest["stream"] = true; providerRequest["stream"] = true;
providerRequest["messages"] = m_chatModel->prepareMessagesForRequest(context); providerRequest["messages"] = m_chatModel->prepareMessagesForRequest(context);
if (!chatTemplate || !chatProvider) { if (promptTemplate)
LOG_MESSAGE("Check settings, provider or template are not set"); promptTemplate->prepareRequest(providerRequest, context);
} else
chatTemplate->prepareRequest(providerRequest, context); qWarning("No prompt template found");
chatProvider->prepareRequest(providerRequest, LLMCore::RequestType::Chat);
if (provider)
provider->prepareRequest(providerRequest, LLMCore::RequestType::Chat);
else
qWarning("No provider found");
LLMCore::LLMConfig config; LLMCore::LLMConfig config;
config.requestType = LLMCore::RequestType::Chat; config.requestType = LLMCore::RequestType::Chat;
config.provider = chatProvider; config.provider = provider;
config.promptTemplate = chatTemplate; config.promptTemplate = promptTemplate;
config.url = QString("%1%2").arg(Settings::generalSettings().chatUrl(), config.url = QString("%1%2").arg(Settings::generalSettings().caUrl(), provider->chatEndpoint());
Settings::generalSettings().chatEndPoint());
config.providerRequest = providerRequest; config.providerRequest = providerRequest;
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion(); config.multiLineCompletion = false;
QJsonObject request; QJsonObject request;
request["id"] = QUuid::createUuid().toString(); request["id"] = QUuid::createUuid().toString();
@@ -122,4 +149,28 @@ void ClientInterface::handleLLMResponse(const QString &response,
} }
} }
QString ClientInterface::getCurrentFileContext() const
{
auto currentEditor = Core::EditorManager::currentEditor();
if (!currentEditor) {
LOG_MESSAGE("No active editor found");
return QString();
}
auto textDocument = qobject_cast<TextEditor::TextDocument *>(currentEditor->document());
if (!textDocument) {
LOG_MESSAGE("Current document is not a text document");
return QString();
}
QString fileInfo = QString("Language: %1\nFile: %2\n\n")
.arg(textDocument->mimeType(), textDocument->filePath().toString());
QString content = textDocument->document()->toPlainText();
LOG_MESSAGE(QString("Got context from file: %1").arg(textDocument->filePath().toString()));
return QString("Current file context:\n%1\nFile content:\n%2").arg(fileInfo, content);
}
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat

View File

@@ -36,7 +36,7 @@ public:
explicit ClientInterface(ChatModel *chatModel, QObject *parent = nullptr); explicit ClientInterface(ChatModel *chatModel, QObject *parent = nullptr);
~ClientInterface(); ~ClientInterface();
void sendMessage(const QString &message); void sendMessage(const QString &message, bool includeCurrentFile = false);
void clearMessages(); void clearMessages();
void cancelRequest(); void cancelRequest();
@@ -45,6 +45,7 @@ signals:
private: private:
void handleLLMResponse(const QString &response, const QJsonObject &request, bool isComplete); void handleLLMResponse(const QString &response, const QJsonObject &request, bool isComplete);
QString getCurrentFileContext() const;
LLMCore::RequestHandler *m_requestHandler; LLMCore::RequestHandler *m_requestHandler;
ChatModel *m_chatModel; ChatModel *m_chatModel;

View File

@@ -137,6 +137,13 @@ ChatRootView {
text: qsTr("Clear Chat") text: qsTr("Clear Chat")
onClicked: clearChat() onClicked: clearChat()
} }
CheckBox {
id: sharingCurrentFile
text: "Share current file with models"
checked: root.isSharingCurrentFile
}
} }
} }
@@ -169,7 +176,7 @@ ChatRootView {
} }
function sendChatMessage() { function sendChatMessage() {
root.sendMessage(messageInput.text); root.sendMessage(messageInput.text, sharingCurrentFile.checked)
messageInput.text = "" messageInput.text = ""
scrollToBottom() scrollToBottom()
} }

View File

@@ -18,8 +18,7 @@
*/ */
#include "ChangesManager.h" #include "ChangesManager.h"
#include "logger/Logger.hpp" #include "settings/CodeCompletionSettings.hpp"
#include "settings/ContextSettings.hpp"
namespace QodeAssist { namespace QodeAssist {
@@ -61,7 +60,7 @@ void ChangesManager::addChange(TextEditor::TextDocument *document,
} else { } else {
documentQueue.enqueue(change); documentQueue.enqueue(change);
if (documentQueue.size() > Settings::contextSettings().maxChangesCacheSize()) { if (documentQueue.size() > Settings::codeCompletionSettings().maxChangesCacheSize()) {
documentQueue.dequeue(); documentQueue.dequeue();
} }
} }

View File

@@ -19,8 +19,6 @@
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
#include "Logger.hpp"
namespace QodeAssist::LLMCore { namespace QodeAssist::LLMCore {
PromptTemplateManager &PromptTemplateManager::instance() PromptTemplateManager &PromptTemplateManager::instance()
@@ -29,48 +27,6 @@ PromptTemplateManager &PromptTemplateManager::instance()
return instance; return instance;
} }
void PromptTemplateManager::setCurrentFimTemplate(const QString &name)
{
LOG_MESSAGE("Setting current FIM provider to: " + name);
if (!m_fimTemplates.contains(name) || m_fimTemplates[name] == nullptr) {
LOG_MESSAGE("Error to set current FIM template" + name);
return;
}
m_currentFimTemplate = m_fimTemplates[name];
}
PromptTemplate *PromptTemplateManager::getCurrentFimTemplate()
{
if (m_currentFimTemplate == nullptr) {
LOG_MESSAGE("Current fim provider is null, return first");
return m_fimTemplates.first();
}
return m_currentFimTemplate;
}
void PromptTemplateManager::setCurrentChatTemplate(const QString &name)
{
LOG_MESSAGE("Setting current chat provider to: " + name);
if (!m_chatTemplates.contains(name) || m_chatTemplates[name] == nullptr) {
LOG_MESSAGE("Error to set current chat template" + name);
return;
}
m_currentChatTemplate = m_chatTemplates[name];
}
PromptTemplate *PromptTemplateManager::getCurrentChatTemplate()
{
if (m_currentChatTemplate == nullptr) {
LOG_MESSAGE("Current chat provider is null, return first");
return m_chatTemplates.first();
}
return m_currentChatTemplate;
}
QStringList PromptTemplateManager::fimTemplatesNames() const QStringList PromptTemplateManager::fimTemplatesNames() const
{ {
return m_fimTemplates.keys(); return m_fimTemplates.keys();
@@ -87,4 +43,14 @@ PromptTemplateManager::~PromptTemplateManager()
qDeleteAll(m_chatTemplates); qDeleteAll(m_chatTemplates);
} }
PromptTemplate *PromptTemplateManager::getFimTemplateByName(const QString &templateName)
{
return m_fimTemplates[templateName];
}
PromptTemplate *PromptTemplateManager::getChatTemplateByName(const QString &templateName)
{
return m_chatTemplates[templateName];
}
} // namespace QodeAssist::LLMCore } // namespace QodeAssist::LLMCore

View File

@@ -46,11 +46,8 @@ public:
} }
} }
void setCurrentFimTemplate(const QString &name); PromptTemplate *getFimTemplateByName(const QString &templateName);
PromptTemplate *getCurrentFimTemplate(); PromptTemplate *getChatTemplateByName(const QString &templateName);
void setCurrentChatTemplate(const QString &name);
PromptTemplate *getCurrentChatTemplate();
QStringList fimTemplatesNames() const; QStringList fimTemplatesNames() const;
QStringList chatTemplatesNames() const; QStringList chatTemplatesNames() const;
@@ -62,8 +59,6 @@ private:
QMap<QString, PromptTemplate *> m_fimTemplates; QMap<QString, PromptTemplate *> m_fimTemplates;
QMap<QString, PromptTemplate *> m_chatTemplates; QMap<QString, PromptTemplate *> m_chatTemplates;
PromptTemplate *m_currentFimTemplate;
PromptTemplate *m_currentChatTemplate;
}; };
} // namespace QodeAssist::LLMCore } // namespace QodeAssist::LLMCore

View File

@@ -40,7 +40,7 @@ public:
virtual void prepareRequest(QJsonObject &request, RequestType type) = 0; virtual void prepareRequest(QJsonObject &request, RequestType type) = 0;
virtual bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) = 0; virtual bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) = 0;
virtual QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) = 0; virtual QList<QString> getInstalledModels(const QString &url) = 0;
}; };
} // namespace QodeAssist::LLMCore } // namespace QodeAssist::LLMCore

View File

@@ -18,8 +18,6 @@
*/ */
#include "ProvidersManager.hpp" #include "ProvidersManager.hpp"
#include "Logger.hpp"
#include <coreplugin/messagemanager.h>
namespace QodeAssist::LLMCore { namespace QodeAssist::LLMCore {
@@ -29,50 +27,6 @@ ProvidersManager &ProvidersManager::instance()
return instance; return instance;
} }
Provider *ProvidersManager::setCurrentFimProvider(const QString &name)
{
LOG_MESSAGE("Setting current FIM provider to: " + name);
if (!m_providers.contains(name)) {
LOG_MESSAGE("Can't find provider with name: " + name);
return nullptr;
}
m_currentFimProvider = m_providers[name];
return m_currentFimProvider;
}
Provider *ProvidersManager::setCurrentChatProvider(const QString &name)
{
LOG_MESSAGE("Setting current chat provider to: " + name);
if (!m_providers.contains(name)) {
LOG_MESSAGE("Can't find chat provider with name: " + name);
return nullptr;
}
m_currentChatProvider = m_providers[name];
return m_currentChatProvider;
}
Provider *ProvidersManager::getCurrentFimProvider()
{
if (m_currentFimProvider == nullptr) {
LOG_MESSAGE("Current fim provider is null, return first");
return m_providers.first();
}
return m_currentFimProvider;
}
Provider *ProvidersManager::getCurrentChatProvider()
{
if (m_currentChatProvider == nullptr) {
LOG_MESSAGE("Current chat provider is null, return first");
return m_providers.first();
}
return m_currentChatProvider;
}
QStringList ProvidersManager::providersNames() const QStringList ProvidersManager::providersNames() const
{ {
return m_providers.keys(); return m_providers.keys();
@@ -83,4 +37,9 @@ ProvidersManager::~ProvidersManager()
qDeleteAll(m_providers); qDeleteAll(m_providers);
} }
Provider *ProvidersManager::getProviderByName(const QString &providerName)
{
return m_providers[providerName];
}
} // namespace QodeAssist::LLMCore } // namespace QodeAssist::LLMCore

View File

@@ -21,6 +21,7 @@
#include <QString> #include <QString>
#include <QMap>
#include "Provider.hpp" #include "Provider.hpp"
namespace QodeAssist::LLMCore { namespace QodeAssist::LLMCore {
@@ -40,11 +41,7 @@ public:
m_providers[name] = provider; m_providers[name] = provider;
} }
Provider *setCurrentFimProvider(const QString &name); Provider *getProviderByName(const QString &providerName);
Provider *setCurrentChatProvider(const QString &name);
Provider *getCurrentFimProvider();
Provider *getCurrentChatProvider();
QStringList providersNames() const; QStringList providersNames() const;
@@ -54,8 +51,6 @@ private:
ProvidersManager &operator=(const ProvidersManager &) = delete; ProvidersManager &operator=(const ProvidersManager &) = delete;
QMap<QString, Provider *> m_providers; QMap<QString, Provider *> m_providers;
Provider *m_currentFimProvider = nullptr;
Provider *m_currentChatProvider = nullptr;
}; };
} // namespace QodeAssist::LLMCore } // namespace QodeAssist::LLMCore

View File

@@ -1,3 +1,22 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
namespace QodeAssist::LLMCore { namespace QodeAssist::LLMCore {

View File

@@ -26,7 +26,8 @@
#include <QNetworkReply> #include <QNetworkReply>
#include "logger/Logger.hpp" #include "logger/Logger.hpp"
#include "settings/PresetPromptsSettings.hpp" #include "settings/ChatAssistantSettings.hpp"
#include "settings/CodeCompletionSettings.hpp"
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
@@ -54,36 +55,43 @@ QString LMStudioProvider::chatEndpoint() const
void LMStudioProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type) void LMStudioProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
{ {
auto &promptSettings = Settings::presetPromptsSettings(); auto prepareMessages = [](QJsonObject &req) -> QJsonArray {
auto settings = promptSettings.getSettings(type); QJsonArray messages;
if (req.contains("system")) {
messages.append(
QJsonObject{{"role", "system"}, {"content", req.take("system").toString()}});
}
if (req.contains("prompt")) {
messages.append(
QJsonObject{{"role", "user"}, {"content", req.take("prompt").toString()}});
}
return messages;
};
QJsonArray messages; auto applyModelParams = [&request](const auto &settings) {
request["max_tokens"] = settings.maxTokens();
request["temperature"] = settings.temperature();
if (request.contains("system")) { if (settings.useTopP())
QJsonObject systemMessage{{"role", "system"}, request["top_p"] = settings.topP();
{"content", request.take("system").toString()}}; if (settings.useTopK())
messages.append(systemMessage); request["top_k"] = settings.topK();
} if (settings.useFrequencyPenalty())
request["frequency_penalty"] = settings.frequencyPenalty();
if (request.contains("prompt")) { if (settings.usePresencePenalty())
QJsonObject userMessage{{"role", "user"}, {"content", request.take("prompt").toString()}}; request["presence_penalty"] = settings.presencePenalty();
messages.append(userMessage); };
}
QJsonArray messages = prepareMessages(request);
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
request["messages"] = std::move(messages); request["messages"] = std::move(messages);
} }
request["max_tokens"] = settings.maxTokens; if (type == LLMCore::RequestType::Fim) {
request["temperature"] = settings.temperature; applyModelParams(Settings::codeCompletionSettings());
if (settings.useTopP) } else {
request["top_p"] = settings.topP; applyModelParams(Settings::chatAssistantSettings());
if (settings.useTopK) }
request["top_k"] = settings.topK;
if (settings.useFrequencyPenalty)
request["frequency_penalty"] = settings.frequencyPenalty;
if (settings.usePresencePenalty)
request["presence_penalty"] = settings.presencePenalty;
} }
bool LMStudioProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse) bool LMStudioProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse)
@@ -127,8 +135,7 @@ bool LMStudioProvider::handleResponse(QNetworkReply *reply, QString &accumulated
return isComplete; return isComplete;
} }
QList<QString> LMStudioProvider::getInstalledModels(const Utils::Environment &env, QList<QString> LMStudioProvider::getInstalledModels(const QString &url)
const QString &url)
{ {
QList<QString> models; QList<QString> models;
QNetworkAccessManager manager; QNetworkAccessManager manager;

View File

@@ -34,7 +34,7 @@ public:
QString chatEndpoint() const override; QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override; void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override; bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override; QList<QString> getInstalledModels(const QString &url) override;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@@ -25,9 +25,9 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QtCore/qeventloop.h> #include <QtCore/qeventloop.h>
#include "llmcore/PromptTemplateManager.hpp"
#include "logger/Logger.hpp" #include "logger/Logger.hpp"
#include "settings/PresetPromptsSettings.hpp" #include "settings/ChatAssistantSettings.hpp"
#include "settings/CodeCompletionSettings.hpp"
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
@@ -55,22 +55,29 @@ QString OllamaProvider::chatEndpoint() const
void OllamaProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type) void OllamaProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
{ {
auto &promptSettings = Settings::presetPromptsSettings(); auto applySettings = [&request](const auto &settings) {
auto settings = promptSettings.getSettings(type); QJsonObject options;
options["num_predict"] = settings.maxTokens();
options["temperature"] = settings.temperature();
QJsonObject options; if (settings.useTopP())
options["num_predict"] = settings.maxTokens; options["top_p"] = settings.topP();
options["temperature"] = settings.temperature; if (settings.useTopK())
if (settings.useTopP) options["top_k"] = settings.topK();
options["top_p"] = settings.topP; if (settings.useFrequencyPenalty())
if (settings.useTopK) options["frequency_penalty"] = settings.frequencyPenalty();
options["top_k"] = settings.topK; if (settings.usePresencePenalty())
if (settings.useFrequencyPenalty) options["presence_penalty"] = settings.presencePenalty();
options["frequency_penalty"] = settings.frequencyPenalty;
if (settings.usePresencePenalty) request["options"] = options;
options["presence_penalty"] = settings.presencePenalty; request["keep_alive"] = settings.ollamaLivetime();
request["options"] = options; };
request["keep_alive"] = settings.ollamaLivetime;
if (type == LLMCore::RequestType::Fim) {
applySettings(Settings::codeCompletionSettings());
} else {
applySettings(Settings::chatAssistantSettings());
}
} }
bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse) bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse)
@@ -124,7 +131,7 @@ bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedRe
return isComplete; return isComplete;
} }
QList<QString> OllamaProvider::getInstalledModels(const Utils::Environment &env, const QString &url) QList<QString> OllamaProvider::getInstalledModels(const QString &url)
{ {
QList<QString> models; QList<QString> models;
QNetworkAccessManager manager; QNetworkAccessManager manager;

View File

@@ -34,7 +34,7 @@ public:
QString chatEndpoint() const override; QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override; void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override; bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override; QList<QString> getInstalledModels(const QString &url) override;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@@ -18,14 +18,14 @@
*/ */
#include "OpenAICompatProvider.hpp" #include "OpenAICompatProvider.hpp"
#include "settings/ChatAssistantSettings.hpp"
#include "settings/CodeCompletionSettings.hpp"
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include "settings/PresetPromptsSettings.hpp"
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
OpenAICompatProvider::OpenAICompatProvider() {} OpenAICompatProvider::OpenAICompatProvider() {}
@@ -52,39 +52,42 @@ QString OpenAICompatProvider::chatEndpoint() const
void OpenAICompatProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type) void OpenAICompatProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
{ {
auto &promptSettings = Settings::presetPromptsSettings(); auto prepareMessages = [](QJsonObject &req) -> QJsonArray {
auto settings = promptSettings.getSettings(type); QJsonArray messages;
QJsonArray messages; if (req.contains("system")) {
messages.append(
QJsonObject{{"role", "system"}, {"content", req.take("system").toString()}});
}
if (req.contains("prompt")) {
messages.append(
QJsonObject{{"role", "user"}, {"content", req.take("prompt").toString()}});
}
return messages;
};
if (request.contains("system")) { auto applyModelParams = [&request](const auto &settings) {
QJsonObject systemMessage{{"role", "system"}, request["max_tokens"] = settings.maxTokens();
{"content", request.take("system").toString()}}; request["temperature"] = settings.temperature();
messages.append(systemMessage);
}
if (request.contains("prompt")) { if (settings.useTopP())
QJsonObject userMessage{{"role", "user"}, {"content", request.take("prompt").toString()}}; request["top_p"] = settings.topP();
messages.append(userMessage); if (settings.useTopK())
} request["top_k"] = settings.topK();
if (settings.useFrequencyPenalty())
request["frequency_penalty"] = settings.frequencyPenalty();
if (settings.usePresencePenalty())
request["presence_penalty"] = settings.presencePenalty();
};
QJsonArray messages = prepareMessages(request);
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
request["messages"] = std::move(messages); request["messages"] = std::move(messages);
} }
request["max_tokens"] = settings.maxTokens; if (type == LLMCore::RequestType::Fim) {
request["temperature"] = settings.temperature; applyModelParams(Settings::codeCompletionSettings());
if (settings.useTopP) } else {
request["top_p"] = settings.topP; applyModelParams(Settings::chatAssistantSettings());
if (settings.useTopK)
request["top_k"] = settings.topK;
if (settings.useFrequencyPenalty)
request["frequency_penalty"] = settings.frequencyPenalty;
if (settings.usePresencePenalty)
request["presence_penalty"] = settings.presencePenalty;
const QString &apiKey = settings.apiKey;
if (!apiKey.isEmpty()) {
request["api_key"] = apiKey;
} }
} }
@@ -129,8 +132,7 @@ bool OpenAICompatProvider::handleResponse(QNetworkReply *reply, QString &accumul
return isComplete; return isComplete;
} }
QList<QString> OpenAICompatProvider::getInstalledModels(const Utils::Environment &env, QList<QString> OpenAICompatProvider::getInstalledModels(const QString &url)
const QString &url)
{ {
return QStringList(); return QStringList();
} }

View File

@@ -34,7 +34,7 @@ public:
QString chatEndpoint() const override; QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override; void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override; bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override; QList<QString> getInstalledModels(const QString &url) override;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@@ -39,6 +39,7 @@
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <utils/icon.h> #include <utils/icon.h>
#include "ConfigurationManager.hpp"
#include "QodeAssistClient.hpp" #include "QodeAssistClient.hpp"
#include "chat/ChatOutputPane.h" #include "chat/ChatOutputPane.h"
#include "chat/NavigationPanel.hpp" #include "chat/NavigationPanel.hpp"
@@ -125,6 +126,8 @@ public:
m_chatOutputPane = new Chat::ChatOutputPane(this); m_chatOutputPane = new Chat::ChatOutputPane(this);
m_navigationPanel = new Chat::NavigationPanel(); m_navigationPanel = new Chat::NavigationPanel();
ConfigurationManager::instance().init();
} }
void extensionsInitialized() final void extensionsInitialized() final

45
settings/ButtonAspect.hpp Normal file
View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QPushButton>
#include <utils/aspects.h>
#include <utils/layoutbuilder.h>
class ButtonAspect : public Utils::BaseAspect
{
Q_OBJECT
public:
ButtonAspect(Utils::AspectContainer *container = nullptr)
: Utils::BaseAspect(container)
{}
void addToLayout(Layouting::Layout &parent) override
{
auto button = new QPushButton(m_buttonText);
connect(button, &QPushButton::clicked, this, &ButtonAspect::clicked);
parent.addItem(button);
}
QString m_buttonText;
signals:
void clicked();
};

View File

@@ -1,10 +1,12 @@
add_library(QodeAssistSettings STATIC add_library(QodeAssistSettings STATIC
GeneralSettings.hpp GeneralSettings.cpp GeneralSettings.hpp GeneralSettings.cpp
ContextSettings.hpp ContextSettings.cpp
CustomPromptSettings.hpp CustomPromptSettings.cpp CustomPromptSettings.hpp CustomPromptSettings.cpp
PresetPromptsSettings.hpp PresetPromptsSettings.cpp
SettingsUtils.hpp SettingsUtils.hpp
SettingsConstants.hpp SettingsConstants.hpp
ButtonAspect.hpp
SettingsTr.hpp
CodeCompletionSettings.hpp CodeCompletionSettings.cpp
ChatAssistantSettings.hpp ChatAssistantSettings.cpp
) )
target_link_libraries(QodeAssistSettings target_link_libraries(QodeAssistSettings
@@ -14,7 +16,5 @@ target_link_libraries(QodeAssistSettings
QtCreator::Core QtCreator::Core
QtCreator::Utils QtCreator::Utils
QodeAssistLogger QodeAssistLogger
PRIVATE
LLMCore
) )
target_include_directories(QodeAssistSettings PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(QodeAssistSettings PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -0,0 +1,236 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ChatAssistantSettings.hpp"
#include <QMessageBox>
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icore.h>
#include <utils/layoutbuilder.h>
#include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp"
namespace QodeAssist::Settings {
ChatAssistantSettings &chatAssistantSettings()
{
static ChatAssistantSettings settings;
return settings;
}
ChatAssistantSettings::ChatAssistantSettings()
{
setAutoApply(false);
setDisplayName(Tr::tr("Chat Assistant"));
// Chat Settings
chatTokensThreshold.setSettingsKey(Constants::CA_TOKENS_THRESHOLD);
chatTokensThreshold.setLabelText(Tr::tr("Chat History Token Limit:"));
chatTokensThreshold.setToolTip(Tr::tr("Maximum number of tokens in chat history. When "
"exceeded, oldest messages will be removed."));
chatTokensThreshold.setRange(1000, 16000);
chatTokensThreshold.setDefaultValue(8000);
sharingCurrentFile.setSettingsKey(Constants::CA_SHARING_CURRENT_FILE);
sharingCurrentFile.setLabelText(Tr::tr("Share Current File With Assistant by Default"));
sharingCurrentFile.setDefaultValue(true);
// General Parameters Settings
temperature.setSettingsKey(Constants::CA_TEMPERATURE);
temperature.setLabelText(Tr::tr("Temperature:"));
temperature.setDefaultValue(0.5);
temperature.setRange(0.0, 2.0);
temperature.setSingleStep(0.1);
maxTokens.setSettingsKey(Constants::CA_MAX_TOKENS);
maxTokens.setLabelText(Tr::tr("Max Tokens:"));
maxTokens.setRange(-1, 10000);
maxTokens.setDefaultValue(2000);
// Advanced Parameters
useTopP.setSettingsKey(Constants::CA_USE_TOP_P);
useTopP.setDefaultValue(false);
useTopP.setLabelText(Tr::tr("Top P:"));
topP.setSettingsKey(Constants::CA_TOP_P);
topP.setDefaultValue(0.9);
topP.setRange(0.0, 1.0);
topP.setSingleStep(0.1);
useTopK.setSettingsKey(Constants::CA_USE_TOP_K);
useTopK.setDefaultValue(false);
useTopK.setLabelText(Tr::tr("Top K:"));
topK.setSettingsKey(Constants::CA_TOP_K);
topK.setDefaultValue(50);
topK.setRange(1, 1000);
usePresencePenalty.setSettingsKey(Constants::CA_USE_PRESENCE_PENALTY);
usePresencePenalty.setDefaultValue(false);
usePresencePenalty.setLabelText(Tr::tr("Presence Penalty:"));
presencePenalty.setSettingsKey(Constants::CA_PRESENCE_PENALTY);
presencePenalty.setDefaultValue(0.0);
presencePenalty.setRange(-2.0, 2.0);
presencePenalty.setSingleStep(0.1);
useFrequencyPenalty.setSettingsKey(Constants::CA_USE_FREQUENCY_PENALTY);
useFrequencyPenalty.setDefaultValue(false);
useFrequencyPenalty.setLabelText(Tr::tr("Frequency Penalty:"));
frequencyPenalty.setSettingsKey(Constants::CA_FREQUENCY_PENALTY);
frequencyPenalty.setDefaultValue(0.0);
frequencyPenalty.setRange(-2.0, 2.0);
frequencyPenalty.setSingleStep(0.1);
// Context Settings
useSystemPrompt.setSettingsKey(Constants::CA_USE_SYSTEM_PROMPT);
useSystemPrompt.setDefaultValue(true);
useSystemPrompt.setLabelText(Tr::tr("Use System Prompt"));
systemPrompt.setSettingsKey(Constants::CA_SYSTEM_PROMPT);
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
systemPrompt.setDefaultValue(
"You are an advanced AI assistant specializing in C++, Qt, and QML development. Your role "
"is to provide helpful, accurate, and detailed responses to questions about coding, "
"debugging, "
"and best practices in these technologies.");
// Ollama Settings
ollamaLivetime.setSettingsKey(Constants::CA_OLLAMA_LIVETIME);
ollamaLivetime.setToolTip(
Tr::tr("Time to suspend Ollama after completion request (in minutes), "
"Only Ollama, -1 to disable"));
ollamaLivetime.setLabelText("Livetime:");
ollamaLivetime.setDefaultValue("5m");
ollamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
contextWindow.setSettingsKey(Constants::CA_OLLAMA_CONTEXT_WINDOW);
contextWindow.setLabelText(Tr::tr("Context Window:"));
contextWindow.setRange(-1, 10000);
contextWindow.setDefaultValue(2048);
// API Configuration Settings
apiKey.setSettingsKey(Constants::CA_API_KEY);
apiKey.setLabelText(Tr::tr("API Key:"));
apiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
apiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
resetToDefaults.m_buttonText = TrConstants::RESET_TO_DEFAULTS;
readSettings();
setupConnections();
setLayouter([this]() {
using namespace Layouting;
auto genGrid = Grid{};
genGrid.addRow({Row{temperature}});
genGrid.addRow({Row{maxTokens}});
auto advancedGrid = Grid{};
advancedGrid.addRow({useTopP, topP});
advancedGrid.addRow({useTopK, topK});
advancedGrid.addRow({usePresencePenalty, presencePenalty});
advancedGrid.addRow({useFrequencyPenalty, frequencyPenalty});
auto ollamaGrid = Grid{};
ollamaGrid.addRow({ollamaLivetime});
ollamaGrid.addRow({contextWindow});
return Column{Row{Stretch{1}, resetToDefaults},
Space{8},
Group{title(Tr::tr("Chat Settings")),
Column{Row{chatTokensThreshold, Stretch{1}}, sharingCurrentFile}},
Space{8},
Group{
title(Tr::tr("General Parameters")),
Row{genGrid, Stretch{1}},
},
Space{8},
Group{title(Tr::tr("Advanced Parameters")),
Column{Row{advancedGrid, Stretch{1}}}},
Space{8},
Group{title(Tr::tr("Context Settings")),
Column{
Row{useSystemPrompt, Stretch{1}},
systemPrompt,
}},
Group{title(Tr::tr("Ollama Settings")), Column{Row{ollamaGrid, Stretch{1}}}},
Space{8},
Group{title(Tr::tr("API Configuration")), Column{apiKey}},
Stretch{1}};
});
}
void ChatAssistantSettings::setupConnections()
{
connect(&resetToDefaults,
&ButtonAspect::clicked,
this,
&ChatAssistantSettings::resetSettingsToDefaults);
}
void ChatAssistantSettings::resetSettingsToDefaults()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
Core::ICore::dialogParent(),
Tr::tr("Reset Settings"),
Tr::tr("Are you sure you want to reset all settings to default values?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
resetAspect(chatTokensThreshold);
resetAspect(temperature);
resetAspect(maxTokens);
resetAspect(useTopP);
resetAspect(topP);
resetAspect(useTopK);
resetAspect(topK);
resetAspect(usePresencePenalty);
resetAspect(presencePenalty);
resetAspect(useFrequencyPenalty);
resetAspect(frequencyPenalty);
resetAspect(useSystemPrompt);
resetAspect(systemPrompt);
resetAspect(ollamaLivetime);
resetAspect(contextWindow);
}
}
class ChatAssistantSettingsPage : public Core::IOptionsPage
{
public:
ChatAssistantSettingsPage()
{
setId(Constants::QODE_ASSIST_CHAT_ASSISTANT_SETTINGS_PAGE_ID);
setDisplayName(Tr::tr("Chat Assistant"));
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
setSettingsProvider([] { return &chatAssistantSettings(); });
}
};
const ChatAssistantSettingsPage chatAssistantSettingsPage;
} // namespace QodeAssist::Settings

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <utils/aspects.h>
#include "ButtonAspect.hpp"
namespace QodeAssist::Settings {
class ChatAssistantSettings : public Utils::AspectContainer
{
public:
ChatAssistantSettings();
ButtonAspect resetToDefaults{this};
// Chat settings
Utils::IntegerAspect chatTokensThreshold{this};
Utils::BoolAspect sharingCurrentFile{this};
// General Parameters Settings
Utils::DoubleAspect temperature{this};
Utils::IntegerAspect maxTokens{this};
// Advanced Parameters
Utils::BoolAspect useTopP{this};
Utils::DoubleAspect topP{this};
Utils::BoolAspect useTopK{this};
Utils::IntegerAspect topK{this};
Utils::BoolAspect usePresencePenalty{this};
Utils::DoubleAspect presencePenalty{this};
Utils::BoolAspect useFrequencyPenalty{this};
Utils::DoubleAspect frequencyPenalty{this};
// Context Settings
Utils::BoolAspect useSystemPrompt{this};
Utils::StringAspect systemPrompt{this};
// Ollama Settings
Utils::StringAspect ollamaLivetime{this};
Utils::IntegerAspect contextWindow{this};
// API Configuration Settings
Utils::StringAspect apiKey{this};
private:
void setupConnections();
void resetSettingsToDefaults();
};
ChatAssistantSettings &chatAssistantSettings();
} // namespace QodeAssist::Settings

View File

@@ -0,0 +1,317 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#include "CodeCompletionSettings.hpp"
#include <QMessageBox>
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icore.h>
#include <utils/layoutbuilder.h>
#include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp"
namespace QodeAssist::Settings {
CodeCompletionSettings &codeCompletionSettings()
{
static CodeCompletionSettings settings;
return settings;
}
CodeCompletionSettings::CodeCompletionSettings()
{
setAutoApply(false);
setDisplayName(Tr::tr("Code Completion"));
// Auto Completion Settings
autoCompletion.setSettingsKey(Constants::CC_AUTO_COMPLETION);
autoCompletion.setLabelText(Tr::tr("Enable Auto Complete"));
autoCompletion.setDefaultValue(true);
multiLineCompletion.setSettingsKey(Constants::CC_MULTILINE_COMPLETION);
multiLineCompletion.setDefaultValue(false);
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion(experimental)"));
startSuggestionTimer.setSettingsKey(Constants::СС_START_SUGGESTION_TIMER);
startSuggestionTimer.setLabelText(Tr::tr("with delay(ms)"));
startSuggestionTimer.setRange(10, 10000);
startSuggestionTimer.setDefaultValue(500);
autoCompletionCharThreshold.setSettingsKey(Constants::СС_AUTO_COMPLETION_CHAR_THRESHOLD);
autoCompletionCharThreshold.setLabelText(Tr::tr("AI suggestion triggers after typing"));
autoCompletionCharThreshold.setToolTip(
Tr::tr("The number of characters that need to be typed within the typing interval "
"before an AI suggestion request is sent."));
autoCompletionCharThreshold.setRange(0, 10);
autoCompletionCharThreshold.setDefaultValue(0);
autoCompletionTypingInterval.setSettingsKey(Constants::СС_AUTO_COMPLETION_TYPING_INTERVAL);
autoCompletionTypingInterval.setLabelText(Tr::tr("character(s) within(ms)"));
autoCompletionTypingInterval.setToolTip(
Tr::tr("The time window (in milliseconds) during which the character threshold "
"must be met to trigger an AI suggestion request."));
autoCompletionTypingInterval.setRange(500, 5000);
autoCompletionTypingInterval.setDefaultValue(2000);
// General Parameters Settings
temperature.setSettingsKey(Constants::CC_TEMPERATURE);
temperature.setLabelText(Tr::tr("Temperature:"));
temperature.setDefaultValue(0.2);
temperature.setRange(0.0, 2.0);
temperature.setSingleStep(0.1);
maxTokens.setSettingsKey(Constants::CC_MAX_TOKENS);
maxTokens.setLabelText(Tr::tr("Max Tokens:"));
maxTokens.setRange(-1, 10000);
maxTokens.setDefaultValue(50);
// Advanced Parameters
useTopP.setSettingsKey(Constants::CC_USE_TOP_P);
useTopP.setDefaultValue(false);
useTopP.setLabelText(Tr::tr("Top P:"));
topP.setSettingsKey(Constants::CC_TOP_P);
topP.setDefaultValue(0.9);
topP.setRange(0.0, 1.0);
topP.setSingleStep(0.1);
useTopK.setSettingsKey(Constants::CC_USE_TOP_K);
useTopK.setDefaultValue(false);
useTopK.setLabelText(Tr::tr("Top K:"));
topK.setSettingsKey(Constants::CC_TOP_K);
topK.setDefaultValue(50);
topK.setRange(1, 1000);
usePresencePenalty.setSettingsKey(Constants::CC_USE_PRESENCE_PENALTY);
usePresencePenalty.setDefaultValue(false);
usePresencePenalty.setLabelText(Tr::tr("Presence Penalty:"));
presencePenalty.setSettingsKey(Constants::CC_PRESENCE_PENALTY);
presencePenalty.setDefaultValue(0.0);
presencePenalty.setRange(-2.0, 2.0);
presencePenalty.setSingleStep(0.1);
useFrequencyPenalty.setSettingsKey(Constants::CC_USE_FREQUENCY_PENALTY);
useFrequencyPenalty.setDefaultValue(false);
useFrequencyPenalty.setLabelText(Tr::tr("Frequency Penalty:"));
frequencyPenalty.setSettingsKey(Constants::CC_FREQUENCY_PENALTY);
frequencyPenalty.setDefaultValue(0.0);
frequencyPenalty.setRange(-2.0, 2.0);
frequencyPenalty.setSingleStep(0.1);
// Context Settings
readFullFile.setSettingsKey(Constants::CC_READ_FULL_FILE);
readFullFile.setLabelText(Tr::tr("Read Full File"));
readFullFile.setDefaultValue(false);
readFileParts.setLabelText(Tr::tr("Read Strings Before Cursor:"));
readFileParts.setDefaultValue(true);
readStringsBeforeCursor.setSettingsKey(Constants::CC_READ_STRINGS_BEFORE_CURSOR);
readStringsBeforeCursor.setRange(0, 10000);
readStringsBeforeCursor.setDefaultValue(50);
readStringsAfterCursor.setSettingsKey(Constants::CC_READ_STRINGS_AFTER_CURSOR);
readStringsAfterCursor.setLabelText(Tr::tr("Read Strings After Cursor:"));
readStringsAfterCursor.setRange(0, 10000);
readStringsAfterCursor.setDefaultValue(30);
useSystemPrompt.setSettingsKey(Constants::CC_USE_SYSTEM_PROMPT);
useSystemPrompt.setDefaultValue(true);
useSystemPrompt.setLabelText(Tr::tr("Use System Prompt"));
systemPrompt.setSettingsKey(Constants::CC_SYSTEM_PROMPT);
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
systemPrompt.setDefaultValue(
"You are an expert C++, Qt, and QML code completion AI. Your task is to provide accurate "
"and contextually appropriate code suggestions.");
useFilePathInContext.setSettingsKey(Constants::CC_USE_FILE_PATH_IN_CONTEXT);
useFilePathInContext.setDefaultValue(false);
useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context"));
useProjectChangesCache.setSettingsKey(Constants::CC_USE_PROJECT_CHANGES_CACHE);
useProjectChangesCache.setDefaultValue(true);
useProjectChangesCache.setLabelText(Tr::tr("Max Changes Cache Size:"));
maxChangesCacheSize.setSettingsKey(Constants::CC_MAX_CHANGES_CACHE_SIZE);
maxChangesCacheSize.setRange(2, 1000);
maxChangesCacheSize.setDefaultValue(10);
// Ollama Settings
ollamaLivetime.setSettingsKey(Constants::CC_OLLAMA_LIVETIME);
ollamaLivetime.setToolTip(
Tr::tr("Time to suspend Ollama after completion request (in minutes), "
"Only Ollama, -1 to disable"));
ollamaLivetime.setLabelText("Livetime:");
ollamaLivetime.setDefaultValue("5m");
ollamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
contextWindow.setSettingsKey(Constants::CC_OLLAMA_CONTEXT_WINDOW);
contextWindow.setLabelText(Tr::tr("Context Window:"));
contextWindow.setRange(-1, 10000);
contextWindow.setDefaultValue(2048);
// API Configuration Settings
apiKey.setSettingsKey(Constants::CC_API_KEY);
apiKey.setLabelText(Tr::tr("API Key:"));
apiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
apiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
readSettings();
readFileParts.setValue(!readFullFile.value());
setupConnections();
setLayouter([this]() {
using namespace Layouting;
auto genGrid = Grid{};
genGrid.addRow({Row{temperature}});
genGrid.addRow({Row{maxTokens}});
auto advancedGrid = Grid{};
advancedGrid.addRow({useTopP, topP});
advancedGrid.addRow({useTopK, topK});
advancedGrid.addRow({usePresencePenalty, presencePenalty});
advancedGrid.addRow({useFrequencyPenalty, frequencyPenalty});
auto ollamaGrid = Grid{};
ollamaGrid.addRow({ollamaLivetime});
ollamaGrid.addRow({contextWindow});
auto contextGrid = Grid{};
contextGrid.addRow({Row{readFullFile}});
contextGrid.addRow({Row{readFileParts, readStringsBeforeCursor, readStringsAfterCursor}});
auto contextItem = Column{Row{contextGrid, Stretch{1}},
Row{useSystemPrompt, Stretch{1}},
systemPrompt,
Row{useFilePathInContext, Stretch{1}},
Row{useProjectChangesCache, maxChangesCacheSize, Stretch{1}}};
return Column{Row{Stretch{1}, resetToDefaults},
Space{8},
Group{title(Tr::tr("Auto Completion Settings")),
Column{autoCompletion,
Space{8},
multiLineCompletion,
Row{autoCompletionCharThreshold,
autoCompletionTypingInterval,
startSuggestionTimer,
Stretch{1}}}},
Space{8},
Group{title(Tr::tr("General Parameters")),
Column{
Row{genGrid, Stretch{1}},
}},
Space{8},
Group{title(Tr::tr("Advanced Parameters")),
Column{Row{advancedGrid, Stretch{1}}}},
Space{8},
Group{title(Tr::tr("Context Settings")), contextItem},
Space{8},
Group{title(Tr::tr("Ollama Settings")), Column{Row{ollamaGrid, Stretch{1}}}},
Space{8},
Group{title(Tr::tr("API Configuration")), Column{apiKey}},
Stretch{1}};
});
}
void CodeCompletionSettings::setupConnections()
{
connect(&resetToDefaults,
&ButtonAspect::clicked,
this,
&CodeCompletionSettings::resetSettingsToDefaults);
connect(&readFullFile, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
if (readFullFile.volatileValue()) {
readFileParts.setValue(false);
writeSettings();
}
});
connect(&readFileParts, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
if (readFileParts.volatileValue()) {
readFullFile.setValue(false);
writeSettings();
}
});
}
void CodeCompletionSettings::resetSettingsToDefaults()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
Core::ICore::dialogParent(),
Tr::tr("Reset Settings"),
Tr::tr("Are you sure you want to reset all settings to default values?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
resetAspect(autoCompletion);
resetAspect(multiLineCompletion);
resetAspect(temperature);
resetAspect(maxTokens);
resetAspect(useTopP);
resetAspect(topP);
resetAspect(useTopK);
resetAspect(topK);
resetAspect(usePresencePenalty);
resetAspect(presencePenalty);
resetAspect(useFrequencyPenalty);
resetAspect(frequencyPenalty);
resetAspect(readFullFile);
resetAspect(readFileParts);
resetAspect(readStringsBeforeCursor);
resetAspect(readStringsAfterCursor);
resetAspect(useSystemPrompt);
resetAspect(systemPrompt);
resetAspect(useFilePathInContext);
resetAspect(useProjectChangesCache);
resetAspect(maxChangesCacheSize);
resetAspect(ollamaLivetime);
resetAspect(contextWindow);
}
}
class CodeCompletionSettingsPage : public Core::IOptionsPage
{
public:
CodeCompletionSettingsPage()
{
setId(Constants::QODE_ASSIST_CODE_COMPLETION_SETTINGS_PAGE_ID);
setDisplayName(Tr::tr("Code Completion"));
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
setSettingsProvider([] { return &codeCompletionSettings(); });
}
};
const CodeCompletionSettingsPage codeCompletionSettingsPage;
} // namespace QodeAssist::Settings

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <utils/aspects.h>
#include "ButtonAspect.hpp"
namespace QodeAssist::Settings {
class CodeCompletionSettings : public Utils::AspectContainer
{
public:
CodeCompletionSettings();
ButtonAspect resetToDefaults{this};
// Auto Completion Settings
Utils::BoolAspect autoCompletion{this};
Utils::BoolAspect multiLineCompletion{this};
Utils::IntegerAspect startSuggestionTimer{this};
Utils::IntegerAspect autoCompletionCharThreshold{this};
Utils::IntegerAspect autoCompletionTypingInterval{this};
// General Parameters Settings
Utils::DoubleAspect temperature{this};
Utils::IntegerAspect maxTokens{this};
// Advanced Parameters
Utils::BoolAspect useTopP{this};
Utils::DoubleAspect topP{this};
Utils::BoolAspect useTopK{this};
Utils::IntegerAspect topK{this};
Utils::BoolAspect usePresencePenalty{this};
Utils::DoubleAspect presencePenalty{this};
Utils::BoolAspect useFrequencyPenalty{this};
Utils::DoubleAspect frequencyPenalty{this};
// Context Settings
Utils::BoolAspect readFullFile{this};
Utils::BoolAspect readFileParts{this};
Utils::IntegerAspect readStringsBeforeCursor{this};
Utils::IntegerAspect readStringsAfterCursor{this};
Utils::BoolAspect useSystemPrompt{this};
Utils::StringAspect systemPrompt{this};
Utils::BoolAspect useFilePathInContext{this};
Utils::BoolAspect useProjectChangesCache{this};
Utils::IntegerAspect maxChangesCacheSize{this};
// Ollama Settings
Utils::StringAspect ollamaLivetime{this};
Utils::IntegerAspect contextWindow{this};
// API Configuration Settings
Utils::StringAspect apiKey{this};
private:
void setupConnections();
void resetSettingsToDefaults();
};
CodeCompletionSettings &codeCompletionSettings();
} // namespace QodeAssist::Settings

View File

@@ -25,6 +25,8 @@
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include "SettingsConstants.hpp" #include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
ContextSettings &contextSettings() ContextSettings &contextSettings()
@@ -39,29 +41,29 @@ ContextSettings::ContextSettings()
setDisplayName(Tr::tr("Context")); setDisplayName(Tr::tr("Context"));
readFullFile.setSettingsKey(Constants::READ_FULL_FILE); readFullFile.setSettingsKey(Constants::CC_READ_FULL_FILE);
readFullFile.setLabelText(Tr::tr("Read Full File")); readFullFile.setLabelText(Tr::tr("Read Full File"));
readFullFile.setDefaultValue(false); readFullFile.setDefaultValue(false);
readStringsBeforeCursor.setSettingsKey(Constants::READ_STRINGS_BEFORE_CURSOR); readStringsBeforeCursor.setSettingsKey(Constants::CC_READ_STRINGS_BEFORE_CURSOR);
readStringsBeforeCursor.setLabelText(Tr::tr("Read Strings Before Cursor")); readStringsBeforeCursor.setLabelText(Tr::tr("Read Strings Before Cursor"));
readStringsBeforeCursor.setRange(0, 10000); readStringsBeforeCursor.setRange(0, 10000);
readStringsBeforeCursor.setDefaultValue(50); readStringsBeforeCursor.setDefaultValue(50);
readStringsAfterCursor.setSettingsKey(Constants::READ_STRINGS_AFTER_CURSOR); readStringsAfterCursor.setSettingsKey(Constants::CC_READ_STRINGS_AFTER_CURSOR);
readStringsAfterCursor.setLabelText(Tr::tr("Read Strings After Cursor")); readStringsAfterCursor.setLabelText(Tr::tr("Read Strings After Cursor"));
readStringsAfterCursor.setRange(0, 10000); readStringsAfterCursor.setRange(0, 10000);
readStringsAfterCursor.setDefaultValue(30); readStringsAfterCursor.setDefaultValue(30);
useFilePathInContext.setSettingsKey(Constants::USE_FILE_PATH_IN_CONTEXT); useFilePathInContext.setSettingsKey(Constants::CC_USE_FILE_PATH_IN_CONTEXT);
useFilePathInContext.setDefaultValue(false); useFilePathInContext.setDefaultValue(false);
useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context")); useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context"));
useSystemPrompt.setSettingsKey(Constants::USE_SYSTEM_PROMPT); useSystemPrompt.setSettingsKey(Constants::CC_USE_SYSTEM_PROMPT);
useSystemPrompt.setDefaultValue(true); useSystemPrompt.setDefaultValue(true);
useSystemPrompt.setLabelText(Tr::tr("Use System Prompt")); useSystemPrompt.setLabelText(Tr::tr("Use System Prompt"));
systemPrompt.setSettingsKey(Constants::SYSTEM_PROMPT); systemPrompt.setSettingsKey(Constants::CC_SYSTEM_PROMPT);
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay); systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
systemPrompt.setDefaultValue( systemPrompt.setDefaultValue(
"You are an expert C++, Qt, and QML code completion AI. Your task is to provide accurate " "You are an expert C++, Qt, and QML code completion AI. Your task is to provide accurate "
@@ -71,11 +73,11 @@ ContextSettings::ContextSettings()
"Qt and QML-specific completions when appropriate. Avoid adding comments or explanations " "Qt and QML-specific completions when appropriate. Avoid adding comments or explanations "
"in your completions."); "in your completions.");
useChatSystemPrompt.setSettingsKey(Constants::USE_CHAT_SYSTEM_PROMPT); useChatSystemPrompt.setSettingsKey(Constants::CA_SYSTEM_PROMPT);
useChatSystemPrompt.setDefaultValue(true); useChatSystemPrompt.setDefaultValue(true);
useChatSystemPrompt.setLabelText(Tr::tr("Use System Prompt for chat")); useChatSystemPrompt.setLabelText(Tr::tr("Use System Prompt for chat"));
chatSystemPrompt.setSettingsKey(Constants::CHAT_SYSTEM_PROMPT); chatSystemPrompt.setSettingsKey(Constants::CA_SYSTEM_PROMPT);
chatSystemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay); chatSystemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
chatSystemPrompt.setDefaultValue( chatSystemPrompt.setDefaultValue(
"You are an advanced AI assistant specializing in C++, Qt, and QML development. Your role " "You are an advanced AI assistant specializing in C++, Qt, and QML development. Your role "
@@ -91,11 +93,11 @@ ContextSettings::ContextSettings()
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults"); resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
useProjectChangesCache.setSettingsKey(Constants::USE_PROJECT_CHANGES_CACHE); useProjectChangesCache.setSettingsKey(Constants::CC_USE_PROJECT_CHANGES_CACHE);
useProjectChangesCache.setDefaultValue(true); useProjectChangesCache.setDefaultValue(true);
useProjectChangesCache.setLabelText(Tr::tr("Use Project Changes Cache")); useProjectChangesCache.setLabelText(Tr::tr("Use Project Changes Cache"));
maxChangesCacheSize.setSettingsKey(Constants::MAX_CHANGES_CACHE_SIZE); maxChangesCacheSize.setSettingsKey(Constants::CC_MAX_CHANGES_CACHE_SIZE);
maxChangesCacheSize.setLabelText(Tr::tr("Max Changes Cache Size")); maxChangesCacheSize.setLabelText(Tr::tr("Max Changes Cache Size"));
maxChangesCacheSize.setRange(2, 1000); maxChangesCacheSize.setRange(2, 1000);
maxChangesCacheSize.setDefaultValue(20); maxChangesCacheSize.setDefaultValue(20);

View File

@@ -21,7 +21,7 @@
#include <utils/aspects.h> #include <utils/aspects.h>
#include "SettingsUtils.hpp" #include "ButtonAspect.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {

View File

@@ -27,6 +27,8 @@
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include "SettingsConstants.hpp" #include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {

View File

@@ -19,9 +19,10 @@
#pragma once #pragma once
#include "SettingsUtils.hpp"
#include <utils/aspects.h> #include <utils/aspects.h>
#include "ButtonAspect.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
class CustomPromptSettings : public Utils::AspectContainer class CustomPromptSettings : public Utils::AspectContainer

View File

@@ -27,10 +27,8 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include "Logger.hpp" #include "Logger.hpp"
#include "PromptTemplateManager.hpp"
#include "Provider.hpp"
#include "ProvidersManager.hpp"
#include "SettingsConstants.hpp" #include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp" #include "SettingsUtils.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
@@ -45,117 +43,63 @@ GeneralSettings::GeneralSettings()
{ {
setAutoApply(false); setAutoApply(false);
setDisplayName(Tr::tr("General")); setDisplayName(TrConstants::GENERAL);
enableQodeAssist.setSettingsKey(Constants::ENABLE_QODE_ASSIST); enableQodeAssist.setSettingsKey(Constants::ENABLE_QODE_ASSIST);
enableQodeAssist.setLabelText(Tr::tr("Enable Qode Assist")); enableQodeAssist.setLabelText(TrConstants::ENABLE_QODE_ASSIST);
enableQodeAssist.setDefaultValue(true); enableQodeAssist.setDefaultValue(true);
enableAutoComplete.setSettingsKey(Constants::ENABLE_AUTO_COMPLETE);
enableAutoComplete.setLabelText(Tr::tr("Enable Auto Complete"));
enableAutoComplete.setDefaultValue(true);
enableLogging.setSettingsKey(Constants::ENABLE_LOGGING); enableLogging.setSettingsKey(Constants::ENABLE_LOGGING);
enableLogging.setLabelText(Tr::tr("Enable Logging")); enableLogging.setLabelText(TrConstants::ENABLE_LOG);
enableLogging.setDefaultValue(false); enableLogging.setDefaultValue(false);
multiLineCompletion.setSettingsKey(Constants::MULTILINE_COMPLETION); resetToDefaults.m_buttonText = TrConstants::RESET_TO_DEFAULTS;
multiLineCompletion.setDefaultValue(false);
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion(experimental)"));
startSuggestionTimer.setSettingsKey(Constants::START_SUGGESTION_TIMER); initStringAspect(ccProvider, Constants::CC_PROVIDER, TrConstants::PROVIDER, "Ollama");
startSuggestionTimer.setLabelText(Tr::tr("with delay(ms)")); ccProvider.setReadOnly(true);
startSuggestionTimer.setRange(10, 10000); ccSelectProvider.m_buttonText = TrConstants::SELECT;
startSuggestionTimer.setDefaultValue(500);
autoCompletionCharThreshold.setSettingsKey(Constants::AUTO_COMPLETION_CHAR_THRESHOLD); initStringAspect(ccModel, Constants::CC_MODEL, TrConstants::MODEL, "codellama:7b-code");
autoCompletionCharThreshold.setLabelText(Tr::tr("AI suggestion triggers after typing")); ccModel.setHistoryCompleter(Constants::CC_MODEL_HISTORY);
autoCompletionCharThreshold.setToolTip( ccSelectModel.m_buttonText = TrConstants::SELECT;
Tr::tr("The number of characters that need to be typed within the typing interval "
"before an AI suggestion request is sent."));
autoCompletionCharThreshold.setRange(0, 10);
autoCompletionCharThreshold.setDefaultValue(0);
autoCompletionTypingInterval.setSettingsKey(Constants::AUTO_COMPLETION_TYPING_INTERVAL); initStringAspect(ccTemplate, Constants::CC_TEMPLATE, TrConstants::TEMPLATE, "CodeLlama FIM");
autoCompletionTypingInterval.setLabelText(Tr::tr("character(s) within(ms)")); ccTemplate.setReadOnly(true);
autoCompletionTypingInterval.setToolTip( ccSelectTemplate.m_buttonText = TrConstants::SELECT;
Tr::tr("The time window (in milliseconds) during which the character threshold "
"must be met to trigger an AI suggestion request."));
autoCompletionTypingInterval.setRange(500, 5000);
autoCompletionTypingInterval.setDefaultValue(2000);
llmProviders.setSettingsKey(Constants::LLM_PROVIDERS); initStringAspect(ccUrl, Constants::CC_URL, TrConstants::URL, "http://localhost:11434");
llmProviders.setDisplayName(Tr::tr("AI Suggest Provider:")); ccUrl.setHistoryCompleter(Constants::CC_URL_HISTORY);
llmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); ccSetUrl.m_buttonText = TrConstants::SELECT;
url.setSettingsKey(Constants::URL); ccStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
url.setLabelText(Tr::tr("URL:")); ccStatus.setLabelText(TrConstants::STATUS);
url.setDisplayStyle(Utils::StringAspect::LineEditDisplay); ccStatus.setDefaultValue("");
ccTest.m_buttonText = TrConstants::TEST;
endPoint.setSettingsKey(Constants::END_POINT); initStringAspect(caProvider, Constants::CA_PROVIDER, TrConstants::PROVIDER, "Ollama");
endPoint.setLabelText(Tr::tr("FIM Endpoint:")); caProvider.setReadOnly(true);
endPoint.setDisplayStyle(Utils::StringAspect::LineEditDisplay); caSelectProvider.m_buttonText = TrConstants::SELECT;
modelName.setSettingsKey(Constants::MODEL_NAME); initStringAspect(caModel, Constants::CA_MODEL, TrConstants::MODEL, "codellama:7b-instruct");
modelName.setLabelText(Tr::tr("Model name:")); caModel.setHistoryCompleter(Constants::CA_MODEL_HISTORY);
modelName.setDisplayStyle(Utils::StringAspect::LineEditDisplay); caSelectModel.m_buttonText = TrConstants::SELECT;
selectModels.m_buttonText = Tr::tr("Select Fill-In-the-Middle Model"); initStringAspect(caTemplate, Constants::CA_TEMPLATE, TrConstants::TEMPLATE, "CodeLlama Chat");
caTemplate.setReadOnly(true);
fimPrompts.setDisplayName(Tr::tr("Fill-In-the-Middle Prompt")); caSelectTemplate.m_buttonText = TrConstants::SELECT;
fimPrompts.setSettingsKey(Constants::FIM_PROMPTS);
fimPrompts.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
chatLlmProviders.setSettingsKey(Constants::CHAT_LLM_PROVIDERS); initStringAspect(caUrl, Constants::CA_URL, TrConstants::URL, "http://localhost:11434");
chatLlmProviders.setDisplayName(Tr::tr("AI Chat Provider:")); caUrl.setHistoryCompleter(Constants::CA_URL_HISTORY);
chatLlmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); caSetUrl.m_buttonText = TrConstants::SELECT;
chatUrl.setSettingsKey(Constants::CHAT_URL); caStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
chatUrl.setLabelText(Tr::tr("URL:")); caStatus.setLabelText(TrConstants::STATUS);
chatUrl.setDisplayStyle(Utils::StringAspect::LineEditDisplay); caStatus.setDefaultValue("");
caTest.m_buttonText = TrConstants::TEST;
chatEndPoint.setSettingsKey(Constants::CHAT_END_POINT);
chatEndPoint.setLabelText(Tr::tr("Chat Endpoint:"));
chatEndPoint.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
chatModelName.setSettingsKey(Constants::CHAT_MODEL_NAME);
chatModelName.setLabelText(Tr::tr("Model name:"));
chatModelName.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
chatSelectModels.m_buttonText = Tr::tr("Select Chat Model");
chatPrompts.setDisplayName(Tr::tr("Chat Prompt"));
chatPrompts.setSettingsKey(Constants::CHAT_PROMPTS);
chatPrompts.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
chatTokensThreshold.setSettingsKey(Constants::CHAT_TOKENS_THRESHOLD);
chatTokensThreshold.setLabelText(Tr::tr("Chat History Token Limit"));
chatTokensThreshold.setToolTip(Tr::tr("Maximum number of tokens in chat history. When "
"exceeded, oldest messages will be removed."));
chatTokensThreshold.setRange(1000, 16000);
chatTokensThreshold.setDefaultValue(8000);
loadProviders();
loadPrompts();
llmProviders.setDefaultValue(llmProviders.indexForDisplay("Ollama"));
chatLlmProviders.setDefaultValue(chatLlmProviders.indexForDisplay("Ollama"));
fimPrompts.setDefaultValue(fimPrompts.indexForDisplay("CodeLlama FIM"));
chatPrompts.setDefaultValue(chatPrompts.indexForDisplay("CodeLlama Chat"));
auto fimProviderName = llmProviders.displayForIndex(llmProviders.value());
setCurrentFimProvider(fimProviderName);
auto chatProviderName = chatLlmProviders.displayForIndex(chatLlmProviders.value());
setCurrentChatProvider(chatProviderName);
readSettings(); readSettings();
auto nameFimPromts = fimPrompts.displayForIndex(fimPrompts.value());
LLMCore::PromptTemplateManager::instance().setCurrentFimTemplate(nameFimPromts);
auto nameChatPromts = chatPrompts.displayForIndex(chatPrompts.value());
LLMCore::PromptTemplateManager::instance().setCurrentChatTemplate(nameChatPromts);
Logger::instance().setLoggingEnabled(enableLogging()); Logger::instance().setLoggingEnabled(enableLogging());
setupConnections(); setupConnections();
@@ -163,226 +107,88 @@ GeneralSettings::GeneralSettings()
setLayouter([this]() { setLayouter([this]() {
using namespace Layouting; using namespace Layouting;
auto rootLayout auto ccGrid = Grid{};
= Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults}, ccGrid.addRow({ccProvider, ccSelectProvider});
Row{enableLogging, Stretch{1}}, ccGrid.addRow({ccModel, ccSelectModel});
Space{8}, ccGrid.addRow({ccTemplate, ccSelectTemplate});
Group{title(Tr::tr("AI Suggestions")), ccGrid.addRow({ccUrl, ccSetUrl});
Column{enableAutoComplete, ccGrid.addRow({ccStatus, ccTest});
multiLineCompletion,
Row{autoCompletionCharThreshold, auto caGrid = Grid{};
autoCompletionTypingInterval, caGrid.addRow({caProvider, caSelectProvider});
startSuggestionTimer, caGrid.addRow({caModel, caSelectModel});
Stretch{1}}, caGrid.addRow({caTemplate, caSelectTemplate});
Row{llmProviders, Stretch{1}}, caGrid.addRow({caUrl, caSetUrl});
Row{url, endPoint, fimUrlIndicator}, caGrid.addRow({caStatus, caTest});
Row{selectModels, modelName, fimModelIndicator},
Row{fimPrompts, Stretch{1}}}}, auto ccGroup = Group{title(TrConstants::CODE_COMPLETION), ccGrid};
Space{16}, auto caGroup = Group{title(TrConstants::CHAT_ASSISTANT), caGrid};
Group{title(Tr::tr("AI Chat")),
Column{Row{chatLlmProviders, Stretch{1}}, auto rootLayout = Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults},
Row{chatUrl, chatEndPoint, chatUrlIndicator}, Row{enableLogging, Stretch{1}},
Row{chatSelectModels, chatModelName, chatModelIndicator}, Space{8},
Row{chatPrompts, Stretch{1}}, ccGroup,
Row{chatTokensThreshold, Stretch{1}}}}, Space{8},
Stretch{1}}; caGroup,
Stretch{1}};
return rootLayout; return rootLayout;
}); });
updateStatusIndicators();
} }
void GeneralSettings::setupConnections() void GeneralSettings::showSelectionDialog(const QStringList &data,
Utils::StringAspect &aspect,
const QString &title,
const QString &text)
{ {
connect(&llmProviders, &Utils::SelectionAspect::volatileValueChanged, this, [this]() { if (data.isEmpty())
auto providerName = llmProviders.displayForIndex(llmProviders.volatileValue()); return;
setCurrentFimProvider(providerName);
modelName.setVolatileValue("");
});
connect(&chatLlmProviders, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
auto providerName = chatLlmProviders.displayForIndex(chatLlmProviders.volatileValue());
setCurrentChatProvider(providerName);
chatModelName.setVolatileValue("");
});
connect(&fimPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() { bool ok;
int index = fimPrompts.volatileValue(); QInputDialog dialog(Core::ICore::dialogParent());
LLMCore::PromptTemplateManager::instance().setCurrentFimTemplate( dialog.setWindowTitle(title);
fimPrompts.displayForIndex(index)); dialog.setLabelText(text);
}); dialog.setComboBoxItems(data);
connect(&chatPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() { dialog.setComboBoxEditable(false);
int index = chatPrompts.volatileValue(); dialog.setFixedSize(400, 150);
LLMCore::PromptTemplateManager::instance().setCurrentChatTemplate(
chatPrompts.displayForIndex(index));
});
connect(&selectModels, &ButtonAspect::clicked, this, [this]() { if (dialog.exec() == QDialog::Accepted) {
auto *provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider(); QString result = dialog.textValue();
showModelSelectionDialog(&modelName, provider); if (!result.isEmpty()) {
}); aspect.setValue(result);
connect(&chatSelectModels, &ButtonAspect::clicked, this, [this]() {
auto *provider = LLMCore::ProvidersManager::instance().getCurrentChatProvider();
showModelSelectionDialog(&chatModelName, provider);
});
connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
Logger::instance().setLoggingEnabled(enableLogging.volatileValue());
});
connect(&resetToDefaults, &ButtonAspect::clicked, this, &GeneralSettings::resetPageToDefaults);
connect(&url,
&Utils::StringAspect::volatileValueChanged,
this,
&GeneralSettings::updateStatusIndicators);
connect(&modelName,
&Utils::StringAspect::volatileValueChanged,
this,
&GeneralSettings::updateStatusIndicators);
connect(&chatUrl,
&Utils::StringAspect::volatileValueChanged,
this,
&GeneralSettings::updateStatusIndicators);
connect(&chatModelName,
&Utils::StringAspect::volatileValueChanged,
this,
&GeneralSettings::updateStatusIndicators);
}
void GeneralSettings::showModelSelectionDialog(Utils::StringAspect *modelNameObj,
LLMCore::Provider *provider)
{
Utils::Environment env = Utils::Environment::systemEnvironment();
QString providerUrl = (modelNameObj == &modelName) ? url() : chatUrl();
if (provider) {
QStringList models = provider->getInstalledModels(env, providerUrl);
bool ok;
QString selectedModel = QInputDialog::getItem(Core::ICore::dialogParent(),
Tr::tr("Select LLM Model"),
Tr::tr("Choose a model:"),
models,
0,
false,
&ok);
if (ok && !selectedModel.isEmpty()) {
modelNameObj->setVolatileValue(selectedModel);
writeSettings(); writeSettings();
} }
} }
} }
void GeneralSettings::setupConnections()
{
connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
Logger::instance().setLoggingEnabled(enableLogging.volatileValue());
});
connect(&resetToDefaults, &ButtonAspect::clicked, this, &GeneralSettings::resetPageToDefaults);
}
void GeneralSettings::resetPageToDefaults() void GeneralSettings::resetPageToDefaults()
{ {
QMessageBox::StandardButton reply; QMessageBox::StandardButton reply;
reply = QMessageBox::question( reply = QMessageBox::question(Core::ICore::dialogParent(),
Core::ICore::dialogParent(), TrConstants::RESET_SETTINGS,
Tr::tr("Reset Settings"), TrConstants::CONFIRMATION,
Tr::tr("Are you sure you want to reset all settings to default values?"), QMessageBox::Yes | QMessageBox::No);
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) { if (reply == QMessageBox::Yes) {
resetAspect(enableQodeAssist); resetAspect(enableQodeAssist);
resetAspect(enableAutoComplete);
resetAspect(enableLogging); resetAspect(enableLogging);
resetAspect(startSuggestionTimer); resetAspect(ccProvider);
resetAspect(autoCompletionTypingInterval); resetAspect(ccModel);
resetAspect(autoCompletionCharThreshold); resetAspect(ccTemplate);
resetAspect(llmProviders); resetAspect(ccUrl);
resetAspect(chatLlmProviders); resetAspect(caProvider);
resetAspect(fimPrompts); resetAspect(caModel);
resetAspect(chatPrompts); resetAspect(caTemplate);
resetAspect(chatTokensThreshold); resetAspect(caUrl);
} writeSettings();
modelName.setVolatileValue("");
chatModelName.setVolatileValue("");
updateStatusIndicators();
}
void GeneralSettings::updateStatusIndicators()
{
bool fimUrlValid = !url.volatileValue().isEmpty() && !endPoint.volatileValue().isEmpty();
bool fimModelValid = !modelName.volatileValue().isEmpty();
bool chatUrlValid = !chatUrl.volatileValue().isEmpty()
&& !chatEndPoint.volatileValue().isEmpty();
bool chatModelValid = !chatModelName.volatileValue().isEmpty();
bool fimPingSuccessful = false;
if (fimUrlValid) {
QUrl pingUrl(url.volatileValue());
fimPingSuccessful = Settings::pingUrl(pingUrl);
}
bool chatPingSuccessful = false;
if (chatUrlValid) {
QUrl pingUrl(chatUrl.volatileValue());
chatPingSuccessful = Settings::pingUrl(pingUrl);
}
setIndicatorStatus(fimModelIndicator,
fimModelValid ? tr("Model is properly configured")
: tr("No model selected or model name is invalid"),
fimModelValid);
setIndicatorStatus(fimUrlIndicator,
fimPingSuccessful ? tr("Server is reachable")
: tr("Server is not reachable or URL is invalid"),
fimPingSuccessful);
setIndicatorStatus(chatModelIndicator,
chatModelValid ? tr("Model is properly configured")
: tr("No model selected or model name is invalid"),
chatModelValid);
setIndicatorStatus(chatUrlIndicator,
chatPingSuccessful ? tr("Server is reachable")
: tr("Server is not reachable or URL is invalid"),
chatPingSuccessful);
}
void GeneralSettings::setIndicatorStatus(Utils::StringAspect &indicator,
const QString &tooltip,
bool isValid)
{
const Utils::Icon &icon = isValid ? Utils::Icons::OK : Utils::Icons::WARNING;
indicator.setLabelPixmap(icon.pixmap());
indicator.setToolTip(tooltip);
}
void GeneralSettings::setCurrentFimProvider(const QString &name)
{
const auto provider = LLMCore::ProvidersManager::instance().setCurrentFimProvider(name);
if (!provider)
return;
url.setValue(provider->url());
endPoint.setValue(provider->completionEndpoint());
}
void GeneralSettings::setCurrentChatProvider(const QString &name)
{
const auto provider = LLMCore::ProvidersManager::instance().setCurrentChatProvider(name);
if (!provider)
return;
chatUrl.setValue(provider->url());
chatEndPoint.setValue(provider->chatEndpoint());
}
void GeneralSettings::loadProviders()
{
for (const auto &name : LLMCore::ProvidersManager::instance().providersNames()) {
llmProviders.addOption(name);
chatLlmProviders.addOption(name);
}
}
void GeneralSettings::loadPrompts()
{
for (const auto &name : LLMCore::PromptTemplateManager::instance().fimTemplatesNames()) {
fimPrompts.addOption(name);
}
for (const auto &name : LLMCore::PromptTemplateManager::instance().chatTemplatesNames()) {
chatPrompts.addOption(name);
} }
} }
@@ -392,7 +198,7 @@ public:
GeneralSettingsPage() GeneralSettingsPage()
{ {
setId(Constants::QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID); setId(Constants::QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID);
setDisplayName(Tr::tr("General")); setDisplayName(TrConstants::GENERAL);
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY); setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
setSettingsProvider([] { return &generalSettings(); }); setSettingsProvider([] { return &generalSettings(); });
} }

View File

@@ -21,7 +21,7 @@
#include <utils/aspects.h> #include <utils/aspects.h>
#include "SettingsUtils.hpp" #include "ButtonAspect.hpp"
namespace QodeAssist::LLMCore { namespace QodeAssist::LLMCore {
class Provider; class Provider;
@@ -34,50 +34,49 @@ public:
GeneralSettings(); GeneralSettings();
Utils::BoolAspect enableQodeAssist{this}; Utils::BoolAspect enableQodeAssist{this};
Utils::BoolAspect enableAutoComplete{this};
Utils::BoolAspect multiLineCompletion{this};
Utils::BoolAspect enableLogging{this}; Utils::BoolAspect enableLogging{this};
Utils::IntegerAspect startSuggestionTimer{this};
Utils::IntegerAspect autoCompletionCharThreshold{this};
Utils::IntegerAspect autoCompletionTypingInterval{this};
Utils::SelectionAspect llmProviders{this};
Utils::StringAspect url{this};
Utils::StringAspect endPoint{this};
Utils::StringAspect modelName{this};
ButtonAspect selectModels{this};
Utils::SelectionAspect fimPrompts{this};
ButtonAspect resetToDefaults{this}; ButtonAspect resetToDefaults{this};
Utils::SelectionAspect chatLlmProviders{this}; // code completion setttings
Utils::StringAspect chatUrl{this}; Utils::StringAspect ccProvider{this};
Utils::StringAspect chatEndPoint{this}; ButtonAspect ccSelectProvider{this};
Utils::StringAspect chatModelName{this}; Utils::StringAspect ccModel{this};
ButtonAspect chatSelectModels{this}; ButtonAspect ccSelectModel{this};
Utils::SelectionAspect chatPrompts{this};
Utils::StringAspect fimModelIndicator{this}; Utils::StringAspect ccTemplate{this};
Utils::StringAspect fimUrlIndicator{this}; ButtonAspect ccSelectTemplate{this};
Utils::StringAspect chatModelIndicator{this};
Utils::StringAspect chatUrlIndicator{this};
Utils::IntegerAspect chatTokensThreshold{this}; Utils::StringAspect ccUrl{this};
ButtonAspect ccSetUrl{this};
Utils::StringAspect ccStatus{this};
ButtonAspect ccTest{this};
// chat assistant settings
Utils::StringAspect caProvider{this};
ButtonAspect caSelectProvider{this};
Utils::StringAspect caModel{this};
ButtonAspect caSelectModel{this};
Utils::StringAspect caTemplate{this};
ButtonAspect caSelectTemplate{this};
Utils::StringAspect caUrl{this};
ButtonAspect caSetUrl{this};
Utils::StringAspect caStatus{this};
ButtonAspect caTest{this};
void showSelectionDialog(const QStringList &data,
Utils::StringAspect &aspect,
const QString &title = {},
const QString &text = {});
private: private:
void setupConnections(); void setupConnections();
void showModelSelectionDialog(Utils::StringAspect *modelNameObj, LLMCore::Provider *provider);
void resetPageToDefaults(); void resetPageToDefaults();
void updateStatusIndicators();
void setIndicatorStatus(Utils::StringAspect &indicator, const QString &tooltip, bool isValid);
void setCurrentFimProvider(const QString &name);
void setCurrentChatProvider(const QString &name);
void loadProviders();
void loadPrompts();
}; };
GeneralSettings &generalSettings(); GeneralSettings &generalSettings();

View File

@@ -24,8 +24,9 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include "RequestType.hpp"
#include "SettingsConstants.hpp" #include "SettingsConstants.hpp"
#include "SettingsTr.hpp"
#include "SettingsUtils.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
@@ -41,118 +42,118 @@ PresetPromptsSettings::PresetPromptsSettings()
setDisplayName(Tr::tr("Preset Prompts Params")); setDisplayName(Tr::tr("Preset Prompts Params"));
fimTemperature.setSettingsKey(Constants::FIM_TEMPERATURE); fimTemperature.setSettingsKey(Constants::CC_TEMPERATURE);
fimTemperature.setLabelText(Tr::tr("Temperature:")); fimTemperature.setLabelText(Tr::tr("Temperature:"));
fimTemperature.setDefaultValue(0.2); fimTemperature.setDefaultValue(0.2);
fimTemperature.setRange(0.0, 10.0); fimTemperature.setRange(0.0, 10.0);
fimTemperature.setSingleStep(0.1); fimTemperature.setSingleStep(0.1);
chatTemperature.setSettingsKey(Constants::CHAT_TEMPERATURE); chatTemperature.setSettingsKey(Constants::CA_TEMPERATURE);
chatTemperature.setLabelText(Tr::tr("Temperature:")); chatTemperature.setLabelText(Tr::tr("Temperature:"));
chatTemperature.setDefaultValue(0.5); chatTemperature.setDefaultValue(0.5);
chatTemperature.setRange(0.0, 10.0); chatTemperature.setRange(0.0, 10.0);
chatTemperature.setSingleStep(0.1); chatTemperature.setSingleStep(0.1);
fimOllamaLivetime.setSettingsKey(Constants::FIM_OLLAMA_LIVETIME); fimOllamaLivetime.setSettingsKey(Constants::CC_OLLAMA_LIVETIME);
fimOllamaLivetime.setLabelText( fimOllamaLivetime.setLabelText(
Tr::tr("Time to suspend Ollama after completion request (in minutes), " Tr::tr("Time to suspend Ollama after completion request (in minutes), "
"Only Ollama, -1 to disable")); "Only Ollama, -1 to disable"));
fimOllamaLivetime.setDefaultValue("5m"); fimOllamaLivetime.setDefaultValue("5m");
fimOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay); fimOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
chatOllamaLivetime.setSettingsKey(Constants::CHAT_OLLAMA_LIVETIME); chatOllamaLivetime.setSettingsKey(Constants::CA_OLLAMA_LIVETIME);
chatOllamaLivetime.setLabelText( chatOllamaLivetime.setLabelText(
Tr::tr("Time to suspend Ollama after completion request (in minutes), " Tr::tr("Time to suspend Ollama after completion request (in minutes), "
"Only Ollama, -1 to disable")); "Only Ollama, -1 to disable"));
chatOllamaLivetime.setDefaultValue("5m"); chatOllamaLivetime.setDefaultValue("5m");
chatOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay); chatOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
fimMaxTokens.setSettingsKey(Constants::FIM_MAX_TOKENS); fimMaxTokens.setSettingsKey(Constants::CC_MAX_TOKENS);
fimMaxTokens.setLabelText(Tr::tr("Max Tokens")); fimMaxTokens.setLabelText(Tr::tr("Max Tokens"));
fimMaxTokens.setRange(-1, 10000); fimMaxTokens.setRange(-1, 10000);
fimMaxTokens.setDefaultValue(50); fimMaxTokens.setDefaultValue(50);
chatMaxTokens.setSettingsKey(Constants::CHAT_MAX_TOKENS); chatMaxTokens.setSettingsKey(Constants::CA_MAX_TOKENS);
chatMaxTokens.setLabelText(Tr::tr("Max Tokens")); chatMaxTokens.setLabelText(Tr::tr("Max Tokens"));
chatMaxTokens.setRange(-1, 10000); chatMaxTokens.setRange(-1, 10000);
chatMaxTokens.setDefaultValue(2000); chatMaxTokens.setDefaultValue(2000);
fimUseTopP.setSettingsKey(Constants::FIM_USE_TOP_P); fimUseTopP.setSettingsKey(Constants::CC_USE_TOP_P);
fimUseTopP.setDefaultValue(false); fimUseTopP.setDefaultValue(false);
fimTopP.setSettingsKey(Constants::FIM_TOP_P); fimTopP.setSettingsKey(Constants::CC_TOP_P);
fimTopP.setLabelText(Tr::tr("use top_p")); fimTopP.setLabelText(Tr::tr("use top_p"));
fimTopP.setDefaultValue(0.9); fimTopP.setDefaultValue(0.9);
fimTopP.setRange(0.0, 1.0); fimTopP.setRange(0.0, 1.0);
fimTopP.setSingleStep(0.1); fimTopP.setSingleStep(0.1);
chatUseTopP.setSettingsKey(Constants::CHAT_USE_TOP_P); chatUseTopP.setSettingsKey(Constants::CA_USE_TOP_P);
chatUseTopP.setDefaultValue(false); chatUseTopP.setDefaultValue(false);
chatTopP.setSettingsKey(Constants::CHAT_TOP_P); chatTopP.setSettingsKey(Constants::CA_TOP_P);
chatTopP.setLabelText(Tr::tr("use top_p")); chatTopP.setLabelText(Tr::tr("use top_p"));
chatTopP.setDefaultValue(0.9); chatTopP.setDefaultValue(0.9);
chatTopP.setRange(0.0, 1.0); chatTopP.setRange(0.0, 1.0);
chatTopP.setSingleStep(0.1); chatTopP.setSingleStep(0.1);
fimUseTopK.setSettingsKey(Constants::FIM_USE_TOP_K); fimUseTopK.setSettingsKey(Constants::CC_USE_TOP_K);
fimUseTopK.setDefaultValue(false); fimUseTopK.setDefaultValue(false);
fimTopK.setSettingsKey(Constants::FIM_TOP_K); fimTopK.setSettingsKey(Constants::CC_TOP_K);
fimTopK.setLabelText(Tr::tr("use top_k")); fimTopK.setLabelText(Tr::tr("use top_k"));
fimTopK.setDefaultValue(50); fimTopK.setDefaultValue(50);
fimTopK.setRange(1, 1000); fimTopK.setRange(1, 1000);
chatUseTopK.setSettingsKey(Constants::CHAT_USE_TOP_K); chatUseTopK.setSettingsKey(Constants::CA_USE_TOP_K);
chatUseTopK.setDefaultValue(false); chatUseTopK.setDefaultValue(false);
chatTopK.setSettingsKey(Constants::CHAT_TOP_K); chatTopK.setSettingsKey(Constants::CA_TOP_K);
chatTopK.setLabelText(Tr::tr("use top_k")); chatTopK.setLabelText(Tr::tr("use top_k"));
chatTopK.setDefaultValue(50); chatTopK.setDefaultValue(50);
chatTopK.setRange(1, 1000); chatTopK.setRange(1, 1000);
fimUsePresencePenalty.setSettingsKey(Constants::FIM_USE_PRESENCE_PENALTY); fimUsePresencePenalty.setSettingsKey(Constants::CC_USE_PRESENCE_PENALTY);
fimUsePresencePenalty.setDefaultValue(false); fimUsePresencePenalty.setDefaultValue(false);
fimPresencePenalty.setSettingsKey(Constants::FIM_PRESENCE_PENALTY); fimPresencePenalty.setSettingsKey(Constants::CC_PRESENCE_PENALTY);
fimPresencePenalty.setLabelText(Tr::tr("use presence_penalty")); fimPresencePenalty.setLabelText(Tr::tr("use presence_penalty"));
fimPresencePenalty.setDefaultValue(0.0); fimPresencePenalty.setDefaultValue(0.0);
fimPresencePenalty.setRange(-2.0, 2.0); fimPresencePenalty.setRange(-2.0, 2.0);
fimPresencePenalty.setSingleStep(0.1); fimPresencePenalty.setSingleStep(0.1);
chatUsePresencePenalty.setSettingsKey(Constants::CHAT_USE_PRESENCE_PENALTY); chatUsePresencePenalty.setSettingsKey(Constants::CA_USE_PRESENCE_PENALTY);
chatUsePresencePenalty.setDefaultValue(false); chatUsePresencePenalty.setDefaultValue(false);
chatPresencePenalty.setSettingsKey(Constants::CHAT_PRESENCE_PENALTY); chatPresencePenalty.setSettingsKey(Constants::CA_PRESENCE_PENALTY);
chatPresencePenalty.setLabelText(Tr::tr("use presence_penalty")); chatPresencePenalty.setLabelText(Tr::tr("use presence_penalty"));
chatPresencePenalty.setDefaultValue(0.0); chatPresencePenalty.setDefaultValue(0.0);
chatPresencePenalty.setRange(-2.0, 2.0); chatPresencePenalty.setRange(-2.0, 2.0);
chatPresencePenalty.setSingleStep(0.1); chatPresencePenalty.setSingleStep(0.1);
fimUseFrequencyPenalty.setSettingsKey(Constants::FIM_USE_FREQUENCY_PENALTY); fimUseFrequencyPenalty.setSettingsKey(Constants::CC_USE_FREQUENCY_PENALTY);
fimUseFrequencyPenalty.setDefaultValue(false); fimUseFrequencyPenalty.setDefaultValue(false);
fimFrequencyPenalty.setSettingsKey(Constants::FIM_FREQUENCY_PENALTY); fimFrequencyPenalty.setSettingsKey(Constants::CC_FREQUENCY_PENALTY);
fimFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty")); fimFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty"));
fimFrequencyPenalty.setDefaultValue(0.0); fimFrequencyPenalty.setDefaultValue(0.0);
fimFrequencyPenalty.setRange(-2.0, 2.0); fimFrequencyPenalty.setRange(-2.0, 2.0);
fimFrequencyPenalty.setSingleStep(0.1); fimFrequencyPenalty.setSingleStep(0.1);
chatUseFrequencyPenalty.setSettingsKey(Constants::CHAT_USE_FREQUENCY_PENALTY); chatUseFrequencyPenalty.setSettingsKey(Constants::CA_USE_FREQUENCY_PENALTY);
chatUseFrequencyPenalty.setDefaultValue(false); chatUseFrequencyPenalty.setDefaultValue(false);
chatFrequencyPenalty.setSettingsKey(Constants::CHAT_FREQUENCY_PENALTY); chatFrequencyPenalty.setSettingsKey(Constants::CA_FREQUENCY_PENALTY);
chatFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty")); chatFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty"));
chatFrequencyPenalty.setDefaultValue(0.0); chatFrequencyPenalty.setDefaultValue(0.0);
chatFrequencyPenalty.setRange(-2.0, 2.0); chatFrequencyPenalty.setRange(-2.0, 2.0);
chatFrequencyPenalty.setSingleStep(0.1); chatFrequencyPenalty.setSingleStep(0.1);
fimApiKey.setSettingsKey(Constants::FIM_API_KEY); fimApiKey.setSettingsKey(Constants::CC_API_KEY);
fimApiKey.setLabelText(Tr::tr("API Key:")); fimApiKey.setLabelText(Tr::tr("API Key:"));
fimApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay); fimApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
fimApiKey.setPlaceHolderText(Tr::tr("Enter your API key here")); fimApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
chatApiKey.setSettingsKey(Constants::CHAT_API_KEY); chatApiKey.setSettingsKey(Constants::CA_API_KEY);
chatApiKey.setLabelText(Tr::tr("API Key:")); chatApiKey.setLabelText(Tr::tr("API Key:"));
chatApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay); chatApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
chatApiKey.setPlaceHolderText(Tr::tr("Enter your API key here")); chatApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
@@ -191,9 +192,8 @@ PresetPromptsSettings::PresetPromptsSettings()
PresetPromptsSettings::PromptSettings PresetPromptsSettings::getSettings(int type) const PresetPromptsSettings::PromptSettings PresetPromptsSettings::getSettings(int type) const
{ {
auto reqtype = static_cast<LLMCore::RequestType>(type);
PromptSettings settings; PromptSettings settings;
if (reqtype == LLMCore::RequestType::Fim) { if (type == 0) {
settings.temperature = fimTemperature(); settings.temperature = fimTemperature();
settings.maxTokens = fimMaxTokens(); settings.maxTokens = fimMaxTokens();
settings.useTopP = fimUseTopP(); settings.useTopP = fimUseTopP();
@@ -206,7 +206,7 @@ PresetPromptsSettings::PromptSettings PresetPromptsSettings::getSettings(int typ
settings.frequencyPenalty = fimFrequencyPenalty(); settings.frequencyPenalty = fimFrequencyPenalty();
settings.ollamaLivetime = fimOllamaLivetime(); settings.ollamaLivetime = fimOllamaLivetime();
settings.apiKey = fimApiKey(); settings.apiKey = fimApiKey();
} else if (reqtype == LLMCore::RequestType::Chat) { } else if (type = 1) {
settings.temperature = chatTemperature(); settings.temperature = chatTemperature();
settings.maxTokens = chatMaxTokens(); settings.maxTokens = chatMaxTokens();
settings.useTopP = chatUseTopP(); settings.useTopP = chatUseTopP();

View File

@@ -19,9 +19,10 @@
#pragma once #pragma once
#include "SettingsUtils.hpp"
#include <utils/aspects.h> #include <utils/aspects.h>
#include "ButtonAspect.hpp"
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
class PresetPromptsSettings : public Utils::AspectContainer class PresetPromptsSettings : public Utils::AspectContainer

View File

@@ -24,36 +24,41 @@ namespace QodeAssist::Constants {
const char ACTION_ID[] = "QodeAssist.Action"; const char ACTION_ID[] = "QodeAssist.Action";
const char MENU_ID[] = "QodeAssist.Menu"; const char MENU_ID[] = "QodeAssist.Menu";
// new settings
const char CC_PROVIDER[] = "QodeAssist.ccProvider";
const char CC_MODEL[] = "QodeAssist.ccModel";
const char CC_MODEL_HISTORY[] = "QodeAssist.ccModelHistory";
const char CC_TEMPLATE[] = "QodeAssist.ccTemplate";
const char CC_URL[] = "QodeAssist.ccUrl";
const char CC_URL_HISTORY[] = "QodeAssist.ccUrlHistory";
const char CA_PROVIDER[] = "QodeAssist.caProvider";
const char CA_MODEL[] = "QodeAssist.caModel";
const char CA_MODEL_HISTORY[] = "QodeAssist.caModelHistory";
const char CA_TEMPLATE[] = "QodeAssist.caTemplate";
const char CA_URL[] = "QodeAssist.caUrl";
const char CA_URL_HISTORY[] = "QodeAssist.caUrlHistory";
// settings // settings
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist"; const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
const char ENABLE_AUTO_COMPLETE[] = "QodeAssist.enableAutoComplete"; const char CC_AUTO_COMPLETION[] = "QodeAssist.ccAutoCompletion";
const char ENABLE_LOGGING[] = "QodeAssist.enableLogging"; const char ENABLE_LOGGING[] = "QodeAssist.enableLogging";
const char LLM_PROVIDERS[] = "QodeAssist.llmProviders";
const char URL[] = "QodeAssist.url";
const char END_POINT[] = "QodeAssist.endPoint";
const char MODEL_NAME[] = "QodeAssist.modelName";
const char SELECT_MODELS[] = "QodeAssist.selectModels";
const char FIM_PROMPTS[] = "QodeAssist.fimPrompts";
const char PROVIDER_PATHS[] = "QodeAssist.providerPaths"; const char PROVIDER_PATHS[] = "QodeAssist.providerPaths";
const char START_SUGGESTION_TIMER[] = "QodeAssist.startSuggestionTimer"; const char СС_START_SUGGESTION_TIMER[] = "QodeAssist.startSuggestionTimer";
const char AUTO_COMPLETION_CHAR_THRESHOLD[] = "QodeAssist.autoCompletionCharThreshold"; const char СС_AUTO_COMPLETION_CHAR_THRESHOLD[] = "QodeAssist.autoCompletionCharThreshold";
const char AUTO_COMPLETION_TYPING_INTERVAL[] = "QodeAssist.autoCompletionTypingInterval"; const char СС_AUTO_COMPLETION_TYPING_INTERVAL[] = "QodeAssist.autoCompletionTypingInterval";
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold"; const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
const char MULTILINE_COMPLETION[] = "QodeAssist.multilineCompletion"; const char CC_MULTILINE_COMPLETION[] = "QodeAssist.ccMultilineCompletion";
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate"; const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
const char CHAT_LLM_PROVIDERS[] = "QodeAssist.chatLlmProviders"; const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold";
const char CHAT_URL[] = "QodeAssist.chatUrl"; const char CA_SHARING_CURRENT_FILE[] = "QodeAssist.caSharingCurrentFile";
const char CHAT_END_POINT[] = "QodeAssist.chatEndPoint";
const char CHAT_MODEL_NAME[] = "QodeAssist.chatModelName";
const char CHAT_SELECT_MODELS[] = "QodeAssist.chatSelectModels";
const char CHAT_PROMPTS[] = "QodeAssist.chatPrompts";
const char CHAT_TOKENS_THRESHOLD[] = "QodeAssist.chatTokensThreshold";
const char QODE_ASSIST_GENERAL_OPTIONS_ID[] = "QodeAssist.GeneralOptions"; const char QODE_ASSIST_GENERAL_OPTIONS_ID[] = "QodeAssist.GeneralOptions";
const char QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID[] = "QodeAssist.1GeneralSettingsPageId"; const char QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID[] = "QodeAssist.1GeneralSettingsPageId";
const char QODE_ASSIST_CONTEXT_SETTINGS_PAGE_ID[] = "QodeAssist.2ContextSettingsPageId"; const char QODE_ASSIST_CODE_COMPLETION_SETTINGS_PAGE_ID[]
const char QODE_ASSIST_PRESET_PROMPTS_SETTINGS_PAGE_ID[] = "QodeAssist.2CodeCompletionSettingsPageId";
= "QodeAssist.3PresetPromptsSettingsPageId"; const char QODE_ASSIST_CHAT_ASSISTANT_SETTINGS_PAGE_ID[]
= "QodeAssist.3ChatAssistantSettingsPageId";
const char QODE_ASSIST_CUSTOM_PROMPT_SETTINGS_PAGE_ID[] = "QodeAssist.4CustomPromptSettingsPageId"; const char QODE_ASSIST_CUSTOM_PROMPT_SETTINGS_PAGE_ID[] = "QodeAssist.4CustomPromptSettingsPageId";
const char QODE_ASSIST_GENERAL_OPTIONS_CATEGORY[] = "QodeAssist.Category"; const char QODE_ASSIST_GENERAL_OPTIONS_CATEGORY[] = "QodeAssist.Category";
@@ -62,41 +67,43 @@ const char QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY[] = "Qode Assist";
const char QODE_ASSIST_REQUEST_SUGGESTION[] = "QodeAssist.RequestSuggestion"; const char QODE_ASSIST_REQUEST_SUGGESTION[] = "QodeAssist.RequestSuggestion";
// context settings // context settings
const char READ_FULL_FILE[] = "QodeAssist.readFullFile"; const char CC_READ_FULL_FILE[] = "QodeAssist.ccReadFullFile";
const char READ_STRINGS_BEFORE_CURSOR[] = "QodeAssist.readStringsBeforeCursor"; const char CC_READ_STRINGS_BEFORE_CURSOR[] = "QodeAssist.ccReadStringsBeforeCursor";
const char READ_STRINGS_AFTER_CURSOR[] = "QodeAssist.readStringsAfterCursor"; const char CC_READ_STRINGS_AFTER_CURSOR[] = "QodeAssist.ccReadStringsAfterCursor";
const char USE_SYSTEM_PROMPT[] = "QodeAssist.useSystemPrompt"; const char CC_USE_SYSTEM_PROMPT[] = "QodeAssist.ccUseSystemPrompt";
const char USE_FILE_PATH_IN_CONTEXT[] = "QodeAssist.useFilePathInContext"; const char CC_USE_FILE_PATH_IN_CONTEXT[] = "QodeAssist.ccUseFilePathInContext";
const char SYSTEM_PROMPT[] = "QodeAssist.systemPrompt"; const char CC_SYSTEM_PROMPT[] = "QodeAssist.ccSystemPrompt";
const char USE_PROJECT_CHANGES_CACHE[] = "QodeAssist.useProjectChangesCache"; const char CC_USE_PROJECT_CHANGES_CACHE[] = "QodeAssist.ccUseProjectChangesCache";
const char MAX_CHANGES_CACHE_SIZE[] = "QodeAssist.maxChangesCacheSize"; const char CC_MAX_CHANGES_CACHE_SIZE[] = "QodeAssist.ccMaxChangesCacheSize";
const char USE_CHAT_SYSTEM_PROMPT[] = "QodeAssist.useChatSystemPrompt"; const char CA_USE_SYSTEM_PROMPT[] = "QodeAssist.useChatSystemPrompt";
const char CHAT_SYSTEM_PROMPT[] = "QodeAssist.chatSystemPrompt"; const char CA_SYSTEM_PROMPT[] = "QodeAssist.chatSystemPrompt";
// preset prompt settings // preset prompt settings
const char FIM_TEMPERATURE[] = "QodeAssist.fimTemperature"; const char CC_TEMPERATURE[] = "QodeAssist.ccTemperature";
const char FIM_MAX_TOKENS[] = "QodeAssist.fimMaxTokens"; const char CC_MAX_TOKENS[] = "QodeAssist.ccMaxTokens";
const char FIM_USE_TOP_P[] = "QodeAssist.fimUseTopP"; const char CC_USE_TOP_P[] = "QodeAssist.ccUseTopP";
const char FIM_TOP_P[] = "QodeAssist.fimTopP"; const char CC_TOP_P[] = "QodeAssist.ccTopP";
const char FIM_USE_TOP_K[] = "QodeAssist.fimUseTopK"; const char CC_USE_TOP_K[] = "QodeAssist.ccUseTopK";
const char FIM_TOP_K[] = "QodeAssist.fimTopK"; const char CC_TOP_K[] = "QodeAssist.ccTopK";
const char FIM_USE_PRESENCE_PENALTY[] = "QodeAssist.fimUsePresencePenalty"; const char CC_USE_PRESENCE_PENALTY[] = "QodeAssist.ccUsePresencePenalty";
const char FIM_PRESENCE_PENALTY[] = "QodeAssist.fimPresencePenalty"; const char CC_PRESENCE_PENALTY[] = "QodeAssist.ccPresencePenalty";
const char FIM_USE_FREQUENCY_PENALTY[] = "QodeAssist.fimUseFrequencyPenalty"; const char CC_USE_FREQUENCY_PENALTY[] = "QodeAssist.fimUseFrequencyPenalty";
const char FIM_FREQUENCY_PENALTY[] = "QodeAssist.fimFrequencyPenalty"; const char CC_FREQUENCY_PENALTY[] = "QodeAssist.fimFrequencyPenalty";
const char FIM_OLLAMA_LIVETIME[] = "QodeAssist.fimOllamaLivetime"; const char CC_OLLAMA_LIVETIME[] = "QodeAssist.fimOllamaLivetime";
const char FIM_API_KEY[] = "QodeAssist.apiKey"; const char CC_OLLAMA_CONTEXT_WINDOW[] = "QodeAssist.ccOllamaContextWindow";
const char CHAT_TEMPERATURE[] = "QodeAssist.chatTemperature"; const char CC_API_KEY[] = "QodeAssist.apiKey";
const char CHAT_MAX_TOKENS[] = "QodeAssist.chatMaxTokens"; const char CA_TEMPERATURE[] = "QodeAssist.chatTemperature";
const char CHAT_USE_TOP_P[] = "QodeAssist.chatUseTopP"; const char CA_MAX_TOKENS[] = "QodeAssist.chatMaxTokens";
const char CHAT_TOP_P[] = "QodeAssist.chatTopP"; const char CA_USE_TOP_P[] = "QodeAssist.chatUseTopP";
const char CHAT_USE_TOP_K[] = "QodeAssist.chatUseTopK"; const char CA_TOP_P[] = "QodeAssist.chatTopP";
const char CHAT_TOP_K[] = "QodeAssist.chatTopK"; const char CA_USE_TOP_K[] = "QodeAssist.chatUseTopK";
const char CHAT_USE_PRESENCE_PENALTY[] = "QodeAssist.chatUsePresencePenalty"; const char CA_TOP_K[] = "QodeAssist.chatTopK";
const char CHAT_PRESENCE_PENALTY[] = "QodeAssist.chatPresencePenalty"; const char CA_USE_PRESENCE_PENALTY[] = "QodeAssist.chatUsePresencePenalty";
const char CHAT_USE_FREQUENCY_PENALTY[] = "QodeAssist.chatUseFrequencyPenalty"; const char CA_PRESENCE_PENALTY[] = "QodeAssist.chatPresencePenalty";
const char CHAT_FREQUENCY_PENALTY[] = "QodeAssist.chatFrequencyPenalty"; const char CA_USE_FREQUENCY_PENALTY[] = "QodeAssist.chatUseFrequencyPenalty";
const char CHAT_OLLAMA_LIVETIME[] = "QodeAssist.chatOllamaLivetime"; const char CA_FREQUENCY_PENALTY[] = "QodeAssist.chatFrequencyPenalty";
const char CHAT_API_KEY[] = "QodeAssist.chatApiKey"; const char CA_OLLAMA_LIVETIME[] = "QodeAssist.chatOllamaLivetime";
const char CA_OLLAMA_CONTEXT_WINDOW[] = "QodeAssist.caOllamaContextWindow";
const char CA_API_KEY[] = "QodeAssist.chatApiKey";
} // namespace QodeAssist::Constants } // namespace QodeAssist::Constants

52
settings/SettingsTr.hpp Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QCoreApplication>
namespace QodeAssist::Settings {
namespace TrConstants {
inline const char *ENABLE_QODE_ASSIST = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Enable Qode Assist");
inline const char *GENERAL = QT_TRANSLATE_NOOP("QtC::QodeAssist", "General");
inline const char *RESET_TO_DEFAULTS = QT_TRANSLATE_NOOP("QtC::QodeAssist",
"Reset Page to Defaults");
inline const char *SELECT = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Select...");
inline const char *PROVIDER = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Provider:");
inline const char *MODEL = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Model:");
inline const char *TEMPLATE = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Template:");
inline const char *URL = QT_TRANSLATE_NOOP("QtC::QodeAssist", "URL:");
inline const char *STATUS = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Status:");
inline const char *TEST = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Test");
inline const char *ENABLE_LOG = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Enable Logging");
inline const char *CODE_COMPLETION = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Code Completion");
inline const char *CHAT_ASSISTANT = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Chat Assistant");
inline const char *RESET_SETTINGS = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Reset Settings");
inline const char *CONFIRMATION
= QT_TRANSLATE_NOOP("QtC::QodeAssist",
"Are you sure you want to reset all settings to default values?");
} // namespace TrConstants
struct Tr
{
Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist)
};
} // namespace QodeAssist::Settings

View File

@@ -29,11 +29,6 @@
namespace QodeAssist::Settings { namespace QodeAssist::Settings {
struct Tr
{
Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist)
};
inline bool pingUrl(const QUrl &url, int timeout = 5000) inline bool pingUrl(const QUrl &url, int timeout = 5000)
{ {
if (!url.isValid()) { if (!url.isValid()) {
@@ -72,25 +67,15 @@ void resetAspect(AspectType &aspect)
aspect.setVolatileValue(aspect.defaultValue()); aspect.setVolatileValue(aspect.defaultValue());
} }
class ButtonAspect : public Utils::BaseAspect inline void initStringAspect(Utils::StringAspect &aspect,
const Utils::Key &settingsKey,
const QString &labelText,
const QString &defaultValue)
{ {
Q_OBJECT aspect.setSettingsKey(settingsKey);
aspect.setLabelText(labelText);
public: aspect.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
ButtonAspect(Utils::AspectContainer *container = nullptr) aspect.setDefaultValue(defaultValue);
: Utils::BaseAspect(container) }
{}
void addToLayout(Layouting::Layout &parent) override
{
auto button = new QPushButton(m_buttonText);
connect(button, &QPushButton::clicked, this, &ButtonAspect::clicked);
parent.addItem(button);
}
QString m_buttonText;
signals:
void clicked();
};
} // namespace QodeAssist::Settings } // namespace QodeAssist::Settings