From 2ee757b64a9e5c73da5cc2a373bcabf60b228567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=A7=CE=B3=CF=86=CF=84=20Kompanion?= Date: Sun, 19 Oct 2025 08:33:27 +0200 Subject: [PATCH] ki: implement multi-text embeddings in OllamaProvider::embed by batching one request per text and aggregating results --- src/KI/Provider/OllamaProvider.cpp | 68 +++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/KI/Provider/OllamaProvider.cpp b/src/KI/Provider/OllamaProvider.cpp index 721ba0a..ce0ebfd 100644 --- a/src/KI/Provider/OllamaProvider.cpp +++ b/src/KI/Provider/OllamaProvider.cpp @@ -108,43 +108,43 @@ QFuture OllamaProvider::chat(const KIThread& thread, const KIChatOptio QFuture OllamaProvider::embed(const QStringList& texts, const KIEmbedOptions& opts) { - QNetworkRequest req{QUrl(QStringLiteral("http://localhost:11434/api/embeddings"))}; - req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json")); + // Execute one request per input text; aggregate outputs. + QFutureInterface fi; + fi.reportStarted(); + if (texts.isEmpty()) { KIEmbeddingResult r; r.model = opts.model; fi.reportResult(r); fi.reportFinished(); return fi.future(); } - QJsonObject data; - data["model"] = opts.model; - data["prompt"] = texts.join("\n"); // Join all texts into a single prompt + struct Accum { QVector> vectors; int remaining = 0; QString model; }; + auto acc = new Accum(); + acc->vectors.resize(texts.size()); + acc->remaining = texts.size(); - auto netReply = m_manager->post(req, QJsonDocument(data).toJson()); + const QUrl url(QStringLiteral("http://localhost:11434/api/embeddings")); + for (int i = 0; i < texts.size(); ++i) { + QNetworkRequest req{url}; + req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json")); + const QJsonObject body{ {QStringLiteral("model"), opts.model}, {QStringLiteral("prompt"), texts[i]} }; + auto rep = m_manager->post(req, QJsonDocument(body).toJson()); + connect(rep, &QNetworkReply::finished, this, [rep, i, acc, fi]() mutable { + if (rep->error() == QNetworkReply::NoError) { + const auto obj = QJsonDocument::fromJson(rep->readAll()).object(); + if (acc->model.isEmpty()) acc->model = obj.value(QStringLiteral("model")).toString(); + const auto arr = obj.value(QStringLiteral("embedding")).toArray(); + QVector vec; vec.reserve(arr.size()); + for (const auto &v : arr) vec.push_back(static_cast(v.toDouble())); + acc->vectors[i] = std::move(vec); + } + rep->deleteLater(); + acc->remaining -= 1; + if (acc->remaining == 0) { + KIEmbeddingResult res; res.vectors = std::move(acc->vectors); res.model = acc->model; + fi.reportResult(res); + fi.reportFinished(); + delete acc; + } + }); + } - QFutureInterface interface; - interface.reportStarted(); - - connect(netReply, &QNetworkReply::finished, this, [netReply, interface]() mutable { - if (netReply->error() != QNetworkReply::NoError) { - // TODO: Handle error - interface.reportFinished(); - netReply->deleteLater(); - return; - } - - const auto json = QJsonDocument::fromJson(netReply->readAll()); - const auto embeddingArray = json["embedding"].toArray(); - - KIEmbeddingResult result; - QVector embedding; - for (const QJsonValue &value : embeddingArray) { - embedding.push_back(value.toDouble()); - } - result.vectors.push_back(embedding); - result.model = json["model"].toString(); - - interface.reportResult(result); - interface.reportFinished(); - netReply->deleteLater(); - }); - - return interface.future(); + return fi.future(); } void OllamaProvider::cancel(quint64 requestId)