mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-02-26 08:53:04 -05:00
refactor: Improve http client (#319)
This commit is contained in:
@ -170,28 +170,26 @@ void ConfigurationManager::selectModel()
|
||||
: isQuickRefactor ? m_generalSettings.qrUrl.volatileValue()
|
||||
: m_generalSettings.caUrl.volatileValue();
|
||||
|
||||
auto &targetSettings = isCodeCompletion ? m_generalSettings.ccModel
|
||||
: isPreset1 ? m_generalSettings.ccPreset1Model
|
||||
: isQuickRefactor ? m_generalSettings.qrModel
|
||||
: m_generalSettings.caModel;
|
||||
auto *targetSettings = &(isCodeCompletion ? m_generalSettings.ccModel
|
||||
: isPreset1 ? m_generalSettings.ccPreset1Model
|
||||
: isQuickRefactor ? m_generalSettings.qrModel
|
||||
: m_generalSettings.caModel);
|
||||
|
||||
if (auto provider = m_providersManager.getProviderByName(providerName)) {
|
||||
if (!provider->supportsModelListing()) {
|
||||
m_generalSettings.showModelsNotSupportedDialog(targetSettings);
|
||||
m_generalSettings.showModelsNotSupportedDialog(*targetSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto modelList = provider->getInstalledModels(providerUrl);
|
||||
|
||||
if (modelList.isEmpty()) {
|
||||
m_generalSettings.showModelsNotFoundDialog(targetSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, &m_generalSettings, [this, modelList, &targetSettings]() {
|
||||
m_generalSettings.showSelectionDialog(
|
||||
modelList, targetSettings, Tr::tr("Select LLM Model"), Tr::tr("Models:"));
|
||||
});
|
||||
provider->getInstalledModels(providerUrl)
|
||||
.then(this, [this, targetSettings](const QList<QString> &modelList) {
|
||||
if (modelList.isEmpty()) {
|
||||
m_generalSettings.showModelsNotFoundDialog(*targetSettings);
|
||||
return;
|
||||
}
|
||||
m_generalSettings.showSelectionDialog(
|
||||
modelList, *targetSettings, Tr::tr("Select LLM Model"), Tr::tr("Models:"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QMutexLocker>
|
||||
#include <QUuid>
|
||||
|
||||
#include <Logger.hpp>
|
||||
|
||||
@ -30,9 +29,7 @@ namespace QodeAssist::LLMCore {
|
||||
HttpClient::HttpClient(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_manager(new QNetworkAccessManager(this))
|
||||
{
|
||||
connect(this, &HttpClient::sendRequest, this, &HttpClient::onSendRequest);
|
||||
}
|
||||
{}
|
||||
|
||||
HttpClient::~HttpClient()
|
||||
{
|
||||
@ -44,156 +41,96 @@ HttpClient::~HttpClient()
|
||||
m_activeRequests.clear();
|
||||
}
|
||||
|
||||
void HttpClient::onSendRequest(const HttpRequest &request)
|
||||
QFuture<QByteArray> HttpClient::get(const QNetworkRequest &request)
|
||||
{
|
||||
QJsonDocument doc(request.payload);
|
||||
LOG_MESSAGE(QString("HttpClient: data: %1").arg(doc.toJson(QJsonDocument::Indented)));
|
||||
LOG_MESSAGE(QString("HttpClient: GET %1").arg(request.url().toString()));
|
||||
|
||||
QNetworkReply *reply
|
||||
= m_manager->post(request.networkRequest, doc.toJson(QJsonDocument::Compact));
|
||||
addActiveRequest(reply, request.requestId);
|
||||
auto promise = std::make_shared<QPromise<QByteArray>>();
|
||||
promise->start();
|
||||
|
||||
QNetworkReply *reply = m_manager->get(request);
|
||||
setupNonStreamingReply(reply, promise);
|
||||
|
||||
return promise->future();
|
||||
}
|
||||
|
||||
QFuture<QByteArray> HttpClient::post(const QNetworkRequest &request, const QJsonObject &payload)
|
||||
{
|
||||
QJsonDocument doc(payload);
|
||||
LOG_MESSAGE(QString("HttpClient: POST %1, data: %2")
|
||||
.arg(request.url().toString(), doc.toJson(QJsonDocument::Indented)));
|
||||
|
||||
auto promise = std::make_shared<QPromise<QByteArray>>();
|
||||
promise->start();
|
||||
|
||||
QNetworkReply *reply = m_manager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||
setupNonStreamingReply(reply, promise);
|
||||
|
||||
return promise->future();
|
||||
}
|
||||
|
||||
QFuture<QByteArray> HttpClient::del(const QNetworkRequest &request,
|
||||
std::optional<QJsonObject> payload)
|
||||
{
|
||||
auto promise = std::make_shared<QPromise<QByteArray>>();
|
||||
promise->start();
|
||||
|
||||
QNetworkReply *reply;
|
||||
if (payload) {
|
||||
QJsonDocument doc(*payload);
|
||||
LOG_MESSAGE(QString("HttpClient: DELETE %1, data: %2")
|
||||
.arg(request.url().toString(), doc.toJson(QJsonDocument::Indented)));
|
||||
reply = m_manager->sendCustomRequest(request, "DELETE", doc.toJson(QJsonDocument::Compact));
|
||||
} else {
|
||||
LOG_MESSAGE(QString("HttpClient: DELETE %1").arg(request.url().toString()));
|
||||
reply = m_manager->deleteResource(request);
|
||||
}
|
||||
|
||||
setupNonStreamingReply(reply, promise);
|
||||
|
||||
return promise->future();
|
||||
}
|
||||
|
||||
void HttpClient::setupNonStreamingReply(QNetworkReply *reply,
|
||||
std::shared_ptr<QPromise<QByteArray>> promise)
|
||||
{
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, promise]() {
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QByteArray responseBody = reply->readAll();
|
||||
QNetworkReply::NetworkError networkError = reply->error();
|
||||
QString networkErrorString = reply->errorString();
|
||||
|
||||
reply->disconnect();
|
||||
reply->deleteLater();
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("HttpClient: Non-streaming request - HTTP Status: %1").arg(statusCode));
|
||||
|
||||
bool hasError = (networkError != QNetworkReply::NoError) || (statusCode >= 400);
|
||||
if (hasError) {
|
||||
QString errorMsg = parseErrorFromResponse(statusCode, responseBody, networkErrorString);
|
||||
LOG_MESSAGE(QString("HttpClient: Non-streaming request - Error: %1").arg(errorMsg));
|
||||
promise->setException(
|
||||
std::make_exception_ptr(std::runtime_error(errorMsg.toStdString())));
|
||||
} else {
|
||||
promise->addResult(responseBody);
|
||||
}
|
||||
promise->finish();
|
||||
});
|
||||
}
|
||||
|
||||
void HttpClient::postStreaming(const QString &requestId, const QNetworkRequest &request,
|
||||
const QJsonObject &payload)
|
||||
{
|
||||
QJsonDocument doc(payload);
|
||||
LOG_MESSAGE(QString("HttpClient: POST streaming %1, data: %2")
|
||||
.arg(request.url().toString(), doc.toJson(QJsonDocument::Indented)));
|
||||
|
||||
QNetworkReply *reply = m_manager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||
addActiveRequest(reply, requestId);
|
||||
|
||||
connect(reply, &QNetworkReply::readyRead, this, &HttpClient::onReadyRead);
|
||||
connect(reply, &QNetworkReply::finished, this, &HttpClient::onFinished);
|
||||
}
|
||||
|
||||
void HttpClient::onReadyRead()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
if (!reply || reply->isFinished())
|
||||
return;
|
||||
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (statusCode >= 400) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString requestId;
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
bool found = false;
|
||||
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
|
||||
if (it.value() == reply) {
|
||||
requestId = it.key();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestId.isEmpty())
|
||||
return;
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
if (!data.isEmpty()) {
|
||||
emit dataReceived(requestId, data);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::onFinished()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QByteArray responseBody = reply->readAll();
|
||||
QNetworkReply::NetworkError networkError = reply->error();
|
||||
QString networkErrorString = reply->errorString();
|
||||
|
||||
reply->disconnect();
|
||||
|
||||
QString requestId;
|
||||
bool hasError = false;
|
||||
QString errorMsg;
|
||||
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
bool found = false;
|
||||
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
|
||||
if (it.value() == reply) {
|
||||
requestId = it.key();
|
||||
m_activeRequests.erase(it);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
hasError = (networkError != QNetworkReply::NoError) || (statusCode >= 400);
|
||||
|
||||
if (hasError) {
|
||||
errorMsg = parseErrorFromResponse(statusCode, responseBody, networkErrorString);
|
||||
}
|
||||
|
||||
LOG_MESSAGE(QString("HttpClient: Request %1 - HTTP Status: %2").arg(requestId).arg(statusCode));
|
||||
|
||||
if (!responseBody.isEmpty()) {
|
||||
LOG_MESSAGE(QString("HttpClient: Request %1 - Response body (%2 bytes): %3")
|
||||
.arg(requestId)
|
||||
.arg(responseBody.size())
|
||||
.arg(QString::fromUtf8(responseBody)));
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
LOG_MESSAGE(QString("HttpClient: Request %1 - Error: %2").arg(requestId, errorMsg));
|
||||
}
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requestId.isEmpty()) {
|
||||
emit requestFinished(requestId, !hasError, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
QString HttpClient::addActiveRequest(QNetworkReply *reply, const QString &requestId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_activeRequests[requestId] = reply;
|
||||
LOG_MESSAGE(QString("HttpClient: Added active request: %1").arg(requestId));
|
||||
return requestId;
|
||||
}
|
||||
|
||||
QString HttpClient::parseErrorFromResponse(
|
||||
int statusCode, const QByteArray &responseBody, const QString &networkErrorString)
|
||||
{
|
||||
QString errorMsg;
|
||||
|
||||
if (!responseBody.isEmpty()) {
|
||||
QJsonDocument errorDoc = QJsonDocument::fromJson(responseBody);
|
||||
if (!errorDoc.isNull() && errorDoc.isObject()) {
|
||||
QJsonObject errorObj = errorDoc.object();
|
||||
if (errorObj.contains("error")) {
|
||||
QJsonObject error = errorObj["error"].toObject();
|
||||
QString message = error["message"].toString();
|
||||
QString type = error["type"].toString();
|
||||
QString code = error["code"].toString();
|
||||
|
||||
errorMsg = QString("HTTP %1: %2").arg(statusCode).arg(message);
|
||||
if (!type.isEmpty())
|
||||
errorMsg += QString(" (type: %1)").arg(type);
|
||||
if (!code.isEmpty())
|
||||
errorMsg += QString(" (code: %1)").arg(code);
|
||||
} else {
|
||||
errorMsg = QString("HTTP %1: %2").arg(statusCode).arg(QString::fromUtf8(responseBody));
|
||||
}
|
||||
} else {
|
||||
errorMsg = QString("HTTP %1: %2").arg(statusCode).arg(QString::fromUtf8(responseBody));
|
||||
}
|
||||
} else {
|
||||
errorMsg = QString("HTTP %1: %2").arg(statusCode).arg(networkErrorString);
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
connect(reply, &QNetworkReply::finished, this, &HttpClient::onStreamingFinished);
|
||||
}
|
||||
|
||||
void HttpClient::cancelRequest(const QString &requestId)
|
||||
@ -212,4 +149,128 @@ void HttpClient::cancelRequest(const QString &requestId)
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::onReadyRead()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!reply || reply->isFinished())
|
||||
return;
|
||||
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (statusCode >= 400)
|
||||
return;
|
||||
|
||||
QString requestId = findRequestId(reply);
|
||||
if (requestId.isEmpty())
|
||||
return;
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
if (!data.isEmpty()) {
|
||||
emit dataReceived(requestId, data);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::onStreamingFinished()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QByteArray responseBody = reply->readAll();
|
||||
QNetworkReply::NetworkError networkError = reply->error();
|
||||
QString networkErrorString = reply->errorString();
|
||||
|
||||
reply->disconnect();
|
||||
|
||||
QString requestId;
|
||||
std::optional<QString> error;
|
||||
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
|
||||
if (it.value() == reply) {
|
||||
requestId = it.key();
|
||||
m_activeRequests.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (requestId.isEmpty()) {
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasError = (networkError != QNetworkReply::NoError) || (statusCode >= 400);
|
||||
if (hasError) {
|
||||
error = parseErrorFromResponse(statusCode, responseBody, networkErrorString);
|
||||
}
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("HttpClient: Request %1 - HTTP Status: %2").arg(requestId).arg(statusCode));
|
||||
|
||||
if (!responseBody.isEmpty()) {
|
||||
LOG_MESSAGE(QString("HttpClient: Request %1 - Response body (%2 bytes): %3")
|
||||
.arg(requestId)
|
||||
.arg(responseBody.size())
|
||||
.arg(QString::fromUtf8(responseBody)));
|
||||
}
|
||||
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("HttpClient: Request %1 - Error: %2").arg(requestId, *error));
|
||||
}
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requestId.isEmpty()) {
|
||||
emit requestFinished(requestId, error);
|
||||
}
|
||||
}
|
||||
|
||||
QString HttpClient::findRequestId(QNetworkReply *reply)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
|
||||
if (it.value() == reply)
|
||||
return it.key();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void HttpClient::addActiveRequest(QNetworkReply *reply, const QString &requestId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_activeRequests[requestId] = reply;
|
||||
LOG_MESSAGE(QString("HttpClient: Added active request: %1").arg(requestId));
|
||||
}
|
||||
|
||||
QString HttpClient::parseErrorFromResponse(
|
||||
int statusCode, const QByteArray &responseBody, const QString &networkErrorString)
|
||||
{
|
||||
if (!responseBody.isEmpty()) {
|
||||
QJsonDocument errorDoc = QJsonDocument::fromJson(responseBody);
|
||||
if (!errorDoc.isNull() && errorDoc.isObject()) {
|
||||
QJsonObject errorObj = errorDoc.object();
|
||||
if (errorObj.contains("error")) {
|
||||
QJsonObject error = errorObj["error"].toObject();
|
||||
QString message = error["message"].toString();
|
||||
QString type = error["type"].toString();
|
||||
QString code = error["code"].toString();
|
||||
|
||||
QString errorMsg = QString("HTTP %1: %2").arg(statusCode).arg(message);
|
||||
if (!type.isEmpty())
|
||||
errorMsg += QString(" (type: %1)").arg(type);
|
||||
if (!code.isEmpty())
|
||||
errorMsg += QString(" (code: %1)").arg(code);
|
||||
return errorMsg;
|
||||
}
|
||||
return QString("HTTP %1: %2")
|
||||
.arg(statusCode)
|
||||
.arg(QString::fromUtf8(responseBody));
|
||||
}
|
||||
return QString("HTTP %1: %2").arg(statusCode).arg(QString::fromUtf8(responseBody));
|
||||
}
|
||||
return QString("HTTP %1: %2").arg(statusCode).arg(networkErrorString);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::LLMCore
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2025 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
@ -19,24 +19,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QHash>
|
||||
#include <QJsonObject>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QPromise>
|
||||
|
||||
namespace QodeAssist::LLMCore {
|
||||
|
||||
struct HttpRequest
|
||||
{
|
||||
QNetworkRequest networkRequest;
|
||||
QString requestId;
|
||||
QJsonObject payload;
|
||||
};
|
||||
|
||||
class HttpClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -45,21 +40,33 @@ public:
|
||||
HttpClient(QObject *parent = nullptr);
|
||||
~HttpClient();
|
||||
|
||||
// Non-streaming — return QFuture with full response
|
||||
QFuture<QByteArray> get(const QNetworkRequest &request);
|
||||
QFuture<QByteArray> post(const QNetworkRequest &request, const QJsonObject &payload);
|
||||
QFuture<QByteArray> del(const QNetworkRequest &request,
|
||||
std::optional<QJsonObject> payload = std::nullopt);
|
||||
|
||||
// Streaming — signal-based with requestId
|
||||
void postStreaming(const QString &requestId, const QNetworkRequest &request,
|
||||
const QJsonObject &payload);
|
||||
|
||||
void cancelRequest(const QString &requestId);
|
||||
|
||||
signals:
|
||||
void sendRequest(const QodeAssist::LLMCore::HttpRequest &request);
|
||||
void dataReceived(const QString &requestId, const QByteArray &data);
|
||||
void requestFinished(const QString &requestId, bool success, const QString &error);
|
||||
void requestFinished(const QString &requestId, std::optional<QString> error);
|
||||
|
||||
private slots:
|
||||
void onSendRequest(const QodeAssist::LLMCore::HttpRequest &request);
|
||||
void onReadyRead();
|
||||
void onFinished();
|
||||
void onStreamingFinished();
|
||||
|
||||
private:
|
||||
QString addActiveRequest(QNetworkReply *reply, const QString &requestId);
|
||||
QString parseErrorFromResponse(int statusCode, const QByteArray &responseBody, const QString &networkErrorString);
|
||||
void setupNonStreamingReply(QNetworkReply *reply, std::shared_ptr<QPromise<QByteArray>> promise);
|
||||
|
||||
QString findRequestId(QNetworkReply *reply);
|
||||
void addActiveRequest(QNetworkReply *reply, const QString &requestId);
|
||||
QString parseErrorFromResponse(int statusCode, const QByteArray &responseBody,
|
||||
const QString &networkErrorString);
|
||||
|
||||
QNetworkAccessManager *m_manager;
|
||||
QHash<QString, QNetworkReply *> m_activeRequests;
|
||||
|
||||
@ -19,6 +19,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <QFuture>
|
||||
#include <utils/environment.h>
|
||||
#include <QNetworkRequest>
|
||||
#include <QObject>
|
||||
@ -57,7 +60,7 @@ public:
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
= 0;
|
||||
virtual QList<QString> getInstalledModels(const QString &url) = 0;
|
||||
virtual QFuture<QList<QString>> getInstalledModels(const QString &url) = 0;
|
||||
virtual QList<QString> validateRequest(const QJsonObject &request, TemplateType type) = 0;
|
||||
virtual QString apiKey() const = 0;
|
||||
virtual void prepareNetworkRequest(QNetworkRequest &networkRequest) const = 0;
|
||||
@ -81,7 +84,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data)
|
||||
= 0;
|
||||
virtual void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
= 0;
|
||||
|
||||
signals:
|
||||
|
||||
@ -19,11 +19,9 @@
|
||||
|
||||
#include "ClaudeProvider.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "llmcore/ValidationUtils.hpp"
|
||||
@ -142,11 +140,8 @@ void ClaudeProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> ClaudeProvider::getInstalledModels(const QString &baseUrl)
|
||||
QFuture<QList<QString>> ClaudeProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
QList<QString> models;
|
||||
QNetworkAccessManager manager;
|
||||
|
||||
QUrl url(baseUrl + "/v1/models");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("limit", "1000");
|
||||
@ -160,32 +155,24 @@ QList<QString> ClaudeProvider::getInstalledModels(const QString &baseUrl)
|
||||
request.setRawHeader("x-api-key", apiKey().toUtf8());
|
||||
}
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
|
||||
if (jsonObject.contains("data")) {
|
||||
QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
if (modelObject.contains("id")) {
|
||||
QString modelId = modelObject["id"].toString();
|
||||
models.append(modelId);
|
||||
models.append(modelObject["id"].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching Claude models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching Claude models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> ClaudeProvider::validateRequest(const QJsonObject &request, LLMCore::TemplateType type)
|
||||
@ -240,12 +227,9 @@ void ClaudeProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(QString("ClaudeProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool ClaudeProvider::supportsTools() const
|
||||
@ -289,11 +273,11 @@ void ClaudeProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void ClaudeProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("ClaudeProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("ClaudeProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -65,8 +65,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -19,11 +19,9 @@
|
||||
|
||||
#include "GoogleAIProvider.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QtCore/qurlquery.h>
|
||||
|
||||
#include "llmcore/ValidationUtils.hpp"
|
||||
@ -156,29 +154,17 @@ void GoogleAIProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> GoogleAIProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> GoogleAIProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
QList<QString> models;
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QString("%1/models?key=%2").arg(url, apiKey()));
|
||||
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
|
||||
if (jsonObject.contains("models")) {
|
||||
QJsonArray modelArray = jsonObject["models"].toArray();
|
||||
models.clear();
|
||||
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
if (modelObject.contains("name")) {
|
||||
@ -190,12 +176,11 @@ QList<QString> GoogleAIProvider::getInstalledModels(const QString &url)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching Google AI models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching Google AI models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> GoogleAIProvider::validateRequest(
|
||||
@ -254,13 +239,10 @@ void GoogleAIProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("GoogleAIProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool GoogleAIProvider::supportsTools() const
|
||||
@ -327,11 +309,11 @@ void GoogleAIProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void GoogleAIProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("GoogleAIProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("GoogleAIProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -62,8 +62,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -27,11 +27,9 @@
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -71,35 +69,24 @@ bool LMStudioProvider::supportsModelListing() const
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QString> LMStudioProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> LMStudioProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
QList<QString> models;
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QString("%1%2").arg(url, "/v1/models"));
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
QString modelId = modelObject["id"].toString();
|
||||
models.append(modelId);
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
models.append(modelObject["id"].toString());
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching LMStudio models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching LMStudio models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> LMStudioProvider::validateRequest(
|
||||
@ -149,13 +136,10 @@ void LMStudioProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("LMStudioProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool LMStudioProvider::supportsTools() const
|
||||
@ -195,11 +179,11 @@ void LMStudioProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void LMStudioProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("LMStudioProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("LMStudioProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -61,8 +61,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -26,11 +26,9 @@
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -121,9 +119,9 @@ void LlamaCppProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> LlamaCppProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> LlamaCppProvider::getInstalledModels(const QString &)
|
||||
{
|
||||
return {};
|
||||
return QtFuture::makeReadyFuture(QList<QString>{});
|
||||
}
|
||||
|
||||
QList<QString> LlamaCppProvider::validateRequest(
|
||||
@ -192,13 +190,10 @@ void LlamaCppProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("LlamaCppProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool LlamaCppProvider::supportsTools() const
|
||||
@ -250,11 +245,11 @@ void LlamaCppProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void LlamaCppProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("LlamaCppProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("LlamaCppProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -61,8 +61,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -27,11 +27,9 @@
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -71,43 +69,32 @@ bool MistralAIProvider::supportsModelListing() const
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QString> MistralAIProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> MistralAIProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
QList<QString> models;
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QString("%1/v1/models").arg(url));
|
||||
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (!apiKey().isEmpty()) {
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(apiKey()).toUtf8());
|
||||
}
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
|
||||
if (jsonObject.contains("data") && jsonObject["object"].toString() == "list") {
|
||||
QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
if (modelObject.contains("id")) {
|
||||
QString modelId = modelObject["id"].toString();
|
||||
models.append(modelId);
|
||||
models.append(modelObject["id"].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching Mistral AI models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching Mistral AI models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> MistralAIProvider::validateRequest(
|
||||
@ -170,13 +157,10 @@ void MistralAIProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("MistralAIProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool MistralAIProvider::supportsTools() const
|
||||
@ -216,11 +200,11 @@ void MistralAIProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void MistralAIProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("MistralAIProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("MistralAIProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -61,8 +61,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -22,8 +22,6 @@
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QtCore/qeventloop.h>
|
||||
|
||||
#include "llmcore/ValidationUtils.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
@ -147,35 +145,25 @@ void OllamaProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> OllamaProvider::getInstalledModels(const QString &url)
|
||||
QFuture<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;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
QJsonArray modelArray = jsonObject["models"].toArray();
|
||||
|
||||
for (const QJsonValue &value : modelArray) {
|
||||
QJsonObject modelObject = value.toObject();
|
||||
QString modelName = modelObject["name"].toString();
|
||||
models.append(modelName);
|
||||
models.append(modelObject["name"].toString());
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> OllamaProvider::validateRequest(const QJsonObject &request, LLMCore::TemplateType type)
|
||||
@ -248,12 +236,9 @@ void OllamaProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(QString("OllamaProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool OllamaProvider::supportsTools() const
|
||||
@ -312,11 +297,11 @@ void OllamaProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void OllamaProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("OllamaProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("OllamaProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -63,8 +63,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -122,9 +122,9 @@ void OpenAICompatProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> OpenAICompatProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> OpenAICompatProvider::getInstalledModels(const QString &)
|
||||
{
|
||||
return QStringList();
|
||||
return QtFuture::makeReadyFuture(QList<QString>{});
|
||||
}
|
||||
|
||||
QList<QString> OpenAICompatProvider::validateRequest(
|
||||
@ -178,13 +178,10 @@ void OpenAICompatProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(
|
||||
QString("OpenAICompatProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool OpenAICompatProvider::supportsTools() const
|
||||
@ -224,11 +221,11 @@ void OpenAICompatProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void OpenAICompatProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("OpenAICompatProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("OpenAICompatProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -61,8 +61,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -27,11 +27,9 @@
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -141,26 +139,17 @@ void OpenAIProvider::prepareRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> OpenAIProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> OpenAIProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
QList<QString> models;
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QString("%1/v1/models").arg(url));
|
||||
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (!apiKey().isEmpty()) {
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(apiKey()).toUtf8());
|
||||
}
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
|
||||
if (jsonObject.contains("data")) {
|
||||
QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
@ -176,12 +165,11 @@ QList<QString> OpenAIProvider::getInstalledModels(const QString &url)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching OpenAI models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching OpenAI models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> OpenAIProvider::validateRequest(const QJsonObject &request, LLMCore::TemplateType type)
|
||||
@ -235,12 +223,9 @@ void OpenAIProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
LOG_MESSAGE(QString("OpenAIProvider: Sending request %1 to %2").arg(requestId, url.toString()));
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool OpenAIProvider::supportsTools() const
|
||||
@ -280,11 +265,11 @@ void OpenAIProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void OpenAIProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("OpenAIProvider request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("OpenAIProvider request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -61,8 +61,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -28,11 +28,9 @@
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
@ -158,26 +156,17 @@ void OpenAIResponsesProvider::prepareRequest(
|
||||
request["stream"] = true;
|
||||
}
|
||||
|
||||
QList<QString> OpenAIResponsesProvider::getInstalledModels(const QString &url)
|
||||
QFuture<QList<QString>> OpenAIResponsesProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
QList<QString> models;
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QString("%1/v1/models").arg(url));
|
||||
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (!apiKey().isEmpty()) {
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(apiKey()).toUtf8());
|
||||
}
|
||||
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QByteArray responseData = reply->readAll();
|
||||
const QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||
const QJsonObject jsonObject = jsonResponse.object();
|
||||
return httpClient()->get(request).then([](const QByteArray &data) {
|
||||
QList<QString> models;
|
||||
const QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
|
||||
|
||||
if (jsonObject.contains("data")) {
|
||||
const QJsonArray modelArray = jsonObject["data"].toArray();
|
||||
@ -200,12 +189,11 @@ QList<QString> OpenAIResponsesProvider::getInstalledModels(const QString &url)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_MESSAGE(QString("Error fetching OpenAI models: %1").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return models;
|
||||
return models;
|
||||
}).onFailed([](const std::exception &e) {
|
||||
LOG_MESSAGE(QString("Error fetching OpenAI models: %1").arg(e.what()));
|
||||
return QList<QString>{};
|
||||
});
|
||||
}
|
||||
|
||||
QList<QString> OpenAIResponsesProvider::validateRequest(
|
||||
@ -280,10 +268,7 @@ void OpenAIResponsesProvider::sendRequest(
|
||||
QNetworkRequest networkRequest(url);
|
||||
prepareNetworkRequest(networkRequest);
|
||||
|
||||
LLMCore::HttpRequest
|
||||
request{.networkRequest = networkRequest, .requestId = requestId, .payload = payload};
|
||||
|
||||
emit httpClient()->sendRequest(request);
|
||||
httpClient()->postStreaming(requestId, networkRequest, payload);
|
||||
}
|
||||
|
||||
bool OpenAIResponsesProvider::supportsTools() const
|
||||
@ -344,11 +329,11 @@ void OpenAIResponsesProvider::onDataReceived(
|
||||
}
|
||||
|
||||
void OpenAIResponsesProvider::onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId, bool success, const QString &error)
|
||||
const QodeAssist::LLMCore::RequestID &requestId, std::optional<QString> error)
|
||||
{
|
||||
if (!success) {
|
||||
LOG_MESSAGE(QString("OpenAIResponses request %1 failed: %2").arg(requestId, error));
|
||||
emit requestFailed(requestId, error);
|
||||
if (error) {
|
||||
LOG_MESSAGE(QString("OpenAIResponses request %1 failed: %2").arg(requestId, *error));
|
||||
emit requestFailed(requestId, *error);
|
||||
cleanupRequest(requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QList<QString> getInstalledModels(const QString &url) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
QList<QString> validateRequest(const QJsonObject &request, LLMCore::TemplateType type) override;
|
||||
QString apiKey() const override;
|
||||
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
|
||||
@ -62,8 +62,7 @@ public slots:
|
||||
const QodeAssist::LLMCore::RequestID &requestId, const QByteArray &data) override;
|
||||
void onRequestFinished(
|
||||
const QodeAssist::LLMCore::RequestID &requestId,
|
||||
bool success,
|
||||
const QString &error) override;
|
||||
std::optional<QString> error) override;
|
||||
|
||||
private slots:
|
||||
void onToolExecutionComplete(
|
||||
|
||||
@ -80,7 +80,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QString> getInstalledModels(const QString &url) override { return {}; }
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &) override
|
||||
{
|
||||
return QtFuture::makeReadyFuture(QList<QString>{});
|
||||
}
|
||||
|
||||
QStringList validateRequest(
|
||||
const QJsonObject &request, LLMCore::TemplateType templateType) override
|
||||
|
||||
Reference in New Issue
Block a user