mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-02-09 16:50:13 -05:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3a2b5a64c | |||
| 0ae12e0fc6 | |||
| 793b855819 | |||
| 8e052ff45c | |||
| 2fb876ff00 | |||
| cd1a9e16e0 | |||
| f07610df5c | |||
| 7cd35082b2 | |||
| c1dd59e65c | |||
| faaf59f163 | |||
| 539a220771 | |||
| 397dd33a96 | |||
| 9361c27d6e | |||
| 15af137728 | |||
| 24ad5fd015 | |||
| 216c28aa5e | |||
| f64ea42071 | |||
| 314ba06db1 | |||
| 384e07ba62 | |||
| 4d06541a36 | |||
| 356f28a97b | |||
| b5ca11ed38 | |||
| d49cd07dd0 | |||
| 8e61651bae | |||
| 1e0063a7bb | |||
| 44add994b9 | |||
| 99136d7b76 | |||
| da7abbd9be |
15
.github/FUNDING.yml
vendored
Normal file
15
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: petrmdev
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
polar: # Replace with a single Polar username
|
||||
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||
thanks_dev: # Replace with a single thanks.dev username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@ -34,14 +34,13 @@ add_qtc_plugin(QodeAssist
|
||||
templates/PromptTemplate.hpp
|
||||
templates/CodeLLamaTemplate.hpp
|
||||
templates/StarCoder2Template.hpp
|
||||
templates/CodeQwenChat.hpp
|
||||
templates/DeepSeekCoderV2.hpp
|
||||
templates/CustomTemplate.hpp
|
||||
providers/LLMProvider.hpp
|
||||
providers/OllamaProvider.hpp providers/OllamaProvider.cpp
|
||||
providers/LMStudioProvider.hpp providers/LMStudioProvider.cpp
|
||||
providers/OpenAICompatProvider.hpp providers/OpenAICompatProvider.cpp
|
||||
LLMProvidersManager.hpp LLMProvidersManager.cpp
|
||||
QodeAssistSettings.hpp QodeAssistSettings.cpp
|
||||
QodeAssist.qrc
|
||||
LSPCompletion.hpp
|
||||
LLMSuggestion.hpp LLMSuggestion.cpp
|
||||
@ -50,4 +49,10 @@ add_qtc_plugin(QodeAssist
|
||||
DocumentContextReader.hpp DocumentContextReader.cpp
|
||||
QodeAssistData.hpp
|
||||
utils/CounterTooltip.hpp utils/CounterTooltip.cpp
|
||||
settings/GeneralSettings.hpp settings/GeneralSettings.cpp
|
||||
settings/ContextSettings.hpp settings/ContextSettings.cpp
|
||||
settings/CustomPromptSettings.hpp settings/CustomPromptSettings.cpp
|
||||
settings/PresetPromptsSettings.hpp settings/PresetPromptsSettings.cpp
|
||||
settings/SettingsUtils.hpp
|
||||
core/ChangesManager.h core/ChangesManager.cpp
|
||||
)
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include <QTextBlock>
|
||||
#include <languageserverprotocol/lsptypes.h>
|
||||
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
|
||||
const QRegularExpression &getYearRegex()
|
||||
{
|
||||
@ -136,7 +136,7 @@ QString DocumentContextReader::getLanguageAndFileInfo() const
|
||||
|
||||
QString DocumentContextReader::getSpecificInstructions() const
|
||||
{
|
||||
QString specificInstruction = settings().specificInstractions().arg(
|
||||
QString specificInstruction = Settings::contextSettings().specificInstractions().arg(
|
||||
LanguageServerProtocol::TextDocumentItem::mimeTypeToLanguageId(m_textDocument->mimeType()));
|
||||
return QString("%1").arg(specificInstruction);
|
||||
}
|
||||
|
||||
@ -28,8 +28,10 @@
|
||||
#include "DocumentContextReader.hpp"
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "core/ChangesManager.h"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
@ -130,12 +132,13 @@ QString LLMClientInterface::сontextBefore(TextEditor::TextEditorWidget *widget,
|
||||
return QString();
|
||||
|
||||
QString contextBefore;
|
||||
if (settings().readFullFile()) {
|
||||
if (Settings::contextSettings().readFullFile()) {
|
||||
contextBefore = reader.readWholeFileBefore(lineNumber, cursorPosition);
|
||||
} else {
|
||||
contextBefore = reader.getContextBefore(lineNumber,
|
||||
cursorPosition,
|
||||
settings().readStringsBeforeCursor());
|
||||
contextBefore
|
||||
= reader.getContextBefore(lineNumber,
|
||||
cursorPosition,
|
||||
Settings::contextSettings().readStringsBeforeCursor());
|
||||
}
|
||||
|
||||
return contextBefore;
|
||||
@ -153,12 +156,12 @@ QString LLMClientInterface::сontextAfter(TextEditor::TextEditorWidget *widget,
|
||||
return QString();
|
||||
|
||||
QString contextAfter;
|
||||
if (settings().readFullFile()) {
|
||||
if (Settings::contextSettings().readFullFile()) {
|
||||
contextAfter = reader.readWholeFileAfter(lineNumber, cursorPosition);
|
||||
} else {
|
||||
contextAfter = reader.getContextAfter(lineNumber,
|
||||
cursorPosition,
|
||||
settings().readStringsAfterCursor());
|
||||
Settings::contextSettings().readStringsAfterCursor());
|
||||
}
|
||||
|
||||
return contextAfter;
|
||||
@ -227,7 +230,7 @@ void LLMClientInterface::handleLLMResponse(QNetworkReply *reply, const QJsonObje
|
||||
|
||||
QJsonObject position = request["params"].toObject()["doc"].toObject()["position"].toObject();
|
||||
|
||||
if (!settings().multiLineCompletion()
|
||||
if (!Settings::generalSettings().multiLineCompletion()
|
||||
&& processSingleLineCompletion(reply, request, accumulatedResponse)) {
|
||||
return;
|
||||
}
|
||||
@ -244,14 +247,14 @@ void LLMClientInterface::handleLLMResponse(QNetworkReply *reply, const QJsonObje
|
||||
}
|
||||
|
||||
void LLMClientInterface::handleCompletion(const QJsonObject &request,
|
||||
const QString &accumulatedCompletion)
|
||||
const QStringView &accumulatedCompletion)
|
||||
{
|
||||
auto updatedContext = prepareContext(request, accumulatedCompletion);
|
||||
sendLLMRequest(request, updatedContext);
|
||||
}
|
||||
|
||||
ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
const QString &accumulatedCompletion)
|
||||
const QStringView &accumulatedCompletion)
|
||||
{
|
||||
QJsonObject params = request["params"].toObject();
|
||||
QJsonObject doc = params["doc"].toObject();
|
||||
@ -264,7 +267,7 @@ ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
|
||||
if (!textDocument) {
|
||||
logMessage("Error: Document is not available for" + filePath.toString());
|
||||
return {"", ""};
|
||||
return ContextData{};
|
||||
}
|
||||
|
||||
int cursorPosition = position["character"].toInt();
|
||||
@ -275,23 +278,27 @@ ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
|
||||
DocumentContextReader reader(widget->textDocument());
|
||||
|
||||
QString recentChanges = ChangesManager::instance().getRecentChangesContext(textDocument);
|
||||
|
||||
QString contextBefore = сontextBefore(widget, lineNumber, cursorPosition);
|
||||
QString contextAfter = сontextAfter(widget, lineNumber, cursorPosition);
|
||||
QString instructions = QString("%1%2").arg(settings().useSpecificInstructions()
|
||||
? reader.getSpecificInstructions()
|
||||
: QString(),
|
||||
settings().useFilePathInContext()
|
||||
? reader.getLanguageAndFileInfo()
|
||||
: QString());
|
||||
QString instructions
|
||||
= QString("%1%2%3").arg(Settings::contextSettings().useSpecificInstructions()
|
||||
? reader.getSpecificInstructions()
|
||||
: QString(),
|
||||
Settings::contextSettings().useFilePathInContext()
|
||||
? reader.getLanguageAndFileInfo()
|
||||
: QString(),
|
||||
Settings::contextSettings().useProjectChangesCache() ? recentChanges
|
||||
: QString());
|
||||
|
||||
QString updatedContextBefore = contextBefore + accumulatedCompletion;
|
||||
|
||||
return {updatedContextBefore, contextAfter, instructions};
|
||||
return {QString("%1%2").arg(contextBefore, accumulatedCompletion), contextAfter, instructions};
|
||||
}
|
||||
|
||||
void LLMClientInterface::updateProvider()
|
||||
{
|
||||
m_serverUrl = QUrl(QString("%1%2").arg(settings().url(), settings().endPoint()));
|
||||
m_serverUrl = QUrl(QString("%1%2").arg(Settings::generalSettings().url(),
|
||||
Settings::generalSettings().endPoint()));
|
||||
}
|
||||
|
||||
void LLMClientInterface::sendCompletionToClient(const QString &completion,
|
||||
@ -332,7 +339,8 @@ void LLMClientInterface::sendCompletionToClient(const QString &completion,
|
||||
|
||||
void LLMClientInterface::sendLLMRequest(const QJsonObject &request, const ContextData &prompt)
|
||||
{
|
||||
QJsonObject providerRequest = {{"model", settings().modelName.value()}, {"stream", true}};
|
||||
QJsonObject providerRequest = {{"model", Settings::generalSettings().modelName.value()},
|
||||
{"stream", true}};
|
||||
|
||||
auto currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
|
||||
currentTemplate->prepareRequest(providerRequest, prompt);
|
||||
@ -378,9 +386,9 @@ void LLMClientInterface::sendLLMRequest(const QJsonObject &request, const Contex
|
||||
});
|
||||
}
|
||||
|
||||
QString LLMClientInterface::removeStopWords(const QString &completion)
|
||||
QString LLMClientInterface::removeStopWords(const QStringView &completion)
|
||||
{
|
||||
QString filteredCompletion = completion;
|
||||
QString filteredCompletion = completion.toString();
|
||||
|
||||
auto currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
|
||||
QStringList stopWords = currentTemplate->stopWords();
|
||||
|
||||
@ -45,12 +45,12 @@ public:
|
||||
bool isComplete);
|
||||
|
||||
void handleCompletion(const QJsonObject &request,
|
||||
const QString &accumulatedCompletion = QString());
|
||||
const QStringView &accumulatedCompletion = QString());
|
||||
void sendLLMRequest(const QJsonObject &request, const ContextData &prompt);
|
||||
void handleLLMResponse(QNetworkReply *reply, const QJsonObject &request);
|
||||
|
||||
ContextData prepareContext(const QJsonObject &request,
|
||||
const QString &accumulatedCompletion = QString{});
|
||||
const QStringView &accumulatedCompletion = QString{});
|
||||
void updateProvider();
|
||||
|
||||
protected:
|
||||
@ -71,7 +71,7 @@ private:
|
||||
|
||||
QString сontextBefore(TextEditor::TextEditorWidget *widget, int lineNumber, int cursorPosition);
|
||||
QString сontextAfter(TextEditor::TextEditorWidget *widget, int lineNumber, int cursorPosition);
|
||||
QString removeStopWords(const QString &completion);
|
||||
QString removeStopWords(const QStringView &completion);
|
||||
|
||||
QUrl m_serverUrl;
|
||||
QNetworkAccessManager *m_manager;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Name" : "QodeAssist",
|
||||
"Version" : "0.0.8",
|
||||
"Version" : "0.1.2",
|
||||
"CompatVersion" : "${IDE_VERSION_COMPAT}",
|
||||
"Vendor" : "Petr Mironychev",
|
||||
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
|
||||
|
||||
@ -31,7 +31,9 @@
|
||||
|
||||
#include "LLMClientInterface.hpp"
|
||||
#include "LLMSuggestion.hpp"
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "core/ChangesManager.h"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
using namespace LanguageServerProtocol;
|
||||
using namespace TextEditor;
|
||||
@ -43,6 +45,7 @@ namespace QodeAssist {
|
||||
|
||||
QodeAssistClient::QodeAssistClient()
|
||||
: LanguageClient::Client(new LLMClientInterface())
|
||||
, m_recentCharCount(0)
|
||||
{
|
||||
setName("Qode Assist");
|
||||
LanguageClient::LanguageFilter filter;
|
||||
@ -51,6 +54,8 @@ QodeAssistClient::QodeAssistClient()
|
||||
|
||||
start();
|
||||
setupConnections();
|
||||
|
||||
m_typingTimer.start();
|
||||
}
|
||||
|
||||
QodeAssistClient::~QodeAssistClient()
|
||||
@ -70,7 +75,7 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
|
||||
this,
|
||||
[this, document](int position, int charsRemoved, int charsAdded) {
|
||||
Q_UNUSED(charsRemoved)
|
||||
if (!settings().enableAutoComplete())
|
||||
if (!Settings::generalSettings().enableAutoComplete())
|
||||
return;
|
||||
|
||||
auto project = ProjectManager::projectForFile(document->filePath());
|
||||
@ -80,13 +85,31 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
|
||||
auto textEditor = BaseTextEditor::currentTextEditor();
|
||||
if (!textEditor || textEditor->document() != document)
|
||||
return;
|
||||
|
||||
if (Settings::contextSettings().useProjectChangesCache())
|
||||
ChangesManager::instance().addChange(document,
|
||||
position,
|
||||
charsRemoved,
|
||||
charsAdded);
|
||||
|
||||
TextEditorWidget *widget = textEditor->editorWidget();
|
||||
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
|
||||
return;
|
||||
const int cursorPosition = widget->textCursor().position();
|
||||
if (cursorPosition < position || cursorPosition > position + charsAdded)
|
||||
return;
|
||||
scheduleRequest(widget);
|
||||
|
||||
m_recentCharCount += charsAdded;
|
||||
|
||||
if (m_typingTimer.elapsed()
|
||||
> Settings::generalSettings().autoCompletionTypingInterval()) {
|
||||
m_recentCharCount = charsAdded;
|
||||
m_typingTimer.restart();
|
||||
}
|
||||
|
||||
if (m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold()) {
|
||||
scheduleRequest(widget);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -130,7 +153,8 @@ void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor)
|
||||
connect(timer, &QTimer::timeout, this, [this, editor]() {
|
||||
if (editor
|
||||
&& editor->textCursor().position()
|
||||
== m_scheduledRequests[editor]->property("cursorPosition").toInt())
|
||||
== m_scheduledRequests[editor]->property("cursorPosition").toInt()
|
||||
&& m_recentCharCount > Settings::generalSettings().autoCompletionCharThreshold())
|
||||
requestCompletions(editor);
|
||||
});
|
||||
connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() {
|
||||
@ -144,9 +168,8 @@ void QodeAssistClient::scheduleRequest(TextEditor::TextEditorWidget *editor)
|
||||
}
|
||||
|
||||
it.value()->setProperty("cursorPosition", editor->textCursor().position());
|
||||
it.value()->start(settings().startSuggestionTimer());
|
||||
it.value()->start(Settings::generalSettings().startSuggestionTimer());
|
||||
}
|
||||
|
||||
void QodeAssistClient::handleCompletions(const GetCompletionRequest::Response &response,
|
||||
TextEditor::TextEditorWidget *editor)
|
||||
{
|
||||
@ -204,7 +227,7 @@ void QodeAssistClient::cancelRunningRequest(TextEditor::TextEditorWidget *editor
|
||||
|
||||
bool QodeAssistClient::isEnabled(ProjectExplorer::Project *project) const
|
||||
{
|
||||
return settings().enableQodeAssist();
|
||||
return Settings::generalSettings().enableQodeAssist();
|
||||
}
|
||||
|
||||
void QodeAssistClient::setupConnections()
|
||||
|
||||
@ -55,6 +55,9 @@ private:
|
||||
QHash<TextEditor::TextEditorWidget *, QTimer *> m_scheduledRequests;
|
||||
QMetaObject::Connection m_documentOpenedConnection;
|
||||
QMetaObject::Connection m_documentClosedConnection;
|
||||
|
||||
QElapsedTimer m_typingTimer;
|
||||
int m_recentCharCount;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
|
||||
@ -49,6 +49,8 @@ const char USE_FREQUENCY_PENALTY[] = "QodeAssist.useFrequencyPenalty";
|
||||
const char FREQUENCY_PENALTY[] = "QodeAssist.frequencyPenalty";
|
||||
const char PROVIDER_PATHS[] = "QodeAssist.providerPaths";
|
||||
const char START_SUGGESTION_TIMER[] = "QodeAssist.startSuggestionTimer";
|
||||
const char AUTO_COMPLETION_CHAR_THRESHOLD[] = "QodeAssist.autoCompletionCharThreshold";
|
||||
const char AUTO_COMPLETION_TYPING_INTERVAL[] = "QodeAssist.autoCompletionTypingInterval";
|
||||
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
|
||||
const char OLLAMA_LIVETIME[] = "QodeAssist.ollamaLivetime";
|
||||
const char SPECIFIC_INSTRUCTIONS[] = "QodeAssist.specificInstractions";
|
||||
@ -56,8 +58,17 @@ const char MULTILINE_COMPLETION[] = "QodeAssist.multilineCompletion";
|
||||
const char API_KEY[] = "QodeAssist.apiKey";
|
||||
const char USE_SPECIFIC_INSTRUCTIONS[] = "QodeAssist.useSpecificInstructions";
|
||||
const char USE_FILE_PATH_IN_CONTEXT[] = "QodeAssist.useFilePathInContext";
|
||||
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
||||
const char USE_PROJECT_CHANGES_CACHE[] = "QodeAssist.useProjectChangesCache";
|
||||
const char MAX_CHANGES_CACHE_SIZE[] = "QodeAssist.maxChangesCacheSize";
|
||||
|
||||
const char QODE_ASSIST_GENERAL_OPTIONS_ID[] = "QodeAssist.GeneralOptions";
|
||||
const char QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID[] = "QodeAssist.1GeneralSettingsPageId";
|
||||
const char QODE_ASSIST_CONTEXT_SETTINGS_PAGE_ID[] = "QodeAssist.2ContextSettingsPageId";
|
||||
const char QODE_ASSIST_PRESET_PROMPTS_SETTINGS_PAGE_ID[]
|
||||
= "QodeAssist.3PresetPromptsSettingsPageId";
|
||||
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_DISPLAY_CATEGORY[] = "Qode Assist";
|
||||
|
||||
|
||||
@ -1,398 +0,0 @@
|
||||
/*
|
||||
* 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 "QodeAssistSettings.hpp"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QtWidgets/qmessagebox.h>
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
QodeAssistSettings &settings()
|
||||
{
|
||||
static QodeAssistSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
QodeAssistSettings::QodeAssistSettings()
|
||||
{
|
||||
setAutoApply(false);
|
||||
|
||||
enableQodeAssist.setSettingsKey(Constants::ENABLE_QODE_ASSIST);
|
||||
enableQodeAssist.setLabelText(Tr::tr("Enable Qode Assist"));
|
||||
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.setLabelText(Tr::tr("Enable Logging"));
|
||||
enableLogging.setDefaultValue(false);
|
||||
|
||||
llmProviders.setSettingsKey(Constants::LLM_PROVIDERS);
|
||||
llmProviders.setDisplayName(Tr::tr("LLM Providers:"));
|
||||
llmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
||||
llmProviders.setDefaultValue(0);
|
||||
|
||||
url.setSettingsKey(Constants::URL);
|
||||
url.setLabelText(Tr::tr("URL:"));
|
||||
url.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
endPoint.setSettingsKey(Constants::END_POINT);
|
||||
endPoint.setLabelText(Tr::tr("Endpoint:"));
|
||||
endPoint.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
modelName.setSettingsKey(Constants::MODEL_NAME);
|
||||
modelName.setLabelText(Tr::tr("LLM Name:"));
|
||||
modelName.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
temperature.setSettingsKey(Constants::TEMPERATURE);
|
||||
temperature.setLabelText(Tr::tr("Temperature:"));
|
||||
temperature.setDefaultValue(0.2);
|
||||
temperature.setRange(0.0, 10.0);
|
||||
|
||||
selectModels.m_buttonText = Tr::tr("Select Model");
|
||||
|
||||
ollamaLivetime.setSettingsKey(Constants::OLLAMA_LIVETIME);
|
||||
ollamaLivetime.setLabelText(
|
||||
Tr::tr("Time to suspend Ollama after completion request (in minutes), "
|
||||
"Only Ollama, -1 to disable"));
|
||||
ollamaLivetime.setDefaultValue("5m");
|
||||
ollamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
fimPrompts.setDisplayName(Tr::tr("Fill-In-Middle Prompt"));
|
||||
fimPrompts.setSettingsKey(Constants::FIM_PROMPTS);
|
||||
fimPrompts.setDefaultValue(0);
|
||||
fimPrompts.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
||||
|
||||
readFullFile.setSettingsKey(Constants::READ_FULL_FILE);
|
||||
readFullFile.setLabelText(Tr::tr("Read Full File"));
|
||||
readFullFile.setDefaultValue(false);
|
||||
|
||||
maxFileThreshold.setSettingsKey(Constants::MAX_FILE_THRESHOLD);
|
||||
maxFileThreshold.setLabelText(Tr::tr("Max File Threshold:"));
|
||||
maxFileThreshold.setRange(10, 100000);
|
||||
maxFileThreshold.setDefaultValue(600);
|
||||
|
||||
readStringsBeforeCursor.setSettingsKey(Constants::READ_STRINGS_BEFORE_CURSOR);
|
||||
readStringsBeforeCursor.setLabelText(Tr::tr("Read Strings Before Cursor"));
|
||||
readStringsBeforeCursor.setDefaultValue(50);
|
||||
|
||||
readStringsAfterCursor.setSettingsKey(Constants::READ_STRINGS_AFTER_CURSOR);
|
||||
readStringsAfterCursor.setLabelText(Tr::tr("Read Strings After Cursor"));
|
||||
readStringsAfterCursor.setDefaultValue(30);
|
||||
|
||||
maxTokens.setSettingsKey(Constants::MAX_TOKENS);
|
||||
maxTokens.setLabelText(Tr::tr("Max Tokens"));
|
||||
maxTokens.setRange(-1, 10000);
|
||||
maxTokens.setDefaultValue(150);
|
||||
|
||||
useTopP.setSettingsKey(Constants::USE_TOP_P);
|
||||
useTopP.setDefaultValue(false);
|
||||
|
||||
topP.setSettingsKey(Constants::TOP_P);
|
||||
topP.setLabelText(Tr::tr("top_p"));
|
||||
topP.setDefaultValue(0.9);
|
||||
topP.setRange(0.0, 1.0);
|
||||
|
||||
useTopK.setSettingsKey(Constants::USE_TOP_K);
|
||||
useTopK.setDefaultValue(false);
|
||||
|
||||
topK.setSettingsKey(Constants::TOP_K);
|
||||
topK.setLabelText(Tr::tr("top_k"));
|
||||
topK.setDefaultValue(50);
|
||||
topK.setRange(1, 1000);
|
||||
|
||||
usePresencePenalty.setSettingsKey(Constants::USE_PRESENCE_PENALTY);
|
||||
usePresencePenalty.setDefaultValue(false);
|
||||
|
||||
presencePenalty.setSettingsKey(Constants::PRESENCE_PENALTY);
|
||||
presencePenalty.setLabelText(Tr::tr("presence_penalty"));
|
||||
presencePenalty.setDefaultValue(0.0);
|
||||
presencePenalty.setRange(-2.0, 2.0);
|
||||
|
||||
useFrequencyPenalty.setSettingsKey(Constants::USE_FREQUENCY_PENALTY);
|
||||
useFrequencyPenalty.setDefaultValue(false);
|
||||
|
||||
frequencyPenalty.setSettingsKey(Constants::FREQUENCY_PENALTY);
|
||||
frequencyPenalty.setLabelText(Tr::tr("frequency_penalty"));
|
||||
frequencyPenalty.setDefaultValue(0.0);
|
||||
frequencyPenalty.setRange(-2.0, 2.0);
|
||||
|
||||
startSuggestionTimer.setSettingsKey(Constants::START_SUGGESTION_TIMER);
|
||||
startSuggestionTimer.setLabelText(Tr::tr("Start Suggestion Timer:"));
|
||||
startSuggestionTimer.setRange(10, 10000);
|
||||
startSuggestionTimer.setDefaultValue(500);
|
||||
|
||||
useFilePathInContext.setSettingsKey(Constants::USE_FILE_PATH_IN_CONTEXT);
|
||||
useFilePathInContext.setDefaultValue(false);
|
||||
useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context"));
|
||||
|
||||
useSpecificInstructions.setSettingsKey(Constants::USE_SPECIFIC_INSTRUCTIONS);
|
||||
useSpecificInstructions.setDefaultValue(false);
|
||||
useSpecificInstructions.setLabelText(Tr::tr("Use Specific Instructions"));
|
||||
|
||||
specificInstractions.setSettingsKey(Constants::SPECIFIC_INSTRUCTIONS);
|
||||
specificInstractions.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||
specificInstractions.setLabelText(
|
||||
Tr::tr("Instructions: Please keep %1 for languge name, warning, it shouldn't too big"));
|
||||
specificInstractions.setDefaultValue(
|
||||
"You are an expert %1 code completion AI."
|
||||
"CRITICAL: Please provide minimal the best possible code completion suggestions.\n");
|
||||
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset to Defaults");
|
||||
multiLineCompletion.setSettingsKey(Constants::MULTILINE_COMPLETION);
|
||||
multiLineCompletion.setDefaultValue(true);
|
||||
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion"));
|
||||
|
||||
apiKey.setSettingsKey(Constants::API_KEY);
|
||||
apiKey.setLabelText(Tr::tr("API Key:"));
|
||||
apiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
apiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
|
||||
|
||||
const auto &manager = LLMProvidersManager::instance();
|
||||
if (!manager.getProviderNames().isEmpty()) {
|
||||
const auto providerNames = manager.getProviderNames();
|
||||
for (const QString &name : providerNames) {
|
||||
llmProviders.addOption(name);
|
||||
}
|
||||
}
|
||||
|
||||
const auto &promptManager = PromptTemplateManager::instance();
|
||||
if (!promptManager.getTemplateNames().isEmpty()) {
|
||||
const auto promptNames = promptManager.getTemplateNames();
|
||||
for (const QString &name : promptNames) {
|
||||
fimPrompts.addOption(name);
|
||||
}
|
||||
}
|
||||
|
||||
readSettings();
|
||||
|
||||
topK.setEnabled(useTopK());
|
||||
topP.setEnabled(useTopP());
|
||||
presencePenalty.setEnabled(usePresencePenalty());
|
||||
frequencyPenalty.setEnabled(useFrequencyPenalty());
|
||||
readStringsAfterCursor.setEnabled(!readFullFile());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile());
|
||||
specificInstractions.setEnabled(useSpecificInstructions());
|
||||
PromptTemplateManager::instance().setCurrentTemplate(fimPrompts.stringValue());
|
||||
LLMProvidersManager::instance().setCurrentProvider(llmProviders.stringValue());
|
||||
|
||||
setLoggingEnabled(enableLogging());
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
|
||||
return Column{Group{title(Tr::tr("General Settings")),
|
||||
Form{Column{enableQodeAssist,
|
||||
enableAutoComplete,
|
||||
multiLineCompletion,
|
||||
enableLogging,
|
||||
Row{Stretch{1}, resetToDefaults}}}},
|
||||
Group{title(Tr::tr("LLM Providers")),
|
||||
Form{Column{llmProviders, Row{url, endPoint}}}},
|
||||
Group{title(Tr::tr("LLM Model Settings")),
|
||||
Form{Column{Row{selectModels, modelName}}}},
|
||||
Group{title(Tr::tr("FIM Prompt Settings")),
|
||||
Form{Column{fimPrompts,
|
||||
readFullFile,
|
||||
maxFileThreshold,
|
||||
readStringsBeforeCursor,
|
||||
readStringsAfterCursor,
|
||||
ollamaLivetime,
|
||||
apiKey,
|
||||
useFilePathInContext,
|
||||
useSpecificInstructions,
|
||||
specificInstractions,
|
||||
temperature,
|
||||
maxTokens,
|
||||
startSuggestionTimer,
|
||||
Row{useTopP, topP, Stretch{1}},
|
||||
Row{useTopK, topK, Stretch{1}},
|
||||
Row{usePresencePenalty, presencePenalty, Stretch{1}},
|
||||
Row{useFrequencyPenalty, frequencyPenalty, Stretch{1}}}}},
|
||||
st};
|
||||
});
|
||||
|
||||
setupConnections();
|
||||
}
|
||||
|
||||
void QodeAssistSettings::setupConnections()
|
||||
{
|
||||
connect(&llmProviders, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = llmProviders.volatileValue();
|
||||
logMessage(QString("currentProvider %1").arg(llmProviders.displayForIndex(index)));
|
||||
LLMProvidersManager::instance().setCurrentProvider(llmProviders.displayForIndex(index));
|
||||
updateProviderSettings();
|
||||
});
|
||||
|
||||
connect(&fimPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = fimPrompts.volatileValue();
|
||||
logMessage(QString("currentPrompt %1").arg(fimPrompts.displayForIndex(index)));
|
||||
PromptTemplateManager::instance().setCurrentTemplate(fimPrompts.displayForIndex(index));
|
||||
});
|
||||
|
||||
connect(&selectModels, &ButtonAspect::clicked, this, [this]() { showModelSelectionDialog(); });
|
||||
connect(&useTopP, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
topP.setEnabled(useTopP.volatileValue());
|
||||
});
|
||||
connect(&useTopK, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
topK.setEnabled(useTopK.volatileValue());
|
||||
});
|
||||
connect(&usePresencePenalty, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
presencePenalty.setEnabled(usePresencePenalty.volatileValue());
|
||||
});
|
||||
connect(&useFrequencyPenalty, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
frequencyPenalty.setEnabled(useFrequencyPenalty.volatileValue());
|
||||
});
|
||||
connect(&readFullFile, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
readStringsAfterCursor.setEnabled(!readFullFile.volatileValue());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile.volatileValue());
|
||||
});
|
||||
connect(&resetToDefaults,
|
||||
&ButtonAspect::clicked,
|
||||
this,
|
||||
&QodeAssistSettings::resetSettingsToDefaults);
|
||||
connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
setLoggingEnabled(enableLogging.volatileValue());
|
||||
});
|
||||
connect(&useSpecificInstructions, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
specificInstractions.setEnabled(useSpecificInstructions.volatileValue());
|
||||
});
|
||||
}
|
||||
|
||||
void QodeAssistSettings::updateProviderSettings()
|
||||
{
|
||||
auto *provider = LLMProvidersManager::instance().getCurrentProvider();
|
||||
|
||||
if (provider) {
|
||||
logMessage(QString("currentProvider %1").arg(provider->name()));
|
||||
url.setValue(provider->url());
|
||||
endPoint.setValue(provider->completionEndpoint());
|
||||
ollamaLivetime.setEnabled(provider->name() == "Ollama");
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QodeAssistSettings::getInstalledModels()
|
||||
{
|
||||
auto *provider = LLMProvidersManager::instance().getCurrentProvider();
|
||||
if (provider) {
|
||||
Utils::Environment env = Utils::Environment::systemEnvironment();
|
||||
return provider->getInstalledModels(env);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void QodeAssistSettings::showModelSelectionDialog()
|
||||
{
|
||||
QStringList models = getInstalledModels();
|
||||
|
||||
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()) {
|
||||
modelName.setValue(selectedModel);
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void QodeAssistSettings::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(enableQodeAssist);
|
||||
resetAspect(enableAutoComplete);
|
||||
resetAspect(llmProviders);
|
||||
resetAspect(url);
|
||||
resetAspect(endPoint);
|
||||
resetAspect(modelName);
|
||||
resetAspect(fimPrompts);
|
||||
resetAspect(temperature);
|
||||
resetAspect(maxTokens);
|
||||
resetAspect(readFullFile);
|
||||
resetAspect(maxFileThreshold);
|
||||
resetAspect(readStringsBeforeCursor);
|
||||
resetAspect(readStringsAfterCursor);
|
||||
resetAspect(useTopP);
|
||||
resetAspect(topP);
|
||||
resetAspect(useTopK);
|
||||
resetAspect(topK);
|
||||
resetAspect(usePresencePenalty);
|
||||
resetAspect(presencePenalty);
|
||||
resetAspect(useFrequencyPenalty);
|
||||
resetAspect(frequencyPenalty);
|
||||
resetAspect(startSuggestionTimer);
|
||||
resetAspect(enableLogging);
|
||||
resetAspect(ollamaLivetime);
|
||||
resetAspect(specificInstractions);
|
||||
resetAspect(multiLineCompletion);
|
||||
resetAspect(useFilePathInContext);
|
||||
resetAspect(useSpecificInstructions);
|
||||
|
||||
fimPrompts.setStringValue("StarCoder2");
|
||||
llmProviders.setStringValue("Ollama");
|
||||
|
||||
updateProviderSettings();
|
||||
apply();
|
||||
|
||||
QMessageBox::information(Core::ICore::dialogParent(),
|
||||
Tr::tr("Settings Reset"),
|
||||
Tr::tr("All settings have been reset to their default values."));
|
||||
}
|
||||
}
|
||||
|
||||
class QodeAssistSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
QodeAssistSettingsPage()
|
||||
{
|
||||
setId(Constants::QODE_ASSIST_GENERAL_OPTIONS_ID);
|
||||
setDisplayName("Qode Assist");
|
||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
||||
setDisplayCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY);
|
||||
setCategoryIconPath(":/resources/images/qoderassist-icon.png");
|
||||
setSettingsProvider([] { return &settings(); });
|
||||
}
|
||||
};
|
||||
|
||||
const QodeAssistSettingsPage settingsPage;
|
||||
|
||||
} // namespace QodeAssist
|
||||
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
template<typename AspectType>
|
||||
void resetAspect(AspectType &aspect)
|
||||
{
|
||||
aspect.setValue(aspect.defaultValue());
|
||||
}
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
class QodeAssistSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
QodeAssistSettings();
|
||||
|
||||
Utils::BoolAspect enableQodeAssist{this};
|
||||
Utils::BoolAspect enableAutoComplete{this};
|
||||
Utils::BoolAspect enableLogging{this};
|
||||
|
||||
Utils::SelectionAspect llmProviders{this};
|
||||
Utils::StringAspect url{this};
|
||||
Utils::StringAspect endPoint{this};
|
||||
|
||||
Utils::StringAspect modelName{this};
|
||||
ButtonAspect selectModels{this};
|
||||
|
||||
Utils::SelectionAspect fimPrompts{this};
|
||||
Utils::DoubleAspect temperature{this};
|
||||
Utils::IntegerAspect maxTokens{this};
|
||||
|
||||
Utils::BoolAspect readFullFile{this};
|
||||
Utils::IntegerAspect readStringsBeforeCursor{this};
|
||||
Utils::IntegerAspect readStringsAfterCursor{this};
|
||||
|
||||
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};
|
||||
|
||||
Utils::IntegerAspect startSuggestionTimer{this};
|
||||
Utils::IntegerAspect maxFileThreshold{this};
|
||||
|
||||
Utils::StringAspect ollamaLivetime{this};
|
||||
Utils::StringAspect specificInstractions{this};
|
||||
Utils::BoolAspect useSpecificInstructions{this};
|
||||
Utils::BoolAspect useFilePathInContext{this};
|
||||
Utils::BoolAspect multiLineCompletion{this};
|
||||
|
||||
Utils::StringAspect apiKey{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
private:
|
||||
void setupConnections();
|
||||
void updateProviderSettings();
|
||||
QStringList getInstalledModels();
|
||||
void showModelSelectionDialog();
|
||||
Utils::Environment getEnvironmentWithProviderPaths() const;
|
||||
void resetSettingsToDefaults();
|
||||
};
|
||||
|
||||
QodeAssistSettings &settings();
|
||||
|
||||
} // namespace QodeAssist
|
||||
60
README.md
60
README.md
@ -3,6 +3,8 @@
|
||||
|
||||
QodeAssist is an AI-powered coding assistant plugin for Qt Creator. It provides intelligent code completion and suggestions for C++ and QML, leveraging large language models through local providers like Ollama. Enhance your coding productivity with context-aware AI assistance directly in your Qt development environment.
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/255a52f1-5cc0-4ca3-b05c-c4cf9cdbe25a" width="600" alt="QodeAssistPreview">
|
||||
|
||||
## Supported LLM Providers
|
||||
QodeAssist currently supports the following LLM (Large Language Model) providers:
|
||||
- [Ollama](https://ollama.com)
|
||||
@ -10,25 +12,53 @@ QodeAssist currently supports the following LLM (Large Language Model) providers
|
||||
- OpenAI compatible providers
|
||||
|
||||
## Supported Models
|
||||
QodeAssist has been tested with the following language models, all trained for Fill-in-theMiddle:
|
||||
|
||||
Ollama:
|
||||
- [starcoder2](https://ollama.com/library/starcoder2)
|
||||
- [codellama](https://ollama.com/library/codellama)
|
||||
QodeAssist has been thoroughly tested and optimized for use with the following language models, all of which are specifically trained for Fill-in-the-Middle (FIM) tasks:
|
||||
|
||||
- CodeLlama
|
||||
- StarCoder2
|
||||
- DeepSeek-Coder-V2-Lite-Base
|
||||
|
||||
LM studio:
|
||||
These models have demonstrated excellent performance in code completion and assistance tasks within the QodeAssist environment.
|
||||
|
||||
### Custom Prompts
|
||||
|
||||
For advanced users or those with specific requirements, QodeAssist offers the flexibility to create, save, and load custom prompts using JSON templates. This feature allows you to tailor the AI's behavior to your exact needs.
|
||||
|
||||
To get started with custom prompts:
|
||||
|
||||
1. Navigate to the "Custom Template" option in the FIM Prompt Settings.
|
||||
2. Create your custom JSON prompt template.
|
||||
3. Use the "Save Custom Template to JSON" button to store your template for future use.
|
||||
4. To use a previously saved template, click "Load Custom Template from JSON".
|
||||
5. Make sure to select "Custom Template" from the dropdown menu in the FIM Prompt Settings on the General page to activate your custom template.
|
||||
|
||||
For inspiration and examples of effective custom prompts, please refer to the `rawPromptExamples` folder in our repository.
|
||||
|
||||
<img width="600" alt="Custom template" src="https://github.com/user-attachments/assets/4a14c552-baba-4531-ab4f-cb1f9ac6620b">
|
||||
<img width="600" alt="Select custom template" src="https://github.com/user-attachments/assets/3651dafd-83f9-4df9-943f-69c28cd3d8a3">
|
||||
|
||||
### Tested Models
|
||||
|
||||
#### Ollama:
|
||||
- [starcoder2](https://ollama.com/library/starcoder2)
|
||||
- [codellama](https://ollama.com/library/codellama)
|
||||
|
||||
#### LM Studio:
|
||||
- [second-state/StarCoder2-7B-GGUF](https://huggingface.co/second-state/StarCoder2-7B-GGUF)
|
||||
- [TheBloke/CodeLlama-7B-GGUF](https://huggingface.co/TheBloke/CodeLlama-7B-GGUF)
|
||||
|
||||
Please note that while these models have been specifically tested and confirmed to work well with QodeAssist, other models compatible with the supported providers may also work. We encourage users to experiment with different models and report their experiences.
|
||||
|
||||
If you've successfully used a model that's not listed here, please let us know by opening an issue or submitting a pull request to update this list.
|
||||
|
||||
## Development Progress
|
||||
|
||||
- [x] Basic plugin with code autocomplete functionality
|
||||
- [ ] Improve and automate settings
|
||||
- [x] Improve and automate settings
|
||||
- [ ] Add chat functionality
|
||||
- [x] Sharing diff with model
|
||||
- [ ] Sharing project source with model
|
||||
- [ ] Support for more providers and models
|
||||
|
||||
## Plugin installation using Ollama as an example
|
||||
@ -48,13 +78,16 @@ ollama run starcoder2:7b
|
||||
|
||||
## Configure Plugin
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/0743d09e-1f02-44ed-9a1a-85e2a0a0c01a" width="800" alt="QodeAssist в действии">
|
||||
|
||||
1. Open Qt Creator settings
|
||||
2. Navigate to the "Qode Assist" tab
|
||||
3. Choose your LLM provider (e.g., Ollama)
|
||||
4. Select the installed model by the "Select Model" button
|
||||
3. Select "General" page
|
||||
4. Choose your LLM provider (e.g., Ollama)
|
||||
5. Select the installed model by the "Select Model" button
|
||||
- For LM Studio you will see current load model
|
||||
5. Choose the prompt template that corresponds to your model
|
||||
6. Apply the settings
|
||||
6. Choose the prompt template that corresponds to your model
|
||||
7. Apply the settings
|
||||
|
||||
You're all set! QodeAssist is now ready to use in Qt Creator.
|
||||
|
||||
@ -91,7 +124,8 @@ Verify that the selected prompt template matches the model you're using
|
||||
If you're still experiencing issues with QodeAssist, you can try resetting the settings to their default values:
|
||||
1. Open Qt Creator settings
|
||||
2. Navigate to the "Qode Assist" tab
|
||||
3. Click on the "Reset to Defaults" button
|
||||
3. Pick settings page for reset
|
||||
4. Click on the "Reset Page to Defaults" button
|
||||
- The API key will not reset
|
||||
- Select model after reset
|
||||
|
||||
@ -104,8 +138,8 @@ If you find QodeAssist helpful, there are several ways you can support the proje
|
||||
|
||||
3. **Spread the Word**: Star our GitHub repository and share QodeAssist with your fellow developers.
|
||||
|
||||
4. **Financial Support**: If you'd like to support the development financially, you can make a donation using one of the following cryptocurrency addresses:
|
||||
|
||||
4. **Financial Support**: If you'd like to support the development financially, you can make a donation using one of the following:
|
||||
- [](https://ko-fi.com/P5P412V96G)
|
||||
- Bitcoin (BTC): `bc1qndq7f0mpnlya48vk7kugvyqj5w89xrg4wzg68t`
|
||||
- Ethereum (ETH): `0xA5e8c37c94b24e25F9f1f292a01AF55F03099D8D`
|
||||
- Litecoin (LTC): `ltc1qlrxnk30s2pcjchzx4qrxvdjt5gzuervy5mv0vy`
|
||||
|
||||
89
core/ChangesManager.cpp
Normal file
89
core/ChangesManager.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 "ChangesManager.h"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
ChangesManager &ChangesManager::instance()
|
||||
{
|
||||
static ChangesManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
ChangesManager::ChangesManager()
|
||||
: QObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ChangesManager::~ChangesManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ChangesManager::addChange(TextEditor::TextDocument *document,
|
||||
int position,
|
||||
int charsRemoved,
|
||||
int charsAdded)
|
||||
{
|
||||
auto &documentQueue = m_documentChanges[document];
|
||||
|
||||
QTextBlock block = document->document()->findBlock(position);
|
||||
int lineNumber = block.blockNumber();
|
||||
QString lineContent = block.text();
|
||||
QString fileName = document->filePath().fileName();
|
||||
|
||||
ChangeInfo change{fileName, lineNumber, lineContent};
|
||||
|
||||
auto it = std::find_if(documentQueue.begin(),
|
||||
documentQueue.end(),
|
||||
[lineNumber](const ChangeInfo &c) { return c.lineNumber == lineNumber; });
|
||||
|
||||
if (it != documentQueue.end()) {
|
||||
it->lineContent = lineContent;
|
||||
} else {
|
||||
documentQueue.enqueue(change);
|
||||
|
||||
if (documentQueue.size() > Settings::contextSettings().maxChangesCacheSize()) {
|
||||
documentQueue.dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
logMessage(QString("ChangesManager: Updated %1 line %2: '%3'")
|
||||
.arg(fileName)
|
||||
.arg(lineNumber)
|
||||
.arg(lineContent));
|
||||
logMessage(QString("ChangesManager: Document queue size %1").arg(documentQueue.size()));
|
||||
}
|
||||
|
||||
QString ChangesManager::getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const
|
||||
{
|
||||
QString context;
|
||||
for (auto it = m_documentChanges.constBegin(); it != m_documentChanges.constEnd(); ++it) {
|
||||
if (it.key() != currentDocument) {
|
||||
for (const auto &change : it.value()) {
|
||||
context += change.lineContent + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
61
core/ChangesManager.h
Normal file
61
core/ChangesManager.h
Normal 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 <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
class ChangesManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct ChangeInfo
|
||||
{
|
||||
QString fileName;
|
||||
int lineNumber;
|
||||
QString lineContent;
|
||||
};
|
||||
|
||||
static ChangesManager &instance();
|
||||
|
||||
void addChange(TextEditor::TextDocument *document,
|
||||
int position,
|
||||
int charsRemoved,
|
||||
int charsAdded);
|
||||
QString getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const;
|
||||
|
||||
private:
|
||||
ChangesManager();
|
||||
~ChangesManager();
|
||||
ChangesManager(const ChangesManager &) = delete;
|
||||
ChangesManager &operator=(const ChangesManager &) = delete;
|
||||
|
||||
void cleanupOldChanges();
|
||||
|
||||
QHash<TextEditor::TextDocument *, QQueue<ChangeInfo>> m_documentChanges;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
@ -26,8 +26,8 @@
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -50,25 +50,27 @@ QString LMStudioProvider::completionEndpoint() const
|
||||
|
||||
void LMStudioProvider::prepareRequest(QJsonObject &request)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
const auto ¤tTemplate = PromptTemplateManager::instance().getCurrentTemplate();
|
||||
|
||||
if (currentTemplate->name() == "Custom Template")
|
||||
return;
|
||||
if (request.contains("prompt")) {
|
||||
QJsonArray messages{
|
||||
{QJsonObject{{"role", "user"}, {"content", request.take("prompt").toString()}}}};
|
||||
request["messages"] = std::move(messages);
|
||||
}
|
||||
|
||||
request["max_tokens"] = settings().maxTokens();
|
||||
request["temperature"] = settings().temperature();
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
request["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
|
||||
if (settings().useTopP())
|
||||
request["top_p"] = settings().topP();
|
||||
if (settings().useTopK())
|
||||
request["top_k"] = settings().topK();
|
||||
if (settings().useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings().frequencyPenalty();
|
||||
if (settings().usePresencePenalty())
|
||||
request["presence_penalty"] = settings().presencePenalty();
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
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)
|
||||
|
||||
@ -26,8 +26,8 @@
|
||||
#include <QtCore/qeventloop.h>
|
||||
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -50,21 +50,24 @@ QString OllamaProvider::completionEndpoint() const
|
||||
|
||||
void OllamaProvider::prepareRequest(QJsonObject &request)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
auto currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
|
||||
if (currentTemplate->name() == "Custom Template")
|
||||
return;
|
||||
|
||||
QJsonObject options;
|
||||
options["num_predict"] = settings().maxTokens();
|
||||
options["keep_alive"] = settings().ollamaLivetime();
|
||||
options["temperature"] = settings().temperature();
|
||||
options["num_predict"] = settings.maxTokens();
|
||||
options["keep_alive"] = settings.ollamaLivetime();
|
||||
options["temperature"] = settings.temperature();
|
||||
options["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
|
||||
if (settings().useTopP())
|
||||
options["top_p"] = settings().topP();
|
||||
if (settings().useTopK())
|
||||
options["top_k"] = settings().topK();
|
||||
if (settings().useFrequencyPenalty())
|
||||
options["frequency_penalty"] = settings().frequencyPenalty();
|
||||
if (settings().usePresencePenalty())
|
||||
options["presence_penalty"] = settings().presencePenalty();
|
||||
if (settings.useTopP())
|
||||
options["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
options["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
options["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
options["presence_penalty"] = settings.presencePenalty();
|
||||
request["options"] = options;
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistSettings.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -48,7 +48,10 @@ QString OpenAICompatProvider::completionEndpoint() const
|
||||
|
||||
void OpenAICompatProvider::prepareRequest(QJsonObject &request)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
const auto ¤tTemplate = PromptTemplateManager::instance().getCurrentTemplate();
|
||||
if (currentTemplate->name() == "Custom Template")
|
||||
return;
|
||||
|
||||
if (request.contains("prompt")) {
|
||||
QJsonArray messages{
|
||||
@ -56,19 +59,19 @@ void OpenAICompatProvider::prepareRequest(QJsonObject &request)
|
||||
request["messages"] = std::move(messages);
|
||||
}
|
||||
|
||||
request["max_tokens"] = settings().maxTokens();
|
||||
request["temperature"] = settings().temperature();
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
request["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
|
||||
if (settings().useTopP())
|
||||
request["top_p"] = settings().topP();
|
||||
if (settings().useTopK())
|
||||
request["top_k"] = settings().topK();
|
||||
if (settings().useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings().frequencyPenalty();
|
||||
if (settings().usePresencePenalty())
|
||||
request["presence_penalty"] = settings().presencePenalty();
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
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.value();
|
||||
const QString &apiKey = settings.apiKey.value();
|
||||
if (!apiKey.isEmpty()) {
|
||||
request["api_key"] = apiKey;
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
#include "providers/OllamaProvider.hpp"
|
||||
#include "providers/OpenAICompatProvider.hpp"
|
||||
#include "templates/CodeLLamaTemplate.hpp"
|
||||
#include "templates/CodeQwenChat.hpp"
|
||||
#include "templates/CustomTemplate.hpp"
|
||||
#include "templates/DeepSeekCoderV2.hpp"
|
||||
#include "templates/StarCoder2Template.hpp"
|
||||
|
||||
@ -80,8 +80,8 @@ public:
|
||||
auto &templateManager = PromptTemplateManager::instance();
|
||||
templateManager.registerTemplate<Templates::CodeLLamaTemplate>();
|
||||
templateManager.registerTemplate<Templates::StarCoder2Template>();
|
||||
templateManager.registerTemplate<Templates::CodeQwenChatTemplate>();
|
||||
templateManager.registerTemplate<Templates::DeepSeekCoderV2Template>();
|
||||
templateManager.registerTemplate<Templates::CustomTemplate>();
|
||||
|
||||
Utils::Icon QCODEASSIST_ICON(
|
||||
{{":/resources/images/qoderassist-icon.png", Utils::Theme::IconsBaseColor}});
|
||||
|
||||
19
rawPromptExamples/OllamaStarCoder2FIM.json
Normal file
19
rawPromptExamples/OllamaStarCoder2FIM.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"prompt": "{{QODE_INSTRUCTIONS}}<fim_prefix>{{QODE_PREFIX}}<fim_suffix>{{QODE_SUFFIX}}<fim_middle>",
|
||||
"options": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"top_k": 40,
|
||||
"num_predict": 175,
|
||||
"stop": [
|
||||
"<|endoftext|>",
|
||||
"<file_sep>",
|
||||
"<fim_prefix>",
|
||||
"<fim_suffix>",
|
||||
"<fim_middle>"
|
||||
],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
"stream": true
|
||||
}
|
||||
16
rawPromptExamples/OpenAICodeqwenChat.json
Normal file
16
rawPromptExamples/OpenAICodeqwenChat.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"max_tokens": 150,
|
||||
"messages": [
|
||||
{
|
||||
"content": "{{QODE_INSTRUCTIONS}}\n### Instruction:{{QODE_PREFIX}}{{QODE_SUFFIX}} ### Response:\n",
|
||||
"role": "user"
|
||||
}
|
||||
],
|
||||
"stop": [
|
||||
"### Instruction:",
|
||||
"### Response:",
|
||||
"\n\n### "
|
||||
],
|
||||
"stream": true,
|
||||
"temperature": 0.2
|
||||
}
|
||||
159
settings/ContextSettings.cpp
Normal file
159
settings/ContextSettings.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 "ContextSettings.hpp"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
ContextSettings &contextSettings()
|
||||
{
|
||||
static ContextSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
ContextSettings::ContextSettings()
|
||||
{
|
||||
setAutoApply(false);
|
||||
|
||||
setDisplayName(Tr::tr("Context"));
|
||||
|
||||
readFullFile.setSettingsKey(Constants::READ_FULL_FILE);
|
||||
readFullFile.setLabelText(Tr::tr("Read Full File"));
|
||||
readFullFile.setDefaultValue(false);
|
||||
|
||||
readStringsBeforeCursor.setSettingsKey(Constants::READ_STRINGS_BEFORE_CURSOR);
|
||||
readStringsBeforeCursor.setLabelText(Tr::tr("Read Strings Before Cursor"));
|
||||
readStringsBeforeCursor.setRange(0, 10000);
|
||||
readStringsBeforeCursor.setDefaultValue(50);
|
||||
|
||||
readStringsAfterCursor.setSettingsKey(Constants::READ_STRINGS_AFTER_CURSOR);
|
||||
readStringsAfterCursor.setLabelText(Tr::tr("Read Strings After Cursor"));
|
||||
readStringsAfterCursor.setRange(0, 10000);
|
||||
readStringsAfterCursor.setDefaultValue(30);
|
||||
|
||||
useFilePathInContext.setSettingsKey(Constants::USE_FILE_PATH_IN_CONTEXT);
|
||||
useFilePathInContext.setDefaultValue(false);
|
||||
useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context"));
|
||||
|
||||
useSpecificInstructions.setSettingsKey(Constants::USE_SPECIFIC_INSTRUCTIONS);
|
||||
useSpecificInstructions.setDefaultValue(false);
|
||||
useSpecificInstructions.setLabelText(Tr::tr("Use Specific Instructions"));
|
||||
|
||||
specificInstractions.setSettingsKey(Constants::SPECIFIC_INSTRUCTIONS);
|
||||
specificInstractions.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||
specificInstractions.setLabelText(
|
||||
Tr::tr("Instructions: Please keep %1 for languge name, warning, it shouldn't too big"));
|
||||
specificInstractions.setDefaultValue(
|
||||
"You are an expert %1 code completion AI."
|
||||
"CRITICAL: Please provide minimal the best possible code completion suggestions.\n");
|
||||
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
useProjectChangesCache.setSettingsKey(Constants::USE_PROJECT_CHANGES_CACHE);
|
||||
useProjectChangesCache.setDefaultValue(true);
|
||||
useProjectChangesCache.setLabelText(Tr::tr("Use Project Changes Cache"));
|
||||
|
||||
maxChangesCacheSize.setSettingsKey(Constants::MAX_CHANGES_CACHE_SIZE);
|
||||
maxChangesCacheSize.setLabelText(Tr::tr("Max Changes Cache Size"));
|
||||
maxChangesCacheSize.setRange(2, 1000);
|
||||
maxChangesCacheSize.setDefaultValue(20);
|
||||
|
||||
readSettings();
|
||||
|
||||
readStringsAfterCursor.setEnabled(!readFullFile());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile());
|
||||
specificInstractions.setEnabled(useSpecificInstructions());
|
||||
|
||||
setupConnection();
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{readFullFile, Stretch{1}, resetToDefaults},
|
||||
Row{readStringsBeforeCursor, Stretch{1}},
|
||||
Row{readStringsAfterCursor, Stretch{1}},
|
||||
useFilePathInContext,
|
||||
useSpecificInstructions,
|
||||
specificInstractions,
|
||||
useProjectChangesCache,
|
||||
Row{maxChangesCacheSize, Stretch{1}},
|
||||
Stretch{1}};
|
||||
});
|
||||
}
|
||||
|
||||
void ContextSettings::setupConnection()
|
||||
{
|
||||
connect(&readFullFile, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
readStringsAfterCursor.setEnabled(!readFullFile.volatileValue());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile.volatileValue());
|
||||
});
|
||||
connect(&useSpecificInstructions, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
specificInstractions.setEnabled(useSpecificInstructions.volatileValue());
|
||||
});
|
||||
connect(&resetToDefaults, &ButtonAspect::clicked, this, &ContextSettings::resetPageToDefaults);
|
||||
}
|
||||
|
||||
void ContextSettings::resetPageToDefaults()
|
||||
{
|
||||
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(readFullFile);
|
||||
resetAspect(readStringsBeforeCursor);
|
||||
resetAspect(readStringsAfterCursor);
|
||||
resetAspect(useFilePathInContext);
|
||||
resetAspect(useSpecificInstructions);
|
||||
resetAspect(specificInstractions);
|
||||
}
|
||||
|
||||
QMessageBox::information(Core::ICore::dialogParent(),
|
||||
Tr::tr("Settings Reset"),
|
||||
Tr::tr("All settings have been reset to their default values."));
|
||||
}
|
||||
|
||||
class ContextSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
ContextSettingsPage()
|
||||
{
|
||||
setId(Constants::QODE_ASSIST_CONTEXT_SETTINGS_PAGE_ID);
|
||||
setDisplayName(Tr::tr("Context"));
|
||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
||||
setDisplayCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY);
|
||||
setCategoryIconPath(":/resources/images/qoderassist-icon.png");
|
||||
setSettingsProvider([] { return &contextSettings(); });
|
||||
}
|
||||
};
|
||||
|
||||
const ContextSettingsPage contextSettingsPage;
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
52
settings/ContextSettings.hpp
Normal file
52
settings/ContextSettings.hpp
Normal 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 <utils/aspects.h>
|
||||
|
||||
#include "SettingsUtils.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
class ContextSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
ContextSettings();
|
||||
|
||||
Utils::BoolAspect readFullFile{this};
|
||||
Utils::IntegerAspect readStringsBeforeCursor{this};
|
||||
Utils::IntegerAspect readStringsAfterCursor{this};
|
||||
|
||||
Utils::StringAspect specificInstractions{this};
|
||||
Utils::BoolAspect useSpecificInstructions{this};
|
||||
Utils::BoolAspect useFilePathInContext{this};
|
||||
Utils::BoolAspect useProjectChangesCache{this};
|
||||
Utils::IntegerAspect maxChangesCacheSize{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
private:
|
||||
void setupConnection();
|
||||
void resetPageToDefaults();
|
||||
};
|
||||
|
||||
ContextSettings &contextSettings();
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
203
settings/CustomPromptSettings.cpp
Normal file
203
settings/CustomPromptSettings.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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 "CustomPromptSettings.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QJsonParseError>
|
||||
#include <QMessageBox>
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
CustomPromptSettings &customPromptSettings()
|
||||
{
|
||||
static CustomPromptSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
CustomPromptSettings::CustomPromptSettings()
|
||||
{
|
||||
setAutoApply(false);
|
||||
|
||||
setDisplayName(Tr::tr("Custom Prompt"));
|
||||
|
||||
customJsonLabel.setLabelText("Custom JSON Template:");
|
||||
customJsonLabel.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
||||
|
||||
customJsonLegend.setLabelText(Tr::tr(R"(Prompt components:
|
||||
- model is set on General Page
|
||||
- {{QODE_INSTRUCTIONS}}: Placeholder for specific instructions or context.
|
||||
- {{QODE_PREFIX}}: Will be replaced with the actual code before the cursor.
|
||||
- {{QODE_SUFFIX}}: Will be replaced with the actual code after the cursor.
|
||||
)"));
|
||||
|
||||
customJsonTemplate.setSettingsKey(Constants::CUSTOM_JSON_TEMPLATE);
|
||||
customJsonTemplate.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||
|
||||
customJsonTemplate.setDefaultValue(R"({
|
||||
"prompt": "{{QODE_INSTRUCTIONS}}<fim_prefix>{{QODE_PREFIX}}<fim_suffix>{{QODE_SUFFIX}}<fim_middle>",
|
||||
"options": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"top_k": 40,
|
||||
"num_predict": 100,
|
||||
"stop": [
|
||||
"<|endoftext|>",
|
||||
"<file_sep>",
|
||||
"<fim_prefix>",
|
||||
"<fim_suffix>",
|
||||
"<fim_middle>"
|
||||
],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
"stream": true
|
||||
})");
|
||||
saveCustomTemplateButton.m_buttonText = (Tr::tr("Save Custom Template to JSON"));
|
||||
loadCustomTemplateButton.m_buttonText = (Tr::tr("Load Custom Template from JSON"));
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
readSettings();
|
||||
|
||||
setupConnection();
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{customJsonLabel, Stretch{1}, resetToDefaults},
|
||||
Row{customJsonTemplate,
|
||||
Column{saveCustomTemplateButton,
|
||||
loadCustomTemplateButton,
|
||||
customJsonLegend,
|
||||
Stretch{1}}}};
|
||||
});
|
||||
}
|
||||
|
||||
void CustomPromptSettings::setupConnection()
|
||||
{
|
||||
connect(&resetToDefaults,
|
||||
&ButtonAspect::clicked,
|
||||
this,
|
||||
&CustomPromptSettings::resetSettingsToDefaults);
|
||||
connect(&saveCustomTemplateButton,
|
||||
&ButtonAspect::clicked,
|
||||
this,
|
||||
&CustomPromptSettings::saveCustomTemplate);
|
||||
connect(&loadCustomTemplateButton,
|
||||
&ButtonAspect::clicked,
|
||||
this,
|
||||
&CustomPromptSettings::loadCustomTemplate);
|
||||
}
|
||||
|
||||
void CustomPromptSettings::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(customJsonTemplate);
|
||||
}
|
||||
|
||||
QMessageBox::information(Core::ICore::dialogParent(),
|
||||
Tr::tr("Settings Reset"),
|
||||
Tr::tr("All settings have been reset to their default values."));
|
||||
}
|
||||
|
||||
void CustomPromptSettings::saveCustomTemplate()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(nullptr,
|
||||
Tr::tr("Save JSON Template"),
|
||||
QString(),
|
||||
Tr::tr("JSON Files (*.json)"));
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(fileName);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << customJsonTemplate.value();
|
||||
file.close();
|
||||
QMessageBox::information(nullptr,
|
||||
Tr::tr("Save Successful"),
|
||||
Tr::tr("JSON template has been saved successfully."));
|
||||
} else {
|
||||
QMessageBox::critical(nullptr,
|
||||
Tr::tr("Save Failed"),
|
||||
Tr::tr("Failed to save JSON template."));
|
||||
}
|
||||
}
|
||||
|
||||
void CustomPromptSettings::loadCustomTemplate()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(nullptr,
|
||||
Tr::tr("Load JSON Template"),
|
||||
QString(),
|
||||
Tr::tr("JSON Files (*.json)"));
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(fileName);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
QString jsonContent = in.readAll();
|
||||
file.close();
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonContent.toUtf8(), &parseError);
|
||||
if (parseError.error == QJsonParseError::NoError) {
|
||||
customJsonTemplate.setVolatileValue(jsonContent);
|
||||
QMessageBox::information(nullptr,
|
||||
Tr::tr("Load Successful"),
|
||||
Tr::tr("JSON template has been loaded successfully."));
|
||||
} else {
|
||||
QMessageBox::critical(nullptr,
|
||||
Tr::tr("Invalid JSON"),
|
||||
Tr::tr("The selected file contains invalid JSON."));
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(nullptr,
|
||||
Tr::tr("Load Failed"),
|
||||
Tr::tr("Failed to load JSON template."));
|
||||
}
|
||||
}
|
||||
|
||||
class CustomPromptSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
CustomPromptSettingsPage()
|
||||
{
|
||||
setId(Constants::QODE_ASSIST_CUSTOM_PROMPT_SETTINGS_PAGE_ID);
|
||||
setDisplayName(Tr::tr("Custom Prompt"));
|
||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
||||
setSettingsProvider([] { return &customPromptSettings(); });
|
||||
}
|
||||
};
|
||||
|
||||
const CustomPromptSettingsPage customPromptSettingsPage;
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
48
settings/CustomPromptSettings.hpp
Normal file
48
settings/CustomPromptSettings.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 "settings/SettingsUtils.hpp"
|
||||
#include <utils/aspects.h>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
class CustomPromptSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
CustomPromptSettings();
|
||||
|
||||
Utils::StringAspect customJsonLabel{this};
|
||||
Utils::StringAspect customJsonTemplate{this};
|
||||
Utils::StringAspect customJsonLegend{this};
|
||||
ButtonAspect saveCustomTemplateButton{this};
|
||||
ButtonAspect loadCustomTemplateButton{this};
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
private:
|
||||
void setupConnection();
|
||||
void resetSettingsToDefaults();
|
||||
void saveCustomTemplate();
|
||||
void loadCustomTemplate();
|
||||
};
|
||||
|
||||
CustomPromptSettings &customPromptSettings();
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
256
settings/GeneralSettings.cpp
Normal file
256
settings/GeneralSettings.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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 "GeneralSettings.hpp"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
GeneralSettings &generalSettings()
|
||||
{
|
||||
static GeneralSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
GeneralSettings::GeneralSettings()
|
||||
{
|
||||
setAutoApply(false);
|
||||
|
||||
setDisplayName(Tr::tr("General"));
|
||||
|
||||
enableQodeAssist.setSettingsKey(Constants::ENABLE_QODE_ASSIST);
|
||||
enableQodeAssist.setLabelText(Tr::tr("Enable Qode Assist"));
|
||||
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.setLabelText(Tr::tr("Enable Logging"));
|
||||
enableLogging.setDefaultValue(false);
|
||||
|
||||
multiLineCompletion.setSettingsKey(Constants::MULTILINE_COMPLETION);
|
||||
multiLineCompletion.setDefaultValue(true);
|
||||
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion"));
|
||||
|
||||
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);
|
||||
|
||||
llmProviders.setSettingsKey(Constants::LLM_PROVIDERS);
|
||||
llmProviders.setDisplayName(Tr::tr("FIM Provider:"));
|
||||
llmProviders.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
||||
llmProviders.setDefaultValue(0);
|
||||
|
||||
url.setSettingsKey(Constants::URL);
|
||||
url.setLabelText(Tr::tr("URL:"));
|
||||
url.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
endPoint.setSettingsKey(Constants::END_POINT);
|
||||
endPoint.setLabelText(Tr::tr("FIM Endpoint:"));
|
||||
endPoint.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
modelName.setSettingsKey(Constants::MODEL_NAME);
|
||||
modelName.setLabelText(Tr::tr("LLM Name:"));
|
||||
modelName.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
selectModels.m_buttonText = Tr::tr("Select Fill-In-the-Middle Model");
|
||||
|
||||
fimPrompts.setDisplayName(Tr::tr("Fill-In-the-Middle Prompt"));
|
||||
fimPrompts.setSettingsKey(Constants::FIM_PROMPTS);
|
||||
fimPrompts.setDefaultValue(0);
|
||||
fimPrompts.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
const auto &manager = LLMProvidersManager::instance();
|
||||
if (!manager.getProviderNames().isEmpty()) {
|
||||
const auto providerNames = manager.getProviderNames();
|
||||
for (const QString &name : providerNames) {
|
||||
llmProviders.addOption(name);
|
||||
}
|
||||
}
|
||||
|
||||
const auto &promptManager = PromptTemplateManager::instance();
|
||||
if (!promptManager.getTemplateNames().isEmpty()) {
|
||||
const auto promptNames = promptManager.getTemplateNames();
|
||||
for (const QString &name : promptNames) {
|
||||
fimPrompts.addOption(name);
|
||||
}
|
||||
}
|
||||
|
||||
readSettings();
|
||||
|
||||
LLMProvidersManager::instance().setCurrentProvider(llmProviders.stringValue());
|
||||
PromptTemplateManager::instance().setCurrentTemplate(fimPrompts.stringValue());
|
||||
setLoggingEnabled(enableLogging());
|
||||
|
||||
setupConnections();
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
|
||||
auto rootLayout = Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults},
|
||||
enableAutoComplete,
|
||||
multiLineCompletion,
|
||||
Row{autoCompletionCharThreshold,
|
||||
autoCompletionTypingInterval,
|
||||
startSuggestionTimer,
|
||||
Stretch{1}},
|
||||
Space{8},
|
||||
enableLogging,
|
||||
Space{8},
|
||||
llmProviders,
|
||||
Row{url, endPoint},
|
||||
Space{8},
|
||||
Row{selectModels, modelName},
|
||||
Space{8},
|
||||
fimPrompts,
|
||||
Stretch{1}};
|
||||
return rootLayout;
|
||||
});
|
||||
}
|
||||
|
||||
void GeneralSettings::setupConnections()
|
||||
{
|
||||
connect(&llmProviders, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = llmProviders.volatileValue();
|
||||
logMessage(QString("currentProvider %1").arg(llmProviders.displayForIndex(index)));
|
||||
LLMProvidersManager::instance().setCurrentProvider(llmProviders.displayForIndex(index));
|
||||
updateProviderSettings();
|
||||
});
|
||||
connect(&fimPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = fimPrompts.volatileValue();
|
||||
logMessage(QString("currentPrompt %1").arg(fimPrompts.displayForIndex(index)));
|
||||
PromptTemplateManager::instance().setCurrentTemplate(fimPrompts.displayForIndex(index));
|
||||
});
|
||||
connect(&selectModels, &ButtonAspect::clicked, this, [this]() { showModelSelectionDialog(); });
|
||||
connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
setLoggingEnabled(enableLogging.volatileValue());
|
||||
});
|
||||
connect(&resetToDefaults, &ButtonAspect::clicked, this, &GeneralSettings::resetPageToDefaults);
|
||||
}
|
||||
|
||||
void GeneralSettings::updateProviderSettings()
|
||||
{
|
||||
const auto provider = LLMProvidersManager::instance().getCurrentProvider();
|
||||
|
||||
if (provider) {
|
||||
url.setVolatileValue(provider->url());
|
||||
endPoint.setVolatileValue(provider->completionEndpoint());
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralSettings::showModelSelectionDialog()
|
||||
{
|
||||
auto *provider = LLMProvidersManager::instance().getCurrentProvider();
|
||||
Utils::Environment env = Utils::Environment::systemEnvironment();
|
||||
|
||||
if (provider) {
|
||||
QStringList models = provider->getInstalledModels(env);
|
||||
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()) {
|
||||
modelName.setVolatileValue(selectedModel);
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralSettings::resetPageToDefaults()
|
||||
{
|
||||
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(enableQodeAssist);
|
||||
resetAspect(enableAutoComplete);
|
||||
resetAspect(llmProviders);
|
||||
resetAspect(url);
|
||||
resetAspect(endPoint);
|
||||
resetAspect(modelName);
|
||||
resetAspect(fimPrompts);
|
||||
resetAspect(enableLogging);
|
||||
resetAspect(startSuggestionTimer);
|
||||
resetAspect(autoCompletionTypingInterval);
|
||||
resetAspect(autoCompletionCharThreshold);
|
||||
}
|
||||
|
||||
fimPrompts.setStringValue("StarCoder2");
|
||||
llmProviders.setStringValue("Ollama");
|
||||
|
||||
QMessageBox::information(Core::ICore::dialogParent(),
|
||||
Tr::tr("Settings Reset"),
|
||||
Tr::tr("All settings have been reset to their default values."));
|
||||
}
|
||||
|
||||
class GeneralSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
GeneralSettingsPage()
|
||||
{
|
||||
setId(Constants::QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID);
|
||||
setDisplayName(Tr::tr("General"));
|
||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
||||
setSettingsProvider([] { return &generalSettings(); });
|
||||
}
|
||||
};
|
||||
|
||||
const GeneralSettingsPage generalSettingsPage;
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
59
settings/GeneralSettings.hpp
Normal file
59
settings/GeneralSettings.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 "settings/SettingsUtils.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
class GeneralSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
GeneralSettings();
|
||||
|
||||
Utils::BoolAspect enableQodeAssist{this};
|
||||
Utils::BoolAspect enableAutoComplete{this};
|
||||
Utils::BoolAspect multiLineCompletion{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};
|
||||
|
||||
private:
|
||||
void setupConnections();
|
||||
void updateProviderSettings();
|
||||
void showModelSelectionDialog();
|
||||
void resetPageToDefaults();
|
||||
};
|
||||
|
||||
GeneralSettings &generalSettings();
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
185
settings/PresetPromptsSettings.cpp
Normal file
185
settings/PresetPromptsSettings.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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 "PresetPromptsSettings.hpp"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
PresetPromptsSettings &presetPromptsSettings()
|
||||
{
|
||||
static PresetPromptsSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
PresetPromptsSettings::PresetPromptsSettings()
|
||||
{
|
||||
setAutoApply(false);
|
||||
|
||||
setDisplayName(Tr::tr("Preset Prompts Params"));
|
||||
|
||||
temperature.setSettingsKey(Constants::TEMPERATURE);
|
||||
temperature.setLabelText(Tr::tr("Temperature:"));
|
||||
temperature.setDefaultValue(0.2);
|
||||
temperature.setRange(0.0, 10.0);
|
||||
|
||||
ollamaLivetime.setSettingsKey(Constants::OLLAMA_LIVETIME);
|
||||
ollamaLivetime.setLabelText(
|
||||
Tr::tr("Time to suspend Ollama after completion request (in minutes), "
|
||||
"Only Ollama, -1 to disable"));
|
||||
ollamaLivetime.setDefaultValue("5m");
|
||||
ollamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
maxTokens.setSettingsKey(Constants::MAX_TOKENS);
|
||||
maxTokens.setLabelText(Tr::tr("Max Tokens"));
|
||||
maxTokens.setRange(-1, 10000);
|
||||
maxTokens.setDefaultValue(150);
|
||||
|
||||
useTopP.setSettingsKey(Constants::USE_TOP_P);
|
||||
useTopP.setDefaultValue(false);
|
||||
|
||||
topP.setSettingsKey(Constants::TOP_P);
|
||||
topP.setLabelText(Tr::tr("top_p"));
|
||||
topP.setDefaultValue(0.9);
|
||||
topP.setRange(0.0, 1.0);
|
||||
|
||||
useTopK.setSettingsKey(Constants::USE_TOP_K);
|
||||
useTopK.setDefaultValue(false);
|
||||
|
||||
topK.setSettingsKey(Constants::TOP_K);
|
||||
topK.setLabelText(Tr::tr("top_k"));
|
||||
topK.setDefaultValue(50);
|
||||
topK.setRange(1, 1000);
|
||||
|
||||
usePresencePenalty.setSettingsKey(Constants::USE_PRESENCE_PENALTY);
|
||||
usePresencePenalty.setDefaultValue(false);
|
||||
|
||||
presencePenalty.setSettingsKey(Constants::PRESENCE_PENALTY);
|
||||
presencePenalty.setLabelText(Tr::tr("presence_penalty"));
|
||||
presencePenalty.setDefaultValue(0.0);
|
||||
presencePenalty.setRange(-2.0, 2.0);
|
||||
|
||||
useFrequencyPenalty.setSettingsKey(Constants::USE_FREQUENCY_PENALTY);
|
||||
useFrequencyPenalty.setDefaultValue(false);
|
||||
|
||||
frequencyPenalty.setSettingsKey(Constants::FREQUENCY_PENALTY);
|
||||
frequencyPenalty.setLabelText(Tr::tr("frequency_penalty"));
|
||||
frequencyPenalty.setDefaultValue(0.0);
|
||||
frequencyPenalty.setRange(-2.0, 2.0);
|
||||
|
||||
apiKey.setSettingsKey(Constants::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();
|
||||
|
||||
topK.setEnabled(useTopK());
|
||||
topP.setEnabled(useTopP());
|
||||
presencePenalty.setEnabled(usePresencePenalty());
|
||||
frequencyPenalty.setEnabled(useFrequencyPenalty());
|
||||
|
||||
setupConnections();
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{temperature, Stretch{1}, resetToDefaults},
|
||||
maxTokens,
|
||||
Row{useTopP, topP, Stretch{1}},
|
||||
Row{useTopK, topK, Stretch{1}},
|
||||
Row{usePresencePenalty, presencePenalty, Stretch{1}},
|
||||
Row{useFrequencyPenalty, frequencyPenalty, Stretch{1}},
|
||||
apiKey,
|
||||
Stretch{1}};
|
||||
});
|
||||
}
|
||||
|
||||
void PresetPromptsSettings::setupConnections()
|
||||
{
|
||||
connect(&useTopP, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
topP.setEnabled(useTopP.volatileValue());
|
||||
});
|
||||
connect(&useTopK, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
topK.setEnabled(useTopK.volatileValue());
|
||||
});
|
||||
connect(&usePresencePenalty, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
presencePenalty.setEnabled(usePresencePenalty.volatileValue());
|
||||
});
|
||||
connect(&useFrequencyPenalty, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
frequencyPenalty.setEnabled(useFrequencyPenalty.volatileValue());
|
||||
});
|
||||
|
||||
connect(&resetToDefaults,
|
||||
&ButtonAspect::clicked,
|
||||
this,
|
||||
&PresetPromptsSettings::resetSettingsToDefaults);
|
||||
}
|
||||
|
||||
void PresetPromptsSettings::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(temperature);
|
||||
resetAspect(maxTokens);
|
||||
resetAspect(ollamaLivetime);
|
||||
resetAspect(useTopP);
|
||||
resetAspect(topP);
|
||||
resetAspect(useTopK);
|
||||
resetAspect(topK);
|
||||
resetAspect(usePresencePenalty);
|
||||
resetAspect(presencePenalty);
|
||||
resetAspect(useFrequencyPenalty);
|
||||
resetAspect(frequencyPenalty);
|
||||
}
|
||||
|
||||
QMessageBox::information(Core::ICore::dialogParent(),
|
||||
Tr::tr("Settings Reset"),
|
||||
Tr::tr("All settings have been reset to their default values."));
|
||||
}
|
||||
|
||||
class PresetPromptsSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
PresetPromptsSettingsPage()
|
||||
{
|
||||
setId(Constants::QODE_ASSIST_PRESET_PROMPTS_SETTINGS_PAGE_ID);
|
||||
setDisplayName(Tr::tr("Preset Prompts Params"));
|
||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
||||
setSettingsProvider([] { return &presetPromptsSettings(); });
|
||||
}
|
||||
};
|
||||
|
||||
const PresetPromptsSettingsPage presetPromptsSettingsPage;
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
59
settings/PresetPromptsSettings.hpp
Normal file
59
settings/PresetPromptsSettings.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 "settings/SettingsUtils.hpp"
|
||||
#include <utils/aspects.h>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
class PresetPromptsSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
PresetPromptsSettings();
|
||||
|
||||
Utils::DoubleAspect temperature{this};
|
||||
Utils::IntegerAspect maxTokens{this};
|
||||
|
||||
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};
|
||||
|
||||
Utils::StringAspect ollamaLivetime{this};
|
||||
Utils::StringAspect apiKey{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
private:
|
||||
void setupConnections();
|
||||
void resetSettingsToDefaults();
|
||||
};
|
||||
|
||||
PresetPromptsSettings &presetPromptsSettings();
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
55
settings/SettingsUtils.hpp
Normal file
55
settings/SettingsUtils.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
template<typename AspectType>
|
||||
void resetAspect(AspectType &aspect)
|
||||
{
|
||||
aspect.setVolatileValue(aspect.defaultValue());
|
||||
}
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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 "PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class CodeQwenChatTemplate : public PromptTemplate
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "CodeQwenChat (experimental)"; }
|
||||
QString promptTemplate() const override { return "%1\n### Instruction:%2%3 ### Response:\n"; }
|
||||
QStringList stopWords() const override
|
||||
{
|
||||
return QStringList() << "### Instruction:" << "### Response:" << "\n\n### ";
|
||||
}
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.instriuctions,
|
||||
context.prefix,
|
||||
context.suffix);
|
||||
request["prompt"] = formattedPrompt;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Templates
|
||||
89
templates/CustomTemplate.hpp
Normal file
89
templates/CustomTemplate.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 "PromptTemplate.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/CustomPromptSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class CustomTemplate : public PromptTemplate
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "Custom Template"; }
|
||||
QString promptTemplate() const override
|
||||
{
|
||||
return Settings::customPromptSettings().customJsonTemplate();
|
||||
}
|
||||
QStringList stopWords() const override { return QStringList(); }
|
||||
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(promptTemplate().toUtf8());
|
||||
if (doc.isNull() || !doc.isObject()) {
|
||||
logMessage(QString("Invalid JSON template in settings"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject templateObj = doc.object();
|
||||
QJsonObject processedObj = processJsonTemplate(templateObj, context);
|
||||
|
||||
for (auto it = processedObj.begin(); it != processedObj.end(); ++it) {
|
||||
request[it.key()] = it.value();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QJsonValue processJsonValue(const QJsonValue &value, const ContextData &context) const
|
||||
{
|
||||
if (value.isString()) {
|
||||
QString str = value.toString();
|
||||
str.replace("{{QODE_INSTRUCTIONS}}", context.instriuctions);
|
||||
str.replace("{{QODE_PREFIX}}", context.prefix);
|
||||
str.replace("{{QODE_SUFFIX}}", context.suffix);
|
||||
return str;
|
||||
} else if (value.isObject()) {
|
||||
return processJsonTemplate(value.toObject(), context);
|
||||
} else if (value.isArray()) {
|
||||
QJsonArray newArray;
|
||||
for (const QJsonValue &arrayValue : value.toArray()) {
|
||||
newArray.append(processJsonValue(arrayValue, context));
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
QJsonObject processJsonTemplate(const QJsonObject &templateObj, const ContextData &context) const
|
||||
{
|
||||
QJsonObject result;
|
||||
for (auto it = templateObj.begin(); it != templateObj.end(); ++it) {
|
||||
result[it.key()] = processJsonValue(it.value(), context);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace QodeAssist::Templates
|
||||
Reference in New Issue
Block a user