Rework General Settings

This commit is contained in:
Petr Mironychev
2024-11-10 20:31:57 +01:00
parent 1ec6098210
commit b141e54e3e
27 changed files with 564 additions and 575 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 )

167
ConfigurationManager.cpp Normal file
View File

@ -0,0 +1,167 @@
/*
* 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();
}
LLMCore::Provider *ConfigurationManager::getCurrentProvider()
{
auto providerName = Settings::generalSettings().ccProvider();
return LLMCore::ProvidersManager::instance().getProviderByName(providerName);
}
LLMCore::PromptTemplate *ConfigurationManager::getCurrentTemplate()
{
auto templateName = Settings::generalSettings().ccTemplate();
return LLMCore::PromptTemplateManager::instance().getFimTemplateByName(templateName);
}
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();
auto *settingsButton = qobject_cast<ButtonAspect *>(sender());
if (!settingsButton)
return;
const auto providerUrl = (settingsButton == &m_generalSettings.ccSelectModel)
? m_generalSettings.ccUrl()
: m_generalSettings.caUrl();
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

61
ConfigurationManager.hpp Normal file
View File

@ -0,0 +1,61 @@
/*
* 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();
LLMCore::Provider *getCurrentProvider();
LLMCore::PromptTemplate *getCurrentTemplate();
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

@ -146,28 +146,28 @@ 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);
LLMCore::LLMConfig config; // LLMCore::LLMConfig config;
config.requestType = LLMCore::RequestType::Fim; // config.requestType = LLMCore::RequestType::Fim;
config.provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider(); // config.provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider();
config.promptTemplate = LLMCore::PromptTemplateManager::instance().getCurrentFimTemplate(); // config.promptTemplate = LLMCore::PromptTemplateManager::instance().getCurrentFimTemplate();
config.url = QUrl(QString("%1%2").arg(Settings::generalSettings().url(), // config.url = QUrl(QString("%1%2").arg(Settings::generalSettings().url(),
Settings::generalSettings().endPoint())); // Settings::generalSettings().endPoint()));
config.providerRequest = {{"model", Settings::generalSettings().modelName.value()}, // config.providerRequest = {{"model", Settings::generalSettings().modelName.value()},
{"stream", true}, // {"stream", true},
{"stop", // {"stop",
QJsonArray::fromStringList(config.promptTemplate->stopWords())}}; // QJsonArray::fromStringList(config.promptTemplate->stopWords())}};
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion(); // config.multiLineCompletion = Settings::generalSettings().multiLineCompletion();
if (Settings::contextSettings().useSystemPrompt()) // if (Settings::contextSettings().useSystemPrompt())
config.providerRequest["system"] = Settings::contextSettings().systemPrompt(); // config.providerRequest["system"] = Settings::contextSettings().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);
m_requestHandler.sendLLMRequest(config, request); // m_requestHandler.sendLLMRequest(config, request);
} }
LLMCore::ContextData LLMClientInterface::prepareContext(const QJsonObject &request, LLMCore::ContextData LLMClientInterface::prepareContext(const QJsonObject &request,

View File

@ -65,52 +65,52 @@ QodeAssistClient::~QodeAssistClient()
void QodeAssistClient::openDocument(TextEditor::TextDocument *document) void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
{ {
auto project = ProjectManager::projectForFile(document->filePath()); // auto project = ProjectManager::projectForFile(document->filePath());
if (!isEnabled(project)) // if (!isEnabled(project))
return; // return;
Client::openDocument(document); // Client::openDocument(document);
connect(document, // connect(document,
&TextDocument::contentsChangedWithPosition, // &TextDocument::contentsChangedWithPosition,
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::generalSettings().enableAutoComplete())
return; // return;
auto project = ProjectManager::projectForFile(document->filePath()); // auto project = ProjectManager::projectForFile(document->filePath());
if (!isEnabled(project)) // if (!isEnabled(project))
return; // return;
auto textEditor = BaseTextEditor::currentTextEditor(); // auto textEditor = BaseTextEditor::currentTextEditor();
if (!textEditor || textEditor->document() != document) // if (!textEditor || textEditor->document() != document)
return; // return;
if (Settings::contextSettings().useProjectChangesCache()) // if (Settings::contextSettings().useProjectChangesCache())
ChangesManager::instance().addChange(document, // ChangesManager::instance().addChange(document,
position, // position,
charsRemoved, // charsRemoved,
charsAdded); // charsAdded);
TextEditorWidget *widget = textEditor->editorWidget(); // TextEditorWidget *widget = textEditor->editorWidget();
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors()) // if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
return; // return;
const int cursorPosition = widget->textCursor().position(); // const int cursorPosition = widget->textCursor().position();
if (cursorPosition < position || cursorPosition > position + charsAdded) // if (cursorPosition < position || cursorPosition > position + charsAdded)
return; // return;
m_recentCharCount += charsAdded; // m_recentCharCount += charsAdded;
if (m_typingTimer.elapsed() // if (m_typingTimer.elapsed()
> Settings::generalSettings().autoCompletionTypingInterval()) { // > Settings::generalSettings().autoCompletionTypingInterval()) {
m_recentCharCount = charsAdded; // m_recentCharCount = charsAdded;
m_typingTimer.restart(); // m_typingTimer.restart();
} // }
if (m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold()) { // if (m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold()) {
scheduleRequest(widget); // scheduleRequest(widget);
} // }
}); // });
} }
bool QodeAssistClient::canOpenProject(ProjectExplorer::Project *project) bool QodeAssistClient::canOpenProject(ProjectExplorer::Project *project)
@ -144,31 +144,31 @@ void QodeAssistClient::requestCompletions(TextEditor::TextEditorWidget *editor)
void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor) void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor)
{ {
cancelRunningRequest(editor); // cancelRunningRequest(editor);
auto it = m_scheduledRequests.find(editor); // auto it = m_scheduledRequests.find(editor);
if (it == m_scheduledRequests.end()) { // if (it == m_scheduledRequests.end()) {
auto timer = new QTimer(this); // auto timer = new QTimer(this);
timer->setSingleShot(true); // timer->setSingleShot(true);
connect(timer, &QTimer::timeout, this, [this, editor]() { // connect(timer, &QTimer::timeout, this, [this, 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::generalSettings().autoCompletionCharThreshold())
requestCompletions(editor); // requestCompletions(editor);
}); // });
connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { // connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() {
delete m_scheduledRequests.take(editor); // delete m_scheduledRequests.take(editor);
cancelRunningRequest(editor); // cancelRunningRequest(editor);
}); // });
connect(editor, &TextEditorWidget::cursorPositionChanged, this, [this, editor] { // connect(editor, &TextEditorWidget::cursorPositionChanged, this, [this, editor] {
cancelRunningRequest(editor); // cancelRunningRequest(editor);
}); // });
it = m_scheduledRequests.insert(editor, timer); // it = m_scheduledRequests.insert(editor, timer);
} // }
it.value()->setProperty("cursorPosition", editor->textCursor().position()); // it.value()->setProperty("cursorPosition", editor->textCursor().position());
it.value()->start(Settings::generalSettings().startSuggestionTimer()); // it.value()->start(Settings::generalSettings().startSuggestionTimer());
} }
void QodeAssistClient::handleCompletions(const GetCompletionRequest::Response &response, void QodeAssistClient::handleCompletions(const GetCompletionRequest::Response &response,
TextEditor::TextEditorWidget *editor) TextEditor::TextEditorWidget *editor)

View File

@ -30,12 +30,12 @@ ChatModel::ChatModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_totalTokens(0) , m_totalTokens(0)
{ {
auto &settings = Settings::generalSettings(); // auto &settings = Settings::generalSettings();
connect(&settings.chatTokensThreshold, // connect(&settings.chatTokensThreshold,
&Utils::BaseAspect::changed, // &Utils::BaseAspect::changed,
this, // this,
&ChatModel::tokensThresholdChanged); // &ChatModel::tokensThresholdChanged);
} }
int ChatModel::rowCount(const QModelIndex &parent) const int ChatModel::rowCount(const QModelIndex &parent) const
@ -183,8 +183,9 @@ int ChatModel::totalTokens() const
int ChatModel::tokensThreshold() const int ChatModel::tokensThreshold() const
{ {
auto &settings = Settings::generalSettings(); // auto &settings = Settings::generalSettings();
return settings.chatTokensThreshold(); // return settings.chatTokensThreshold();
return 0;
} }
QString ChatModel::lastMessageId() const QString ChatModel::lastMessageId() const

View File

@ -31,12 +31,12 @@ ChatRootView::ChatRootView(QQuickItem *parent)
, m_chatModel(new ChatModel(this)) , m_chatModel(new ChatModel(this))
, m_clientInterface(new ClientInterface(m_chatModel, this)) , m_clientInterface(new ClientInterface(m_chatModel, this))
{ {
auto &settings = Settings::generalSettings(); // auto &settings = Settings::generalSettings();
connect(&settings.chatModelName, // connect(&settings.chatModelName,
&Utils::BaseAspect::changed, // &Utils::BaseAspect::changed,
this, // this,
&ChatRootView::currentTemplateChanged); // &ChatRootView::currentTemplateChanged);
generateColors(); generateColors();
} }
@ -111,7 +111,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

View File

@ -56,46 +56,46 @@ ClientInterface::~ClientInterface() = default;
void ClientInterface::sendMessage(const QString &message) void ClientInterface::sendMessage(const QString &message)
{ {
cancelRequest(); // cancelRequest();
LOG_MESSAGE("Sending message: " + message); // LOG_MESSAGE("Sending message: " + message);
LOG_MESSAGE("chatProvider " + Settings::generalSettings().chatLlmProviders.stringValue()); // LOG_MESSAGE("chatProvider " + Settings::generalSettings().chatLlmProviders.stringValue());
LOG_MESSAGE("chatTemplate " + Settings::generalSettings().chatPrompts.stringValue()); // LOG_MESSAGE("chatTemplate " + Settings::generalSettings().chatPrompts.stringValue());
auto chatTemplate = LLMCore::PromptTemplateManager::instance().getCurrentChatTemplate(); // auto chatTemplate = LLMCore::PromptTemplateManager::instance().getCurrentChatTemplate();
auto chatProvider = LLMCore::ProvidersManager::instance().getCurrentChatProvider(); // auto chatProvider = LLMCore::ProvidersManager::instance().getCurrentChatProvider();
LLMCore::ContextData context; // LLMCore::ContextData context;
context.prefix = message; // context.prefix = message;
context.suffix = ""; // context.suffix = "";
if (Settings::contextSettings().useChatSystemPrompt()) // if (Settings::contextSettings().useChatSystemPrompt())
context.systemPrompt = Settings::contextSettings().chatSystemPrompt(); // context.systemPrompt = Settings::contextSettings().chatSystemPrompt();
QJsonObject providerRequest; // QJsonObject providerRequest;
providerRequest["model"] = Settings::generalSettings().chatModelName(); // providerRequest["model"] = Settings::generalSettings().chatModelName();
providerRequest["stream"] = true; // providerRequest["stream"] = true;
providerRequest["messages"] = m_chatModel->prepareMessagesForRequest(context); // providerRequest["messages"] = m_chatModel->prepareMessagesForRequest(context);
if (!chatTemplate || !chatProvider) { // if (!chatTemplate || !chatProvider) {
LOG_MESSAGE("Check settings, provider or template are not set"); // LOG_MESSAGE("Check settings, provider or template are not set");
} // }
chatTemplate->prepareRequest(providerRequest, context); // chatTemplate->prepareRequest(providerRequest, context);
chatProvider->prepareRequest(providerRequest, LLMCore::RequestType::Chat); // chatProvider->prepareRequest(providerRequest, LLMCore::RequestType::Chat);
LLMCore::LLMConfig config; // LLMCore::LLMConfig config;
config.requestType = LLMCore::RequestType::Chat; // config.requestType = LLMCore::RequestType::Chat;
config.provider = chatProvider; // config.provider = chatProvider;
config.promptTemplate = chatTemplate; // config.promptTemplate = chatTemplate;
config.url = QString("%1%2").arg(Settings::generalSettings().chatUrl(), // config.url = QString("%1%2").arg(Settings::generalSettings().chatUrl(),
Settings::generalSettings().chatEndPoint()); // Settings::generalSettings().chatEndPoint());
config.providerRequest = providerRequest; // config.providerRequest = providerRequest;
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion(); // config.multiLineCompletion = Settings::generalSettings().multiLineCompletion();
QJsonObject request; // QJsonObject request;
request["id"] = QUuid::createUuid().toString(); // request["id"] = QUuid::createUuid().toString();
m_chatModel->addMessage(message, ChatModel::ChatRole::User, ""); // m_chatModel->addMessage(message, ChatModel::ChatRole::User, "");
m_requestHandler->sendLLMRequest(config, request); // m_requestHandler->sendLLMRequest(config, request);
} }
void ClientInterface::clearMessages() void ClientInterface::clearMessages()

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

@ -127,8 +127,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,7 +25,6 @@
#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/PresetPromptsSettings.hpp"
@ -124,7 +123,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

@ -129,8 +129,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

View File

@ -16,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

@ -27,9 +27,6 @@
#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 "SettingsTr.hpp"
#include "SettingsUtils.hpp" #include "SettingsUtils.hpp"
@ -46,117 +43,59 @@ 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")); ccSelectModel.m_buttonText = TrConstants::SELECT;
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); 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:")); ccSetUrl.m_buttonText = TrConstants::SELECT;
llmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
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:")); caSelectModel.m_buttonText = TrConstants::SELECT;
modelName.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
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:")); caSetUrl.m_buttonText = TrConstants::SELECT;
chatLlmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
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();
@ -164,226 +103,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});
ccGrid.addRow({ccModel, ccSelectModel});
ccGrid.addRow({ccTemplate, ccSelectTemplate});
ccGrid.addRow({ccUrl, ccSetUrl});
ccGrid.addRow({ccStatus, ccTest});
auto caGrid = Grid{};
caGrid.addRow({caProvider, caSelectProvider});
caGrid.addRow({caModel, caSelectModel});
caGrid.addRow({caTemplate, caSelectTemplate});
caGrid.addRow({caUrl, caSetUrl});
caGrid.addRow({caStatus, caTest});
auto ccGroup = Group{title(TrConstants::CODE_COMPLETION), ccGrid};
auto caGroup = Group{title(TrConstants::CHAT_ASSISTANT), caGrid};
auto rootLayout = Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults},
Row{enableLogging, Stretch{1}}, Row{enableLogging, Stretch{1}},
Space{8}, Space{8},
Group{title(Tr::tr("AI Suggestions")), ccGroup,
Column{enableAutoComplete, Space{8},
multiLineCompletion, caGroup,
Row{autoCompletionCharThreshold,
autoCompletionTypingInterval,
startSuggestionTimer,
Stretch{1}},
Row{llmProviders, Stretch{1}},
Row{url, endPoint, fimUrlIndicator},
Row{selectModels, modelName, fimModelIndicator},
Row{fimPrompts, Stretch{1}}}},
Space{16},
Group{title(Tr::tr("AI Chat")),
Column{Row{chatLlmProviders, Stretch{1}},
Row{chatUrl, chatEndPoint, chatUrlIndicator},
Row{chatSelectModels, chatModelName, chatModelIndicator},
Row{chatPrompts, Stretch{1}},
Row{chatTokensThreshold, Stretch{1}}}},
Stretch{1}}; 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]() {
int index = fimPrompts.volatileValue();
LLMCore::PromptTemplateManager::instance().setCurrentFimTemplate(
fimPrompts.displayForIndex(index));
});
connect(&chatPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
int index = chatPrompts.volatileValue();
LLMCore::PromptTemplateManager::instance().setCurrentChatTemplate(
chatPrompts.displayForIndex(index));
});
connect(&selectModels, &ButtonAspect::clicked, this, [this]() {
auto *provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider();
showModelSelectionDialog(&modelName, provider);
});
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; bool ok;
QString selectedModel = QInputDialog::getItem(Core::ICore::dialogParent(), QInputDialog dialog(Core::ICore::dialogParent());
Tr::tr("Select LLM Model"), dialog.setWindowTitle(title);
Tr::tr("Choose a model:"), dialog.setLabelText(text);
models, dialog.setComboBoxItems(data);
0, dialog.setComboBoxEditable(false);
false, dialog.setFixedSize(400, 150);
&ok);
if (ok && !selectedModel.isEmpty()) { if (dialog.exec() == QDialog::Accepted) {
modelNameObj->setVolatileValue(selectedModel); QString result = dialog.textValue();
if (!result.isEmpty()) {
aspect.setValue(result);
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);
} }
} }
@ -393,7 +194,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

@ -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,7 +24,6 @@
#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 "SettingsTr.hpp"
#include "SettingsUtils.hpp" #include "SettingsUtils.hpp"
@ -193,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();
@ -208,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

@ -24,6 +24,17 @@ 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_TEMPLATE[] = "QodeAssist.ccTemplate";
const char CC_URL[] = "QodeAssist.ccUrl";
const char CA_PROVIDER[] = "QodeAssist.caProvider";
const char CA_MODEL[] = "QodeAssist.caModel";
const char CA_TEMPLATE[] = "QodeAssist.caTemplate";
const char CA_URL[] = "QodeAssist.caUrl";
// 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 ENABLE_AUTO_COMPLETE[] = "QodeAssist.enableAutoComplete";

View File

@ -23,6 +23,27 @@
namespace QodeAssist::Settings { 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 struct Tr
{ {
Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist) Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist)

View File

@ -67,4 +67,15 @@ void resetAspect(AspectType &aspect)
aspect.setVolatileValue(aspect.defaultValue()); aspect.setVolatileValue(aspect.defaultValue());
} }
inline void initStringAspect(Utils::StringAspect &aspect,
const Utils::Key &settingsKey,
const QString &labelText,
const QString &defaultValue)
{
aspect.setSettingsKey(settingsKey);
aspect.setLabelText(labelText);
aspect.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
aspect.setDefaultValue(defaultValue);
}
} // namespace QodeAssist::Settings } // namespace QodeAssist::Settings