Move to get models by request to provider

This commit is contained in:
Petr Mironychev 2024-09-01 18:19:37 +02:00
parent 6703a7026d
commit a974b0aa82
7 changed files with 48 additions and 102 deletions

View File

@ -1,6 +1,6 @@
{ {
"Name" : "QodeAssist", "Name" : "QodeAssist",
"Version" : "0.0.7", "Version" : "0.0.8",
"CompatVersion" : "${IDE_VERSION_COMPAT}", "CompatVersion" : "${IDE_VERSION_COMPAT}",
"Vendor" : "Petr Mironychev", "Vendor" : "Petr Mironychev",
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd", "Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",

View File

@ -77,7 +77,7 @@ QodeAssistSettings::QodeAssistSettings()
temperature.setDefaultValue(0.2); temperature.setDefaultValue(0.2);
temperature.setRange(0.0, 10.0); temperature.setRange(0.0, 10.0);
selectModels.m_buttonText = Tr::tr("Select Models"); selectModels.m_buttonText = Tr::tr("Select Model");
ollamaLivetime.setSettingsKey(Constants::OLLAMA_LIVETIME); ollamaLivetime.setSettingsKey(Constants::OLLAMA_LIVETIME);
ollamaLivetime.setLabelText( ollamaLivetime.setLabelText(
@ -145,9 +145,6 @@ QodeAssistSettings::QodeAssistSettings()
frequencyPenalty.setDefaultValue(0.0); frequencyPenalty.setDefaultValue(0.0);
frequencyPenalty.setRange(-2.0, 2.0); frequencyPenalty.setRange(-2.0, 2.0);
providerPaths.setSettingsKey(Constants::PROVIDER_PATHS);
providerPaths.setLabelText(Tr::tr("Provider Paths:"));
startSuggestionTimer.setSettingsKey(Constants::START_SUGGESTION_TIMER); startSuggestionTimer.setSettingsKey(Constants::START_SUGGESTION_TIMER);
startSuggestionTimer.setLabelText(Tr::tr("Start Suggestion Timer:")); startSuggestionTimer.setLabelText(Tr::tr("Start Suggestion Timer:"));
startSuggestionTimer.setRange(10, 10000); startSuggestionTimer.setRange(10, 10000);
@ -219,7 +216,7 @@ QodeAssistSettings::QodeAssistSettings()
enableLogging, enableLogging,
Row{Stretch{1}, resetToDefaults}}}}, Row{Stretch{1}, resetToDefaults}}}},
Group{title(Tr::tr("LLM Providers")), Group{title(Tr::tr("LLM Providers")),
Form{Column{llmProviders, Row{url, endPoint}, providerPaths}}}, Form{Column{llmProviders, Row{url, endPoint}}}},
Group{title(Tr::tr("LLM Model Settings")), Group{title(Tr::tr("LLM Model Settings")),
Form{Column{Row{selectModels, modelName}}}}, Form{Column{Row{selectModels, modelName}}}},
Group{title(Tr::tr("FIM Prompt Settings")), Group{title(Tr::tr("FIM Prompt Settings")),
@ -306,7 +303,7 @@ QStringList QodeAssistSettings::getInstalledModels()
{ {
auto *provider = LLMProvidersManager::instance().getCurrentProvider(); auto *provider = LLMProvidersManager::instance().getCurrentProvider();
if (provider) { if (provider) {
auto env = getEnvironmentWithProviderPaths(); Utils::Environment env = Utils::Environment::systemEnvironment();
return provider->getInstalledModels(env); return provider->getInstalledModels(env);
} }
return {}; return {};
@ -331,16 +328,6 @@ void QodeAssistSettings::showModelSelectionDialog()
} }
} }
Utils::Environment QodeAssistSettings::getEnvironmentWithProviderPaths() const
{
Utils::Environment env = Utils::Environment::systemEnvironment();
const QStringList additionalPaths = providerPaths.volatileValue();
for (const QString &path : additionalPaths) {
env.prependOrSetPath(path);
}
return env;
}
void QodeAssistSettings::resetSettingsToDefaults() void QodeAssistSettings::resetSettingsToDefaults()
{ {
QMessageBox::StandardButton reply; QMessageBox::StandardButton reply;

View File

@ -88,8 +88,6 @@ public:
Utils::BoolAspect useFrequencyPenalty{this}; Utils::BoolAspect useFrequencyPenalty{this};
Utils::DoubleAspect frequencyPenalty{this}; Utils::DoubleAspect frequencyPenalty{this};
Utils::StringListAspect providerPaths{this};
Utils::IntegerAspect startSuggestionTimer{this}; Utils::IntegerAspect startSuggestionTimer{this};
Utils::IntegerAspect maxFileThreshold{this}; Utils::IntegerAspect maxFileThreshold{this};

View File

@ -15,6 +15,7 @@ QodeAssist has been tested with the following language models, all trained for F
Ollama: Ollama:
- [starcoder2](https://ollama.com/library/starcoder2) - [starcoder2](https://ollama.com/library/starcoder2)
- [codellama](https://ollama.com/library/codellama) - [codellama](https://ollama.com/library/codellama)
- DeepSeek-Coder-V2-Lite-Base
LM studio: LM studio:
- [second-state/StarCoder2-7B-GGUF](https://huggingface.co/second-state/StarCoder2-7B-GGUF) - [second-state/StarCoder2-7B-GGUF](https://huggingface.co/second-state/StarCoder2-7B-GGUF)
@ -30,7 +31,7 @@ If you've successfully used a model that's not listed here, please let us know b
- [ ] Add chat functionality - [ ] Add chat functionality
- [ ] Support for more providers and models - [ ] Support for more providers and models
## Installation Plugin ## Plugin installation using Ollama as an example
1. Install QtCreator 14.0 1. Install QtCreator 14.0
2. Install [Ollama](https://ollama.com). Make sure to review the system requirements before installation. 2. Install [Ollama](https://ollama.com). Make sure to review the system requirements before installation.
@ -50,9 +51,8 @@ ollama run starcoder2:7b
1. Open Qt Creator settings 1. Open Qt Creator settings
2. Navigate to the "Qode Assist" tab 2. Navigate to the "Qode Assist" tab
3. Choose your LLM provider (e.g., Ollama) 3. Choose your LLM provider (e.g., Ollama)
- If you haven't added the provider to your system PATH, specify the path to the provider executable in the "Provider Paths" field 4. Select the installed model by the "Select Model" button
4. Select the installed model - For LM Studio you will see current load model
- If you need to enter the model name manually, it indicates that the plugin cannot locate the provider's executable file. However, this doesn't affect the plugin's functionality it will still work correctly. This autoselector input option is provided for your convenience, allowing you to easily select and use different models
5. Choose the prompt template that corresponds to your model 5. Choose the prompt template that corresponds to your model
6. Apply the settings 6. Apply the settings

View File

@ -19,14 +19,15 @@
#include "LMStudioProvider.hpp" #include "LMStudioProvider.hpp"
#include <QEventLoop>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include <QProcess>
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
#include "QodeAssistSettings.hpp" #include "QodeAssistSettings.hpp"
#include "QodeAssistUtils.hpp"
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
@ -113,53 +114,32 @@ bool LMStudioProvider::handleResponse(QNetworkReply *reply, QString &accumulated
QList<QString> LMStudioProvider::getInstalledModels(const Utils::Environment &env) QList<QString> LMStudioProvider::getInstalledModels(const Utils::Environment &env)
{ {
QProcess process; QList<QString> models;
process.setEnvironment(env.toStringList()); QNetworkAccessManager manager;
QString lmsConsoleName; QNetworkRequest request(QUrl(url() + "/v1/models"));
#ifdef Q_OS_WIN
lmsConsoleName = "lms.exe";
#else
lmsConsoleName = "lms";
#endif
auto lmsPath = env.searchInPath(lmsConsoleName).toString();
if (!QFileInfo::exists(lmsPath)) { QNetworkReply *reply = manager.get(request);
qWarning() << "LMS executable not found at" << lmsPath;
return {};
}
process.start(lmsPath, QStringList() << "ls"); QEventLoop loop;
if (!process.waitForStarted()) { QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
qWarning() << "Failed to start LMS process:" << process.errorString(); loop.exec();
return {};
}
if (!process.waitForFinished()) { if (reply->error() == QNetworkReply::NoError) {
qWarning() << "LMS process did not finish:" << process.errorString(); QByteArray responseData = reply->readAll();
return {}; QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
} QJsonObject jsonObject = jsonResponse.object();
QJsonArray modelArray = jsonObject["data"].toArray();
QStringList models; for (const QJsonValue &value : modelArray) {
if (process.exitCode() == 0) { QJsonObject modelObject = value.toObject();
QString output = QString::fromUtf8(process.readAllStandardOutput()); QString modelId = modelObject["id"].toString();
QStringList lines = output.split('\n', Qt::SkipEmptyParts); models.append(modelId);
// Skip the header lines
for (int i = 2; i < lines.size(); ++i) {
QString line = lines[i].trimmed();
if (!line.isEmpty()) {
// The model name is the first column
QString modelName = line.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts)
.first();
models.append(modelName);
}
} }
qDebug() << "Models:" << models;
} else { } else {
// Handle error logMessage(QString("Error fetching models: %1").arg(reply->errorString()));
qWarning() << "Error running 'lms list':" << process.errorString();
} }
reply->deleteLater();
return models; return models;
} }

View File

@ -23,10 +23,11 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include <QProcess> #include <QtCore/qeventloop.h>
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
#include "QodeAssistSettings.hpp" #include "QodeAssistSettings.hpp"
#include "QodeAssistUtils.hpp"
namespace QodeAssist::Providers { namespace QodeAssist::Providers {
@ -96,50 +97,31 @@ bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedRe
QList<QString> OllamaProvider::getInstalledModels(const Utils::Environment &env) QList<QString> OllamaProvider::getInstalledModels(const Utils::Environment &env)
{ {
QProcess process; QList<QString> models;
process.setEnvironment(env.toStringList()); QNetworkAccessManager manager;
QString ollamaConsoleName; QNetworkRequest request(QUrl(url() + "/api/tags"));
#ifdef Q_OS_WIN QNetworkReply *reply = manager.get(request);
ollamaConsoleName = "ollama.exe";
#else
ollamaConsoleName = "ollama";
#endif
auto ollamaPath = env.searchInPath(ollamaConsoleName).toString(); QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if (!QFileInfo::exists(ollamaPath)) { if (reply->error() == QNetworkReply::NoError) {
qWarning() << "Ollama executable not found at" << ollamaPath; QByteArray responseData = reply->readAll();
return {}; QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
} QJsonObject jsonObject = jsonResponse.object();
QJsonArray modelArray = jsonObject["models"].toArray();
process.start(ollamaPath, QStringList() << "list"); for (const QJsonValue &value : modelArray) {
if (!process.waitForStarted()) { QJsonObject modelObject = value.toObject();
qWarning() << "Failed to start Ollama process:" << process.errorString(); QString modelName = modelObject["name"].toString();
return {}; models.append(modelName);
}
if (!process.waitForFinished()) {
qWarning() << "Ollama process did not finish:" << process.errorString();
return {};
}
QStringList models;
if (process.exitCode() == 0) {
QString output = QString::fromUtf8(process.readAllStandardOutput());
QStringList lines = output.split('\n', Qt::SkipEmptyParts);
for (int i = 1; i < lines.size(); ++i) {
QString line = lines[i].trimmed();
if (!line.isEmpty()) {
QString modelName = line.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts)
.first();
models.append(modelName);
}
} }
} else { } else {
qWarning() << "Error running 'ollama list':" << process.errorString(); logMessage(QString("Error fetching models: %1").arg(reply->errorString()));
} }
reply->deleteLater();
return models; return models;
} }

View File

@ -23,7 +23,6 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include <QProcess>
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
#include "QodeAssistSettings.hpp" #include "QodeAssistSettings.hpp"