The GUI should come up immediately and not wait on deserializing from disk.

This commit is contained in:
Adam Treat 2023-05-06 20:01:14 -04:00
parent eb7b61a76d
commit ab13148430
3 changed files with 89 additions and 37 deletions

View File

@ -7,6 +7,21 @@
#define CHAT_FORMAT_MAGIC 0xF5D553CC #define CHAT_FORMAT_MAGIC 0xF5D553CC
#define CHAT_FORMAT_VERSION 100 #define CHAT_FORMAT_VERSION 100
ChatListModel::ChatListModel(QObject *parent)
: QAbstractListModel(parent)
, m_newChat(nullptr)
, m_dummyChat(nullptr)
, m_currentChat(nullptr)
, m_shouldSaveChats(false)
{
addDummyChat();
ChatsRestoreThread *thread = new ChatsRestoreThread;
connect(thread, &ChatsRestoreThread::chatsRestored, this, &ChatListModel::restoreChats);
connect(thread, &ChatsRestoreThread::finished, thread, &QObject::deleteLater);
thread->start();
}
bool ChatListModel::shouldSaveChats() const bool ChatListModel::shouldSaveChats() const
{ {
return m_shouldSaveChats; return m_shouldSaveChats;
@ -36,6 +51,8 @@ void ChatListModel::saveChats() const
if (!m_shouldSaveChats) if (!m_shouldSaveChats)
return; return;
QElapsedTimer timer;
timer.start();
const QString savePath = Download::globalInstance()->downloadLocalModelsPath(); const QString savePath = Download::globalInstance()->downloadLocalModelsPath();
for (Chat *chat : m_chats) { for (Chat *chat : m_chats) {
QString fileName = "gpt4all-" + chat->id() + ".chat"; QString fileName = "gpt4all-" + chat->id() + ".chat";
@ -58,11 +75,15 @@ void ChatListModel::saveChats() const
} }
file.close(); file.close();
} }
qint64 elapsedTime = timer.elapsed();
qDebug() << "serializing chats took:" << elapsedTime << "ms";
} }
void ChatListModel::restoreChats() void ChatsRestoreThread::run()
{ {
beginResetModel(); QElapsedTimer timer;
timer.start();
QList<Chat*> chats;
{ {
// Look for any files in the original spot which was the settings config directory // Look for any files in the original spot which was the settings config directory
QSettings settings; QSettings settings;
@ -80,13 +101,13 @@ void ChatListModel::restoreChats()
continue; continue;
} }
QDataStream in(&file); QDataStream in(&file);
Chat *chat = new Chat(this); Chat *chat = new Chat;
chat->moveToThread(qApp->thread());
if (!chat->deserialize(in)) { if (!chat->deserialize(in)) {
qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName(); qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName();
file.remove(); file.remove();
} else { } else {
connect(chat, &Chat::nameChanged, this, &ChatListModel::nameChanged); chats.append(chat);
m_chats.append(chat);
} }
qDebug() << "deserializing chat" << f; qDebug() << "deserializing chat" << f;
file.remove(); // No longer storing in this directory file.remove(); // No longer storing in this directory
@ -126,20 +147,51 @@ void ChatListModel::restoreChats()
if (version <= 100) if (version <= 100)
in.setVersion(QDataStream::Qt_6_5); in.setVersion(QDataStream::Qt_6_5);
Chat *chat = new Chat(this); Chat *chat = new Chat;
chat->moveToThread(qApp->thread());
if (!chat->deserialize(in)) { if (!chat->deserialize(in)) {
qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName(); qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName();
file.remove(); file.remove();
} else { } else {
connect(chat, &Chat::nameChanged, this, &ChatListModel::nameChanged); chats.append(chat);
m_chats.append(chat);
} }
qDebug() << "deserializing chat" << f; qDebug() << "deserializing chat" << f;
file.close(); file.close();
} }
} }
std::sort(m_chats.begin(), m_chats.end(), [](const Chat* a, const Chat* b) { std::sort(chats.begin(), chats.end(), [](const Chat* a, const Chat* b) {
return a->creationDate() > b->creationDate(); return a->creationDate() > b->creationDate();
}); });
qint64 elapsedTime = timer.elapsed();
qDebug() << "deserializing chats took:" << elapsedTime << "ms";
emit chatsRestored(chats);
}
void ChatListModel::restoreChats(const QList<Chat*> &chats)
{
for (Chat* chat : chats) {
chat->setParent(this);
connect(chat, &Chat::nameChanged, this, &ChatListModel::nameChanged);
}
beginResetModel();
// Setup the new chats
m_chats = chats;
if (!m_chats.isEmpty()) {
Chat *firstChat = m_chats.first();
if (firstChat->chatModel()->count() < 2)
setNewChat(firstChat);
else
setCurrentChat(firstChat);
} else
addChat();
// Clean up the dummy
delete m_dummyChat;
m_dummyChat = nullptr;
endResetModel(); endResetModel();
} }

View File

@ -4,6 +4,16 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include "chat.h" #include "chat.h"
class ChatsRestoreThread : public QThread
{
Q_OBJECT
public:
void run() override;
Q_SIGNALS:
void chatsRestored(QList<Chat*> chats);
};
class ChatListModel : public QAbstractListModel class ChatListModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
@ -12,13 +22,7 @@ class ChatListModel : public QAbstractListModel
Q_PROPERTY(bool shouldSaveChats READ shouldSaveChats WRITE setShouldSaveChats NOTIFY shouldSaveChatsChanged) Q_PROPERTY(bool shouldSaveChats READ shouldSaveChats WRITE setShouldSaveChats NOTIFY shouldSaveChatsChanged)
public: public:
explicit ChatListModel(QObject *parent = nullptr) explicit ChatListModel(QObject *parent = nullptr);
: QAbstractListModel(parent)
, m_currentChat(nullptr)
, m_newChat(nullptr)
, m_shouldSaveChats(false)
{
}
enum Roles { enum Roles {
IdRole = Qt::UserRole + 1, IdRole = Qt::UserRole + 1,
@ -61,7 +65,7 @@ public:
Q_INVOKABLE void addChat() Q_INVOKABLE void addChat()
{ {
// Don't add a new chat if we already have one // Don't add a new chat if we already have one
if (m_newChat) if (m_newChat || m_dummyChat)
return; return;
// Create a new chat pointer and connect it to determine when it is populated // Create a new chat pointer and connect it to determine when it is populated
@ -78,6 +82,18 @@ public:
setCurrentChat(m_newChat); setCurrentChat(m_newChat);
} }
Q_INVOKABLE void addDummyChat()
{
// Create a new dummy chat pointer and don't connect it
m_dummyChat = new Chat(this);
beginInsertRows(QModelIndex(), 0, 0);
m_chats.prepend(m_dummyChat);
endInsertRows();
emit countChanged();
m_currentChat = m_dummyChat;
emit currentChatChanged();
}
void setNewChat(Chat* chat) void setNewChat(Chat* chat)
{ {
// Don't add a new chat if we already have one // Don't add a new chat if we already have one
@ -101,7 +117,6 @@ public:
removeChatFile(chat); removeChatFile(chat);
emit disconnectChat(chat);
if (chat == m_newChat) { if (chat == m_newChat) {
m_newChat->disconnect(this); m_newChat->disconnect(this);
m_newChat = nullptr; m_newChat = nullptr;
@ -140,13 +155,9 @@ public:
return; return;
} }
if (m_currentChat) { if (m_currentChat && m_currentChat->isModelLoaded())
if (m_currentChat->isModelLoaded())
m_currentChat->unloadModel(); m_currentChat->unloadModel();
emit disconnect(m_currentChat);
}
emit connectChat(chat);
m_currentChat = chat; m_currentChat = chat;
if (!m_currentChat->isModelLoaded()) if (!m_currentChat->isModelLoaded())
m_currentChat->reloadModel(); m_currentChat->reloadModel();
@ -163,12 +174,10 @@ public:
void removeChatFile(Chat *chat) const; void removeChatFile(Chat *chat) const;
void saveChats() const; void saveChats() const;
void restoreChats(); void restoreChats(const QList<Chat*> &chats);
Q_SIGNALS: Q_SIGNALS:
void countChanged(); void countChanged();
void connectChat(Chat*);
void disconnectChat(Chat*);
void currentChatChanged(); void currentChatChanged();
void shouldSaveChatsChanged(); void shouldSaveChatsChanged();
@ -206,6 +215,7 @@ private Q_SLOTS:
private: private:
bool m_shouldSaveChats; bool m_shouldSaveChats;
Chat* m_newChat; Chat* m_newChat;
Chat* m_dummyChat;
Chat* m_currentChat; Chat* m_currentChat;
QList<Chat*> m_chats; QList<Chat*> m_chats;
}; };

10
llm.cpp
View File

@ -24,16 +24,6 @@ LLM::LLM()
{ {
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
this, &LLM::aboutToQuit); this, &LLM::aboutToQuit);
m_chatListModel->restoreChats();
if (m_chatListModel->count()) {
Chat *firstChat = m_chatListModel->get(0);
if (firstChat->chatModel()->count() < 2)
m_chatListModel->setNewChat(firstChat);
else
m_chatListModel->setCurrentChat(firstChat);
} else
m_chatListModel->addChat();
} }
bool LLM::checkForUpdates() const bool LLM::checkForUpdates() const