Files
z-bar-qt/Plugins/ZShell/Llm/chat.hpp
T

118 lines
3.6 KiB
C++

#pragma once
#include <QByteArray>
#include <QList>
#include <QNetworkAccessManager>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QtQml>
#include <functional>
#include "chatstore.hpp"
class QQmlEngine;
class QJSEngine;
class QNetworkReply;
namespace ZShell {
class Chat : public QObject {
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
Q_PROPERTY(QString endpoint READ endpoint NOTIFY endpointChanged)
Q_PROPERTY(QString model READ model NOTIFY modelChanged)
Q_PROPERTY(QStringList availableModels READ availableModels NOTIFY availableModelsChanged)
Q_PROPERTY(int contextSize READ contextSize NOTIFY contextSizeChanged)
Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
Q_PROPERTY(ChatStore* chats READ chats CONSTANT)
Q_PROPERTY(QString streamingChatId READ streamingChatId NOTIFY streamingChatIdChanged)
public:
explicit Chat(QObject* parent = nullptr);
~Chat();
[[nodiscard]] bool busy() const { return m_busy; }
[[nodiscard]] QString endpoint() const { return m_endpoint; }
[[nodiscard]] QString model() const { return m_model; }
[[nodiscard]] QStringList availableModels() const { return m_availableModels; }
[[nodiscard]] int contextSize() const { return m_contextSize; }
[[nodiscard]] int lastTokenCount() const { return m_lastTokenCount; }
[[nodiscard]] QString lastError() const { return m_lastError; }
[[nodiscard]] ChatStore* chats() const { return m_store; }
[[nodiscard]] QString streamingChatId() const { return m_streamingChatId; }
[[nodiscard]] ChatSession* streamingSession() const { return m_active; }
Q_INVOKABLE void send(const QString& chatId, const QString& content);
Q_INVOKABLE void stop();
Q_INVOKABLE void clearConversation(const QString& chatId);
Q_INVOKABLE void dismissError();
Q_INVOKABLE void refreshModels();
Q_INVOKABLE void selectModel(const QString& id);
static Chat* create(QQmlEngine*, QJSEngine*);
Q_SIGNALS:
void busyChanged();
void endpointChanged();
void modelChanged();
void availableModelsChanged();
void contextSizeChanged();
void errorOccurred(const QString& message);
void lastErrorChanged();
void streamingChatIdChanged();
private:
void beginAssistant();
void endStream();
void finalize();
void fail(const QString& message);
void handleLine(const QByteArray& line);
void drainBuffer();
void probeContextSize();
void setContextSize(int size);
void updateTokenUsage(const QJsonObject& data);
static void trimHistory(ChatSession* session, int contextSize);
void shortRequest(
const QString& tag,
const QString& systemPrompt,
const QString& userText,
std::function<void(QString result)> onResult);
void requestTitle(const QString& chatId, const QString& userText);
void requestIcon(const QString& chatId, const QString& userText);
static QString titleFrom(const QString& content);
static QString completionsPath(const QString& endpoint, const QString& subpath);
static QString serverErrorMessage(
const QByteArray& body, const QString& fallback);
static void setBusy(Chat* chat, bool value);
static void setStreamingChatId(Chat* chat, const QString& id);
QNetworkAccessManager m_manager;
ChatStore* m_store = nullptr;
QNetworkReply* m_reply = nullptr;
QByteArray m_buffer;
ChatSession* m_active = nullptr;
ChatMessage* m_streaming = nullptr;
QString m_pendingClearChatId;
bool m_busy = false;
QString m_endpoint;
QString m_model;
QStringList m_availableModels;
QString m_lastError;
QString m_streamingChatId;
double m_temperature = 0.7;
int m_contextSize = 0;
int m_lastTokenCount = 0;
static Chat* s_instance;
friend class ChatStore;
};
} // namespace ZShell