mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-02-10 01:00:23 -05:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40a568ebd9 | |||
| 5b43eb4fd2 | |||
| 9c2516cd4c | |||
| 2257e6e45f | |||
| 80eda8c167 | |||
| 3db2691114 | |||
| bf518b4a01 | |||
| 46829720d8 | |||
| 9158a3ac0d | |||
| d6e02d9d2a | |||
| 9c8cac4e3a | |||
| 965af4a945 | |||
| 95f29fefc7 | |||
| 1dd50b6c83 | |||
| 146e772514 | |||
| 4b851f1662 | |||
| 6fea300825 | |||
| 14bf0e6c94 | |||
| 0c045e65df | |||
| 15138b4644 | |||
| 5c98de7440 | |||
| b808d0ec10 | |||
| 30fcd7e019 | |||
| 7442256bab | |||
| 8be279a5fd | |||
| d77e13cddb | |||
| 162c068431 | |||
| 4e8ff55355 | |||
| 8df21e96bd |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -3,7 +3,7 @@
|
||||
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
|
||||
ko_fi: palm1r
|
||||
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
|
||||
|
||||
@ -12,6 +12,11 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
find_package(QtCreator REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED)
|
||||
|
||||
add_subdirectory(llmcore)
|
||||
add_subdirectory(settings)
|
||||
add_subdirectory(logger)
|
||||
add_subdirectory(chatview)
|
||||
|
||||
add_qtc_plugin(QodeAssist
|
||||
PLUGIN_DEPENDS
|
||||
QtCreator::Core
|
||||
@ -30,36 +35,26 @@ add_qtc_plugin(QodeAssist
|
||||
QodeAssistConstants.hpp
|
||||
QodeAssisttr.h
|
||||
LLMClientInterface.hpp LLMClientInterface.cpp
|
||||
PromptTemplateManager.hpp PromptTemplateManager.cpp
|
||||
templates/PromptTemplate.hpp
|
||||
templates/CodeLlamaFimTemplate.hpp
|
||||
templates/StarCoder2Template.hpp
|
||||
templates/DeepSeekCoderV2.hpp
|
||||
templates/CustomTemplate.hpp
|
||||
templates/DeepSeekCoderChatTemplate.hpp
|
||||
templates/CodeLlamaInstruct.hpp
|
||||
providers/LLMProvider.hpp
|
||||
templates/CodeLlamaFim.hpp
|
||||
templates/StarCoder2Fim.hpp
|
||||
templates/DeepSeekCoderFim.hpp
|
||||
templates/CustomFimTemplate.hpp
|
||||
templates/DeepSeekCoderChat.hpp
|
||||
templates/CodeLlamaChat.hpp
|
||||
templates/QwenChat.hpp
|
||||
templates/StarCoderChat.hpp
|
||||
providers/OllamaProvider.hpp providers/OllamaProvider.cpp
|
||||
providers/LMStudioProvider.hpp providers/LMStudioProvider.cpp
|
||||
providers/OpenAICompatProvider.hpp providers/OpenAICompatProvider.cpp
|
||||
LLMProvidersManager.hpp LLMProvidersManager.cpp
|
||||
QodeAssist.qrc
|
||||
LSPCompletion.hpp
|
||||
LLMSuggestion.hpp LLMSuggestion.cpp
|
||||
QodeAssistClient.hpp QodeAssistClient.cpp
|
||||
QodeAssistUtils.hpp
|
||||
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
|
||||
core/LLMRequestHandler.hpp core/LLMRequestHandler.cpp
|
||||
core/LLMRequestConfig.hpp
|
||||
chat/ChatWidget.h chat/ChatWidget.cpp
|
||||
chat/ChatOutputPane.h chat/ChatOutputPane.cpp
|
||||
chat/ChatClientInterface.hpp chat/ChatClientInterface.cpp
|
||||
chat/NavigationPanel.hpp chat/NavigationPanel.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(QodeAssist PRIVATE QodeAssistChatViewplugin)
|
||||
|
||||
@ -135,13 +135,6 @@ QString DocumentContextReader::getLanguageAndFileInfo() const
|
||||
.arg(language, mimeType, filePath, fileExtension);
|
||||
}
|
||||
|
||||
QString DocumentContextReader::getSpecificInstructions() const
|
||||
{
|
||||
QString specificInstruction = Settings::contextSettings().specificInstractions().arg(
|
||||
LanguageServerProtocol::TextDocumentItem::mimeTypeToLanguageId(m_textDocument->mimeType()));
|
||||
return QString("%1").arg(specificInstruction);
|
||||
}
|
||||
|
||||
CopyrightInfo DocumentContextReader::findCopyright()
|
||||
{
|
||||
CopyrightInfo result = {-1, -1, false};
|
||||
@ -210,7 +203,7 @@ CopyrightInfo DocumentContextReader::copyrightInfo() const
|
||||
return m_copyrightInfo;
|
||||
}
|
||||
|
||||
ContextData DocumentContextReader::prepareContext(int lineNumber, int cursorPosition) const
|
||||
LLMCore::ContextData DocumentContextReader::prepareContext(int lineNumber, int cursorPosition) const
|
||||
{
|
||||
QString contextBefore = getContextBefore(lineNumber, cursorPosition);
|
||||
QString contextAfter = getContextAfter(lineNumber, cursorPosition);
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
#include <QTextDocument>
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
#include "QodeAssistData.hpp"
|
||||
#include <llmcore/ContextData.hpp>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
@ -44,13 +44,12 @@ public:
|
||||
QString readWholeFileBefore(int lineNumber, int cursorPosition) const;
|
||||
QString readWholeFileAfter(int lineNumber, int cursorPosition) const;
|
||||
QString getLanguageAndFileInfo() const;
|
||||
QString getSpecificInstructions() const;
|
||||
CopyrightInfo findCopyright();
|
||||
QString getContextBetween(int startLine, int endLine, int cursorPosition) const;
|
||||
|
||||
CopyrightInfo copyrightInfo() const;
|
||||
|
||||
ContextData prepareContext(int lineNumber, int cursorPosition) const;
|
||||
LLMCore::ContextData prepareContext(int lineNumber, int cursorPosition) const;
|
||||
|
||||
private:
|
||||
QString getContextBefore(int lineNumber, int cursorPosition) const;
|
||||
|
||||
@ -23,13 +23,13 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <llmcore/RequestConfig.hpp>
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
#include "DocumentContextReader.hpp"
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "core/LLMRequestConfig.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "llmcore/PromptTemplateManager.hpp"
|
||||
#include "llmcore/ProvidersManager.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
@ -39,7 +39,7 @@ LLMClientInterface::LLMClientInterface()
|
||||
: m_requestHandler(this)
|
||||
{
|
||||
connect(&m_requestHandler,
|
||||
&LLMRequestHandler::completionReceived,
|
||||
&LLMCore::RequestHandler::completionReceived,
|
||||
this,
|
||||
&LLMClientInterface::sendCompletionToClient);
|
||||
}
|
||||
@ -80,7 +80,7 @@ void LLMClientInterface::sendData(const QByteArray &data)
|
||||
} else if (method == "exit") {
|
||||
// TODO make exit handler
|
||||
} else {
|
||||
logMessage(QString("Unknown method: %1").arg(method));
|
||||
LOG_MESSAGE(QString("Unknown method: %1").arg(method));
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,9 +88,9 @@ void LLMClientInterface::handleCancelRequest(const QJsonObject &request)
|
||||
{
|
||||
QString id = request["params"].toObject()["id"].toString();
|
||||
if (m_requestHandler.cancelRequest(id)) {
|
||||
logMessage(QString("Request %1 cancelled successfully").arg(id));
|
||||
LOG_MESSAGE(QString("Request %1 cancelled successfully").arg(id));
|
||||
} else {
|
||||
logMessage(QString("Request %1 not found").arg(id));
|
||||
LOG_MESSAGE(QString("Request %1 not found").arg(id));
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,10 +148,10 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
||||
{
|
||||
auto updatedContext = prepareContext(request);
|
||||
|
||||
LLMConfig config;
|
||||
config.requestType = RequestType::Fim;
|
||||
config.provider = LLMProvidersManager::instance().getCurrentFimProvider();
|
||||
config.promptTemplate = PromptTemplateManager::instance().getCurrentFimTemplate();
|
||||
LLMCore::LLMConfig config;
|
||||
config.requestType = LLMCore::RequestType::Fim;
|
||||
config.provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider();
|
||||
config.promptTemplate = LLMCore::PromptTemplateManager::instance().getCurrentFimTemplate();
|
||||
config.url = QUrl(QString("%1%2").arg(Settings::generalSettings().url(),
|
||||
Settings::generalSettings().endPoint()));
|
||||
|
||||
@ -159,18 +159,19 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
||||
{"stream", true},
|
||||
{"stop",
|
||||
QJsonArray::fromStringList(config.promptTemplate->stopWords())}};
|
||||
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion();
|
||||
|
||||
if (Settings::contextSettings().useSpecificInstructions())
|
||||
config.providerRequest["system"] = Settings::contextSettings().specificInstractions();
|
||||
if (Settings::contextSettings().useSystemPrompt())
|
||||
config.providerRequest["system"] = Settings::contextSettings().systemPrompt();
|
||||
|
||||
config.promptTemplate->prepareRequest(config.providerRequest, updatedContext);
|
||||
config.provider->prepareRequest(config.providerRequest);
|
||||
config.provider->prepareRequest(config.providerRequest, LLMCore::RequestType::Fim);
|
||||
|
||||
m_requestHandler.sendLLMRequest(config, request);
|
||||
}
|
||||
|
||||
ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
const QStringView &accumulatedCompletion)
|
||||
LLMCore::ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
const QStringView &accumulatedCompletion)
|
||||
{
|
||||
QJsonObject params = request["params"].toObject();
|
||||
QJsonObject doc = params["doc"].toObject();
|
||||
@ -182,8 +183,8 @@ ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
filePath);
|
||||
|
||||
if (!textDocument) {
|
||||
logMessage("Error: Document is not available for" + filePath.toString());
|
||||
return ContextData{};
|
||||
LOG_MESSAGE("Error: Document is not available for" + filePath.toString());
|
||||
return LLMCore::ContextData{};
|
||||
}
|
||||
|
||||
int cursorPosition = position["character"].toInt();
|
||||
@ -218,11 +219,11 @@ void LLMClientInterface::sendCompletionToClient(const QString &completion,
|
||||
result[LanguageServerProtocol::isIncompleteKey] = !isComplete;
|
||||
response[LanguageServerProtocol::resultKey] = result;
|
||||
|
||||
logMessage(
|
||||
LOG_MESSAGE(
|
||||
QString("Completions: \n%1")
|
||||
.arg(QString::fromUtf8(QJsonDocument(completions).toJson(QJsonDocument::Indented))));
|
||||
|
||||
logMessage(QString("Full response: \n%1")
|
||||
LOG_MESSAGE(QString("Full response: \n%1")
|
||||
.arg(QString::fromUtf8(QJsonDocument(response).toJson(QJsonDocument::Indented))));
|
||||
|
||||
QString requestId = request["id"].toString();
|
||||
@ -250,7 +251,7 @@ void LLMClientInterface::logPerformance(const QString &requestId,
|
||||
const QString &operation,
|
||||
qint64 elapsedMs)
|
||||
{
|
||||
logMessage(QString("Performance: %1 %2 took %3 ms").arg(requestId, operation).arg(elapsedMs));
|
||||
LOG_MESSAGE(QString("Performance: %1 %2 took %3 ms").arg(requestId, operation).arg(elapsedMs));
|
||||
}
|
||||
|
||||
void LLMClientInterface::parseCurrentMessage() {}
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include "QodeAssistData.hpp"
|
||||
#include "core/LLMRequestHandler.hpp"
|
||||
#include <llmcore/ContextData.hpp>
|
||||
#include <llmcore/RequestHandler.hpp>
|
||||
|
||||
class QNetworkReply;
|
||||
class QNetworkAccessManager;
|
||||
@ -58,10 +58,10 @@ private:
|
||||
void handleExit(const QJsonObject &request);
|
||||
void handleCancelRequest(const QJsonObject &request);
|
||||
|
||||
ContextData prepareContext(const QJsonObject &request,
|
||||
const QStringView &accumulatedCompletion = QString{});
|
||||
LLMCore::ContextData prepareContext(const QJsonObject &request,
|
||||
const QStringView &accumulatedCompletion = QString{});
|
||||
|
||||
LLMRequestHandler m_requestHandler;
|
||||
LLMCore::RequestHandler m_requestHandler;
|
||||
QElapsedTimer m_completionTimer;
|
||||
QMap<QString, qint64> m_requestStartTimes;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Name" : "QodeAssist",
|
||||
"Version" : "0.2.3",
|
||||
"Version" : "0.3.3",
|
||||
"CompatVersion" : "${IDE_VERSION_COMPAT}",
|
||||
"Vendor" : "Petr Mironychev",
|
||||
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
|
||||
|
||||
@ -24,60 +24,6 @@ namespace QodeAssist::Constants {
|
||||
const char ACTION_ID[] = "QodeAssist.Action";
|
||||
const char MENU_ID[] = "QodeAssist.Menu";
|
||||
|
||||
// settings
|
||||
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
|
||||
const char ENABLE_AUTO_COMPLETE[] = "QodeAssist.enableAutoComplete";
|
||||
const char ENABLE_LOGGING[] = "QodeAssist.enableLogging";
|
||||
const char LLM_PROVIDERS[] = "QodeAssist.llmProviders";
|
||||
const char URL[] = "QodeAssist.url";
|
||||
const char END_POINT[] = "QodeAssist.endPoint";
|
||||
const char MODEL_NAME[] = "QodeAssist.modelName";
|
||||
const char SELECT_MODELS[] = "QodeAssist.selectModels";
|
||||
const char FIM_PROMPTS[] = "QodeAssist.fimPrompts";
|
||||
const char TEMPERATURE[] = "QodeAssist.temperature";
|
||||
const char MAX_TOKENS[] = "QodeAssist.maxTokens";
|
||||
const char READ_FULL_FILE[] = "QodeAssist.readFullFile";
|
||||
const char READ_STRINGS_BEFORE_CURSOR[] = "QodeAssist.readStringsBeforeCursor";
|
||||
const char READ_STRINGS_AFTER_CURSOR[] = "QodeAssist.readStringsAfterCursor";
|
||||
const char USE_TOP_P[] = "QodeAssist.useTopP";
|
||||
const char TOP_P[] = "QodeAssist.topP";
|
||||
const char USE_TOP_K[] = "QodeAssist.useTopK";
|
||||
const char TOP_K[] = "QodeAssist.topK";
|
||||
const char USE_PRESENCE_PENALTY[] = "QodeAssist.usePresencePenalty";
|
||||
const char PRESENCE_PENALTY[] = "QodeAssist.presencePenalty";
|
||||
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 SYSTEM_PROMPT[] = "QodeAssist.systemPrompt";
|
||||
const char MULTILINE_COMPLETION[] = "QodeAssist.multilineCompletion";
|
||||
const char API_KEY[] = "QodeAssist.apiKey";
|
||||
const char USE_SYSTEM_PROMPT[] = "QodeAssist.useSystemPrompt";
|
||||
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 CHAT_LLM_PROVIDERS[] = "QodeAssist.chatLlmProviders";
|
||||
const char CHAT_URL[] = "QodeAssist.chatUrl";
|
||||
const char CHAT_END_POINT[] = "QodeAssist.chatEndPoint";
|
||||
const char CHAT_MODEL_NAME[] = "QodeAssist.chatModelName";
|
||||
const char CHAT_SELECT_MODELS[] = "QodeAssist.chatSelectModels";
|
||||
const char CHAT_PROMPTS[] = "QodeAssist.chatPrompts";
|
||||
|
||||
const char 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";
|
||||
|
||||
const char QODE_ASSIST_REQUEST_SUGGESTION[] = "QodeAssist.RequestSuggestion";
|
||||
|
||||
} // namespace QodeAssist::Constants
|
||||
|
||||
@ -1,107 +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 <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
inline bool &loggingEnabled()
|
||||
{
|
||||
static bool enabled = false;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
inline void setLoggingEnabled(bool enable)
|
||||
{
|
||||
loggingEnabled() = enable;
|
||||
}
|
||||
|
||||
inline void logMessage(const QString &message, bool silent = true)
|
||||
{
|
||||
if (!loggingEnabled())
|
||||
return;
|
||||
|
||||
const QString prefixedMessage = QLatin1String("[Qode Assist] ") + message;
|
||||
if (silent) {
|
||||
Core::MessageManager::writeSilently(prefixedMessage);
|
||||
} else {
|
||||
Core::MessageManager::writeFlashing(prefixedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
inline void logMessages(const QStringList &messages, bool silent = true)
|
||||
{
|
||||
if (!loggingEnabled())
|
||||
return;
|
||||
|
||||
QStringList prefixedMessages;
|
||||
qDebug() << prefixedMessages;
|
||||
|
||||
for (const QString &message : messages) {
|
||||
prefixedMessages << (QLatin1String("[Qode Assist] ") + message);
|
||||
}
|
||||
if (silent) {
|
||||
Core::MessageManager::writeSilently(prefixedMessages);
|
||||
} else {
|
||||
Core::MessageManager::writeFlashing(prefixedMessages);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool pingUrl(const QUrl &url, int timeout = 5000)
|
||||
{
|
||||
if (!url.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
|
||||
|
||||
QScopedPointer<QNetworkReply> reply(manager.get(request));
|
||||
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||
|
||||
timer.start(timeout);
|
||||
loop.exec();
|
||||
|
||||
if (timer.isActive()) {
|
||||
timer.stop();
|
||||
return (reply->error() == QNetworkReply::NoError);
|
||||
} else {
|
||||
QObject::disconnect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
reply->abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
128
README.md
128
README.md
@ -1,26 +1,96 @@
|
||||
# QodeAssist
|
||||
# QodeAssist - AI-powered coding assistant plugin for Qt Creator
|
||||
[](https://github.com/Palm1r/QodeAssist/actions/workflows/build_cmake.yml)
|
||||
|
||||
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.
|
||||
|
||||
Code completion:
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/255a52f1-5cc0-4ca3-b05c-c4cf9cdbe25a" width="600" alt="QodeAssistPreview">
|
||||
|
||||
|
||||
Chat with LLM models in side panels:
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/ead5a5d9-b40a-4f17-af05-77fa2bcb3a61" width="600" alt="QodeAssistChat">
|
||||
|
||||
Chat with LLM models in bottom panel:
|
||||
|
||||
<img width="326" alt="QodeAssistBottomPanel" src="https://github.com/user-attachments/assets/4cc64c23-a294-4df8-9153-39ad6fdab34b">
|
||||
|
||||
## Plugin installation using Ollama as an example
|
||||
|
||||
1. Install Latest QtCreator
|
||||
2. Install [Ollama](https://ollama.com). Make sure to review the system requirements before installation.
|
||||
3. Install a language models in Ollama via terminal. For example, you can run:
|
||||
|
||||
For suggestions:
|
||||
```
|
||||
ollama run codellama:7b-code
|
||||
```
|
||||
For chat:
|
||||
```
|
||||
ollama run codellama:7b-instruct
|
||||
```
|
||||
4. Download the QodeAssist plugin for your QtCreator.
|
||||
5. Launch Qt Creator and install the plugin:
|
||||
- Go to MacOS: Qt Creator -> About Plugins...
|
||||
Windows\Linux: Help -> About Plugins...
|
||||
- Click on "Install Plugin..."
|
||||
- Select the downloaded QodeAssist plugin archive file
|
||||
|
||||
## Configure Plugin
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/00ad980f-b470-48eb-9aaa-077783d38798" width="600" alt="Configuere QodeAssist">
|
||||
|
||||
1. Open Qt Creator settings
|
||||
2. Navigate to the "Qode Assist" tab
|
||||
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 loaded model
|
||||
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.
|
||||
|
||||
[](https://ko-fi.com/P5P412V96G)
|
||||
|
||||
## Supported LLM Providers
|
||||
QodeAssist currently supports the following LLM (Large Language Model) providers:
|
||||
- [Ollama](https://ollama.com)
|
||||
- [LM Studio](https://lmstudio.ai)
|
||||
- OpenAI compatible providers
|
||||
|
||||
## QtCreator Version Compatibility
|
||||
|
||||
- QtCreator 14.0.2 - 0.2.3 - 0.3.x
|
||||
- QtCreator 14.0.1 - 0.2.2 plugin version and below
|
||||
|
||||
## Supported Models
|
||||
|
||||
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:
|
||||
QodeAssist has been thoroughly tested and optimized for use with the following language models:
|
||||
|
||||
- Llama
|
||||
- CodeLlama
|
||||
- StarCoder2
|
||||
- DeepSeek-Coder-V2-Lite-Base
|
||||
- DeepSeek-Coder-V2
|
||||
- Qwen-2.5
|
||||
|
||||
These models have demonstrated excellent performance in code completion and assistance tasks within the QodeAssist environment.
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.
|
||||
@ -38,65 +108,15 @@ For inspiration and examples of effective custom prompts, please refer to the `r
|
||||
<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
|
||||
- [x] Improve and automate settings
|
||||
- [ ] Add chat functionality
|
||||
- [x] 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
|
||||
|
||||
1. Install QtCreator 14.0
|
||||
2. Install [Ollama](https://ollama.com). Make sure to review the system requirements before installation.
|
||||
3. Install a language models in Ollama. For example, you can run:
|
||||
|
||||
For suggestions:
|
||||
```
|
||||
ollama run codellama:7b-code
|
||||
```
|
||||
For chat:
|
||||
```
|
||||
ollama run codellama:7b-instruct
|
||||
```
|
||||
4. Download the QodeAssist plugin.
|
||||
5. Launch Qt Creator and install the plugin:
|
||||
- Go to MacOS: Qt Creator -> About Plugins...
|
||||
Windows\Linux: Help -> About Plugins...
|
||||
- Click on "Install Plugin..."
|
||||
- Select the downloaded QodeAssist plugin archive file
|
||||
|
||||
## 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. 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
|
||||
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.
|
||||
|
||||
## Hotkeys
|
||||
|
||||
- To call manual request to suggestion, you can use or change it in settings
|
||||
|
||||
@ -1,192 +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 "ChatClientInterface.hpp"
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QUuid>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
int ChatHistory::estimateTokenCount(const QString &text) const
|
||||
{
|
||||
return text.length() / 4;
|
||||
}
|
||||
|
||||
void ChatHistory::addMessage(ChatMessage::Role role, const QString &content)
|
||||
{
|
||||
int tokenCount = estimateTokenCount(content);
|
||||
m_messages.append({role, content, tokenCount});
|
||||
m_totalTokens += tokenCount;
|
||||
trim();
|
||||
}
|
||||
void ChatHistory::clear()
|
||||
{
|
||||
m_messages.clear();
|
||||
m_totalTokens = 0;
|
||||
}
|
||||
|
||||
QVector<ChatMessage> ChatHistory::getMessages() const
|
||||
{
|
||||
return m_messages;
|
||||
}
|
||||
|
||||
QString ChatHistory::getSystemPrompt() const
|
||||
{
|
||||
return m_systemPrompt;
|
||||
}
|
||||
|
||||
void ChatHistory::setSystemPrompt(const QString &prompt)
|
||||
{
|
||||
m_systemPrompt = prompt;
|
||||
}
|
||||
|
||||
void ChatHistory::trim()
|
||||
{
|
||||
while (m_messages.size() > MAX_HISTORY_SIZE || m_totalTokens > MAX_TOKENS) {
|
||||
if (!m_messages.isEmpty()) {
|
||||
m_totalTokens -= m_messages.first().tokenCount;
|
||||
m_messages.removeFirst();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChatClientInterface::ChatClientInterface(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_requestHandler(new LLMRequestHandler(this))
|
||||
{
|
||||
connect(m_requestHandler,
|
||||
&LLMRequestHandler::completionReceived,
|
||||
this,
|
||||
[this](const QString &completion, const QJsonObject &, bool isComplete) {
|
||||
handleLLMResponse(completion, isComplete);
|
||||
});
|
||||
|
||||
connect(m_requestHandler,
|
||||
&LLMRequestHandler::requestFinished,
|
||||
this,
|
||||
[this](const QString &, bool success, const QString &errorString) {
|
||||
if (!success) {
|
||||
emit errorOccurred(errorString);
|
||||
}
|
||||
});
|
||||
|
||||
m_chatHistory.setSystemPrompt("You are a helpful C++ and QML programming assistant.");
|
||||
}
|
||||
|
||||
ChatClientInterface::~ChatClientInterface() = default;
|
||||
|
||||
void ChatClientInterface::sendMessage(const QString &message)
|
||||
{
|
||||
logMessage("Sending message: " + message);
|
||||
logMessage("chatProvider " + Settings::generalSettings().chatLlmProviders.stringValue());
|
||||
logMessage("chatTemplate " + Settings::generalSettings().chatPrompts.stringValue());
|
||||
|
||||
auto chatTemplate = PromptTemplateManager::instance().getCurrentChatTemplate();
|
||||
auto chatProvider = LLMProvidersManager::instance().getCurrentChatProvider();
|
||||
|
||||
ContextData context;
|
||||
context.prefix = message;
|
||||
context.suffix = "";
|
||||
if (Settings::contextSettings().useSpecificInstructions())
|
||||
context.instriuctions = Settings::contextSettings().specificInstractions();
|
||||
|
||||
QJsonObject providerRequest;
|
||||
providerRequest["model"] = Settings::generalSettings().chatModelName();
|
||||
providerRequest["stream"] = true;
|
||||
providerRequest["messages"] = prepareMessagesForRequest();
|
||||
|
||||
chatTemplate->prepareRequest(providerRequest, context);
|
||||
chatProvider->prepareRequest(providerRequest);
|
||||
|
||||
LLMConfig config;
|
||||
config.requestType = RequestType::Chat;
|
||||
config.provider = chatProvider;
|
||||
config.promptTemplate = chatTemplate;
|
||||
config.url = QString("%1%2").arg(Settings::generalSettings().chatUrl(),
|
||||
Settings::generalSettings().chatEndPoint());
|
||||
config.providerRequest = providerRequest;
|
||||
|
||||
QJsonObject request;
|
||||
request["id"] = QUuid::createUuid().toString();
|
||||
|
||||
m_accumulatedResponse.clear();
|
||||
m_chatHistory.addMessage(ChatMessage::Role::User, message);
|
||||
m_requestHandler->sendLLMRequest(config, request);
|
||||
}
|
||||
|
||||
void ChatClientInterface::clearMessages()
|
||||
{
|
||||
m_chatHistory.clear();
|
||||
m_accumulatedResponse.clear();
|
||||
logMessage("Chat history cleared");
|
||||
}
|
||||
|
||||
QVector<ChatMessage> ChatClientInterface::getChatHistory() const
|
||||
{
|
||||
return m_chatHistory.getMessages();
|
||||
}
|
||||
|
||||
void ChatClientInterface::handleLLMResponse(const QString &response, bool isComplete)
|
||||
{
|
||||
m_accumulatedResponse += response;
|
||||
|
||||
if (isComplete) {
|
||||
logMessage("Message completed. Final response: " + m_accumulatedResponse);
|
||||
emit messageReceived(m_accumulatedResponse.trimmed());
|
||||
|
||||
m_chatHistory.addMessage(ChatMessage::Role::Assistant, m_accumulatedResponse.trimmed());
|
||||
m_accumulatedResponse.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QJsonArray ChatClientInterface::prepareMessagesForRequest() const
|
||||
{
|
||||
QJsonArray messages;
|
||||
|
||||
messages.append(QJsonObject{{"role", "system"}, {"content", m_chatHistory.getSystemPrompt()}});
|
||||
|
||||
for (const auto &message : m_chatHistory.getMessages()) {
|
||||
QString role;
|
||||
switch (message.role) {
|
||||
case ChatMessage::Role::User:
|
||||
role = "user";
|
||||
break;
|
||||
case ChatMessage::Role::Assistant:
|
||||
role = "assistant";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
messages.append(QJsonObject{{"role", role}, {"content", message.content}});
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
@ -1,83 +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 <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include "QodeAssistData.hpp"
|
||||
#include "core/LLMRequestHandler.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
struct ChatMessage
|
||||
{
|
||||
enum class Role { System, User, Assistant };
|
||||
Role role;
|
||||
QString content;
|
||||
int tokenCount;
|
||||
};
|
||||
|
||||
class ChatHistory
|
||||
{
|
||||
public:
|
||||
void addMessage(ChatMessage::Role role, const QString &content);
|
||||
void clear();
|
||||
QVector<ChatMessage> getMessages() const;
|
||||
QString getSystemPrompt() const;
|
||||
void setSystemPrompt(const QString &prompt);
|
||||
void trim();
|
||||
|
||||
private:
|
||||
QVector<ChatMessage> m_messages;
|
||||
QString m_systemPrompt;
|
||||
int m_totalTokens = 0;
|
||||
static const int MAX_HISTORY_SIZE = 50;
|
||||
static const int MAX_TOKENS = 4000;
|
||||
|
||||
int estimateTokenCount(const QString &text) const;
|
||||
};
|
||||
|
||||
class ChatClientInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ChatClientInterface(QObject *parent = nullptr);
|
||||
~ChatClientInterface();
|
||||
|
||||
void sendMessage(const QString &message);
|
||||
void clearMessages();
|
||||
QVector<ChatMessage> getChatHistory() const;
|
||||
|
||||
signals:
|
||||
void messageReceived(const QString &message);
|
||||
void errorOccurred(const QString &error);
|
||||
|
||||
private:
|
||||
void handleLLMResponse(const QString &response, bool isComplete);
|
||||
QJsonArray prepareMessagesForRequest() const;
|
||||
|
||||
LLMRequestHandler *m_requestHandler;
|
||||
QString m_accumulatedResponse;
|
||||
ChatHistory m_chatHistory;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatWidget.h"
|
||||
#include "chatview/ChatWidget.hpp"
|
||||
#include <coreplugin/ioutputpane.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
@ -1,147 +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 "ChatWidget.h"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QScrollBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
ChatWidget::ChatWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_showTimestamp(false)
|
||||
, m_chatClient(new ChatClientInterface(this))
|
||||
{
|
||||
setupUi();
|
||||
|
||||
connect(m_sendButton, &QPushButton::clicked, this, &ChatWidget::sendMessage);
|
||||
connect(m_messageInput, &QLineEdit::returnPressed, this, &ChatWidget::sendMessage);
|
||||
|
||||
connect(m_chatClient, &ChatClientInterface::messageReceived, this, &ChatWidget::receiveMessage);
|
||||
connect(m_chatClient, &ChatClientInterface::errorOccurred, this, &ChatWidget::handleError);
|
||||
|
||||
logMessage("ChatWidget initialized");
|
||||
}
|
||||
|
||||
void ChatWidget::setupUi()
|
||||
{
|
||||
m_chatDisplay = new QTextEdit(this);
|
||||
m_chatDisplay->setReadOnly(true);
|
||||
|
||||
m_messageInput = new QLineEdit(this);
|
||||
m_sendButton = new QPushButton("Send", this);
|
||||
|
||||
QHBoxLayout *inputLayout = new QHBoxLayout;
|
||||
inputLayout->addWidget(m_messageInput);
|
||||
inputLayout->addWidget(m_sendButton);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(m_chatDisplay);
|
||||
mainLayout->addLayout(inputLayout);
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void ChatWidget::sendMessage()
|
||||
{
|
||||
QString message = m_messageInput->text().trimmed();
|
||||
if (!message.isEmpty()) {
|
||||
logMessage("Sending message: " + message);
|
||||
addMessage(message, true);
|
||||
m_chatClient->sendMessage(message);
|
||||
m_messageInput->clear();
|
||||
addMessage("AI is typing...", false);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWidget::receiveMessage(const QString &message)
|
||||
{
|
||||
updateLastAIMessage(message);
|
||||
}
|
||||
|
||||
void ChatWidget::receivePartialMessage(const QString &partialMessage)
|
||||
{
|
||||
logMessage("Received partial message: " + partialMessage);
|
||||
m_currentAIResponse += partialMessage;
|
||||
updateLastAIMessage(m_currentAIResponse);
|
||||
}
|
||||
|
||||
void ChatWidget::onMessageCompleted()
|
||||
{
|
||||
updateLastAIMessage(m_currentAIResponse);
|
||||
m_currentAIResponse.clear();
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
void ChatWidget::handleError(const QString &error)
|
||||
{
|
||||
logMessage("Error occurred: " + error);
|
||||
addMessage("Error: " + error, false);
|
||||
}
|
||||
|
||||
void ChatWidget::addMessage(const QString &message, bool fromUser)
|
||||
{
|
||||
auto prefix = fromUser ? "You: " : "AI: ";
|
||||
QString timestamp = m_showTimestamp ? QDateTime::currentDateTime().toString("[hh:mm:ss] ") : "";
|
||||
QString fullMessage = timestamp + prefix + message;
|
||||
m_chatDisplay->append(fullMessage);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
void ChatWidget::updateLastAIMessage(const QString &message)
|
||||
{
|
||||
QTextCursor cursor = m_chatDisplay->textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
|
||||
cursor.removeSelectedText();
|
||||
|
||||
QString timestamp = m_showTimestamp ? QDateTime::currentDateTime().toString("[hh:mm:ss] ") : "";
|
||||
cursor.insertText(timestamp + "AI: " + message);
|
||||
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
m_chatDisplay->setTextCursor(cursor);
|
||||
|
||||
scrollToBottom();
|
||||
m_chatDisplay->repaint();
|
||||
}
|
||||
|
||||
void ChatWidget::clear()
|
||||
{
|
||||
m_chatDisplay->clear();
|
||||
m_currentAIResponse.clear();
|
||||
m_chatClient->clearMessages();
|
||||
}
|
||||
|
||||
void ChatWidget::scrollToBottom()
|
||||
{
|
||||
QScrollBar *scrollBar = m_chatDisplay->verticalScrollBar();
|
||||
scrollBar->setValue(scrollBar->maximum());
|
||||
}
|
||||
|
||||
void ChatWidget::setShowTimestamp(bool show)
|
||||
{
|
||||
m_showTimestamp = show;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
45
chat/NavigationPanel.cpp
Normal file
45
chat/NavigationPanel.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "NavigationPanel.hpp"
|
||||
|
||||
#include "chatview/ChatWidget.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
NavigationPanel::NavigationPanel() {
|
||||
setDisplayName(tr("QodeAssist Chat"));
|
||||
setPriority(500);
|
||||
setId("QodeAssistChat");
|
||||
setActivationSequence(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C));
|
||||
}
|
||||
|
||||
NavigationPanel::~NavigationPanel()
|
||||
{
|
||||
}
|
||||
|
||||
Core::NavigationView NavigationPanel::createWidget()
|
||||
{
|
||||
Core::NavigationView view;
|
||||
view.widget = new ChatWidget;
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
||||
37
chat/NavigationPanel.hpp
Normal file
37
chat/NavigationPanel.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <coreplugin/inavigationwidgetfactory.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
class NavigationPanel : public Core::INavigationWidgetFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NavigationPanel();
|
||||
~NavigationPanel();
|
||||
|
||||
Core::NavigationView createWidget() override;
|
||||
};
|
||||
|
||||
}
|
||||
35
chatview/CMakeLists.txt
Normal file
35
chatview/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
qt_add_library(QodeAssistChatView STATIC)
|
||||
|
||||
qt_add_qml_module(QodeAssistChatView
|
||||
URI ChatView
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
qml/RootItem.qml
|
||||
qml/ChatItem.qml
|
||||
qml/Badge.qml
|
||||
qml/dialog/CodeBlock.qml
|
||||
qml/dialog/TextBlock.qml
|
||||
SOURCES
|
||||
ChatWidget.hpp ChatWidget.cpp
|
||||
ChatModel.hpp ChatModel.cpp
|
||||
ChatRootView.hpp ChatRootView.cpp
|
||||
ClientInterface.hpp ClientInterface.cpp
|
||||
MessagePart.hpp
|
||||
ChatUtils.h ChatUtils.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(QodeAssistChatView
|
||||
PUBLIC
|
||||
Qt::Widgets
|
||||
Qt::Quick
|
||||
Qt::QuickWidgets
|
||||
Qt::Network
|
||||
QtCreator::Core
|
||||
QtCreator::Utils
|
||||
LLMCore
|
||||
QodeAssistSettings
|
||||
)
|
||||
|
||||
target_include_directories(QodeAssistChatView
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
195
chatview/ChatModel.cpp
Normal file
195
chatview/ChatModel.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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 "ChatModel.hpp"
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtQml>
|
||||
#include <utils/aspects.h>
|
||||
|
||||
#include "GeneralSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
ChatModel::ChatModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_totalTokens(0)
|
||||
{
|
||||
auto &settings = Settings::generalSettings();
|
||||
|
||||
connect(&settings.chatTokensThreshold,
|
||||
&Utils::BaseAspect::changed,
|
||||
this,
|
||||
&ChatModel::tokensThresholdChanged);
|
||||
}
|
||||
|
||||
int ChatModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_messages.size();
|
||||
}
|
||||
|
||||
QVariant ChatModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= m_messages.size())
|
||||
return QVariant();
|
||||
|
||||
const Message &message = m_messages[index.row()];
|
||||
switch (static_cast<Roles>(role)) {
|
||||
case Roles::RoleType:
|
||||
return QVariant::fromValue(message.role);
|
||||
case Roles::Content: {
|
||||
return message.content;
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ChatModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Roles::RoleType] = "roleType";
|
||||
roles[Roles::Content] = "content";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void ChatModel::addMessage(const QString &content, ChatRole role, const QString &id)
|
||||
{
|
||||
int tokenCount = estimateTokenCount(content);
|
||||
|
||||
if (!m_messages.isEmpty() && !id.isEmpty() && m_messages.last().id == id) {
|
||||
Message &lastMessage = m_messages.last();
|
||||
int oldTokenCount = lastMessage.tokenCount;
|
||||
lastMessage.content = content;
|
||||
lastMessage.tokenCount = tokenCount;
|
||||
m_totalTokens += (tokenCount - oldTokenCount);
|
||||
emit dataChanged(index(m_messages.size() - 1), index(m_messages.size() - 1));
|
||||
} else {
|
||||
beginInsertRows(QModelIndex(), m_messages.size(), m_messages.size());
|
||||
m_messages.append({role, content, tokenCount, id});
|
||||
m_totalTokens += tokenCount;
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
trim();
|
||||
emit totalTokensChanged();
|
||||
}
|
||||
|
||||
QVector<ChatModel::Message> ChatModel::getChatHistory() const
|
||||
{
|
||||
return m_messages;
|
||||
}
|
||||
|
||||
void ChatModel::trim()
|
||||
{
|
||||
while (m_totalTokens > tokensThreshold()) {
|
||||
if (!m_messages.isEmpty()) {
|
||||
m_totalTokens -= m_messages.first().tokenCount;
|
||||
beginRemoveRows(QModelIndex(), 0, 0);
|
||||
m_messages.removeFirst();
|
||||
endRemoveRows();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ChatModel::estimateTokenCount(const QString &text) const
|
||||
{
|
||||
return text.length() / 4;
|
||||
}
|
||||
|
||||
void ChatModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_messages.clear();
|
||||
m_totalTokens = 0;
|
||||
endResetModel();
|
||||
emit totalTokensChanged();
|
||||
}
|
||||
|
||||
QList<MessagePart> ChatModel::processMessageContent(const QString &content) const
|
||||
{
|
||||
QList<MessagePart> parts;
|
||||
QRegularExpression codeBlockRegex("```(\\w*)\\n?([\\s\\S]*?)```");
|
||||
int lastIndex = 0;
|
||||
auto blockMatches = codeBlockRegex.globalMatch(content);
|
||||
|
||||
while (blockMatches.hasNext()) {
|
||||
auto match = blockMatches.next();
|
||||
if (match.capturedStart() > lastIndex) {
|
||||
QString textBetween = content.mid(lastIndex, match.capturedStart() - lastIndex).trimmed();
|
||||
if (!textBetween.isEmpty()) {
|
||||
parts.append({MessagePart::Text, textBetween, ""});
|
||||
}
|
||||
}
|
||||
parts.append({MessagePart::Code, match.captured(2).trimmed(), match.captured(1)});
|
||||
lastIndex = match.capturedEnd();
|
||||
}
|
||||
|
||||
if (lastIndex < content.length()) {
|
||||
QString remainingText = content.mid(lastIndex).trimmed();
|
||||
if (!remainingText.isEmpty()) {
|
||||
parts.append({MessagePart::Text, remainingText, ""});
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
QJsonArray ChatModel::prepareMessagesForRequest(LLMCore::ContextData context) const
|
||||
{
|
||||
QJsonArray messages;
|
||||
|
||||
messages.append(QJsonObject{{"role", "system"}, {"content", context.systemPrompt}});
|
||||
|
||||
for (const auto &message : m_messages) {
|
||||
QString role;
|
||||
switch (message.role) {
|
||||
case ChatRole::User:
|
||||
role = "user";
|
||||
break;
|
||||
case ChatRole::Assistant:
|
||||
role = "assistant";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
messages.append(QJsonObject{{"role", role}, {"content", message.content}});
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
int ChatModel::totalTokens() const
|
||||
{
|
||||
return m_totalTokens;
|
||||
}
|
||||
|
||||
int ChatModel::tokensThreshold() const
|
||||
{
|
||||
auto &settings = Settings::generalSettings();
|
||||
return settings.chatTokensThreshold();
|
||||
}
|
||||
|
||||
QString ChatModel::lastMessageId() const
|
||||
{
|
||||
return !m_messages.isEmpty() ? m_messages.last().id : "";
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
85
chatview/ChatModel.hpp
Normal file
85
chatview/ChatModel.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ContextData.hpp"
|
||||
#include "MessagePart.hpp"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
class ChatModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int totalTokens READ totalTokens NOTIFY totalTokensChanged FINAL)
|
||||
Q_PROPERTY(int tokensThreshold READ tokensThreshold NOTIFY tokensThresholdChanged FINAL)
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
enum Roles { RoleType = Qt::UserRole, Content };
|
||||
|
||||
enum ChatRole { System, User, Assistant };
|
||||
Q_ENUM(ChatRole)
|
||||
|
||||
struct Message
|
||||
{
|
||||
ChatRole role;
|
||||
QString content;
|
||||
int tokenCount;
|
||||
QString id;
|
||||
};
|
||||
|
||||
explicit ChatModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE void addMessage(const QString &content, ChatRole role, const QString &id);
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE QList<MessagePart> processMessageContent(const QString &content) const;
|
||||
|
||||
QVector<Message> getChatHistory() const;
|
||||
QJsonArray prepareMessagesForRequest(LLMCore::ContextData context) const;
|
||||
|
||||
int totalTokens() const;
|
||||
int tokensThreshold() const;
|
||||
|
||||
QString currentModel() const;
|
||||
QString lastMessageId() const;
|
||||
|
||||
signals:
|
||||
void totalTokensChanged();
|
||||
void tokensThresholdChanged();
|
||||
|
||||
private:
|
||||
void trim();
|
||||
int estimateTokenCount(const QString &text) const;
|
||||
|
||||
QVector<Message> m_messages;
|
||||
int m_totalTokens = 0;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
Q_DECLARE_METATYPE(QodeAssist::Chat::ChatModel::Message)
|
||||
Q_DECLARE_METATYPE(QodeAssist::Chat::MessagePart)
|
||||
132
chatview/ChatRootView.cpp
Normal file
132
chatview/ChatRootView.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 "ChatRootView.hpp"
|
||||
#include <QtGui/qclipboard.h>
|
||||
#include <utils/theme/theme.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include "GeneralSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
ChatRootView::ChatRootView(QQuickItem *parent)
|
||||
: QQuickItem(parent)
|
||||
, m_chatModel(new ChatModel(this))
|
||||
, m_clientInterface(new ClientInterface(m_chatModel, this))
|
||||
{
|
||||
auto &settings = Settings::generalSettings();
|
||||
|
||||
connect(&settings.chatModelName,
|
||||
&Utils::BaseAspect::changed,
|
||||
this,
|
||||
&ChatRootView::currentTemplateChanged);
|
||||
generateColors();
|
||||
}
|
||||
|
||||
ChatModel *ChatRootView::chatModel() const
|
||||
{
|
||||
return m_chatModel;
|
||||
}
|
||||
|
||||
QColor ChatRootView::backgroundColor() const
|
||||
{
|
||||
return Utils::creatorColor(Utils::Theme::BackgroundColorNormal);
|
||||
}
|
||||
|
||||
void ChatRootView::sendMessage(const QString &message) const
|
||||
{
|
||||
m_clientInterface->sendMessage(message);
|
||||
}
|
||||
|
||||
void ChatRootView::copyToClipboard(const QString &text)
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
||||
void ChatRootView::cancelRequest()
|
||||
{
|
||||
m_clientInterface->cancelRequest();
|
||||
}
|
||||
|
||||
void ChatRootView::generateColors()
|
||||
{
|
||||
QColor baseColor = backgroundColor();
|
||||
bool isDarkTheme = baseColor.lightness() < 128;
|
||||
|
||||
if (isDarkTheme) {
|
||||
m_primaryColor = generateColor(baseColor, 0.1, 1.2, 1.4);
|
||||
m_secondaryColor = generateColor(baseColor, -0.1, 1.1, 1.2);
|
||||
m_codeColor = generateColor(baseColor, 0.05, 0.8, 1.1);
|
||||
} else {
|
||||
m_primaryColor = generateColor(baseColor, 0.05, 1.05, 1.1);
|
||||
m_secondaryColor = generateColor(baseColor, -0.05, 1.1, 1.2);
|
||||
m_codeColor = generateColor(baseColor, 0.02, 0.95, 1.05);
|
||||
}
|
||||
}
|
||||
|
||||
QColor ChatRootView::generateColor(const QColor &baseColor,
|
||||
float hueShift,
|
||||
float saturationMod,
|
||||
float lightnessMod)
|
||||
{
|
||||
float h, s, l, a;
|
||||
baseColor.getHslF(&h, &s, &l, &a);
|
||||
bool isDarkTheme = l < 0.5;
|
||||
|
||||
h = fmod(h + hueShift + 1.0, 1.0);
|
||||
|
||||
s = qBound(0.0f, s * saturationMod, 1.0f);
|
||||
|
||||
if (isDarkTheme) {
|
||||
l = qBound(0.0f, l * lightnessMod, 1.0f);
|
||||
} else {
|
||||
l = qBound(0.0f, l / lightnessMod, 1.0f);
|
||||
}
|
||||
|
||||
h = qBound(0.0f, h, 1.0f);
|
||||
s = qBound(0.0f, s, 1.0f);
|
||||
l = qBound(0.0f, l, 1.0f);
|
||||
a = qBound(0.0f, a, 1.0f);
|
||||
|
||||
return QColor::fromHslF(h, s, l, a);
|
||||
}
|
||||
|
||||
QString ChatRootView::currentTemplate() const
|
||||
{
|
||||
auto &settings = Settings::generalSettings();
|
||||
return settings.chatModelName();
|
||||
}
|
||||
|
||||
QColor ChatRootView::primaryColor() const
|
||||
{
|
||||
return m_primaryColor;
|
||||
}
|
||||
|
||||
QColor ChatRootView::secondaryColor() const
|
||||
{
|
||||
return m_secondaryColor;
|
||||
}
|
||||
|
||||
QColor ChatRootView::codeColor() const
|
||||
{
|
||||
return m_codeColor;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
76
chatview/ChatRootView.hpp
Normal file
76
chatview/ChatRootView.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <QQuickItem>
|
||||
|
||||
#include "ChatModel.hpp"
|
||||
#include "ClientInterface.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
class ChatRootView : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ChatModel *chatModel READ chatModel NOTIFY chatModelChanged FINAL)
|
||||
Q_PROPERTY(QString currentTemplate READ currentTemplate NOTIFY currentTemplateChanged FINAL)
|
||||
Q_PROPERTY(QColor backgroundColor READ backgroundColor CONSTANT FINAL)
|
||||
Q_PROPERTY(QColor primaryColor READ primaryColor CONSTANT FINAL)
|
||||
Q_PROPERTY(QColor secondaryColor READ secondaryColor CONSTANT FINAL)
|
||||
Q_PROPERTY(QColor codeColor READ codeColor CONSTANT FINAL)
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
ChatRootView(QQuickItem *parent = nullptr);
|
||||
|
||||
ChatModel *chatModel() const;
|
||||
QString currentTemplate() const;
|
||||
|
||||
QColor backgroundColor() const;
|
||||
QColor primaryColor() const;
|
||||
QColor secondaryColor() const;
|
||||
|
||||
QColor codeColor() const;
|
||||
|
||||
public slots:
|
||||
void sendMessage(const QString &message) const;
|
||||
void copyToClipboard(const QString &text);
|
||||
void cancelRequest();
|
||||
|
||||
signals:
|
||||
void chatModelChanged();
|
||||
void currentTemplateChanged();
|
||||
|
||||
private:
|
||||
void generateColors();
|
||||
QColor generateColor(const QColor &baseColor,
|
||||
float hueShift,
|
||||
float saturationMod,
|
||||
float lightnessMod);
|
||||
|
||||
ChatModel *m_chatModel;
|
||||
ClientInterface *m_clientInterface;
|
||||
QString m_currentTemplate;
|
||||
QColor m_primaryColor;
|
||||
QColor m_secondaryColor;
|
||||
QColor m_codeColor;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
13
chatview/ChatUtils.cpp
Normal file
13
chatview/ChatUtils.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "ChatUtils.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
void ChatUtils::copyToClipboard(const QString &text)
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
21
chatview/ChatUtils.h
Normal file
21
chatview/ChatUtils.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
// Q_NAMESPACE
|
||||
|
||||
class ChatUtils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(ChatUtils)
|
||||
|
||||
public:
|
||||
explicit ChatUtils(QObject *parent = nullptr)
|
||||
: QObject(parent) {};
|
||||
|
||||
Q_INVOKABLE void copyToClipboard(const QString &text);
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
43
chatview/ChatWidget.cpp
Normal file
43
chatview/ChatWidget.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 "ChatWidget.hpp"
|
||||
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
ChatWidget::ChatWidget(QWidget *parent)
|
||||
: QQuickWidget(parent)
|
||||
{
|
||||
setSource(QUrl("qrc:/ChatView/qml/RootItem.qml"));
|
||||
setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
}
|
||||
|
||||
void ChatWidget::clear()
|
||||
{
|
||||
QMetaObject::invokeMethod(rootObject(), "clearChat");
|
||||
}
|
||||
|
||||
void ChatWidget::scrollToBottom()
|
||||
{
|
||||
QMetaObject::invokeMethod(rootObject(), "scrollToBottom");
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
@ -19,45 +19,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QWidget>
|
||||
|
||||
#include "ChatClientInterface.hpp"
|
||||
#include <QtQuickWidgets/QtQuickWidgets>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
class ChatWidget : public QWidget
|
||||
class ChatWidget : public QQuickWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ChatWidget(QWidget *parent = nullptr);
|
||||
~ChatWidget() = default;
|
||||
|
||||
void clear();
|
||||
void scrollToBottom();
|
||||
void setShowTimestamp(bool show);
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE void scrollToBottom();
|
||||
|
||||
void receiveMessage(const QString &message);
|
||||
|
||||
private slots:
|
||||
void sendMessage();
|
||||
void receivePartialMessage(const QString &partialMessage);
|
||||
void onMessageCompleted();
|
||||
void handleError(const QString &error);
|
||||
|
||||
private:
|
||||
QTextEdit *m_chatDisplay;
|
||||
QLineEdit *m_messageInput;
|
||||
QPushButton *m_sendButton;
|
||||
bool m_showTimestamp;
|
||||
ChatClientInterface *m_chatClient;
|
||||
QString m_currentAIResponse;
|
||||
|
||||
void setupUi();
|
||||
void addMessage(const QString &message, bool fromUser = true);
|
||||
void updateLastAIMessage(const QString &message);
|
||||
signals:
|
||||
void clearPressed();
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
}
|
||||
125
chatview/ClientInterface.cpp
Normal file
125
chatview/ClientInterface.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 "ClientInterface.hpp"
|
||||
#include "ContextSettings.hpp"
|
||||
#include "GeneralSettings.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "ProvidersManager.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QUuid>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
ClientInterface::ClientInterface(ChatModel *chatModel, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_requestHandler(new LLMCore::RequestHandler(this))
|
||||
, m_chatModel(chatModel)
|
||||
{
|
||||
connect(m_requestHandler,
|
||||
&LLMCore::RequestHandler::completionReceived,
|
||||
this,
|
||||
[this](const QString &completion, const QJsonObject &request, bool isComplete) {
|
||||
handleLLMResponse(completion, request, isComplete);
|
||||
});
|
||||
|
||||
connect(m_requestHandler,
|
||||
&LLMCore::RequestHandler::requestFinished,
|
||||
this,
|
||||
[this](const QString &, bool success, const QString &errorString) {
|
||||
if (!success) {
|
||||
emit errorOccurred(errorString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ClientInterface::~ClientInterface() = default;
|
||||
|
||||
void ClientInterface::sendMessage(const QString &message)
|
||||
{
|
||||
cancelRequest();
|
||||
|
||||
LOG_MESSAGE("Sending message: " + message);
|
||||
LOG_MESSAGE("chatProvider " + Settings::generalSettings().chatLlmProviders.stringValue());
|
||||
LOG_MESSAGE("chatTemplate " + Settings::generalSettings().chatPrompts.stringValue());
|
||||
|
||||
auto chatTemplate = LLMCore::PromptTemplateManager::instance().getCurrentChatTemplate();
|
||||
auto chatProvider = LLMCore::ProvidersManager::instance().getCurrentChatProvider();
|
||||
|
||||
LLMCore::ContextData context;
|
||||
context.prefix = message;
|
||||
context.suffix = "";
|
||||
if (Settings::contextSettings().useChatSystemPrompt())
|
||||
context.systemPrompt = Settings::contextSettings().chatSystemPrompt();
|
||||
|
||||
QJsonObject providerRequest;
|
||||
providerRequest["model"] = Settings::generalSettings().chatModelName();
|
||||
providerRequest["stream"] = true;
|
||||
providerRequest["messages"] = m_chatModel->prepareMessagesForRequest(context);
|
||||
|
||||
if (!chatTemplate || !chatProvider) {
|
||||
LOG_MESSAGE("Check settings, provider or template are not set");
|
||||
}
|
||||
chatTemplate->prepareRequest(providerRequest, context);
|
||||
chatProvider->prepareRequest(providerRequest, LLMCore::RequestType::Chat);
|
||||
|
||||
LLMCore::LLMConfig config;
|
||||
config.requestType = LLMCore::RequestType::Chat;
|
||||
config.provider = chatProvider;
|
||||
config.promptTemplate = chatTemplate;
|
||||
config.url = QString("%1%2").arg(Settings::generalSettings().chatUrl(),
|
||||
Settings::generalSettings().chatEndPoint());
|
||||
config.providerRequest = providerRequest;
|
||||
config.multiLineCompletion = Settings::generalSettings().multiLineCompletion();
|
||||
|
||||
QJsonObject request;
|
||||
request["id"] = QUuid::createUuid().toString();
|
||||
|
||||
m_chatModel->addMessage(message, ChatModel::ChatRole::User, "");
|
||||
m_requestHandler->sendLLMRequest(config, request);
|
||||
}
|
||||
|
||||
void ClientInterface::clearMessages()
|
||||
{
|
||||
m_chatModel->clear();
|
||||
LOG_MESSAGE("Chat history cleared");
|
||||
}
|
||||
|
||||
void ClientInterface::cancelRequest()
|
||||
{
|
||||
auto id = m_chatModel->lastMessageId();
|
||||
m_requestHandler->cancelRequest(id);
|
||||
}
|
||||
|
||||
void ClientInterface::handleLLMResponse(const QString &response,
|
||||
const QJsonObject &request,
|
||||
bool isComplete)
|
||||
{
|
||||
QString messageId = request["id"].toString();
|
||||
m_chatModel->addMessage(response.trimmed(), ChatModel::ChatRole::Assistant, messageId);
|
||||
|
||||
if (isComplete) {
|
||||
LOG_MESSAGE("Message completed. Final response for message " + messageId + ": " + response);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
53
chatview/ClientInterface.hpp
Normal file
53
chatview/ClientInterface.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "ChatModel.hpp"
|
||||
#include "RequestHandler.hpp"
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
|
||||
class ClientInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClientInterface(ChatModel *chatModel, QObject *parent = nullptr);
|
||||
~ClientInterface();
|
||||
|
||||
void sendMessage(const QString &message);
|
||||
void clearMessages();
|
||||
void cancelRequest();
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &error);
|
||||
|
||||
private:
|
||||
void handleLLMResponse(const QString &response, const QJsonObject &request, bool isComplete);
|
||||
|
||||
LLMCore::RequestHandler *m_requestHandler;
|
||||
ChatModel *m_chatModel;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Chat
|
||||
51
chatview/MessagePart.hpp
Normal file
51
chatview/MessagePart.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace QodeAssist::Chat {
|
||||
Q_NAMESPACE
|
||||
|
||||
class MessagePart
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(PartType type MEMBER type CONSTANT FINAL)
|
||||
Q_PROPERTY(QString text MEMBER text CONSTANT FINAL)
|
||||
Q_PROPERTY(QString language MEMBER language CONSTANT FINAL)
|
||||
QML_VALUE_TYPE(messagePart)
|
||||
public:
|
||||
enum PartType { Code, Text };
|
||||
Q_ENUM(PartType)
|
||||
|
||||
PartType type;
|
||||
QString text;
|
||||
QString language;
|
||||
};
|
||||
|
||||
class MessagePartType : public MessagePart
|
||||
{
|
||||
Q_GADGET
|
||||
};
|
||||
|
||||
QML_NAMED_ELEMENT(MessagePart)
|
||||
QML_FOREIGN_NAMESPACE(QodeAssist::Chat::MessagePartType)
|
||||
} // namespace QodeAssist::Chat
|
||||
40
chatview/qml/Badge.qml
Normal file
40
chatview/qml/Badge.qml
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property alias text: badgeText.text
|
||||
property alias fontColor: badgeText.color
|
||||
|
||||
width: badgeText.implicitWidth + radius
|
||||
height: badgeText.implicitHeight + 6
|
||||
color: "lightgreen"
|
||||
radius: height / 2
|
||||
border.width: 1
|
||||
border.color: "gray"
|
||||
|
||||
Text {
|
||||
id: badgeText
|
||||
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
91
chatview/qml/ChatItem.qml
Normal file
91
chatview/qml/ChatItem.qml
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import ChatView
|
||||
import "./dialog"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property alias msgModel: msgCreator.model
|
||||
property color fontColor
|
||||
property color codeBgColor
|
||||
property color selectionColor
|
||||
|
||||
height: msgColumn.height
|
||||
radius: 8
|
||||
|
||||
Column {
|
||||
id: msgColumn
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
|
||||
Repeater {
|
||||
id: msgCreator
|
||||
delegate: Loader {
|
||||
property var itemData: modelData
|
||||
|
||||
width: parent.width
|
||||
sourceComponent: {
|
||||
switch(modelData.type) {
|
||||
case MessagePart.Text: return textComponent;
|
||||
case MessagePart.Code: return codeBlockComponent;
|
||||
default: return textComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textComponent
|
||||
|
||||
TextBlock {
|
||||
height: implicitHeight + 10
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: 10
|
||||
text: itemData.text
|
||||
color: fontColor
|
||||
selectionColor: root.selectionColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: codeBlockComponent
|
||||
|
||||
CodeBlock {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 10
|
||||
right: parent.right
|
||||
rightMargin: 10
|
||||
}
|
||||
|
||||
code: itemData.text
|
||||
language: itemData.language
|
||||
color: root.codeBgColor
|
||||
selectionColor: root.selectionColor
|
||||
}
|
||||
}
|
||||
}
|
||||
176
chatview/qml/RootItem.qml
Normal file
176
chatview/qml/RootItem.qml
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic as QQC
|
||||
import QtQuick.Layouts
|
||||
import ChatView
|
||||
|
||||
ChatRootView {
|
||||
id: root
|
||||
|
||||
Rectangle {
|
||||
id: bg
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
fill: parent
|
||||
}
|
||||
spacing: 10
|
||||
|
||||
ListView {
|
||||
id: chatListView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
leftMargin: 5
|
||||
model: root.chatModel
|
||||
clip: true
|
||||
spacing: 10
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
cacheBuffer: 2000
|
||||
|
||||
delegate: ChatItem {
|
||||
width: ListView.view.width - scroll.width
|
||||
msgModel: root.chatModel.processMessageContent(model.content)
|
||||
color: model.roleType === ChatModel.User ? root.primaryColor : root.secondaryColor
|
||||
fontColor: root.primaryColor.hslLightness > 0.5 ? "black" : "white"
|
||||
codeBgColor: root.codeColor
|
||||
selectionColor: root.primaryColor.hslLightness > 0.5 ? Qt.darker(root.primaryColor, 1.5)
|
||||
: Qt.lighter(root.primaryColor, 1.5)
|
||||
|
||||
}
|
||||
|
||||
header: Item {
|
||||
width: ListView.view.width - scroll.width
|
||||
height: 30
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scroll
|
||||
}
|
||||
|
||||
onCountChanged: {
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
onContentHeightChanged: {
|
||||
if (atYEnd) {
|
||||
scrollToBottom()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: view
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 30
|
||||
Layout.maximumHeight: root.height / 2
|
||||
|
||||
QQC.TextArea {
|
||||
id: messageInput
|
||||
|
||||
placeholderText: qsTr("Type your message here...")
|
||||
placeholderTextColor: "#888"
|
||||
color: root.primaryColor.hslLightness > 0.5 ? "black" : "white"
|
||||
background: Rectangle {
|
||||
radius: 2
|
||||
color: root.primaryColor
|
||||
border.color: root.primaryColor.hslLightness > 0.5 ? Qt.lighter(root.primaryColor, 1.5)
|
||||
: Qt.darker(root.primaryColor, 1.5)
|
||||
border.width: 1
|
||||
}
|
||||
Keys.onPressed: function(event) {
|
||||
if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && !(event.modifiers & Qt.ShiftModifier)) {
|
||||
sendChatMessage()
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
|
||||
Button {
|
||||
id: sendButton
|
||||
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
text: qsTr("Send")
|
||||
onClicked: sendChatMessage()
|
||||
}
|
||||
|
||||
Button {
|
||||
id: stopButton
|
||||
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
text: qsTr("Stop")
|
||||
onClicked: root.cancelRequest()
|
||||
}
|
||||
|
||||
Button {
|
||||
id: clearButton
|
||||
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
text: qsTr("Clear Chat")
|
||||
onClicked: clearChat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: bar
|
||||
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 5
|
||||
right: parent.right
|
||||
rightMargin: scroll.width
|
||||
}
|
||||
spacing: 10
|
||||
|
||||
Badge {
|
||||
text: "%1/%2".arg(root.chatModel.totalTokens).arg(root.chatModel.tokensThreshold)
|
||||
color: root.codeColor
|
||||
fontColor: root.primaryColor.hslLightness > 0.5 ? "black" : "white"
|
||||
}
|
||||
}
|
||||
|
||||
function clearChat() {
|
||||
root.chatModel.clear()
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
Qt.callLater(chatListView.positionViewAtEnd)
|
||||
}
|
||||
|
||||
function sendChatMessage() {
|
||||
root.sendMessage(messageInput.text);
|
||||
messageInput.text = ""
|
||||
scrollToBottom()
|
||||
}
|
||||
}
|
||||
100
chatview/qml/dialog/CodeBlock.qml
Normal file
100
chatview/qml/dialog/CodeBlock.qml
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import ChatView
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string code: ""
|
||||
property string language: ""
|
||||
property color selectionColor
|
||||
|
||||
readonly property string monospaceFont: {
|
||||
switch (Qt.platform.os) {
|
||||
case "windows":
|
||||
return "Consolas";
|
||||
case "osx":
|
||||
return "Menlo";
|
||||
case "linux":
|
||||
return "DejaVu Sans Mono";
|
||||
default:
|
||||
return "monospace";
|
||||
}
|
||||
}
|
||||
|
||||
border.color: root.color.hslLightness > 0.5 ? Qt.darker(root.color, 1.3)
|
||||
: Qt.lighter(root.color, 1.3)
|
||||
border.width: 2
|
||||
radius: 4
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: codeText.implicitHeight + 20
|
||||
|
||||
ChatUtils {
|
||||
id: utils
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: codeText
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
text: root.code
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
font.family: monospaceFont
|
||||
font.pointSize: 12
|
||||
color: parent.color.hslLightness > 0.5 ? "black" : "white"
|
||||
wrapMode: Text.WordWrap
|
||||
selectionColor: root.selectionColor
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 5
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
text: root.language
|
||||
color: root.color.hslLightness > 0.5 ? Qt.darker(root.color, 1.1)
|
||||
: Qt.lighter(root.color, 1.1)
|
||||
font.pointSize: 8
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 5
|
||||
text: "Copy"
|
||||
onClicked: {
|
||||
utils.copyToClipboard(root.code)
|
||||
text = qsTr("Copied")
|
||||
copyTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: copyTimer
|
||||
interval: 2000
|
||||
onTriggered: parent.text = qsTr("Copy")
|
||||
}
|
||||
}
|
||||
}
|
||||
29
chatview/qml/dialog/TextBlock.qml
Normal file
29
chatview/qml/dialog/TextBlock.qml
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
|
||||
TextEdit {
|
||||
id: root
|
||||
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.StyledText
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "ChangesManager.h"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
23
llmcore/CMakeLists.txt
Normal file
23
llmcore/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
||||
add_library(LLMCore STATIC
|
||||
RequestType.hpp
|
||||
Provider.hpp
|
||||
ProvidersManager.hpp ProvidersManager.cpp
|
||||
ContextData.hpp
|
||||
PromptTemplate.hpp
|
||||
PromptTemplateManager.hpp PromptTemplateManager.cpp
|
||||
RequestConfig.hpp
|
||||
RequestHandler.hpp RequestHandler.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(LLMCore
|
||||
PUBLIC
|
||||
Qt::Core
|
||||
Qt::Network
|
||||
QtCreator::Core
|
||||
QtCreator::Utils
|
||||
QtCreator::ExtensionSystem
|
||||
PRIVATE
|
||||
QodeAssistLogger
|
||||
)
|
||||
|
||||
target_include_directories(LLMCore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@ -21,13 +21,13 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
struct ContextData
|
||||
{
|
||||
QString prefix;
|
||||
QString suffix;
|
||||
QString instriuctions;
|
||||
QString systemPrompt;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -23,9 +23,9 @@
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include "QodeAssistData.hpp"
|
||||
#include "ContextData.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
enum class TemplateType { Chat, Fim };
|
||||
|
||||
@ -39,4 +39,4 @@ public:
|
||||
virtual QStringList stopWords() const = 0;
|
||||
virtual void prepareRequest(QJsonObject &request, const ContextData &context) const = 0;
|
||||
};
|
||||
} // namespace QodeAssist::Templates
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -19,9 +19,9 @@
|
||||
|
||||
#include "PromptTemplateManager.hpp"
|
||||
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
PromptTemplateManager &PromptTemplateManager::instance()
|
||||
{
|
||||
@ -31,20 +31,20 @@ PromptTemplateManager &PromptTemplateManager::instance()
|
||||
|
||||
void PromptTemplateManager::setCurrentFimTemplate(const QString &name)
|
||||
{
|
||||
logMessage("Setting current FIM provider to: " + name);
|
||||
LOG_MESSAGE("Setting current FIM provider to: " + name);
|
||||
if (!m_fimTemplates.contains(name) || m_fimTemplates[name] == nullptr) {
|
||||
logMessage("Error to set current FIM template" + name);
|
||||
LOG_MESSAGE("Error to set current FIM template" + name);
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentFimTemplate = m_fimTemplates[name];
|
||||
}
|
||||
|
||||
Templates::PromptTemplate *PromptTemplateManager::getCurrentFimTemplate()
|
||||
PromptTemplate *PromptTemplateManager::getCurrentFimTemplate()
|
||||
{
|
||||
if (m_currentFimTemplate == nullptr) {
|
||||
logMessage("Current fim provider is null");
|
||||
return nullptr;
|
||||
LOG_MESSAGE("Current fim provider is null, return first");
|
||||
return m_fimTemplates.first();
|
||||
}
|
||||
|
||||
return m_currentFimTemplate;
|
||||
@ -52,19 +52,21 @@ Templates::PromptTemplate *PromptTemplateManager::getCurrentFimTemplate()
|
||||
|
||||
void PromptTemplateManager::setCurrentChatTemplate(const QString &name)
|
||||
{
|
||||
logMessage("Setting current chat provider to: " + name);
|
||||
LOG_MESSAGE("Setting current chat provider to: " + name);
|
||||
if (!m_chatTemplates.contains(name) || m_chatTemplates[name] == nullptr) {
|
||||
logMessage("Error to set current chat template" + name);
|
||||
LOG_MESSAGE("Error to set current chat template" + name);
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentChatTemplate = m_chatTemplates[name];
|
||||
}
|
||||
|
||||
Templates::PromptTemplate *PromptTemplateManager::getCurrentChatTemplate()
|
||||
PromptTemplate *PromptTemplateManager::getCurrentChatTemplate()
|
||||
{
|
||||
if (m_currentChatTemplate == nullptr)
|
||||
logMessage("Current chat provider is null");
|
||||
if (m_currentChatTemplate == nullptr) {
|
||||
LOG_MESSAGE("Current chat provider is null, return first");
|
||||
return m_chatTemplates.first();
|
||||
}
|
||||
|
||||
return m_currentChatTemplate;
|
||||
}
|
||||
@ -85,4 +87,4 @@ PromptTemplateManager::~PromptTemplateManager()
|
||||
qDeleteAll(m_chatTemplates);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -22,9 +22,9 @@
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
#include "templates/PromptTemplate.hpp"
|
||||
#include "PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
class PromptTemplateManager
|
||||
{
|
||||
@ -35,22 +35,22 @@ public:
|
||||
template<typename T>
|
||||
void registerTemplate()
|
||||
{
|
||||
static_assert(std::is_base_of<Templates::PromptTemplate, T>::value,
|
||||
static_assert(std::is_base_of<PromptTemplate, T>::value,
|
||||
"T must inherit from PromptTemplate");
|
||||
T *template_ptr = new T();
|
||||
QString name = template_ptr->name();
|
||||
if (template_ptr->type() == Templates::TemplateType::Fim) {
|
||||
if (template_ptr->type() == TemplateType::Fim) {
|
||||
m_fimTemplates[name] = template_ptr;
|
||||
} else if (template_ptr->type() == Templates::TemplateType::Chat) {
|
||||
} else if (template_ptr->type() == TemplateType::Chat) {
|
||||
m_chatTemplates[name] = template_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setCurrentFimTemplate(const QString &name);
|
||||
Templates::PromptTemplate *getCurrentFimTemplate();
|
||||
PromptTemplate *getCurrentFimTemplate();
|
||||
|
||||
void setCurrentChatTemplate(const QString &name);
|
||||
Templates::PromptTemplate *getCurrentChatTemplate();
|
||||
PromptTemplate *getCurrentChatTemplate();
|
||||
|
||||
QStringList fimTemplatesNames() const;
|
||||
QStringList chatTemplatesNames() const;
|
||||
@ -60,10 +60,10 @@ private:
|
||||
PromptTemplateManager(const PromptTemplateManager &) = delete;
|
||||
PromptTemplateManager &operator=(const PromptTemplateManager &) = delete;
|
||||
|
||||
QMap<QString, Templates::PromptTemplate *> m_fimTemplates;
|
||||
QMap<QString, Templates::PromptTemplate *> m_chatTemplates;
|
||||
Templates::PromptTemplate *m_currentFimTemplate;
|
||||
Templates::PromptTemplate *m_currentChatTemplate;
|
||||
QMap<QString, PromptTemplate *> m_fimTemplates;
|
||||
QMap<QString, PromptTemplate *> m_chatTemplates;
|
||||
PromptTemplate *m_currentFimTemplate;
|
||||
PromptTemplate *m_currentChatTemplate;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -20,26 +20,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include "RequestType.hpp"
|
||||
#include <utils/environment.h>
|
||||
|
||||
class QNetworkReply;
|
||||
class QJsonObject;
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
class LLMProvider
|
||||
class Provider
|
||||
{
|
||||
public:
|
||||
virtual ~LLMProvider() = default;
|
||||
virtual ~Provider() = default;
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QString url() const = 0;
|
||||
virtual QString completionEndpoint() const = 0;
|
||||
virtual QString chatEndpoint() const = 0;
|
||||
|
||||
virtual void prepareRequest(QJsonObject &request) = 0;
|
||||
virtual void prepareRequest(QJsonObject &request, RequestType type) = 0;
|
||||
virtual bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) = 0;
|
||||
virtual QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) = 0;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -17,23 +17,23 @@
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "ProvidersManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
#include "QodeAssistUtils.hpp"
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
LLMProvidersManager &LLMProvidersManager::instance()
|
||||
ProvidersManager &ProvidersManager::instance()
|
||||
{
|
||||
static LLMProvidersManager instance;
|
||||
static ProvidersManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Providers::LLMProvider *LLMProvidersManager::setCurrentFimProvider(const QString &name)
|
||||
Provider *ProvidersManager::setCurrentFimProvider(const QString &name)
|
||||
{
|
||||
logMessage("Setting current FIM provider to: " + name);
|
||||
LOG_MESSAGE("Setting current FIM provider to: " + name);
|
||||
if (!m_providers.contains(name)) {
|
||||
logMessage("Can't find provider with name: " + name);
|
||||
LOG_MESSAGE("Can't find provider with name: " + name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -41,11 +41,11 @@ Providers::LLMProvider *LLMProvidersManager::setCurrentFimProvider(const QString
|
||||
return m_currentFimProvider;
|
||||
}
|
||||
|
||||
Providers::LLMProvider *LLMProvidersManager::setCurrentChatProvider(const QString &name)
|
||||
Provider *ProvidersManager::setCurrentChatProvider(const QString &name)
|
||||
{
|
||||
logMessage("Setting current chat provider to: " + name);
|
||||
LOG_MESSAGE("Setting current chat provider to: " + name);
|
||||
if (!m_providers.contains(name)) {
|
||||
logMessage("Can't find chat provider with name: " + name);
|
||||
LOG_MESSAGE("Can't find chat provider with name: " + name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -53,34 +53,34 @@ Providers::LLMProvider *LLMProvidersManager::setCurrentChatProvider(const QStrin
|
||||
return m_currentChatProvider;
|
||||
}
|
||||
|
||||
Providers::LLMProvider *LLMProvidersManager::getCurrentFimProvider()
|
||||
Provider *ProvidersManager::getCurrentFimProvider()
|
||||
{
|
||||
if (m_currentFimProvider == nullptr) {
|
||||
logMessage("Current fim provider is null");
|
||||
return nullptr;
|
||||
LOG_MESSAGE("Current fim provider is null, return first");
|
||||
return m_providers.first();
|
||||
}
|
||||
|
||||
return m_currentFimProvider;
|
||||
}
|
||||
|
||||
Providers::LLMProvider *LLMProvidersManager::getCurrentChatProvider()
|
||||
Provider *ProvidersManager::getCurrentChatProvider()
|
||||
{
|
||||
if (m_currentChatProvider == nullptr) {
|
||||
logMessage("Current chat provider is null");
|
||||
return nullptr;
|
||||
LOG_MESSAGE("Current chat provider is null, return first");
|
||||
return m_providers.first();
|
||||
}
|
||||
|
||||
return m_currentChatProvider;
|
||||
}
|
||||
|
||||
QStringList LLMProvidersManager::providersNames() const
|
||||
QStringList ProvidersManager::providersNames() const
|
||||
{
|
||||
return m_providers.keys();
|
||||
}
|
||||
|
||||
LLMProvidersManager::~LLMProvidersManager()
|
||||
ProvidersManager::~ProvidersManager()
|
||||
{
|
||||
qDeleteAll(m_providers);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -21,42 +21,41 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "providers/LLMProvider.hpp"
|
||||
#include "Provider.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
class LLMProvidersManager
|
||||
class ProvidersManager
|
||||
{
|
||||
public:
|
||||
static LLMProvidersManager &instance();
|
||||
~LLMProvidersManager();
|
||||
static ProvidersManager &instance();
|
||||
~ProvidersManager();
|
||||
|
||||
template<typename T>
|
||||
void registerProvider()
|
||||
{
|
||||
static_assert(std::is_base_of<Providers::LLMProvider, T>::value,
|
||||
"T must inherit from LLMProvider");
|
||||
static_assert(std::is_base_of<Provider, T>::value, "T must inherit from Provider");
|
||||
T *provider = new T();
|
||||
QString name = provider->name();
|
||||
m_providers[name] = provider;
|
||||
}
|
||||
|
||||
Providers::LLMProvider *setCurrentFimProvider(const QString &name);
|
||||
Providers::LLMProvider *setCurrentChatProvider(const QString &name);
|
||||
Provider *setCurrentFimProvider(const QString &name);
|
||||
Provider *setCurrentChatProvider(const QString &name);
|
||||
|
||||
Providers::LLMProvider *getCurrentFimProvider();
|
||||
Providers::LLMProvider *getCurrentChatProvider();
|
||||
Provider *getCurrentFimProvider();
|
||||
Provider *getCurrentChatProvider();
|
||||
|
||||
QStringList providersNames() const;
|
||||
|
||||
private:
|
||||
LLMProvidersManager() = default;
|
||||
LLMProvidersManager(const LLMProvidersManager &) = delete;
|
||||
LLMProvidersManager &operator=(const LLMProvidersManager &) = delete;
|
||||
ProvidersManager() = default;
|
||||
ProvidersManager(const ProvidersManager &) = delete;
|
||||
ProvidersManager &operator=(const ProvidersManager &) = delete;
|
||||
|
||||
QMap<QString, Providers::LLMProvider *> m_providers;
|
||||
Providers::LLMProvider *m_currentFimProvider = nullptr;
|
||||
Providers::LLMProvider *m_currentChatProvider = nullptr;
|
||||
QMap<QString, Provider *> m_providers;
|
||||
Provider *m_currentFimProvider = nullptr;
|
||||
Provider *m_currentChatProvider = nullptr;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -21,20 +21,20 @@
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QUrl>
|
||||
#include "providers/LLMProvider.hpp"
|
||||
#include "templates/PromptTemplate.hpp"
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "Provider.hpp"
|
||||
#include "RequestType.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
enum class RequestType { Fim, Chat };
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
struct LLMConfig
|
||||
{
|
||||
QUrl url;
|
||||
Providers::LLMProvider *provider;
|
||||
Templates::PromptTemplate *promptTemplate;
|
||||
Provider *provider;
|
||||
PromptTemplate *promptTemplate;
|
||||
QJsonObject providerRequest;
|
||||
RequestType requestType;
|
||||
bool multiLineCompletion;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -17,24 +17,22 @@
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LLMRequestHandler.hpp"
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "RequestHandler.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
LLMRequestHandler::LLMRequestHandler(QObject *parent)
|
||||
RequestHandler::RequestHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_manager(new QNetworkAccessManager(this))
|
||||
{}
|
||||
|
||||
void LLMRequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &request)
|
||||
void RequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &request)
|
||||
{
|
||||
logMessage(QString("Sending request to llm: \nurl: %1\nRequest body:\n%2")
|
||||
LOG_MESSAGE(QString("Sending request to llm: \nurl: %1\nRequest body:\n%2")
|
||||
.arg(config.url.toString(),
|
||||
QString::fromUtf8(
|
||||
QJsonDocument(config.providerRequest).toJson(QJsonDocument::Indented))));
|
||||
@ -45,7 +43,7 @@ void LLMRequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObjec
|
||||
QNetworkReply *reply = m_manager->post(networkRequest,
|
||||
QJsonDocument(config.providerRequest).toJson());
|
||||
if (!reply) {
|
||||
logMessage("Error: Failed to create network reply");
|
||||
LOG_MESSAGE("Error: Failed to create network reply");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -60,47 +58,43 @@ void LLMRequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObjec
|
||||
reply->deleteLater();
|
||||
m_activeRequests.remove(requestId);
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
logMessage(QString("Error in QodeAssist request: %1").arg(reply->errorString()));
|
||||
LOG_MESSAGE(QString("Error in QodeAssist request: %1").arg(reply->errorString()));
|
||||
emit requestFinished(requestId, false, reply->errorString());
|
||||
} else {
|
||||
logMessage("Request finished successfully");
|
||||
LOG_MESSAGE("Request finished successfully");
|
||||
emit requestFinished(requestId, true, QString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LLMRequestHandler::handleLLMResponse(QNetworkReply *reply,
|
||||
const QJsonObject &request,
|
||||
const LLMConfig &config)
|
||||
void RequestHandler::handleLLMResponse(QNetworkReply *reply,
|
||||
const QJsonObject &request,
|
||||
const LLMConfig &config)
|
||||
{
|
||||
QString &accumulatedResponse = m_accumulatedResponses[reply];
|
||||
|
||||
bool isComplete = config.provider->handleResponse(reply, accumulatedResponse);
|
||||
|
||||
if (config.requestType == RequestType::Fim) {
|
||||
if (!Settings::generalSettings().multiLineCompletion()
|
||||
if (!config.multiLineCompletion
|
||||
&& processSingleLineCompletion(reply, request, accumulatedResponse, config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isComplete) {
|
||||
auto cleanedCompletion = removeStopWords(accumulatedResponse,
|
||||
config.promptTemplate->stopWords());
|
||||
emit completionReceived(cleanedCompletion, request, true);
|
||||
}
|
||||
} else if (config.requestType == RequestType::Chat) {
|
||||
emit completionReceived(accumulatedResponse, request, isComplete);
|
||||
}
|
||||
|
||||
if (isComplete || reply->isFinished()) {
|
||||
if (isComplete) {
|
||||
if (config.requestType == RequestType::Fim) {
|
||||
auto cleanedCompletion = removeStopWords(accumulatedResponse,
|
||||
config.promptTemplate->stopWords());
|
||||
emit completionReceived(cleanedCompletion, request, true);
|
||||
} else {
|
||||
emit completionReceived(accumulatedResponse, request, true);
|
||||
}
|
||||
} else {
|
||||
emit completionReceived(accumulatedResponse, request, false);
|
||||
}
|
||||
if (isComplete)
|
||||
m_accumulatedResponses.remove(reply);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMRequestHandler::cancelRequest(const QString &id)
|
||||
bool RequestHandler::cancelRequest(const QString &id)
|
||||
{
|
||||
if (m_activeRequests.contains(id)) {
|
||||
QNetworkReply *reply = m_activeRequests[id];
|
||||
@ -113,8 +107,8 @@ bool LLMRequestHandler::cancelRequest(const QString &id)
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLMRequestHandler::prepareNetworkRequest(QNetworkRequest &networkRequest,
|
||||
const QJsonObject &providerRequest)
|
||||
void RequestHandler::prepareNetworkRequest(QNetworkRequest &networkRequest,
|
||||
const QJsonObject &providerRequest)
|
||||
{
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
@ -124,10 +118,10 @@ void LLMRequestHandler::prepareNetworkRequest(QNetworkRequest &networkRequest,
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMRequestHandler::processSingleLineCompletion(QNetworkReply *reply,
|
||||
const QJsonObject &request,
|
||||
const QString &accumulatedResponse,
|
||||
const LLMConfig &config)
|
||||
bool RequestHandler::processSingleLineCompletion(QNetworkReply *reply,
|
||||
const QJsonObject &request,
|
||||
const QString &accumulatedResponse,
|
||||
const LLMConfig &config)
|
||||
{
|
||||
int newlinePos = accumulatedResponse.indexOf('\n');
|
||||
|
||||
@ -145,8 +139,7 @@ bool LLMRequestHandler::processSingleLineCompletion(QNetworkReply *reply,
|
||||
return false;
|
||||
}
|
||||
|
||||
QString LLMRequestHandler::removeStopWords(const QStringView &completion,
|
||||
const QStringList &stopWords)
|
||||
QString RequestHandler::removeStopWords(const QStringView &completion, const QStringList &stopWords)
|
||||
{
|
||||
QString filteredCompletion = completion.toString();
|
||||
|
||||
@ -157,4 +150,4 @@ QString LLMRequestHandler::removeStopWords(const QStringView &completion,
|
||||
return filteredCompletion;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
@ -23,19 +23,18 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QObject>
|
||||
|
||||
#include "QodeAssistData.hpp"
|
||||
#include "core/LLMRequestConfig.hpp"
|
||||
#include "RequestConfig.hpp"
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
namespace QodeAssist {
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
class LLMRequestHandler : public QObject
|
||||
class RequestHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LLMRequestHandler(QObject *parent = nullptr);
|
||||
explicit RequestHandler(QObject *parent = nullptr);
|
||||
|
||||
void sendLLMRequest(const LLMConfig &config, const QJsonObject &request);
|
||||
void handleLLMResponse(QNetworkReply *reply,
|
||||
@ -61,4 +60,4 @@ private:
|
||||
QString removeStopWords(const QStringView &completion, const QStringList &stopWords);
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
} // namespace QodeAssist::LLMCore
|
||||
6
llmcore/RequestType.hpp
Normal file
6
llmcore/RequestType.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
enum RequestType { Fim, Chat };
|
||||
}
|
||||
14
logger/CMakeLists.txt
Normal file
14
logger/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
add_library(QodeAssistLogger STATIC
|
||||
Logger.cpp
|
||||
Logger.hpp
|
||||
)
|
||||
|
||||
target_link_libraries(QodeAssistLogger
|
||||
PUBLIC
|
||||
Qt::Core
|
||||
QtCreator::Core
|
||||
)
|
||||
|
||||
target_include_directories(QodeAssistLogger
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
55
logger/Logger.cpp
Normal file
55
logger/Logger.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "Logger.hpp"
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
Logger &Logger::instance()
|
||||
{
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Logger::Logger()
|
||||
: m_loggingEnabled(false)
|
||||
{}
|
||||
|
||||
void Logger::setLoggingEnabled(bool enable)
|
||||
{
|
||||
m_loggingEnabled = enable;
|
||||
}
|
||||
|
||||
bool Logger::isLoggingEnabled() const
|
||||
{
|
||||
return m_loggingEnabled;
|
||||
}
|
||||
|
||||
void Logger::log(const QString &message, bool silent)
|
||||
{
|
||||
if (!m_loggingEnabled)
|
||||
return;
|
||||
|
||||
const QString prefixedMessage = QLatin1String("[Qode Assist] ") + message;
|
||||
if (silent) {
|
||||
Core::MessageManager::writeSilently(prefixedMessage);
|
||||
} else {
|
||||
Core::MessageManager::writeFlashing(prefixedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::logMessages(const QStringList &messages, bool silent)
|
||||
{
|
||||
if (!m_loggingEnabled)
|
||||
return;
|
||||
|
||||
QStringList prefixedMessages;
|
||||
for (const QString &message : messages) {
|
||||
prefixedMessages << (QLatin1String("[Qode Assist] ") + message);
|
||||
}
|
||||
|
||||
if (silent) {
|
||||
Core::MessageManager::writeSilently(prefixedMessages);
|
||||
} else {
|
||||
Core::MessageManager::writeFlashing(prefixedMessages);
|
||||
}
|
||||
}
|
||||
} // namespace QodeAssist
|
||||
33
logger/Logger.hpp
Normal file
33
logger/Logger.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
class Logger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Logger &instance();
|
||||
|
||||
void setLoggingEnabled(bool enable);
|
||||
bool isLoggingEnabled() const;
|
||||
|
||||
void log(const QString &message, bool silent = true);
|
||||
void logMessages(const QStringList &messages, bool silent = true);
|
||||
|
||||
private:
|
||||
Logger();
|
||||
~Logger() = default;
|
||||
Logger(const Logger &) = delete;
|
||||
Logger &operator=(const Logger &) = delete;
|
||||
|
||||
bool m_loggingEnabled;
|
||||
};
|
||||
|
||||
#define LOG_MESSAGE(msg) QodeAssist::Logger::instance().log(msg)
|
||||
#define LOG_MESSAGES(msgs) QodeAssist::Logger::instance().logMessages(msgs)
|
||||
|
||||
} // namespace QodeAssist
|
||||
@ -25,7 +25,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
@ -52,9 +52,11 @@ QString LMStudioProvider::chatEndpoint() const
|
||||
return "/v1/chat/completions";
|
||||
}
|
||||
|
||||
void LMStudioProvider::prepareRequest(QJsonObject &request)
|
||||
void LMStudioProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
auto &promptSettings = Settings::presetPromptsSettings();
|
||||
auto settings = promptSettings.getSettings(type);
|
||||
|
||||
QJsonArray messages;
|
||||
|
||||
if (request.contains("system")) {
|
||||
@ -72,16 +74,16 @@ void LMStudioProvider::prepareRequest(QJsonObject &request)
|
||||
request["messages"] = std::move(messages);
|
||||
}
|
||||
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
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();
|
||||
request["max_tokens"] = settings.maxTokens;
|
||||
request["temperature"] = settings.temperature;
|
||||
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)
|
||||
@ -150,7 +152,7 @@ QList<QString> LMStudioProvider::getInstalledModels(const Utils::Environment &en
|
||||
models.append(modelId);
|
||||
}
|
||||
} else {
|
||||
logMessage(QString("Error fetching models: %1").arg(reply->errorString()));
|
||||
LOG_MESSAGE(QString("Error fetching models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LLMProvider.hpp"
|
||||
#include "llmcore/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class LMStudioProvider : public LLMProvider
|
||||
class LMStudioProvider : public LLMCore::Provider
|
||||
{
|
||||
public:
|
||||
LMStudioProvider();
|
||||
@ -32,7 +32,7 @@ public:
|
||||
QString url() const override;
|
||||
QString completionEndpoint() const override;
|
||||
QString chatEndpoint() const override;
|
||||
void prepareRequest(QJsonObject &request) override;
|
||||
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
|
||||
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
|
||||
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override;
|
||||
};
|
||||
|
||||
@ -25,8 +25,8 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QtCore/qeventloop.h>
|
||||
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "llmcore/PromptTemplateManager.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/PresetPromptsSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
@ -53,23 +53,24 @@ QString OllamaProvider::chatEndpoint() const
|
||||
return "/api/chat";
|
||||
}
|
||||
|
||||
void OllamaProvider::prepareRequest(QJsonObject &request)
|
||||
void OllamaProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
auto &promptSettings = Settings::presetPromptsSettings();
|
||||
auto settings = promptSettings.getSettings(type);
|
||||
|
||||
QJsonObject options;
|
||||
options["num_predict"] = settings.maxTokens();
|
||||
options["temperature"] = settings.temperature();
|
||||
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();
|
||||
options["num_predict"] = settings.maxTokens;
|
||||
options["temperature"] = settings.temperature;
|
||||
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;
|
||||
request["keep_alive"] = settings.ollamaLivetime();
|
||||
request["keep_alive"] = settings.ollamaLivetime;
|
||||
}
|
||||
|
||||
bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse)
|
||||
@ -85,7 +86,7 @@ bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedRe
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(line);
|
||||
if (doc.isNull()) {
|
||||
logMessage("Invalid JSON response from Ollama: " + QString::fromUtf8(line));
|
||||
LOG_MESSAGE("Invalid JSON response from Ollama: " + QString::fromUtf8(line));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -93,7 +94,7 @@ bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedRe
|
||||
|
||||
if (responseObj.contains("error")) {
|
||||
QString errorMessage = responseObj["error"].toString();
|
||||
logMessage("Error in Ollama response: " + errorMessage);
|
||||
LOG_MESSAGE("Error in Ollama response: " + errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedRe
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logMessage("Unknown endpoint: " + endpoint);
|
||||
LOG_MESSAGE("Unknown endpoint: " + endpoint);
|
||||
}
|
||||
|
||||
if (responseObj.contains("done") && responseObj["done"].toBool()) {
|
||||
@ -146,7 +147,7 @@ QList<QString> OllamaProvider::getInstalledModels(const Utils::Environment &env,
|
||||
models.append(modelName);
|
||||
}
|
||||
} else {
|
||||
logMessage(QString("Error fetching models: %1").arg(reply->errorString()));
|
||||
LOG_MESSAGE(QString("Error fetching models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LLMProvider.hpp"
|
||||
#include "llmcore/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OllamaProvider : public LLMProvider
|
||||
class OllamaProvider : public LLMCore::Provider
|
||||
{
|
||||
public:
|
||||
OllamaProvider();
|
||||
@ -32,7 +32,7 @@ public:
|
||||
QString url() const override;
|
||||
QString completionEndpoint() const override;
|
||||
QString chatEndpoint() const override;
|
||||
void prepareRequest(QJsonObject &request) override;
|
||||
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
|
||||
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
|
||||
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override;
|
||||
};
|
||||
|
||||
@ -50,9 +50,10 @@ QString OpenAICompatProvider::chatEndpoint() const
|
||||
return "/v1/chat/completions";
|
||||
}
|
||||
|
||||
void OpenAICompatProvider::prepareRequest(QJsonObject &request)
|
||||
void OpenAICompatProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType type)
|
||||
{
|
||||
auto &settings = Settings::presetPromptsSettings();
|
||||
auto &promptSettings = Settings::presetPromptsSettings();
|
||||
auto settings = promptSettings.getSettings(type);
|
||||
QJsonArray messages;
|
||||
|
||||
if (request.contains("system")) {
|
||||
@ -70,18 +71,18 @@ void OpenAICompatProvider::prepareRequest(QJsonObject &request)
|
||||
request["messages"] = std::move(messages);
|
||||
}
|
||||
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
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();
|
||||
request["max_tokens"] = settings.maxTokens;
|
||||
request["temperature"] = settings.temperature;
|
||||
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;
|
||||
if (!apiKey.isEmpty()) {
|
||||
request["api_key"] = apiKey;
|
||||
}
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LLMProvider.hpp"
|
||||
#include "llmcore/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OpenAICompatProvider : public LLMProvider
|
||||
class OpenAICompatProvider : public LLMCore::Provider
|
||||
{
|
||||
public:
|
||||
OpenAICompatProvider();
|
||||
@ -32,7 +32,7 @@ public:
|
||||
QString url() const override;
|
||||
QString completionEndpoint() const override;
|
||||
QString chatEndpoint() const override;
|
||||
void prepareRequest(QJsonObject &request) override;
|
||||
void prepareRequest(QJsonObject &request, LLMCore::RequestType type) override;
|
||||
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
|
||||
QList<QString> getInstalledModels(const Utils::Environment &env, const QString &url) override;
|
||||
};
|
||||
|
||||
@ -39,21 +39,23 @@
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <utils/icon.h>
|
||||
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistClient.hpp"
|
||||
#include "chat/ChatOutputPane.h"
|
||||
#include "chat/NavigationPanel.hpp"
|
||||
#include "llmcore/PromptTemplateManager.hpp"
|
||||
#include "llmcore/ProvidersManager.hpp"
|
||||
#include "providers/LMStudioProvider.hpp"
|
||||
#include "providers/OllamaProvider.hpp"
|
||||
#include "providers/OpenAICompatProvider.hpp"
|
||||
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "templates/CodeLlamaFimTemplate.hpp"
|
||||
#include "templates/CodeLlamaInstruct.hpp"
|
||||
#include "templates/CustomTemplate.hpp"
|
||||
#include "templates/DeepSeekCoderChatTemplate.hpp"
|
||||
#include "templates/DeepSeekCoderV2.hpp"
|
||||
#include "templates/StarCoder2Template.hpp"
|
||||
#include "templates/CodeLlamaChat.hpp"
|
||||
#include "templates/CodeLlamaFim.hpp"
|
||||
#include "templates/CustomFimTemplate.hpp"
|
||||
#include "templates/DeepSeekCoderChat.hpp"
|
||||
#include "templates/DeepSeekCoderFim.hpp"
|
||||
#include "templates/QwenChat.hpp"
|
||||
#include "templates/StarCoder2Fim.hpp"
|
||||
#include "templates/StarCoderChat.hpp"
|
||||
|
||||
using namespace Utils;
|
||||
using namespace Core;
|
||||
@ -73,23 +75,28 @@ public:
|
||||
|
||||
~QodeAssistPlugin() final
|
||||
{
|
||||
|
||||
delete m_qodeAssistClient;
|
||||
delete m_chatOutputPane;
|
||||
delete m_navigationPanel;
|
||||
}
|
||||
|
||||
void initialize() final
|
||||
{
|
||||
auto &providerManager = LLMProvidersManager::instance();
|
||||
auto &providerManager = LLMCore::ProvidersManager::instance();
|
||||
providerManager.registerProvider<Providers::OllamaProvider>();
|
||||
providerManager.registerProvider<Providers::LMStudioProvider>();
|
||||
providerManager.registerProvider<Providers::OpenAICompatProvider>();
|
||||
|
||||
auto &templateManager = PromptTemplateManager::instance();
|
||||
templateManager.registerTemplate<Templates::CodeLlamaFimTemplate>();
|
||||
templateManager.registerTemplate<Templates::StarCoder2Template>();
|
||||
templateManager.registerTemplate<Templates::DeepSeekCoderV2Template>();
|
||||
auto &templateManager = LLMCore::PromptTemplateManager::instance();
|
||||
templateManager.registerTemplate<Templates::CodeLlamaFim>();
|
||||
templateManager.registerTemplate<Templates::StarCoder2Fim>();
|
||||
templateManager.registerTemplate<Templates::DeepSeekCoderFim>();
|
||||
templateManager.registerTemplate<Templates::CustomTemplate>();
|
||||
templateManager.registerTemplate<Templates::DeepSeekCoderChatTemplate>();
|
||||
templateManager.registerTemplate<Templates::CodeLlamaInstructTemplate>();
|
||||
templateManager.registerTemplate<Templates::DeepSeekCoderChat>();
|
||||
templateManager.registerTemplate<Templates::CodeLlamaChat>();
|
||||
templateManager.registerTemplate<Templates::QwenChat>();
|
||||
templateManager.registerTemplate<Templates::LlamaChat>();
|
||||
templateManager.registerTemplate<Templates::StarCoderChat>();
|
||||
|
||||
Utils::Icon QCODEASSIST_ICON(
|
||||
{{":/resources/images/qoderassist-icon.png", Utils::Theme::IconsBaseColor}});
|
||||
@ -116,6 +123,7 @@ public:
|
||||
StatusBarManager::addStatusBarWidget(toggleButton, StatusBarManager::RightCorner);
|
||||
|
||||
m_chatOutputPane = new Chat::ChatOutputPane(this);
|
||||
m_navigationPanel = new Chat::NavigationPanel();
|
||||
}
|
||||
|
||||
void extensionsInitialized() final
|
||||
@ -150,6 +158,7 @@ public:
|
||||
private:
|
||||
QPointer<QodeAssistClient> m_qodeAssistClient;
|
||||
QPointer<Chat::ChatOutputPane> m_chatOutputPane;
|
||||
QPointer<Chat::NavigationPanel> m_navigationPanel;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Internal
|
||||
|
||||
31
settings/Assisttr.h
Normal file
31
settings/Assisttr.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
struct Tr
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist)
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
20
settings/CMakeLists.txt
Normal file
20
settings/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
add_library(QodeAssistSettings STATIC
|
||||
GeneralSettings.hpp GeneralSettings.cpp
|
||||
ContextSettings.hpp ContextSettings.cpp
|
||||
CustomPromptSettings.hpp CustomPromptSettings.cpp
|
||||
PresetPromptsSettings.hpp PresetPromptsSettings.cpp
|
||||
SettingsUtils.hpp
|
||||
SettingsConstants.hpp
|
||||
)
|
||||
|
||||
target_link_libraries(QodeAssistSettings
|
||||
PUBLIC
|
||||
Qt::Core
|
||||
Qt::Network
|
||||
QtCreator::Core
|
||||
QtCreator::Utils
|
||||
QodeAssistLogger
|
||||
PRIVATE
|
||||
LLMCore
|
||||
)
|
||||
target_include_directories(QodeAssistSettings PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@ -24,8 +24,7 @@
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
#include "SettingsConstants.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
ContextSettings &contextSettings()
|
||||
@ -58,17 +57,37 @@ ContextSettings::ContextSettings()
|
||||
useFilePathInContext.setDefaultValue(false);
|
||||
useFilePathInContext.setLabelText(Tr::tr("Use File Path in Context"));
|
||||
|
||||
useSpecificInstructions.setSettingsKey(Constants::USE_SYSTEM_PROMPT);
|
||||
useSpecificInstructions.setDefaultValue(true);
|
||||
useSpecificInstructions.setLabelText(Tr::tr("Use System Prompt"));
|
||||
useSystemPrompt.setSettingsKey(Constants::USE_SYSTEM_PROMPT);
|
||||
useSystemPrompt.setDefaultValue(true);
|
||||
useSystemPrompt.setLabelText(Tr::tr("Use System Prompt"));
|
||||
|
||||
specificInstractions.setSettingsKey(Constants::SYSTEM_PROMPT);
|
||||
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");
|
||||
systemPrompt.setSettingsKey(Constants::SYSTEM_PROMPT);
|
||||
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||
systemPrompt.setDefaultValue(
|
||||
"You are an expert C++, Qt, and QML code completion AI. Your task is to provide accurate "
|
||||
"and "
|
||||
"contextually appropriate code suggestions. Focus on completing the code in a way that "
|
||||
"follows best practices, is efficient, and matches the surrounding code style. Prioritize "
|
||||
"Qt and QML-specific completions when appropriate. Avoid adding comments or explanations "
|
||||
"in your completions.");
|
||||
|
||||
useChatSystemPrompt.setSettingsKey(Constants::USE_CHAT_SYSTEM_PROMPT);
|
||||
useChatSystemPrompt.setDefaultValue(true);
|
||||
useChatSystemPrompt.setLabelText(Tr::tr("Use System Prompt for chat"));
|
||||
|
||||
chatSystemPrompt.setSettingsKey(Constants::CHAT_SYSTEM_PROMPT);
|
||||
chatSystemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||
chatSystemPrompt.setDefaultValue(
|
||||
"You are an advanced AI assistant specializing in C++, Qt, and QML development. Your role "
|
||||
"is "
|
||||
"to provide helpful, accurate, and detailed responses to questions about coding, "
|
||||
"debugging, "
|
||||
"and best practices in these technologies. Offer clear explanations, code examples when "
|
||||
"appropriate, and guidance on Qt Creator usage. Always prioritize officially recommended "
|
||||
"Qt "
|
||||
"and C++ practices. If you're unsure about something, state it clearly and suggest where "
|
||||
"the "
|
||||
"user might find more information.");
|
||||
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
@ -85,21 +104,26 @@ ContextSettings::ContextSettings()
|
||||
|
||||
readStringsAfterCursor.setEnabled(!readFullFile());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile());
|
||||
specificInstractions.setEnabled(useSpecificInstructions());
|
||||
systemPrompt.setEnabled(useSystemPrompt());
|
||||
|
||||
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}};
|
||||
return Column{Row{Stretch{1}, resetToDefaults},
|
||||
Group{title(Tr::tr("AI Suggestions Context")),
|
||||
Column{Row{readFullFile, Stretch{1}},
|
||||
Row{readStringsBeforeCursor, Stretch{1}},
|
||||
Row{readStringsAfterCursor, Stretch{1}},
|
||||
useFilePathInContext,
|
||||
useSystemPrompt,
|
||||
systemPrompt,
|
||||
useProjectChangesCache,
|
||||
Row{maxChangesCacheSize, Stretch{1}},
|
||||
Stretch{1}}},
|
||||
Space{16},
|
||||
Group{title(Tr::tr("AI Chat Context")),
|
||||
Column{useChatSystemPrompt, chatSystemPrompt}}};
|
||||
});
|
||||
}
|
||||
|
||||
@ -109,8 +133,8 @@ void ContextSettings::setupConnection()
|
||||
readStringsAfterCursor.setEnabled(!readFullFile.volatileValue());
|
||||
readStringsBeforeCursor.setEnabled(!readFullFile.volatileValue());
|
||||
});
|
||||
connect(&useSpecificInstructions, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
specificInstractions.setEnabled(useSpecificInstructions.volatileValue());
|
||||
connect(&useSystemPrompt, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
systemPrompt.setEnabled(useSystemPrompt.volatileValue());
|
||||
});
|
||||
connect(&resetToDefaults, &ButtonAspect::clicked, this, &ContextSettings::resetPageToDefaults);
|
||||
}
|
||||
@ -129,8 +153,10 @@ void ContextSettings::resetPageToDefaults()
|
||||
resetAspect(readStringsBeforeCursor);
|
||||
resetAspect(readStringsAfterCursor);
|
||||
resetAspect(useFilePathInContext);
|
||||
resetAspect(useSpecificInstructions);
|
||||
resetAspect(specificInstractions);
|
||||
resetAspect(useSystemPrompt);
|
||||
resetAspect(systemPrompt);
|
||||
resetAspect(useChatSystemPrompt);
|
||||
resetAspect(chatSystemPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -34,11 +34,13 @@ public:
|
||||
Utils::IntegerAspect readStringsBeforeCursor{this};
|
||||
Utils::IntegerAspect readStringsAfterCursor{this};
|
||||
|
||||
Utils::StringAspect specificInstractions{this};
|
||||
Utils::BoolAspect useSpecificInstructions{this};
|
||||
Utils::BoolAspect useSystemPrompt{this};
|
||||
Utils::StringAspect systemPrompt{this};
|
||||
Utils::BoolAspect useFilePathInContext{this};
|
||||
Utils::BoolAspect useProjectChangesCache{this};
|
||||
Utils::IntegerAspect maxChangesCacheSize{this};
|
||||
Utils::BoolAspect useChatSystemPrompt{this};
|
||||
Utils::StringAspect chatSystemPrompt{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
|
||||
@ -26,8 +26,7 @@
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
#include "SettingsConstants.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
@ -85,12 +84,13 @@ CustomPromptSettings::CustomPromptSettings()
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{customJsonLabel, Stretch{1}, resetToDefaults},
|
||||
Row{customJsonTemplate,
|
||||
Column{saveCustomTemplateButton,
|
||||
loadCustomTemplateButton,
|
||||
customJsonLegend,
|
||||
Stretch{1}}}};
|
||||
return Column{Group{title(Tr::tr("Custom prompt for FIM model")),
|
||||
Column{Row{customJsonLabel, Stretch{1}, resetToDefaults},
|
||||
Row{customJsonTemplate,
|
||||
Column{saveCustomTemplateButton,
|
||||
loadCustomTemplateButton,
|
||||
customJsonLegend,
|
||||
Stretch{1}}}}}};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "settings/SettingsUtils.hpp"
|
||||
#include "SettingsUtils.hpp"
|
||||
#include <utils/aspects.h>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
@ -26,11 +26,12 @@
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
#include "Provider.hpp"
|
||||
#include "ProvidersManager.hpp"
|
||||
#include "SettingsConstants.hpp"
|
||||
#include "SettingsUtils.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
@ -128,27 +129,34 @@ GeneralSettings::GeneralSettings()
|
||||
chatPrompts.setSettingsKey(Constants::CHAT_PROMPTS);
|
||||
chatPrompts.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
||||
|
||||
chatTokensThreshold.setSettingsKey(Constants::CHAT_TOKENS_THRESHOLD);
|
||||
chatTokensThreshold.setLabelText(Tr::tr("Chat History Token Limit"));
|
||||
chatTokensThreshold.setToolTip(Tr::tr("Maximum number of tokens in chat history. When "
|
||||
"exceeded, oldest messages will be removed."));
|
||||
chatTokensThreshold.setRange(1000, 16000);
|
||||
chatTokensThreshold.setDefaultValue(8000);
|
||||
|
||||
loadProviders();
|
||||
loadPrompts();
|
||||
|
||||
llmProviders.setDefaultValue(llmProviders.indexForDisplay("Ollama"));
|
||||
chatLlmProviders.setDefaultValue(chatLlmProviders.indexForDisplay("Ollama"));
|
||||
fimPrompts.setDefaultValue(fimPrompts.indexForDisplay("CodeLLama FIM"));
|
||||
chatPrompts.setDefaultValue(chatPrompts.indexForDisplay("CodeLLama Chat"));
|
||||
|
||||
readSettings();
|
||||
fimPrompts.setDefaultValue(fimPrompts.indexForDisplay("CodeLlama FIM"));
|
||||
chatPrompts.setDefaultValue(chatPrompts.indexForDisplay("CodeLlama Chat"));
|
||||
|
||||
auto fimProviderName = llmProviders.displayForIndex(llmProviders.value());
|
||||
setCurrentFimProvider(fimProviderName);
|
||||
auto chatProviderName = chatLlmProviders.displayForIndex(chatLlmProviders.value());
|
||||
setCurrentChatProvider(chatProviderName);
|
||||
|
||||
auto nameFimPromts = fimPrompts.displayForIndex(fimPrompts.value());
|
||||
PromptTemplateManager::instance().setCurrentFimTemplate(nameFimPromts);
|
||||
auto nameChatPromts = chatPrompts.displayForIndex(chatPrompts.value());
|
||||
PromptTemplateManager::instance().setCurrentChatTemplate(nameChatPromts);
|
||||
readSettings();
|
||||
|
||||
setLoggingEnabled(enableLogging());
|
||||
auto nameFimPromts = fimPrompts.displayForIndex(fimPrompts.value());
|
||||
LLMCore::PromptTemplateManager::instance().setCurrentFimTemplate(nameFimPromts);
|
||||
auto nameChatPromts = chatPrompts.displayForIndex(chatPrompts.value());
|
||||
LLMCore::PromptTemplateManager::instance().setCurrentChatTemplate(nameChatPromts);
|
||||
|
||||
Logger::instance().setLoggingEnabled(enableLogging());
|
||||
|
||||
setupConnections();
|
||||
|
||||
@ -157,26 +165,26 @@ GeneralSettings::GeneralSettings()
|
||||
|
||||
auto rootLayout
|
||||
= Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults},
|
||||
enableAutoComplete,
|
||||
multiLineCompletion,
|
||||
Row{autoCompletionCharThreshold,
|
||||
autoCompletionTypingInterval,
|
||||
startSuggestionTimer,
|
||||
Stretch{1}},
|
||||
Space{8},
|
||||
enableLogging,
|
||||
Row{enableLogging, Stretch{1}},
|
||||
Space{8},
|
||||
Group{title(Tr::tr("AI Suggestions")),
|
||||
Column{Row{llmProviders, Stretch{1}},
|
||||
Column{enableAutoComplete,
|
||||
multiLineCompletion,
|
||||
Row{autoCompletionCharThreshold,
|
||||
autoCompletionTypingInterval,
|
||||
startSuggestionTimer,
|
||||
Stretch{1}},
|
||||
Row{llmProviders, Stretch{1}},
|
||||
Row{url, endPoint, fimUrlIndicator},
|
||||
Row{selectModels, modelName, fimModelIndicator},
|
||||
Row{fimPrompts, Stretch{1}}}},
|
||||
Space{16},
|
||||
Group{title(Tr::tr("AI Chat(experimental)")),
|
||||
Group{title(Tr::tr("AI Chat")),
|
||||
Column{Row{chatLlmProviders, Stretch{1}},
|
||||
Row{chatUrl, chatEndPoint, chatUrlIndicator},
|
||||
Row{chatSelectModels, chatModelName, chatModelIndicator},
|
||||
Row{chatPrompts, Stretch{1}}}},
|
||||
Row{chatPrompts, Stretch{1}},
|
||||
Row{chatTokensThreshold, Stretch{1}}}},
|
||||
Stretch{1}};
|
||||
return rootLayout;
|
||||
});
|
||||
@ -199,24 +207,26 @@ void GeneralSettings::setupConnections()
|
||||
|
||||
connect(&fimPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = fimPrompts.volatileValue();
|
||||
PromptTemplateManager::instance().setCurrentFimTemplate(fimPrompts.displayForIndex(index));
|
||||
LLMCore::PromptTemplateManager::instance().setCurrentFimTemplate(
|
||||
fimPrompts.displayForIndex(index));
|
||||
});
|
||||
connect(&chatPrompts, &Utils::SelectionAspect::volatileValueChanged, this, [this]() {
|
||||
int index = chatPrompts.volatileValue();
|
||||
PromptTemplateManager::instance().setCurrentChatTemplate(chatPrompts.displayForIndex(index));
|
||||
LLMCore::PromptTemplateManager::instance().setCurrentChatTemplate(
|
||||
chatPrompts.displayForIndex(index));
|
||||
});
|
||||
|
||||
connect(&selectModels, &ButtonAspect::clicked, this, [this]() {
|
||||
auto *provider = LLMProvidersManager::instance().getCurrentFimProvider();
|
||||
auto *provider = LLMCore::ProvidersManager::instance().getCurrentFimProvider();
|
||||
showModelSelectionDialog(&modelName, provider);
|
||||
});
|
||||
connect(&chatSelectModels, &ButtonAspect::clicked, this, [this]() {
|
||||
auto *provider = LLMProvidersManager::instance().getCurrentChatProvider();
|
||||
auto *provider = LLMCore::ProvidersManager::instance().getCurrentChatProvider();
|
||||
showModelSelectionDialog(&chatModelName, provider);
|
||||
});
|
||||
|
||||
connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||
setLoggingEnabled(enableLogging.volatileValue());
|
||||
Logger::instance().setLoggingEnabled(enableLogging.volatileValue());
|
||||
});
|
||||
connect(&resetToDefaults, &ButtonAspect::clicked, this, &GeneralSettings::resetPageToDefaults);
|
||||
|
||||
@ -239,7 +249,7 @@ void GeneralSettings::setupConnections()
|
||||
}
|
||||
|
||||
void GeneralSettings::showModelSelectionDialog(Utils::StringAspect *modelNameObj,
|
||||
Providers::LLMProvider *provider)
|
||||
LLMCore::Provider *provider)
|
||||
{
|
||||
Utils::Environment env = Utils::Environment::systemEnvironment();
|
||||
QString providerUrl = (modelNameObj == &modelName) ? url() : chatUrl();
|
||||
@ -282,6 +292,7 @@ void GeneralSettings::resetPageToDefaults()
|
||||
resetAspect(chatLlmProviders);
|
||||
resetAspect(fimPrompts);
|
||||
resetAspect(chatPrompts);
|
||||
resetAspect(chatTokensThreshold);
|
||||
}
|
||||
|
||||
modelName.setVolatileValue("");
|
||||
@ -301,12 +312,12 @@ void GeneralSettings::updateStatusIndicators()
|
||||
bool fimPingSuccessful = false;
|
||||
if (fimUrlValid) {
|
||||
QUrl pingUrl(url.volatileValue());
|
||||
fimPingSuccessful = QodeAssist::pingUrl(pingUrl);
|
||||
fimPingSuccessful = Settings::pingUrl(pingUrl);
|
||||
}
|
||||
bool chatPingSuccessful = false;
|
||||
if (chatUrlValid) {
|
||||
QUrl pingUrl(chatUrl.volatileValue());
|
||||
chatPingSuccessful = QodeAssist::pingUrl(pingUrl);
|
||||
chatPingSuccessful = Settings::pingUrl(pingUrl);
|
||||
}
|
||||
|
||||
setIndicatorStatus(fimModelIndicator,
|
||||
@ -339,7 +350,7 @@ void GeneralSettings::setIndicatorStatus(Utils::StringAspect &indicator,
|
||||
|
||||
void GeneralSettings::setCurrentFimProvider(const QString &name)
|
||||
{
|
||||
const auto provider = LLMProvidersManager::instance().setCurrentFimProvider(name);
|
||||
const auto provider = LLMCore::ProvidersManager::instance().setCurrentFimProvider(name);
|
||||
if (!provider)
|
||||
return;
|
||||
|
||||
@ -349,7 +360,7 @@ void GeneralSettings::setCurrentFimProvider(const QString &name)
|
||||
|
||||
void GeneralSettings::setCurrentChatProvider(const QString &name)
|
||||
{
|
||||
const auto provider = LLMProvidersManager::instance().setCurrentChatProvider(name);
|
||||
const auto provider = LLMCore::ProvidersManager::instance().setCurrentChatProvider(name);
|
||||
if (!provider)
|
||||
return;
|
||||
|
||||
@ -359,7 +370,7 @@ void GeneralSettings::setCurrentChatProvider(const QString &name)
|
||||
|
||||
void GeneralSettings::loadProviders()
|
||||
{
|
||||
for (const auto &name : LLMProvidersManager::instance().providersNames()) {
|
||||
for (const auto &name : LLMCore::ProvidersManager::instance().providersNames()) {
|
||||
llmProviders.addOption(name);
|
||||
chatLlmProviders.addOption(name);
|
||||
}
|
||||
@ -367,10 +378,10 @@ void GeneralSettings::loadProviders()
|
||||
|
||||
void GeneralSettings::loadPrompts()
|
||||
{
|
||||
for (const auto &name : PromptTemplateManager::instance().fimTemplatesNames()) {
|
||||
for (const auto &name : LLMCore::PromptTemplateManager::instance().fimTemplatesNames()) {
|
||||
fimPrompts.addOption(name);
|
||||
}
|
||||
for (const auto &name : PromptTemplateManager::instance().chatTemplatesNames()) {
|
||||
for (const auto &name : LLMCore::PromptTemplateManager::instance().chatTemplatesNames()) {
|
||||
chatPrompts.addOption(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,11 @@
|
||||
|
||||
#include <utils/aspects.h>
|
||||
|
||||
#include "providers/LLMProvider.hpp"
|
||||
#include "settings/SettingsUtils.hpp"
|
||||
#include "SettingsUtils.hpp"
|
||||
|
||||
namespace QodeAssist::LLMCore {
|
||||
class Provider;
|
||||
}
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
class GeneralSettings : public Utils::AspectContainer
|
||||
@ -61,10 +63,11 @@ public:
|
||||
Utils::StringAspect chatModelIndicator{this};
|
||||
Utils::StringAspect chatUrlIndicator{this};
|
||||
|
||||
Utils::IntegerAspect chatTokensThreshold{this};
|
||||
|
||||
private:
|
||||
void setupConnections();
|
||||
void showModelSelectionDialog(Utils::StringAspect *modelNameObj,
|
||||
Providers::LLMProvider *provider);
|
||||
void showModelSelectionDialog(Utils::StringAspect *modelNameObj, LLMCore::Provider *provider);
|
||||
void resetPageToDefaults();
|
||||
|
||||
void updateStatusIndicators();
|
||||
|
||||
@ -24,8 +24,8 @@
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include "QodeAssistConstants.hpp"
|
||||
#include "QodeAssisttr.h"
|
||||
#include "RequestType.hpp"
|
||||
#include "SettingsConstants.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
@ -41,63 +41,121 @@ PresetPromptsSettings::PresetPromptsSettings()
|
||||
|
||||
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);
|
||||
temperature.setSingleStep(0.1);
|
||||
fimTemperature.setSettingsKey(Constants::FIM_TEMPERATURE);
|
||||
fimTemperature.setLabelText(Tr::tr("Temperature:"));
|
||||
fimTemperature.setDefaultValue(0.2);
|
||||
fimTemperature.setRange(0.0, 10.0);
|
||||
fimTemperature.setSingleStep(0.1);
|
||||
|
||||
ollamaLivetime.setSettingsKey(Constants::OLLAMA_LIVETIME);
|
||||
ollamaLivetime.setLabelText(
|
||||
chatTemperature.setSettingsKey(Constants::CHAT_TEMPERATURE);
|
||||
chatTemperature.setLabelText(Tr::tr("Temperature:"));
|
||||
chatTemperature.setDefaultValue(0.5);
|
||||
chatTemperature.setRange(0.0, 10.0);
|
||||
chatTemperature.setSingleStep(0.1);
|
||||
|
||||
fimOllamaLivetime.setSettingsKey(Constants::FIM_OLLAMA_LIVETIME);
|
||||
fimOllamaLivetime.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);
|
||||
fimOllamaLivetime.setDefaultValue("5m");
|
||||
fimOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
maxTokens.setSettingsKey(Constants::MAX_TOKENS);
|
||||
maxTokens.setLabelText(Tr::tr("Max Tokens"));
|
||||
maxTokens.setRange(-1, 10000);
|
||||
maxTokens.setDefaultValue(150);
|
||||
chatOllamaLivetime.setSettingsKey(Constants::CHAT_OLLAMA_LIVETIME);
|
||||
chatOllamaLivetime.setLabelText(
|
||||
Tr::tr("Time to suspend Ollama after completion request (in minutes), "
|
||||
"Only Ollama, -1 to disable"));
|
||||
chatOllamaLivetime.setDefaultValue("5m");
|
||||
chatOllamaLivetime.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
||||
useTopP.setSettingsKey(Constants::USE_TOP_P);
|
||||
useTopP.setDefaultValue(false);
|
||||
fimMaxTokens.setSettingsKey(Constants::FIM_MAX_TOKENS);
|
||||
fimMaxTokens.setLabelText(Tr::tr("Max Tokens"));
|
||||
fimMaxTokens.setRange(-1, 10000);
|
||||
fimMaxTokens.setDefaultValue(50);
|
||||
|
||||
topP.setSettingsKey(Constants::TOP_P);
|
||||
topP.setLabelText(Tr::tr("use top_p"));
|
||||
topP.setDefaultValue(0.9);
|
||||
topP.setRange(0.0, 1.0);
|
||||
topP.setSingleStep(0.1);
|
||||
chatMaxTokens.setSettingsKey(Constants::CHAT_MAX_TOKENS);
|
||||
chatMaxTokens.setLabelText(Tr::tr("Max Tokens"));
|
||||
chatMaxTokens.setRange(-1, 10000);
|
||||
chatMaxTokens.setDefaultValue(2000);
|
||||
|
||||
useTopK.setSettingsKey(Constants::USE_TOP_K);
|
||||
useTopK.setDefaultValue(false);
|
||||
fimUseTopP.setSettingsKey(Constants::FIM_USE_TOP_P);
|
||||
fimUseTopP.setDefaultValue(false);
|
||||
|
||||
topK.setSettingsKey(Constants::TOP_K);
|
||||
topK.setLabelText(Tr::tr("use top_k"));
|
||||
topK.setDefaultValue(50);
|
||||
topK.setRange(1, 1000);
|
||||
fimTopP.setSettingsKey(Constants::FIM_TOP_P);
|
||||
fimTopP.setLabelText(Tr::tr("use top_p"));
|
||||
fimTopP.setDefaultValue(0.9);
|
||||
fimTopP.setRange(0.0, 1.0);
|
||||
fimTopP.setSingleStep(0.1);
|
||||
|
||||
usePresencePenalty.setSettingsKey(Constants::USE_PRESENCE_PENALTY);
|
||||
usePresencePenalty.setDefaultValue(false);
|
||||
chatUseTopP.setSettingsKey(Constants::CHAT_USE_TOP_P);
|
||||
chatUseTopP.setDefaultValue(false);
|
||||
|
||||
presencePenalty.setSettingsKey(Constants::PRESENCE_PENALTY);
|
||||
presencePenalty.setLabelText(Tr::tr("use presence_penalty"));
|
||||
presencePenalty.setDefaultValue(0.0);
|
||||
presencePenalty.setRange(-2.0, 2.0);
|
||||
presencePenalty.setSingleStep(0.1);
|
||||
chatTopP.setSettingsKey(Constants::CHAT_TOP_P);
|
||||
chatTopP.setLabelText(Tr::tr("use top_p"));
|
||||
chatTopP.setDefaultValue(0.9);
|
||||
chatTopP.setRange(0.0, 1.0);
|
||||
chatTopP.setSingleStep(0.1);
|
||||
|
||||
useFrequencyPenalty.setSettingsKey(Constants::USE_FREQUENCY_PENALTY);
|
||||
useFrequencyPenalty.setDefaultValue(false);
|
||||
fimUseTopK.setSettingsKey(Constants::FIM_USE_TOP_K);
|
||||
fimUseTopK.setDefaultValue(false);
|
||||
|
||||
frequencyPenalty.setSettingsKey(Constants::FREQUENCY_PENALTY);
|
||||
frequencyPenalty.setLabelText(Tr::tr("use frequency_penalty"));
|
||||
frequencyPenalty.setDefaultValue(0.0);
|
||||
frequencyPenalty.setRange(-2.0, 2.0);
|
||||
frequencyPenalty.setSingleStep(0.1);
|
||||
fimTopK.setSettingsKey(Constants::FIM_TOP_K);
|
||||
fimTopK.setLabelText(Tr::tr("use top_k"));
|
||||
fimTopK.setDefaultValue(50);
|
||||
fimTopK.setRange(1, 1000);
|
||||
|
||||
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"));
|
||||
chatUseTopK.setSettingsKey(Constants::CHAT_USE_TOP_K);
|
||||
chatUseTopK.setDefaultValue(false);
|
||||
|
||||
chatTopK.setSettingsKey(Constants::CHAT_TOP_K);
|
||||
chatTopK.setLabelText(Tr::tr("use top_k"));
|
||||
chatTopK.setDefaultValue(50);
|
||||
chatTopK.setRange(1, 1000);
|
||||
|
||||
fimUsePresencePenalty.setSettingsKey(Constants::FIM_USE_PRESENCE_PENALTY);
|
||||
fimUsePresencePenalty.setDefaultValue(false);
|
||||
|
||||
fimPresencePenalty.setSettingsKey(Constants::FIM_PRESENCE_PENALTY);
|
||||
fimPresencePenalty.setLabelText(Tr::tr("use presence_penalty"));
|
||||
fimPresencePenalty.setDefaultValue(0.0);
|
||||
fimPresencePenalty.setRange(-2.0, 2.0);
|
||||
fimPresencePenalty.setSingleStep(0.1);
|
||||
|
||||
chatUsePresencePenalty.setSettingsKey(Constants::CHAT_USE_PRESENCE_PENALTY);
|
||||
chatUsePresencePenalty.setDefaultValue(false);
|
||||
|
||||
chatPresencePenalty.setSettingsKey(Constants::CHAT_PRESENCE_PENALTY);
|
||||
chatPresencePenalty.setLabelText(Tr::tr("use presence_penalty"));
|
||||
chatPresencePenalty.setDefaultValue(0.0);
|
||||
chatPresencePenalty.setRange(-2.0, 2.0);
|
||||
chatPresencePenalty.setSingleStep(0.1);
|
||||
|
||||
fimUseFrequencyPenalty.setSettingsKey(Constants::FIM_USE_FREQUENCY_PENALTY);
|
||||
fimUseFrequencyPenalty.setDefaultValue(false);
|
||||
|
||||
fimFrequencyPenalty.setSettingsKey(Constants::FIM_FREQUENCY_PENALTY);
|
||||
fimFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty"));
|
||||
fimFrequencyPenalty.setDefaultValue(0.0);
|
||||
fimFrequencyPenalty.setRange(-2.0, 2.0);
|
||||
fimFrequencyPenalty.setSingleStep(0.1);
|
||||
|
||||
chatUseFrequencyPenalty.setSettingsKey(Constants::CHAT_USE_FREQUENCY_PENALTY);
|
||||
chatUseFrequencyPenalty.setDefaultValue(false);
|
||||
|
||||
chatFrequencyPenalty.setSettingsKey(Constants::CHAT_FREQUENCY_PENALTY);
|
||||
chatFrequencyPenalty.setLabelText(Tr::tr("use frequency_penalty"));
|
||||
chatFrequencyPenalty.setDefaultValue(0.0);
|
||||
chatFrequencyPenalty.setRange(-2.0, 2.0);
|
||||
chatFrequencyPenalty.setSingleStep(0.1);
|
||||
|
||||
fimApiKey.setSettingsKey(Constants::FIM_API_KEY);
|
||||
fimApiKey.setLabelText(Tr::tr("API Key:"));
|
||||
fimApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
fimApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
|
||||
|
||||
chatApiKey.setSettingsKey(Constants::CHAT_API_KEY);
|
||||
chatApiKey.setLabelText(Tr::tr("API Key:"));
|
||||
chatApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
chatApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
|
||||
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
@ -107,17 +165,64 @@ PresetPromptsSettings::PresetPromptsSettings()
|
||||
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{temperature, Stretch{1}, resetToDefaults},
|
||||
Row{maxTokens, Stretch{1}},
|
||||
Row{useTopP, topP, Stretch{1}},
|
||||
Row{useTopK, topK, Stretch{1}},
|
||||
Row{usePresencePenalty, presencePenalty, Stretch{1}},
|
||||
Row{useFrequencyPenalty, frequencyPenalty, Stretch{1}},
|
||||
apiKey,
|
||||
return Column{Row{Stretch{1}, resetToDefaults},
|
||||
Group{title(Tr::tr("Prompt settings for FIM")),
|
||||
Column{Row{fimTemperature, Stretch{1}},
|
||||
Row{fimMaxTokens, Stretch{1}},
|
||||
Row{fimUseTopP, fimTopP, Stretch{1}},
|
||||
Row{fimUseTopK, fimTopK, Stretch{1}},
|
||||
Row{fimUsePresencePenalty, fimPresencePenalty, Stretch{1}},
|
||||
Row{fimUseFrequencyPenalty, fimFrequencyPenalty, Stretch{1}},
|
||||
Row{fimOllamaLivetime, Stretch{1}},
|
||||
fimApiKey}},
|
||||
Space{16},
|
||||
Group{title(Tr::tr("Prompt settings for Chat")),
|
||||
Column{Row{chatTemperature, Stretch{1}},
|
||||
Row{chatMaxTokens, Stretch{1}},
|
||||
Row{chatUseTopP, chatTopP, Stretch{1}},
|
||||
Row{chatUseTopK, chatTopK, Stretch{1}},
|
||||
Row{fimUsePresencePenalty, fimPresencePenalty, Stretch{1}},
|
||||
Row{fimUseFrequencyPenalty, fimFrequencyPenalty, Stretch{1}},
|
||||
Row{chatOllamaLivetime, Stretch{1}},
|
||||
chatApiKey}},
|
||||
Stretch{1}};
|
||||
});
|
||||
}
|
||||
|
||||
PresetPromptsSettings::PromptSettings PresetPromptsSettings::getSettings(int type) const
|
||||
{
|
||||
auto reqtype = static_cast<LLMCore::RequestType>(type);
|
||||
PromptSettings settings;
|
||||
if (reqtype == LLMCore::RequestType::Fim) {
|
||||
settings.temperature = fimTemperature();
|
||||
settings.maxTokens = fimMaxTokens();
|
||||
settings.useTopP = fimUseTopP();
|
||||
settings.topP = fimTopP();
|
||||
settings.useTopK = fimUseTopK();
|
||||
settings.topK = fimTopK();
|
||||
settings.usePresencePenalty = fimUsePresencePenalty();
|
||||
settings.presencePenalty = fimPresencePenalty();
|
||||
settings.useFrequencyPenalty = fimUseFrequencyPenalty();
|
||||
settings.frequencyPenalty = fimFrequencyPenalty();
|
||||
settings.ollamaLivetime = fimOllamaLivetime();
|
||||
settings.apiKey = fimApiKey();
|
||||
} else if (reqtype == LLMCore::RequestType::Chat) {
|
||||
settings.temperature = chatTemperature();
|
||||
settings.maxTokens = chatMaxTokens();
|
||||
settings.useTopP = chatUseTopP();
|
||||
settings.topP = chatTopP();
|
||||
settings.useTopK = chatUseTopK();
|
||||
settings.topK = chatTopK();
|
||||
settings.usePresencePenalty = chatUsePresencePenalty();
|
||||
settings.presencePenalty = chatPresencePenalty();
|
||||
settings.useFrequencyPenalty = chatUseFrequencyPenalty();
|
||||
settings.frequencyPenalty = chatFrequencyPenalty();
|
||||
settings.ollamaLivetime = chatOllamaLivetime();
|
||||
settings.apiKey = chatApiKey();
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
void PresetPromptsSettings::setupConnections()
|
||||
{
|
||||
connect(&resetToDefaults,
|
||||
@ -136,17 +241,28 @@ void PresetPromptsSettings::resetSettingsToDefaults()
|
||||
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);
|
||||
resetAspect(fimTemperature);
|
||||
resetAspect(fimMaxTokens);
|
||||
resetAspect(fimOllamaLivetime);
|
||||
resetAspect(fimUseTopP);
|
||||
resetAspect(fimTopP);
|
||||
resetAspect(fimUseTopK);
|
||||
resetAspect(fimTopK);
|
||||
resetAspect(fimUsePresencePenalty);
|
||||
resetAspect(fimPresencePenalty);
|
||||
resetAspect(fimUseFrequencyPenalty);
|
||||
resetAspect(fimFrequencyPenalty);
|
||||
resetAspect(chatTemperature);
|
||||
resetAspect(chatMaxTokens);
|
||||
resetAspect(chatUseTopP);
|
||||
resetAspect(chatTopP);
|
||||
resetAspect(chatUseTopK);
|
||||
resetAspect(chatTopK);
|
||||
resetAspect(chatUsePresencePenalty);
|
||||
resetAspect(chatPresencePenalty);
|
||||
resetAspect(chatUseFrequencyPenalty);
|
||||
resetAspect(chatFrequencyPenalty);
|
||||
resetAspect(chatOllamaLivetime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "settings/SettingsUtils.hpp"
|
||||
#include "SettingsUtils.hpp"
|
||||
#include <utils/aspects.h>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
@ -27,28 +27,63 @@ namespace QodeAssist::Settings {
|
||||
class PresetPromptsSettings : public Utils::AspectContainer
|
||||
{
|
||||
public:
|
||||
struct PromptSettings
|
||||
{
|
||||
double temperature;
|
||||
int maxTokens;
|
||||
bool useTopP;
|
||||
double topP;
|
||||
bool useTopK;
|
||||
int topK;
|
||||
bool usePresencePenalty;
|
||||
double presencePenalty;
|
||||
bool useFrequencyPenalty;
|
||||
double frequencyPenalty;
|
||||
QString ollamaLivetime;
|
||||
QString apiKey;
|
||||
};
|
||||
|
||||
PresetPromptsSettings();
|
||||
|
||||
Utils::DoubleAspect temperature{this};
|
||||
Utils::IntegerAspect maxTokens{this};
|
||||
Utils::DoubleAspect fimTemperature{this};
|
||||
Utils::IntegerAspect fimMaxTokens{this};
|
||||
|
||||
Utils::BoolAspect useTopP{this};
|
||||
Utils::DoubleAspect topP{this};
|
||||
Utils::DoubleAspect chatTemperature{this};
|
||||
Utils::IntegerAspect chatMaxTokens{this};
|
||||
|
||||
Utils::BoolAspect useTopK{this};
|
||||
Utils::IntegerAspect topK{this};
|
||||
Utils::BoolAspect fimUseTopP{this};
|
||||
Utils::DoubleAspect fimTopP{this};
|
||||
|
||||
Utils::BoolAspect usePresencePenalty{this};
|
||||
Utils::DoubleAspect presencePenalty{this};
|
||||
Utils::BoolAspect chatUseTopP{this};
|
||||
Utils::DoubleAspect chatTopP{this};
|
||||
|
||||
Utils::BoolAspect useFrequencyPenalty{this};
|
||||
Utils::DoubleAspect frequencyPenalty{this};
|
||||
Utils::BoolAspect fimUseTopK{this};
|
||||
Utils::IntegerAspect fimTopK{this};
|
||||
|
||||
Utils::StringAspect ollamaLivetime{this};
|
||||
Utils::StringAspect apiKey{this};
|
||||
Utils::BoolAspect chatUseTopK{this};
|
||||
Utils::IntegerAspect chatTopK{this};
|
||||
|
||||
Utils::BoolAspect fimUsePresencePenalty{this};
|
||||
Utils::DoubleAspect fimPresencePenalty{this};
|
||||
|
||||
Utils::BoolAspect chatUsePresencePenalty{this};
|
||||
Utils::DoubleAspect chatPresencePenalty{this};
|
||||
|
||||
Utils::BoolAspect fimUseFrequencyPenalty{this};
|
||||
Utils::DoubleAspect fimFrequencyPenalty{this};
|
||||
|
||||
Utils::BoolAspect chatUseFrequencyPenalty{this};
|
||||
Utils::DoubleAspect chatFrequencyPenalty{this};
|
||||
|
||||
Utils::StringAspect fimOllamaLivetime{this};
|
||||
Utils::StringAspect chatOllamaLivetime{this};
|
||||
Utils::StringAspect fimApiKey{this};
|
||||
Utils::StringAspect chatApiKey{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
PromptSettings getSettings(int type) const;
|
||||
|
||||
private:
|
||||
void setupConnections();
|
||||
void resetSettingsToDefaults();
|
||||
|
||||
102
settings/SettingsConstants.hpp
Normal file
102
settings/SettingsConstants.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
namespace QodeAssist::Constants {
|
||||
|
||||
const char ACTION_ID[] = "QodeAssist.Action";
|
||||
const char MENU_ID[] = "QodeAssist.Menu";
|
||||
|
||||
// settings
|
||||
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
|
||||
const char ENABLE_AUTO_COMPLETE[] = "QodeAssist.enableAutoComplete";
|
||||
const char ENABLE_LOGGING[] = "QodeAssist.enableLogging";
|
||||
const char LLM_PROVIDERS[] = "QodeAssist.llmProviders";
|
||||
const char URL[] = "QodeAssist.url";
|
||||
const char END_POINT[] = "QodeAssist.endPoint";
|
||||
const char MODEL_NAME[] = "QodeAssist.modelName";
|
||||
const char SELECT_MODELS[] = "QodeAssist.selectModels";
|
||||
const char FIM_PROMPTS[] = "QodeAssist.fimPrompts";
|
||||
const char PROVIDER_PATHS[] = "QodeAssist.providerPaths";
|
||||
const char 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 MULTILINE_COMPLETION[] = "QodeAssist.multilineCompletion";
|
||||
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
||||
const char CHAT_LLM_PROVIDERS[] = "QodeAssist.chatLlmProviders";
|
||||
const char CHAT_URL[] = "QodeAssist.chatUrl";
|
||||
const char CHAT_END_POINT[] = "QodeAssist.chatEndPoint";
|
||||
const char CHAT_MODEL_NAME[] = "QodeAssist.chatModelName";
|
||||
const char CHAT_SELECT_MODELS[] = "QodeAssist.chatSelectModels";
|
||||
const char CHAT_PROMPTS[] = "QodeAssist.chatPrompts";
|
||||
const char CHAT_TOKENS_THRESHOLD[] = "QodeAssist.chatTokensThreshold";
|
||||
|
||||
const char QODE_ASSIST_GENERAL_OPTIONS_ID[] = "QodeAssist.GeneralOptions";
|
||||
const char QODE_ASSIST_GENERAL_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";
|
||||
|
||||
const char QODE_ASSIST_REQUEST_SUGGESTION[] = "QodeAssist.RequestSuggestion";
|
||||
|
||||
// context settings
|
||||
const char READ_FULL_FILE[] = "QodeAssist.readFullFile";
|
||||
const char READ_STRINGS_BEFORE_CURSOR[] = "QodeAssist.readStringsBeforeCursor";
|
||||
const char READ_STRINGS_AFTER_CURSOR[] = "QodeAssist.readStringsAfterCursor";
|
||||
const char USE_SYSTEM_PROMPT[] = "QodeAssist.useSystemPrompt";
|
||||
const char USE_FILE_PATH_IN_CONTEXT[] = "QodeAssist.useFilePathInContext";
|
||||
const char SYSTEM_PROMPT[] = "QodeAssist.systemPrompt";
|
||||
const char USE_PROJECT_CHANGES_CACHE[] = "QodeAssist.useProjectChangesCache";
|
||||
const char MAX_CHANGES_CACHE_SIZE[] = "QodeAssist.maxChangesCacheSize";
|
||||
const char USE_CHAT_SYSTEM_PROMPT[] = "QodeAssist.useChatSystemPrompt";
|
||||
const char CHAT_SYSTEM_PROMPT[] = "QodeAssist.chatSystemPrompt";
|
||||
|
||||
// preset prompt settings
|
||||
const char FIM_TEMPERATURE[] = "QodeAssist.fimTemperature";
|
||||
const char FIM_MAX_TOKENS[] = "QodeAssist.fimMaxTokens";
|
||||
const char FIM_USE_TOP_P[] = "QodeAssist.fimUseTopP";
|
||||
const char FIM_TOP_P[] = "QodeAssist.fimTopP";
|
||||
const char FIM_USE_TOP_K[] = "QodeAssist.fimUseTopK";
|
||||
const char FIM_TOP_K[] = "QodeAssist.fimTopK";
|
||||
const char FIM_USE_PRESENCE_PENALTY[] = "QodeAssist.fimUsePresencePenalty";
|
||||
const char FIM_PRESENCE_PENALTY[] = "QodeAssist.fimPresencePenalty";
|
||||
const char FIM_USE_FREQUENCY_PENALTY[] = "QodeAssist.fimUseFrequencyPenalty";
|
||||
const char FIM_FREQUENCY_PENALTY[] = "QodeAssist.fimFrequencyPenalty";
|
||||
const char FIM_OLLAMA_LIVETIME[] = "QodeAssist.fimOllamaLivetime";
|
||||
const char FIM_API_KEY[] = "QodeAssist.apiKey";
|
||||
const char CHAT_TEMPERATURE[] = "QodeAssist.chatTemperature";
|
||||
const char CHAT_MAX_TOKENS[] = "QodeAssist.chatMaxTokens";
|
||||
const char CHAT_USE_TOP_P[] = "QodeAssist.chatUseTopP";
|
||||
const char CHAT_TOP_P[] = "QodeAssist.chatTopP";
|
||||
const char CHAT_USE_TOP_K[] = "QodeAssist.chatUseTopK";
|
||||
const char CHAT_TOP_K[] = "QodeAssist.chatTopK";
|
||||
const char CHAT_USE_PRESENCE_PENALTY[] = "QodeAssist.chatUsePresencePenalty";
|
||||
const char CHAT_PRESENCE_PENALTY[] = "QodeAssist.chatPresencePenalty";
|
||||
const char CHAT_USE_FREQUENCY_PENALTY[] = "QodeAssist.chatUseFrequencyPenalty";
|
||||
const char CHAT_FREQUENCY_PENALTY[] = "QodeAssist.chatFrequencyPenalty";
|
||||
const char CHAT_OLLAMA_LIVETIME[] = "QodeAssist.chatOllamaLivetime";
|
||||
const char CHAT_API_KEY[] = "QodeAssist.chatApiKey";
|
||||
|
||||
} // namespace QodeAssist::Constants
|
||||
@ -19,12 +19,53 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QPushButton>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <utils/aspects.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
struct Tr
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(QtC::QodeAssist)
|
||||
};
|
||||
|
||||
inline bool pingUrl(const QUrl &url, int timeout = 5000)
|
||||
{
|
||||
if (!url.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
|
||||
|
||||
QScopedPointer<QNetworkReply> reply(manager.get(request));
|
||||
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||
|
||||
timer.start(timeout);
|
||||
loop.exec();
|
||||
|
||||
if (timer.isActive()) {
|
||||
timer.stop();
|
||||
return (reply->error() == QNetworkReply::NoError);
|
||||
} else {
|
||||
QObject::disconnect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
reply->abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AspectType>
|
||||
void resetAspect(AspectType &aspect)
|
||||
{
|
||||
|
||||
@ -20,19 +20,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qjsonarray.h>
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class CodeLlamaInstructTemplate : public PromptTemplate
|
||||
class CodeLlamaChat : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
TemplateType type() const override { return TemplateType::Chat; }
|
||||
QString name() const override { return "CodeLLama Chat"; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Chat; }
|
||||
QString name() const override { return "CodeLlama Chat"; }
|
||||
QString promptTemplate() const override { return "[INST] %1 [/INST]"; }
|
||||
QStringList stopWords() const override { return QStringList() << "[INST]" << "[/INST]"; }
|
||||
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.prefix);
|
||||
QJsonArray messages = request["messages"].toArray();
|
||||
@ -46,4 +46,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class LlamaChat : public CodeLlamaChat
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "Llama Chat"; }
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Templates
|
||||
@ -19,24 +19,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class CodeLlamaFimTemplate : public PromptTemplate
|
||||
class CodeLlamaFim : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
TemplateType type() const override { return TemplateType::Fim; }
|
||||
QString name() const override { return "CodeLLama FIM"; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
||||
QString name() const override { return "CodeLlama FIM"; }
|
||||
QString promptTemplate() const override { return "%1<PRE> %2 <SUF>%3 <MID>"; }
|
||||
QStringList stopWords() const override
|
||||
{
|
||||
return QStringList() << "<EOT>" << "<PRE>" << "<SUF" << "<MID>";
|
||||
}
|
||||
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.instriuctions,
|
||||
QString formattedPrompt = promptTemplate().arg(context.systemPrompt,
|
||||
context.prefix,
|
||||
context.suffix);
|
||||
request["prompt"] = formattedPrompt;
|
||||
@ -19,20 +19,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/CustomPromptSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class CustomTemplate : public PromptTemplate
|
||||
class CustomTemplate : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
TemplateType type() const override { return TemplateType::Fim; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
||||
QString name() const override { return "Custom FIM Template"; }
|
||||
QString promptTemplate() const override
|
||||
{
|
||||
@ -40,11 +40,11 @@ public:
|
||||
}
|
||||
QStringList stopWords() const override { return QStringList(); }
|
||||
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(promptTemplate().toUtf8());
|
||||
if (doc.isNull() || !doc.isObject()) {
|
||||
logMessage(QString("Invalid JSON template in settings"));
|
||||
LOG_MESSAGE(QString("Invalid JSON template in settings"));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -58,11 +58,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
QJsonValue processJsonValue(const QJsonValue &value, const ContextData &context) const
|
||||
QJsonValue processJsonValue(const QJsonValue &value, const LLMCore::ContextData &context) const
|
||||
{
|
||||
if (value.isString()) {
|
||||
QString str = value.toString();
|
||||
str.replace("{{QODE_INSTRUCTIONS}}", context.instriuctions);
|
||||
str.replace("{{QODE_INSTRUCTIONS}}", context.systemPrompt);
|
||||
str.replace("{{QODE_PREFIX}}", context.prefix);
|
||||
str.replace("{{QODE_SUFFIX}}", context.suffix);
|
||||
return str;
|
||||
@ -78,7 +78,8 @@ private:
|
||||
return value;
|
||||
}
|
||||
|
||||
QJsonObject processJsonTemplate(const QJsonObject &templateObj, const ContextData &context) const
|
||||
QJsonObject processJsonTemplate(const QJsonObject &templateObj,
|
||||
const LLMCore::ContextData &context) const
|
||||
{
|
||||
QJsonObject result;
|
||||
for (auto it = templateObj.begin(); it != templateObj.end(); ++it) {
|
||||
54
templates/DeepSeekCoderChat.hpp
Normal file
54
templates/DeepSeekCoderChat.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <QJsonArray>
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class DeepSeekCoderChat : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "DeepSeekCoder Chat"; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Chat; }
|
||||
|
||||
QString promptTemplate() const override { return "### Instruction:\n%1\n### Response:\n"; }
|
||||
|
||||
QStringList stopWords() const override
|
||||
{
|
||||
return QStringList() << "### Instruction:" << "### Response:" << "\n\n### " << "<|EOT|>";
|
||||
}
|
||||
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.prefix);
|
||||
QJsonArray messages = request["messages"].toArray();
|
||||
|
||||
QJsonObject newMessage;
|
||||
newMessage["role"] = "user";
|
||||
newMessage["content"] = formattedPrompt;
|
||||
messages.append(newMessage);
|
||||
|
||||
request["messages"] = messages;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Templates
|
||||
@ -19,23 +19,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class DeepSeekCoderV2Template : public PromptTemplate
|
||||
class DeepSeekCoderFim : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
TemplateType type() const override { return TemplateType::Fim; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
||||
QString name() const override { return "DeepSeekCoder FIM"; }
|
||||
QString promptTemplate() const override
|
||||
{
|
||||
return "%1<|fim▁begin|>%2<|fim▁hole|>%3<|fim▁end|>";
|
||||
}
|
||||
QStringList stopWords() const override { return QStringList(); }
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.instriuctions,
|
||||
QString formattedPrompt = promptTemplate().arg(context.systemPrompt,
|
||||
context.prefix,
|
||||
context.suffix);
|
||||
request["prompt"] = formattedPrompt;
|
||||
@ -20,15 +20,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <QJsonArray>
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class DeepSeekCoderChatTemplate : public PromptTemplate
|
||||
class QwenChat : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "DeepSeek Coder Chat"; }
|
||||
TemplateType type() const override { return TemplateType::Chat; }
|
||||
QString name() const override { return "Qwen Chat"; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Chat; }
|
||||
|
||||
QString promptTemplate() const override { return "### Instruction:\n%1\n### Response:\n"; }
|
||||
|
||||
@ -37,7 +37,7 @@ public:
|
||||
return QStringList() << "### Instruction:" << "### Response:" << "\n\n### " << "<|EOT|>";
|
||||
}
|
||||
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.prefix);
|
||||
QJsonArray messages = request["messages"].toArray();
|
||||
@ -19,14 +19,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PromptTemplate.hpp"
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class StarCoder2Template : public PromptTemplate
|
||||
class StarCoder2Fim : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
TemplateType type() const override { return TemplateType::Fim; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
||||
QString name() const override { return "StarCoder2 FIM"; }
|
||||
QString promptTemplate() const override { return "%1<fim_prefix>%2<fim_suffix>%3<fim_middle>"; }
|
||||
QStringList stopWords() const override
|
||||
@ -34,9 +34,9 @@ public:
|
||||
return QStringList() << "<|endoftext|>" << "<file_sep>" << "<fim_prefix>" << "<fim_suffix>"
|
||||
<< "<fim_middle>";
|
||||
}
|
||||
void prepareRequest(QJsonObject &request, const ContextData &context) const override
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.instriuctions,
|
||||
QString formattedPrompt = promptTemplate().arg(context.systemPrompt,
|
||||
context.prefix,
|
||||
context.suffix);
|
||||
request["prompt"] = formattedPrompt;
|
||||
51
templates/StarCoderChat.hpp
Normal file
51
templates/StarCoderChat.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 <QJsonArray>
|
||||
#include "llmcore/PromptTemplate.hpp"
|
||||
|
||||
namespace QodeAssist::Templates {
|
||||
|
||||
class StarCoderChat : public LLMCore::PromptTemplate
|
||||
{
|
||||
public:
|
||||
QString name() const override { return "StarCoder Chat"; }
|
||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Chat; }
|
||||
QString promptTemplate() const override { return "### Instruction:\n%1\n### Response:\n"; }
|
||||
QStringList stopWords() const override
|
||||
{
|
||||
return QStringList() << "###"
|
||||
<< "<|endoftext|>" << "<file_sep>";
|
||||
}
|
||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
||||
{
|
||||
QString formattedPrompt = promptTemplate().arg(context.prefix);
|
||||
QJsonArray messages = request["messages"].toArray();
|
||||
|
||||
QJsonObject newMessage;
|
||||
newMessage["role"] = "user";
|
||||
newMessage["content"] = formattedPrompt;
|
||||
messages.append(newMessage);
|
||||
|
||||
request["messages"] = messages;
|
||||
}
|
||||
};
|
||||
} // namespace QodeAssist::Templates
|
||||
Reference in New Issue
Block a user