mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2025-05-28 03:10:28 -04:00
✨ feat: Add using instruct model in code completion
* ✨ feat: Add MessageBuilder for code completion * ✨ feat: Add move text from request to comments * ✨ feat: Add settings for process text of instruct model * 🐛 fix: Add stop to ollama request validator * 🐛 fix: Template double delete
This commit is contained in:
parent
7376a11a05
commit
ac8080542d
@ -67,4 +67,5 @@ add_qtc_plugin(QodeAssist
|
|||||||
chat/ChatOutputPane.h chat/ChatOutputPane.cpp
|
chat/ChatOutputPane.h chat/ChatOutputPane.cpp
|
||||||
chat/NavigationPanel.hpp chat/NavigationPanel.cpp
|
chat/NavigationPanel.hpp chat/NavigationPanel.cpp
|
||||||
ConfigurationManager.hpp ConfigurationManager.cpp
|
ConfigurationManager.hpp ConfigurationManager.cpp
|
||||||
|
CodeHandler.hpp CodeHandler.cpp
|
||||||
)
|
)
|
||||||
|
115
CodeHandler.cpp
Normal file
115
CodeHandler.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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 "CodeHandler.hpp"
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
namespace QodeAssist {
|
||||||
|
|
||||||
|
QString CodeHandler::processText(QString text)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QStringList lines = text.split('\n');
|
||||||
|
bool inCodeBlock = false;
|
||||||
|
QString pendingComments;
|
||||||
|
QString currentLanguage;
|
||||||
|
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
if (line.trimmed().startsWith("```")) {
|
||||||
|
if (!inCodeBlock) {
|
||||||
|
currentLanguage = detectLanguage(line);
|
||||||
|
}
|
||||||
|
inCodeBlock = !inCodeBlock;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCodeBlock) {
|
||||||
|
if (!pendingComments.isEmpty()) {
|
||||||
|
QStringList commentLines = pendingComments.split('\n');
|
||||||
|
QString commentPrefix = getCommentPrefix(currentLanguage);
|
||||||
|
|
||||||
|
for (const QString &commentLine : commentLines) {
|
||||||
|
if (!commentLine.trimmed().isEmpty()) {
|
||||||
|
result += commentPrefix + " " + commentLine.trimmed() + "\n";
|
||||||
|
} else {
|
||||||
|
result += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingComments.clear();
|
||||||
|
}
|
||||||
|
result += line + "\n";
|
||||||
|
} else {
|
||||||
|
QString trimmed = line.trimmed();
|
||||||
|
if (!trimmed.isEmpty()) {
|
||||||
|
pendingComments += trimmed + "\n";
|
||||||
|
} else {
|
||||||
|
pendingComments += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CodeHandler::getCommentPrefix(const QString &language)
|
||||||
|
{
|
||||||
|
static const QHash<QString, QString> commentPrefixes
|
||||||
|
= {{"python", "#"}, {"py", "#"}, {"lua", "--"}, {"javascript", "//"},
|
||||||
|
{"js", "//"}, {"typescript", "//"}, {"ts", "//"}, {"cpp", "//"},
|
||||||
|
{"c++", "//"}, {"c", "//"}, {"java", "//"}, {"csharp", "//"},
|
||||||
|
{"cs", "//"}, {"php", "//"}, {"ruby", "#"}, {"rb", "#"},
|
||||||
|
{"rust", "//"}, {"rs", "//"}, {"go", "//"}, {"swift", "//"},
|
||||||
|
{"kotlin", "//"}, {"kt", "//"}, {"scala", "//"}, {"r", "#"},
|
||||||
|
{"shell", "#"}, {"bash", "#"}, {"sh", "#"}, {"perl", "#"},
|
||||||
|
{"pl", "#"}, {"haskell", "--"}, {"hs", "--"}};
|
||||||
|
|
||||||
|
return commentPrefixes.value(language.toLower(), "//");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CodeHandler::detectLanguage(const QString &line)
|
||||||
|
{
|
||||||
|
QString trimmed = line.trimmed();
|
||||||
|
if (trimmed.length() <= 3) { // Если только ```
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed.mid(3).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRegularExpression &CodeHandler::getFullCodeBlockRegex()
|
||||||
|
{
|
||||||
|
static const QRegularExpression
|
||||||
|
regex(R"(```[\w\s]*\n([\s\S]*?)```)", QRegularExpression::MultilineOption);
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRegularExpression &CodeHandler::getPartialStartBlockRegex()
|
||||||
|
{
|
||||||
|
static const QRegularExpression
|
||||||
|
regex(R"(```[\w\s]*\n([\s\S]*?)$)", QRegularExpression::MultilineOption);
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRegularExpression &CodeHandler::getPartialEndBlockRegex()
|
||||||
|
{
|
||||||
|
static const QRegularExpression regex(R"(^([\s\S]*?)```)", QRegularExpression::MultilineOption);
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist
|
42
CodeHandler.hpp
Normal file
42
CodeHandler.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QRegularExpression>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace QodeAssist {
|
||||||
|
|
||||||
|
class CodeHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QString processText(QString text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString getCommentPrefix(const QString &language);
|
||||||
|
static QString detectLanguage(const QString &line);
|
||||||
|
|
||||||
|
static const QRegularExpression &getFullCodeBlockRegex();
|
||||||
|
static const QRegularExpression &getPartialStartBlockRegex();
|
||||||
|
static const QRegularExpression &getPartialEndBlockRegex();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QodeAssist
|
@ -26,7 +26,9 @@
|
|||||||
#include <llmcore/RequestConfig.hpp>
|
#include <llmcore/RequestConfig.hpp>
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
|
|
||||||
|
#include "CodeHandler.hpp"
|
||||||
#include "DocumentContextReader.hpp"
|
#include "DocumentContextReader.hpp"
|
||||||
|
#include "llmcore/MessageBuilder.hpp"
|
||||||
#include "llmcore/PromptTemplateManager.hpp"
|
#include "llmcore/PromptTemplateManager.hpp"
|
||||||
#include "llmcore/ProvidersManager.hpp"
|
#include "llmcore/ProvidersManager.hpp"
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
@ -167,11 +169,13 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LLMCore::LLMConfig config;
|
LLMCore::LLMConfig config;
|
||||||
config.requestType = LLMCore::RequestType::Fim;
|
config.requestType = LLMCore::RequestType::CodeCompletion;
|
||||||
config.provider = provider;
|
config.provider = provider;
|
||||||
config.promptTemplate = promptTemplate;
|
config.promptTemplate = promptTemplate;
|
||||||
config.url = QUrl(
|
config.url = QUrl(QString("%1%2").arg(
|
||||||
QString("%1%2").arg(Settings::generalSettings().ccUrl(), provider->completionEndpoint()));
|
Settings::generalSettings().ccUrl(),
|
||||||
|
promptTemplate->type() == LLMCore::TemplateType::Fim ? provider->completionEndpoint()
|
||||||
|
: provider->chatEndpoint()));
|
||||||
config.apiKey = Settings::codeCompletionSettings().apiKey();
|
config.apiKey = Settings::codeCompletionSettings().apiKey();
|
||||||
|
|
||||||
config.providerRequest
|
config.providerRequest
|
||||||
@ -180,20 +184,27 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
|
|
||||||
config.multiLineCompletion = completeSettings.multiLineCompletion();
|
config.multiLineCompletion = completeSettings.multiLineCompletion();
|
||||||
|
|
||||||
|
const auto stopWords = QJsonArray::fromStringList(config.promptTemplate->stopWords());
|
||||||
|
if (!stopWords.isEmpty())
|
||||||
|
config.providerRequest["stop"] = stopWords;
|
||||||
|
|
||||||
QString systemPrompt;
|
QString systemPrompt;
|
||||||
if (completeSettings.useSystemPrompt())
|
if (completeSettings.useSystemPrompt())
|
||||||
systemPrompt.append(completeSettings.systemPrompt());
|
systemPrompt.append(completeSettings.systemPrompt());
|
||||||
if (!updatedContext.fileContext.isEmpty())
|
if (!updatedContext.fileContext.isEmpty())
|
||||||
systemPrompt.append(updatedContext.fileContext);
|
systemPrompt.append(updatedContext.fileContext);
|
||||||
if (!systemPrompt.isEmpty())
|
|
||||||
config.providerRequest["system"] = systemPrompt;
|
|
||||||
|
|
||||||
const auto stopWords = QJsonArray::fromStringList(config.promptTemplate->stopWords());
|
auto message = LLMCore::MessageBuilder()
|
||||||
if (!stopWords.isEmpty())
|
.addSystemMessage(systemPrompt)
|
||||||
config.providerRequest["stop"] = stopWords;
|
.addUserMessage(updatedContext.prefix)
|
||||||
|
.addSuffix(updatedContext.suffix)
|
||||||
|
.addtTokenizer(promptTemplate);
|
||||||
|
|
||||||
config.promptTemplate->prepareRequest(config.providerRequest, updatedContext);
|
message.saveTo(
|
||||||
config.provider->prepareRequest(config.providerRequest, LLMCore::RequestType::Fim);
|
config.providerRequest,
|
||||||
|
providerName == "Ollama" ? LLMCore::ProvidersApi::Ollama : LLMCore::ProvidersApi::OpenAI);
|
||||||
|
|
||||||
|
config.provider->prepareRequest(config.providerRequest, LLMCore::RequestType::CodeCompletion);
|
||||||
|
|
||||||
auto errors = config.provider->validateRequest(config.providerRequest, promptTemplate->type());
|
auto errors = config.provider->validateRequest(config.providerRequest, promptTemplate->type());
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
@ -232,19 +243,31 @@ void LLMClientInterface::sendCompletionToClient(const QString &completion,
|
|||||||
const QJsonObject &request,
|
const QJsonObject &request,
|
||||||
bool isComplete)
|
bool isComplete)
|
||||||
{
|
{
|
||||||
|
auto templateName = Settings::generalSettings().ccTemplate();
|
||||||
|
auto promptTemplate = LLMCore::PromptTemplateManager::instance().getFimTemplateByName(
|
||||||
|
templateName);
|
||||||
|
|
||||||
QJsonObject position = request["params"].toObject()["doc"].toObject()["position"].toObject();
|
QJsonObject position = request["params"].toObject()["doc"].toObject()["position"].toObject();
|
||||||
|
|
||||||
QJsonObject response;
|
QJsonObject response;
|
||||||
response["jsonrpc"] = "2.0";
|
response["jsonrpc"] = "2.0";
|
||||||
response[LanguageServerProtocol::idKey] = request["id"];
|
response[LanguageServerProtocol::idKey] = request["id"];
|
||||||
|
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray completions;
|
QJsonArray completions;
|
||||||
QJsonObject completionItem;
|
QJsonObject completionItem;
|
||||||
completionItem[LanguageServerProtocol::textKey] = completion;
|
|
||||||
|
QString processedCompletion
|
||||||
|
= promptTemplate->type() == LLMCore::TemplateType::Chat
|
||||||
|
&& Settings::codeCompletionSettings().smartProcessInstuctText()
|
||||||
|
? CodeHandler::processText(completion)
|
||||||
|
: completion;
|
||||||
|
|
||||||
|
completionItem[LanguageServerProtocol::textKey] = processedCompletion;
|
||||||
QJsonObject range;
|
QJsonObject range;
|
||||||
range["start"] = position;
|
range["start"] = position;
|
||||||
QJsonObject end = position;
|
QJsonObject end = position;
|
||||||
end["character"] = position["character"].toInt() + completion.length();
|
end["character"] = position["character"].toInt() + processedCompletion.length();
|
||||||
range["end"] = end;
|
range["end"] = end;
|
||||||
completionItem[LanguageServerProtocol::rangeKey] = range;
|
completionItem[LanguageServerProtocol::rangeKey] = range;
|
||||||
completionItem[LanguageServerProtocol::positionKey] = position;
|
completionItem[LanguageServerProtocol::positionKey] = position;
|
||||||
|
@ -10,6 +10,7 @@ add_library(LLMCore STATIC
|
|||||||
OllamaMessage.hpp OllamaMessage.cpp
|
OllamaMessage.hpp OllamaMessage.cpp
|
||||||
OpenAIMessage.hpp OpenAIMessage.cpp
|
OpenAIMessage.hpp OpenAIMessage.cpp
|
||||||
ValidationUtils.hpp ValidationUtils.cpp
|
ValidationUtils.hpp ValidationUtils.cpp
|
||||||
|
MessageBuilder.hpp MessageBuilder.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(LLMCore
|
target_link_libraries(LLMCore
|
||||||
|
3
llmcore/MessageBuilder.cpp
Normal file
3
llmcore/MessageBuilder.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "MessageBuilder.hpp"
|
||||||
|
|
||||||
|
namespace QodeAssist::LLMCore {} // namespace QodeAssist::LLMCore
|
127
llmcore/MessageBuilder.hpp
Normal file
127
llmcore/MessageBuilder.hpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "PromptTemplate.hpp"
|
||||||
|
|
||||||
|
namespace QodeAssist::LLMCore {
|
||||||
|
|
||||||
|
enum class MessageRole { System, User, Assistant };
|
||||||
|
|
||||||
|
enum class OllamaFormat { Messages, Completions };
|
||||||
|
|
||||||
|
enum class ProvidersApi { Ollama, OpenAI };
|
||||||
|
|
||||||
|
static const QString ROLE_SYSTEM = "system";
|
||||||
|
static const QString ROLE_USER = "user";
|
||||||
|
static const QString ROLE_ASSISTANT = "assistant";
|
||||||
|
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
MessageRole role;
|
||||||
|
QString content;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MessageBuilder &addSystemMessage(const QString &content)
|
||||||
|
{
|
||||||
|
m_systemMessage = content;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder &addUserMessage(const QString &content)
|
||||||
|
{
|
||||||
|
m_messages.append({MessageRole::User, content});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder &addSuffix(const QString &content)
|
||||||
|
{
|
||||||
|
m_suffix = content;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder &addtTokenizer(PromptTemplate *promptTemplate)
|
||||||
|
{
|
||||||
|
m_promptTemplate = promptTemplate;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString roleToString(MessageRole role) const
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case MessageRole::System:
|
||||||
|
return ROLE_SYSTEM;
|
||||||
|
case MessageRole::User:
|
||||||
|
return ROLE_USER;
|
||||||
|
case MessageRole::Assistant:
|
||||||
|
return ROLE_ASSISTANT;
|
||||||
|
default:
|
||||||
|
return ROLE_USER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveTo(QJsonObject &request, ProvidersApi api)
|
||||||
|
{
|
||||||
|
if (!m_promptTemplate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api == ProvidersApi::Ollama) {
|
||||||
|
ContextData context{
|
||||||
|
m_messages.isEmpty() ? QString() : m_messages.last().content,
|
||||||
|
m_suffix,
|
||||||
|
m_systemMessage};
|
||||||
|
|
||||||
|
if (m_promptTemplate->type() == TemplateType::Fim) {
|
||||||
|
m_promptTemplate->prepareRequest(request, context);
|
||||||
|
} else {
|
||||||
|
QJsonArray messages;
|
||||||
|
|
||||||
|
messages.append(QJsonObject{{"role", "system"}, {"content", m_systemMessage}});
|
||||||
|
messages.append(
|
||||||
|
QJsonObject{{"role", "user"}, {"content", m_messages.last().content}});
|
||||||
|
request["messages"] = messages;
|
||||||
|
m_promptTemplate->prepareRequest(request, {});
|
||||||
|
}
|
||||||
|
} else if (api == ProvidersApi::OpenAI) {
|
||||||
|
QJsonArray messages;
|
||||||
|
|
||||||
|
messages.append(QJsonObject{{"role", "system"}, {"content", m_systemMessage}});
|
||||||
|
messages.append(QJsonObject{{"role", "user"}, {"content", m_messages.last().content}});
|
||||||
|
request["messages"] = messages;
|
||||||
|
m_promptTemplate->prepareRequest(request, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_systemMessage;
|
||||||
|
QString m_suffix;
|
||||||
|
QVector<Message> m_messages;
|
||||||
|
PromptTemplate *m_promptTemplate;
|
||||||
|
};
|
||||||
|
} // namespace QodeAssist::LLMCore
|
@ -40,7 +40,6 @@ QStringList PromptTemplateManager::chatTemplatesNames() const
|
|||||||
PromptTemplateManager::~PromptTemplateManager()
|
PromptTemplateManager::~PromptTemplateManager()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_fimTemplates);
|
qDeleteAll(m_fimTemplates);
|
||||||
qDeleteAll(m_chatTemplates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PromptTemplate *PromptTemplateManager::getFimTemplateByName(const QString &templateName)
|
PromptTemplate *PromptTemplateManager::getFimTemplateByName(const QString &templateName)
|
||||||
|
@ -39,9 +39,8 @@ public:
|
|||||||
"T must inherit from PromptTemplate");
|
"T must inherit from PromptTemplate");
|
||||||
T *template_ptr = new T();
|
T *template_ptr = new T();
|
||||||
QString name = template_ptr->name();
|
QString name = template_ptr->name();
|
||||||
if (template_ptr->type() == TemplateType::Fim) {
|
m_fimTemplates[name] = template_ptr;
|
||||||
m_fimTemplates[name] = template_ptr;
|
if (template_ptr->type() == TemplateType::Chat) {
|
||||||
} else if (template_ptr->type() == TemplateType::Chat) {
|
|
||||||
m_chatTemplates[name] = template_ptr;
|
m_chatTemplates[name] = template_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ void RequestHandler::handleLLMResponse(QNetworkReply *reply,
|
|||||||
|
|
||||||
bool isComplete = config.provider->handleResponse(reply, accumulatedResponse);
|
bool isComplete = config.provider->handleResponse(reply, accumulatedResponse);
|
||||||
|
|
||||||
if (config.requestType == RequestType::Fim) {
|
if (config.requestType == RequestType::CodeCompletion) {
|
||||||
if (!config.multiLineCompletion
|
if (!config.multiLineCompletion
|
||||||
&& processSingleLineCompletion(reply, request, accumulatedResponse, config)) {
|
&& processSingleLineCompletion(reply, request, accumulatedResponse, config)) {
|
||||||
return;
|
return;
|
||||||
@ -84,7 +84,6 @@ void RequestHandler::handleLLMResponse(QNetworkReply *reply,
|
|||||||
if (isComplete) {
|
if (isComplete) {
|
||||||
auto cleanedCompletion = removeStopWords(accumulatedResponse,
|
auto cleanedCompletion = removeStopWords(accumulatedResponse,
|
||||||
config.promptTemplate->stopWords());
|
config.promptTemplate->stopWords());
|
||||||
removeCodeBlockWrappers(cleanedCompletion);
|
|
||||||
|
|
||||||
emit completionReceived(cleanedCompletion, request, true);
|
emit completionReceived(cleanedCompletion, request, true);
|
||||||
}
|
}
|
||||||
@ -126,7 +125,6 @@ bool RequestHandler::processSingleLineCompletion(
|
|||||||
const LLMConfig &config)
|
const LLMConfig &config)
|
||||||
{
|
{
|
||||||
QString cleanedResponse = accumulatedResponse;
|
QString cleanedResponse = accumulatedResponse;
|
||||||
removeCodeBlockWrappers(cleanedResponse);
|
|
||||||
|
|
||||||
int newlinePos = cleanedResponse.indexOf('\n');
|
int newlinePos = cleanedResponse.indexOf('\n');
|
||||||
if (newlinePos != -1) {
|
if (newlinePos != -1) {
|
||||||
|
@ -21,5 +21,5 @@
|
|||||||
|
|
||||||
namespace QodeAssist::LLMCore {
|
namespace QodeAssist::LLMCore {
|
||||||
|
|
||||||
enum RequestType { Fim, Chat };
|
enum RequestType { CodeCompletion, Chat };
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ void LMStudioProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType
|
|||||||
request["messages"] = std::move(messages);
|
request["messages"] = std::move(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == LLMCore::RequestType::Fim) {
|
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||||
applyModelParams(Settings::codeCompletionSettings());
|
applyModelParams(Settings::codeCompletionSettings());
|
||||||
} else {
|
} else {
|
||||||
applyModelParams(Settings::chatAssistantSettings());
|
applyModelParams(Settings::chatAssistantSettings());
|
||||||
|
@ -66,6 +66,7 @@ void OllamaProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType t
|
|||||||
QJsonObject options;
|
QJsonObject options;
|
||||||
options["num_predict"] = settings.maxTokens();
|
options["num_predict"] = settings.maxTokens();
|
||||||
options["temperature"] = settings.temperature();
|
options["temperature"] = settings.temperature();
|
||||||
|
options["stop"] = request.take("stop");
|
||||||
|
|
||||||
if (settings.useTopP())
|
if (settings.useTopP())
|
||||||
options["top_p"] = settings.topP();
|
options["top_p"] = settings.topP();
|
||||||
@ -80,7 +81,7 @@ void OllamaProvider::prepareRequest(QJsonObject &request, LLMCore::RequestType t
|
|||||||
request["keep_alive"] = settings.ollamaLivetime();
|
request["keep_alive"] = settings.ollamaLivetime();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type == LLMCore::RequestType::Fim) {
|
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||||
applySettings(Settings::codeCompletionSettings());
|
applySettings(Settings::codeCompletionSettings());
|
||||||
} else {
|
} else {
|
||||||
applySettings(Settings::chatAssistantSettings());
|
applySettings(Settings::chatAssistantSettings());
|
||||||
@ -150,6 +151,7 @@ QList<QString> OllamaProvider::validateRequest(const QJsonObject &request, LLMCo
|
|||||||
{"options",
|
{"options",
|
||||||
QJsonObject{
|
QJsonObject{
|
||||||
{"temperature", {}},
|
{"temperature", {}},
|
||||||
|
{"stop", {}},
|
||||||
{"top_p", {}},
|
{"top_p", {}},
|
||||||
{"top_k", {}},
|
{"top_k", {}},
|
||||||
{"num_predict", {}},
|
{"num_predict", {}},
|
||||||
@ -164,6 +166,7 @@ QList<QString> OllamaProvider::validateRequest(const QJsonObject &request, LLMCo
|
|||||||
{"options",
|
{"options",
|
||||||
QJsonObject{
|
QJsonObject{
|
||||||
{"temperature", {}},
|
{"temperature", {}},
|
||||||
|
{"stop", {}},
|
||||||
{"top_p", {}},
|
{"top_p", {}},
|
||||||
{"top_k", {}},
|
{"top_k", {}},
|
||||||
{"num_predict", {}},
|
{"num_predict", {}},
|
||||||
|
@ -93,7 +93,7 @@ void OpenAICompatProvider::prepareRequest(QJsonObject &request, LLMCore::Request
|
|||||||
request["messages"] = std::move(messages);
|
request["messages"] = std::move(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == LLMCore::RequestType::Fim) {
|
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||||
applyModelParams(Settings::codeCompletionSettings());
|
applyModelParams(Settings::codeCompletionSettings());
|
||||||
} else {
|
} else {
|
||||||
applyModelParams(Settings::chatAssistantSettings());
|
applyModelParams(Settings::chatAssistantSettings());
|
||||||
|
@ -77,7 +77,7 @@ void OpenRouterProvider::prepareRequest(QJsonObject &request, LLMCore::RequestTy
|
|||||||
request["messages"] = std::move(messages);
|
request["messages"] = std::move(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == LLMCore::RequestType::Fim) {
|
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||||
applyModelParams(Settings::codeCompletionSettings());
|
applyModelParams(Settings::codeCompletionSettings());
|
||||||
} else {
|
} else {
|
||||||
applyModelParams(Settings::chatAssistantSettings());
|
applyModelParams(Settings::chatAssistantSettings());
|
||||||
|
@ -48,13 +48,17 @@ CodeCompletionSettings::CodeCompletionSettings()
|
|||||||
autoCompletion.setDefaultValue(true);
|
autoCompletion.setDefaultValue(true);
|
||||||
|
|
||||||
multiLineCompletion.setSettingsKey(Constants::CC_MULTILINE_COMPLETION);
|
multiLineCompletion.setSettingsKey(Constants::CC_MULTILINE_COMPLETION);
|
||||||
multiLineCompletion.setDefaultValue(false);
|
multiLineCompletion.setDefaultValue(true);
|
||||||
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion(experimental)"));
|
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion"));
|
||||||
|
|
||||||
stream.setSettingsKey(Constants::CC_STREAM);
|
stream.setSettingsKey(Constants::CC_STREAM);
|
||||||
stream.setDefaultValue(true);
|
stream.setDefaultValue(true);
|
||||||
stream.setLabelText(Tr::tr("Enable stream option"));
|
stream.setLabelText(Tr::tr("Enable stream option"));
|
||||||
|
|
||||||
|
smartProcessInstuctText.setSettingsKey(Constants::CC_SMART_PROCESS_INSTRUCT_TEXT);
|
||||||
|
smartProcessInstuctText.setDefaultValue(true);
|
||||||
|
smartProcessInstuctText.setLabelText(Tr::tr("Enable smart process text from instruct model"));
|
||||||
|
|
||||||
startSuggestionTimer.setSettingsKey(Constants::СС_START_SUGGESTION_TIMER);
|
startSuggestionTimer.setSettingsKey(Constants::СС_START_SUGGESTION_TIMER);
|
||||||
startSuggestionTimer.setLabelText(Tr::tr("with delay(ms)"));
|
startSuggestionTimer.setLabelText(Tr::tr("with delay(ms)"));
|
||||||
startSuggestionTimer.setRange(10, 10000);
|
startSuggestionTimer.setRange(10, 10000);
|
||||||
@ -147,8 +151,8 @@ CodeCompletionSettings::CodeCompletionSettings()
|
|||||||
|
|
||||||
systemPrompt.setSettingsKey(Constants::CC_SYSTEM_PROMPT);
|
systemPrompt.setSettingsKey(Constants::CC_SYSTEM_PROMPT);
|
||||||
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
systemPrompt.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
||||||
systemPrompt.setDefaultValue("You are an expert C++, Qt, and QML code completion AI. ANSWER "
|
systemPrompt.setDefaultValue("You are an expert C++, Qt, and QML code completion AI. Answer "
|
||||||
"should be SHORT and in CODE");
|
"should be ONLY in CODE and without repeating current.");
|
||||||
|
|
||||||
useFilePathInContext.setSettingsKey(Constants::CC_USE_FILE_PATH_IN_CONTEXT);
|
useFilePathInContext.setSettingsKey(Constants::CC_USE_FILE_PATH_IN_CONTEXT);
|
||||||
useFilePathInContext.setDefaultValue(true);
|
useFilePathInContext.setDefaultValue(true);
|
||||||
@ -227,6 +231,7 @@ CodeCompletionSettings::CodeCompletionSettings()
|
|||||||
Space{8},
|
Space{8},
|
||||||
multiLineCompletion,
|
multiLineCompletion,
|
||||||
stream,
|
stream,
|
||||||
|
smartProcessInstuctText,
|
||||||
Row{autoCompletionCharThreshold,
|
Row{autoCompletionCharThreshold,
|
||||||
autoCompletionTypingInterval,
|
autoCompletionTypingInterval,
|
||||||
startSuggestionTimer,
|
startSuggestionTimer,
|
||||||
|
@ -36,6 +36,7 @@ public:
|
|||||||
Utils::BoolAspect autoCompletion{this};
|
Utils::BoolAspect autoCompletion{this};
|
||||||
Utils::BoolAspect multiLineCompletion{this};
|
Utils::BoolAspect multiLineCompletion{this};
|
||||||
Utils::BoolAspect stream{this};
|
Utils::BoolAspect stream{this};
|
||||||
|
Utils::BoolAspect smartProcessInstuctText{this};
|
||||||
|
|
||||||
Utils::IntegerAspect startSuggestionTimer{this};
|
Utils::IntegerAspect startSuggestionTimer{this};
|
||||||
Utils::IntegerAspect autoCompletionCharThreshold{this};
|
Utils::IntegerAspect autoCompletionCharThreshold{this};
|
||||||
|
@ -50,6 +50,7 @@ const char СС_AUTO_COMPLETION_TYPING_INTERVAL[] = "QodeAssist.autoCompletionTy
|
|||||||
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
|
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
|
||||||
const char CC_MULTILINE_COMPLETION[] = "QodeAssist.ccMultilineCompletion";
|
const char CC_MULTILINE_COMPLETION[] = "QodeAssist.ccMultilineCompletion";
|
||||||
const char CC_STREAM[] = "QodeAssist.ccStream";
|
const char CC_STREAM[] = "QodeAssist.ccStream";
|
||||||
|
const char CC_SMART_PROCESS_INSTRUCT_TEXT[] = "QodeAssist.ccSmartProcessInstructText";
|
||||||
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
||||||
const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold";
|
const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold";
|
||||||
const char CA_SHARING_CURRENT_FILE[] = "QodeAssist.caSharingCurrentFile";
|
const char CA_SHARING_CURRENT_FILE[] = "QodeAssist.caSharingCurrentFile";
|
||||||
|
Loading…
Reference in New Issue
Block a user