fix handling of responses that come in chunks, and non-200 status codes

This commit is contained in:
Jared Van Bortel 2025-02-28 12:32:48 -05:00
parent d20cfbbec9
commit 1ba555a174
2 changed files with 41 additions and 13 deletions

View File

@ -4,7 +4,7 @@
#include <QCoro/QCoroTask> // IWYU pragma: keep #include <QCoro/QCoroTask> // IWYU pragma: keep
#include <boost/json.hpp> // IWYU pragma: keep #include <boost/json.hpp> // IWYU pragma: keep
#include <boost/system.hpp> #include <boost/system.hpp> // IWYU pragma: keep
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
@ -17,27 +17,27 @@
#include <variant> #include <variant>
class QNetworkRequest; class QNetworkRequest;
class QRestReply;
namespace gpt4all::backend { namespace gpt4all::backend {
struct ResponseError { struct ResponseError {
public:
struct BadStatus { int code; };
private: private:
using ErrorCode = std::variant< using ErrorCode = std::variant<
QNetworkReply::NetworkError, QNetworkReply::NetworkError,
boost::system::error_code boost::system::error_code,
BadStatus
>; >;
public: public:
ErrorCode error; ErrorCode error;
QString errorString; QString errorString;
ResponseError(const QNetworkReply *reply) ResponseError(const QRestReply *reply);
: error(reply->error())
, errorString(reply->errorString())
{
assert(reply->error());
}
ResponseError(const boost::system::system_error &e) ResponseError(const boost::system::system_error &e)
: error(e.code()) : error(e.code())

View File

@ -8,6 +8,9 @@
#include <QByteArray> #include <QByteArray>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QRestReply>
#include <QVariant>
#include <QtAssert>
#include <coroutine> #include <coroutine>
#include <expected> #include <expected>
@ -21,6 +24,26 @@ namespace json = boost::json;
namespace gpt4all::backend { namespace gpt4all::backend {
ResponseError::ResponseError(const QRestReply *reply)
{
auto *nr = reply->networkReply();
if (reply->hasError()) {
error = nr->error();
errorString = nr->errorString();
} else if (!reply->isHttpStatusSuccess()) {
auto code = reply->httpStatus();
auto reason = nr->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
error = BadStatus(code);
errorString = u"HTTP %1%2%3 for URL \"%4\""_s.arg(
QString::number(code),
reason.isValid() ? u" "_s : QString(),
reason.toString(),
nr->request().url().toString()
);
} else
Q_UNREACHABLE();
}
QNetworkRequest OllamaClient::makeRequest(const QString &path) const QNetworkRequest OllamaClient::makeRequest(const QString &path) const
{ {
QNetworkRequest req(m_baseUrl.resolved(QUrl(path))); QNetworkRequest req(m_baseUrl.resolved(QUrl(path)));
@ -30,16 +53,21 @@ QNetworkRequest OllamaClient::makeRequest(const QString &path) const
auto OllamaClient::processResponse(QNetworkReply &reply) -> QCoro::Task<DataOrRespErr<json::value>> auto OllamaClient::processResponse(QNetworkReply &reply) -> QCoro::Task<DataOrRespErr<json::value>>
{ {
QRestReply restReply(&reply);
if (reply.error()) if (reply.error())
co_return std::unexpected(&reply); co_return std::unexpected(&restReply);
auto coroReply = qCoro(reply); auto coroReply = qCoro(reply);
do { for (;;) {
auto chunk = co_await coroReply.readAll(); auto chunk = co_await coroReply.readAll();
if (reply.error()) if (!restReply.isSuccess())
co_return std::unexpected(&reply); co_return std::unexpected(&restReply);
if (chunk.isEmpty()) {
Q_ASSERT(reply.atEnd());
break;
}
m_parser.write(chunk.data(), chunk.size()); m_parser.write(chunk.data(), chunk.size());
} while (!reply.atEnd()); }
m_parser.finish(); m_parser.finish();
co_return m_parser.release(); co_return m_parser.release();