#include "session.hpp" #include #include #include #include #include namespace ZShell { ChatSession::ChatSession(const QString& id, QObject* parent) : QObject(parent), m_id(id) { } void ChatSession::setTitle(const QString& value) { if (m_title == value) return; m_title = value; Q_EMIT titleChanged(); } void ChatSession::setUpdatedAt(qint64 value) { if (m_updatedAt == value) return; m_updatedAt = value; Q_EMIT updatedAtChanged(); } void ChatSession::setCount(int value) { if (m_messageCount == value) return; m_messageCount = value; Q_EMIT messageCountChanged(); } void ChatSession::setMeta( const QString& title, qint64 createdAt, qint64 updatedAt, int messageCount) { m_title = title; m_createdAt = createdAt; m_updatedAt = updatedAt; m_messageCount = messageCount; } void ChatSession::ensureLoaded() { if (m_loaded || m_path.isEmpty()) return; m_loaded = true; loadMessages(); } void ChatSession::loadMessages() { QFile file(m_path); if (file.open(QIODevice::ReadOnly)) { const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); file.close(); if (doc.isObject()) { const QJsonObject obj = doc.object(); m_title = obj["title"].toString(m_title); m_createdAt = obj["createdAt"].toVariant().toLongLong() || m_createdAt; m_updatedAt = obj["updatedAt"].toVariant().toLongLong() || m_updatedAt; for (const QJsonValue& value : obj["messages"].toArray()) { const QJsonObject msg = value.toObject(); const QString content = msg["content"].toString(); const QString reasoning = msg["reasoning"].toString(); if (content.isEmpty() && reasoning.isEmpty()) continue; auto* message = new ChatMessage( msg["role"].toString() == "user" ? ChatMessage::Role::User : ChatMessage::Role::Assistant, content, msg["timestamp"].toVariant().toLongLong(), this); message->setReasoning(reasoning); message->setElapsedMs( msg["reasoningElapsedMs"].toVariant().toLongLong(), msg["contentElapsedMs"].toVariant().toLongLong()); m_messages.append(message); } } } else { qWarning() << "ChatSession: failed to load" << m_path << ":" << file.errorString(); } setCount(int(m_messages.size())); Q_EMIT titleChanged(); Q_EMIT messagesChanged(); } ChatMessage* ChatSession::appendMessage( ChatMessage::Role role, const QString& content, qint64 timestamp) { ensureLoaded(); auto* message = new ChatMessage(role, content, timestamp, this); m_messages.append(message); setCount(int(m_messages.size())); Q_EMIT messagesChanged(); return message; } void ChatSession::removeMessage(ChatMessage* message) { if (!message || !m_messages.removeOne(message)) return; delete message; setCount(int(m_messages.size())); Q_EMIT messagesChanged(); } void ChatSession::clearMessages() { ensureLoaded(); if (m_messages.isEmpty()) return; qDeleteAll(m_messages); m_messages.clear(); setCount(0); Q_EMIT messagesChanged(); } QJsonObject ChatSession::document() { ensureLoaded(); QJsonArray arr; for (const auto* message : m_messages) { QJsonObject messageObj; messageObj[QStringLiteral("role")] = message->role() == ChatMessage::Role::User ? QStringLiteral("user") : QStringLiteral("assistant"); messageObj[QStringLiteral("content")] = message->content(); if (!message->reasoning().isEmpty()) messageObj[QStringLiteral("reasoning")] = message->reasoning(); const qint64 reasoningMs = message->reasoningElapsedMs(); if (reasoningMs > 0) messageObj[QStringLiteral("reasoningElapsedMs")] = reasoningMs; const qint64 contentMs = message->contentElapsedMs(); if (contentMs > 0) messageObj[QStringLiteral("contentElapsedMs")] = contentMs; messageObj[QStringLiteral("timestamp")] = message->timestamp(); arr.append(messageObj); } QJsonObject doc; doc[QStringLiteral("id")] = m_id; doc[QStringLiteral("title")] = m_title; doc[QStringLiteral("createdAt")] = m_createdAt; doc[QStringLiteral("updatedAt")] = m_updatedAt; doc[QStringLiteral("messages")] = arr; return doc; } } // namespace ZShell