Compare commits

..

11 Commits

Author SHA1 Message Date
9d40e8ca25 chore: Upgrade plugin to 0.5.5 version 2025-03-20 19:02:11 +01:00
5b16c5403a fix: Add authorization while getting installed models (#142) (#147) 2025-03-20 11:33:38 +01:00
4ddbe0b8b9 feat: Support Ollama authorization via BaseAuth (#145) (#146) 2025-03-20 11:14:50 +01:00
f41e063c02 chore: Upgrade plugin version to 0.5.4 2025-03-17 02:51:31 +01:00
9d7d084448 fix: Wrong template replace to first template (#143) 2025-03-17 02:48:18 +01:00
1ca1ffc629 fix: Remove reading from replay leading to crash (#142) 2025-03-17 01:22:27 +01:00
8419577ae5 fix: Resolve thread-related QNetworkAccessManager issue (#140)
Fixes "QObject: Cannot create children for a parent that is in a different thread" error by creating QNetworkAccessManager in the same thread where it's used, ensuring proper thread affinity for network operations.
2025-03-16 09:47:04 +01:00
91a6a88130 doc: Add default path for installed plugin 2025-03-14 11:35:37 +01:00
be38abc505 chore: upgrade plugin to 0.5.3 (#139) 2025-03-14 10:59:23 +01:00
f2e0afb6b8 fix: Add qml in code handler for processing model answers (#138) 2025-03-14 10:47:30 +01:00
3cf07238fd doc: Update QtC version to 16 2025-03-14 09:32:54 +01:00
14 changed files with 88 additions and 20 deletions

View File

@ -13,7 +13,7 @@
"Linux"
],
"license": "GPLv3",
"version": "0.5.2",
"version": "0.5.5",
"status": "draft",
"is_pack": false,
"released_at": null,
@ -25,8 +25,23 @@
},
{
"version": "0.5.2",
"is_latest": true,
"is_latest": false,
"released_at": "2025-03-13T17:00:00Z"
},
{
"version": "0.5.3",
"is_latest": false,
"released_at": "2025-03-14T11:00:00Z"
},
{
"version": "0.5.4",
"is_latest": false,
"released_at": "2025-03-17T03:00:00Z"
},
{
"version": "0.5.5",
"is_latest": true,
"released_at": "2025-03-20T19:00:00Z"
}
],
"icon": "https://github.com/user-attachments/assets/dc336712-83cb-440d-8761-8d0a31de898d",

View File

@ -52,6 +52,7 @@ const QVector<LanguageProperties> &getKnownLanguages()
{"shell", "#", {"shell", "bash", "sh"}, {"sh", "bash"}},
{"perl", "#", {"pl", "perl"}, {"pl"}},
{"hs", "--", {"hs", "haskell"}, {"hs"}},
{"qml", "//", {"qml"}, {"qml"}},
};
return knownLanguages;

View File

@ -36,6 +36,7 @@ void ConfigurationManager::init()
{
setupConnections();
updateAllTemplateDescriptions();
checkAllTemplate();
}
void ConfigurationManager::updateTemplateDescription(const Utils::StringAspect &templateAspect)
@ -59,6 +60,26 @@ void ConfigurationManager::updateAllTemplateDescriptions()
updateTemplateDescription(m_generalSettings.caTemplate);
}
void ConfigurationManager::checkTemplate(const Utils::StringAspect &templateAspect)
{
LLMCore::PromptTemplate *templ = m_templateManger.getFimTemplateByName(templateAspect.value());
if (templ->name() == templateAspect.value())
return;
if (&templateAspect == &m_generalSettings.ccTemplate) {
m_generalSettings.ccTemplate.setValue(templ->name());
} else if (&templateAspect == &m_generalSettings.caTemplate) {
m_generalSettings.caTemplate.setValue(templ->name());
}
}
void ConfigurationManager::checkAllTemplate()
{
checkTemplate(m_generalSettings.ccTemplate);
checkTemplate(m_generalSettings.caTemplate);
}
ConfigurationManager::ConfigurationManager(QObject *parent)
: QObject(parent)
, m_generalSettings(Settings::generalSettings())

View File

@ -38,6 +38,8 @@ public:
void updateTemplateDescription(const Utils::StringAspect &templateAspect);
void updateAllTemplateDescriptions();
void checkTemplate(const Utils::StringAspect &templateAspect);
void checkAllTemplate();
public slots:
void selectProvider();

View File

@ -1,13 +1,13 @@
{
"Id" : "qodeassist",
"Name" : "QodeAssist",
"Version" : "0.5.2",
"Version" : "0.5.5",
"Vendor" : "Petr Mironychev",
"VendorId" : "petrmironychev",
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
"License" : "GPLv3",
"Description": "QodeAssist is an AI-powered coding assistant for Qt Creator. It provides intelligent code completion and suggestions for your code. Prerequisites: Requires one of the supported LLM providers installed (e.g., Ollama or LM Studio) and a compatible large language model downloaded for your chosen provider (e.g., CodeLlama, StarCoder2).",
"Url" : "https://github.com/Palm1r/QodeAssist",
"DocumentationUrl" : "",
"DocumentationUrl" : "https://github.com/Palm1r/QodeAssist",
${IDE_PLUGIN_DEPENDENCIES}
}

View File

@ -2,7 +2,7 @@
[![Build plugin](https://github.com/Palm1r/QodeAssist/actions/workflows/build_cmake.yml/badge.svg?branch=main)](https://github.com/Palm1r/QodeAssist/actions/workflows/build_cmake.yml)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/Palm1r/QodeAssist/total?color=41%2C173%2C71)
![GitHub Tag](https://img.shields.io/github/v/tag/Palm1r/QodeAssist)
![Static Badge](https://img.shields.io/badge/QtCreator-15.0.1-brightgreen)
![Static Badge](https://img.shields.io/badge/QtCreator-16.0.0-brightgreen)
[![](https://dcbadge.limes.pink/api/server/BGMkUsXUgf?style=flat)](https://discord.gg/BGMkUsXUgf)
![qodeassist-icon](https://github.com/user-attachments/assets/dc336712-83cb-440d-8761-8d0a31de898d) 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.
@ -94,6 +94,8 @@ Join our Discord Community: Have questions or want to discuss QodeAssist? Join o
1. Install Latest Qt Creator
2. Download the QodeAssist plugin for your Qt Creator
- Remove old version plugin if already was installed
- on macOS for QtCreator 16: ~/Library/Application Support/QtProject/Qt Creator/plugins/16.0.0/petrmironychev.qodeassist
- on windows for QtCreator 16: C:\Users\<user>\AppData\Local\QtProject\qtcreator\plugins\16.0.0\petrmironychev.qodeassist\lib\qtcreator\plugins
3. Launch Qt Creator and install the plugin:
- Go to:
- MacOS: Qt Creator -> About Plugins...
@ -237,7 +239,8 @@ Linked files provide persistent context throughout the conversation:
## QtCreator Version Compatibility
- QtCreator 15.0.1 - 0.4.8 - 0.5.x
- QtCreator 16.0.0 - 0.5.2 - 0.5.x
- QtCreator 15.0.1 - 0.4.8 - 0.5.1
- QtCreator 15.0.0 - 0.4.0 - 0.4.7
- QtCreator 14.0.2 - 0.2.3 - 0.3.x
- QtCreator 14.0.1 - 0.2.2 plugin version and below

View File

@ -27,7 +27,6 @@ namespace QodeAssist::LLMCore {
RequestHandler::RequestHandler(QObject *parent)
: RequestHandlerBase(parent)
, m_manager(new QNetworkAccessManager(this))
{}
void RequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &request)
@ -38,11 +37,12 @@ void RequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &
QString::fromUtf8(
QJsonDocument(config.providerRequest).toJson(QJsonDocument::Indented))));
QNetworkAccessManager *manager = new QNetworkAccessManager();
QNetworkRequest networkRequest(config.url);
config.provider->prepareNetworkRequest(networkRequest);
QNetworkReply *reply
= m_manager->post(networkRequest, QJsonDocument(config.providerRequest).toJson());
= manager->post(networkRequest, QJsonDocument(config.providerRequest).toJson());
if (!reply) {
LOG_MESSAGE("Error: Failed to create network reply");
return;
@ -55,19 +55,23 @@ void RequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &
handleLLMResponse(reply, request, config);
});
connect(reply, &QNetworkReply::finished, this, [this, reply, requestId]() {
reply->deleteLater();
connect(reply, &QNetworkReply::finished, this, [this, reply, requestId, manager]() {
m_activeRequests.remove(requestId);
if (reply->error() != QNetworkReply::NoError) {
LOG_MESSAGE(QString("Error details: %1\nStatus code: %2\nResponse: %3")
.arg(reply->errorString())
.arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt())
.arg(QString(reply->readAll())));
emit requestFinished(requestId, false, reply->errorString());
QString errorMessage = reply->errorString();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
LOG_MESSAGE(
QString("Error details: %1\nStatus code: %2").arg(errorMessage).arg(statusCode));
emit requestFinished(requestId, false, errorMessage);
} else {
LOG_MESSAGE("Request finished successfully");
emit requestFinished(requestId, true, QString());
}
reply->deleteLater();
manager->deleteLater();
});
}

View File

@ -40,7 +40,6 @@ public:
void handleLLMResponse(QNetworkReply *reply, const QJsonObject &request, const LLMConfig &config);
private:
QNetworkAccessManager *m_manager;
QMap<QString, QNetworkReply *> m_activeRequests;
QMap<QNetworkReply *, QString> m_accumulatedResponses;

View File

@ -30,7 +30,6 @@
#include "logger/Logger.hpp"
#include "settings/ChatAssistantSettings.hpp"
#include "settings/CodeCompletionSettings.hpp"
#include "settings/GeneralSettings.hpp"
#include "settings/ProviderSettings.hpp"
namespace QodeAssist::Providers {

View File

@ -30,6 +30,7 @@
#include "logger/Logger.hpp"
#include "settings/ChatAssistantSettings.hpp"
#include "settings/CodeCompletionSettings.hpp"
#include "settings/ProviderSettings.hpp"
namespace QodeAssist::Providers {
@ -139,6 +140,7 @@ QList<QString> OllamaProvider::getInstalledModels(const QString &url)
QList<QString> models;
QNetworkAccessManager manager;
QNetworkRequest request(QString("%1%2").arg(url, "/api/tags"));
prepareNetworkRequest(request);
QNetworkReply *reply = manager.get(request);
QEventLoop loop;
@ -210,6 +212,10 @@ QString OllamaProvider::apiKey() const
void OllamaProvider::prepareNetworkRequest(QNetworkRequest &networkRequest) const
{
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
const auto key = Settings::providerSettings().ollamaBasicAuthApiKey();
if (!key.isEmpty()) {
networkRequest.setRawHeader("Authorization", "Basic " + key.toLatin1());
}
}
LLMCore::ProviderID OllamaProvider::providerID() const

View File

@ -94,7 +94,7 @@ GeneralSettings::GeneralSettings()
ccModel.setHistoryCompleter(Constants::CC_MODEL_HISTORY);
ccSelectModel.m_buttonText = TrConstants::SELECT;
initStringAspect(ccTemplate, Constants::CC_TEMPLATE, TrConstants::TEMPLATE, "Ollama Auto FIM");
initStringAspect(ccTemplate, Constants::CC_TEMPLATE, TrConstants::TEMPLATE, "Ollama FIM");
ccTemplate.setReadOnly(true);
ccSelectTemplate.m_buttonText = TrConstants::SELECT;
@ -140,7 +140,7 @@ GeneralSettings::GeneralSettings()
ccPreset1SelectModel.m_buttonText = TrConstants::SELECT;
initStringAspect(
ccPreset1Template, Constants::CC_PRESET1_TEMPLATE, TrConstants::TEMPLATE, "Ollama Auto FIM");
ccPreset1Template, Constants::CC_PRESET1_TEMPLATE, TrConstants::TEMPLATE, "Ollama FIM");
ccPreset1Template.setReadOnly(true);
ccPreset1SelectTemplate.m_buttonText = TrConstants::SELECT;
@ -153,7 +153,7 @@ GeneralSettings::GeneralSettings()
caModel.setHistoryCompleter(Constants::CA_MODEL_HISTORY);
caSelectModel.m_buttonText = TrConstants::SELECT;
initStringAspect(caTemplate, Constants::CA_TEMPLATE, TrConstants::TEMPLATE, "Ollama Auto Chat");
initStringAspect(caTemplate, Constants::CA_TEMPLATE, TrConstants::TEMPLATE, "Ollama Chat");
caTemplate.setReadOnly(true);
caSelectTemplate.m_buttonText = TrConstants::SELECT;

View File

@ -96,6 +96,15 @@ ProviderSettings::ProviderSettings()
googleAiApiKey.setDefaultValue("");
googleAiApiKey.setAutoApply(true);
// Ollama with BasicAuth Settings
ollamaBasicAuthApiKey.setSettingsKey(Constants::OLLAMA_BASIC_AUTH_API_KEY);
ollamaBasicAuthApiKey.setLabelText(Tr::tr("Ollama BasicAuth API Key:"));
ollamaBasicAuthApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
ollamaBasicAuthApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
ollamaBasicAuthApiKey.setHistoryCompleter(Constants::OLLAMA_BASIC_AUTH_API_KEY_HISTORY);
ollamaBasicAuthApiKey.setDefaultValue("");
ollamaBasicAuthApiKey.setAutoApply(true);
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
readSettings();
@ -119,6 +128,8 @@ ProviderSettings::ProviderSettings()
Group{title(Tr::tr("Mistral AI Settings")), Column{mistralAiApiKey}},
Space{8},
Group{title(Tr::tr("Google AI Settings")), Column{googleAiApiKey}},
Space{8},
Group{title(Tr::tr("Ollama Settings")), Column{ollamaBasicAuthApiKey}},
Stretch{1}};
});
}
@ -141,6 +152,9 @@ void ProviderSettings::setupConnections()
connect(&googleAiApiKey, &ButtonAspect::changed, this, [this]() {
googleAiApiKey.writeSettings();
});
connect(&ollamaBasicAuthApiKey, &ButtonAspect::changed, this, [this]() {
ollamaBasicAuthApiKey.writeSettings();
});
}
void ProviderSettings::resetSettingsToDefaults()
@ -159,6 +173,7 @@ void ProviderSettings::resetSettingsToDefaults()
resetAspect(openAiApiKey);
resetAspect(mistralAiApiKey);
resetAspect(googleAiApiKey);
resetAspect(ollamaBasicAuthApiKey);
}
}

View File

@ -39,6 +39,7 @@ public:
Utils::StringAspect openAiApiKey{this};
Utils::StringAspect mistralAiApiKey{this};
Utils::StringAspect googleAiApiKey{this};
Utils::StringAspect ollamaBasicAuthApiKey{this};
private:
void setupConnections();

View File

@ -100,6 +100,8 @@ const char MISTRAL_AI_API_KEY[] = "QodeAssist.mistralAiApiKey";
const char MISTRAL_AI_API_KEY_HISTORY[] = "QodeAssist.mistralAiApiKeyHistory";
const char GOOGLE_AI_API_KEY[] = "QodeAssist.googleAiApiKey";
const char GOOGLE_AI_API_KEY_HISTORY[] = "QodeAssist.googleAiApiKeyHistory";
const char OLLAMA_BASIC_AUTH_API_KEY[] = "QodeAssist.ollamaBasicAuthApiKey";
const char OLLAMA_BASIC_AUTH_API_KEY_HISTORY[] = "QodeAssist.ollamaBasicAuthApiKeyHistory";
// context settings
const char CC_READ_FULL_FILE[] = "QodeAssist.ccReadFullFile";