mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-23 14:07:58 +00:00
Always save chats to disk, but save them as text by default. This also changes
the UI behavior to always open a 'New Chat' and setting it as current instead of setting a restored chat as current. This improves usability by not requiring the user to wait if they want to immediately start chatting.
This commit is contained in:
parent
aed2068342
commit
908aec27fe
@ -385,7 +385,11 @@ bool Chat::serialize(QDataStream &stream, int version) const
|
||||
stream << m_modelInfo.filename();
|
||||
if (version > 2)
|
||||
stream << m_collections;
|
||||
if (!m_llmodel->serialize(stream, version, true /*serializeKV*/))
|
||||
|
||||
const bool serializeKV = MySettings::globalInstance()->saveChatsContext();
|
||||
if (version > 5)
|
||||
stream << serializeKV;
|
||||
if (!m_llmodel->serialize(stream, version, serializeKV))
|
||||
return false;
|
||||
if (!m_chatModel->serialize(stream, version))
|
||||
return false;
|
||||
@ -413,7 +417,6 @@ bool Chat::deserialize(QDataStream &stream, int version)
|
||||
if (!m_modelInfo.id().isEmpty())
|
||||
emit modelInfoChanged();
|
||||
|
||||
bool deserializeKV = true; // make this a setting
|
||||
bool discardKV = m_modelInfo.id().isEmpty();
|
||||
|
||||
// Prior to version 2 gptj models had a bug that fixed the kv_cache to F32 instead of F16 so
|
||||
@ -425,6 +428,11 @@ bool Chat::deserialize(QDataStream &stream, int version)
|
||||
stream >> m_collections;
|
||||
emit collectionListChanged(m_collections);
|
||||
}
|
||||
|
||||
bool deserializeKV = true;
|
||||
if (version > 5)
|
||||
stream >> deserializeKV;
|
||||
|
||||
m_llmodel->setModelInfo(m_modelInfo);
|
||||
if (!m_llmodel->deserialize(stream, version, deserializeKV, discardKV))
|
||||
return false;
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
}
|
||||
ChatModel *chatModel() { return m_chatModel; }
|
||||
|
||||
bool isNewChat() const { return m_name == tr("New Chat") && !m_chatModel->count(); }
|
||||
|
||||
Q_INVOKABLE void reset();
|
||||
Q_INVOKABLE void processSystemPrompt();
|
||||
Q_INVOKABLE bool isModelLoaded() const;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
#define CHAT_FORMAT_MAGIC 0xF5D553CC
|
||||
#define CHAT_FORMAT_VERSION 5
|
||||
#define CHAT_FORMAT_VERSION 6
|
||||
|
||||
class MyChatListModel: public ChatListModel { };
|
||||
Q_GLOBAL_STATIC(MyChatListModel, chatListModelInstance)
|
||||
@ -17,11 +17,10 @@ ChatListModel *ChatListModel::globalInstance()
|
||||
ChatListModel::ChatListModel()
|
||||
: QAbstractListModel(nullptr)
|
||||
, m_newChat(nullptr)
|
||||
, m_dummyChat(nullptr)
|
||||
, m_serverChat(nullptr)
|
||||
, m_currentChat(nullptr)
|
||||
{
|
||||
addDummyChat();
|
||||
addChat();
|
||||
|
||||
ChatsRestoreThread *thread = new ChatsRestoreThread;
|
||||
connect(thread, &ChatsRestoreThread::chatRestored, this, &ChatListModel::restoreChat);
|
||||
@ -59,10 +58,7 @@ void ChatListModel::saveChats()
|
||||
for (Chat *chat : m_chats) {
|
||||
if (chat == m_serverChat)
|
||||
continue;
|
||||
const bool isChatGPT = chat->modelInfo().isChatGPT;
|
||||
if (!isChatGPT && !MySettings::globalInstance()->saveChats())
|
||||
continue;
|
||||
if (isChatGPT && !MySettings::globalInstance()->saveChatGPTChats())
|
||||
if (chat->isNewChat())
|
||||
continue;
|
||||
toSave.append(chat);
|
||||
}
|
||||
@ -197,47 +193,47 @@ void ChatsRestoreThread::run()
|
||||
});
|
||||
|
||||
for (FileInfo &f : files) {
|
||||
QFile file(f.file);
|
||||
bool success = file.open(QIODevice::ReadOnly);
|
||||
if (!success) {
|
||||
qWarning() << "ERROR: Couldn't restore chat from file:" << file.fileName();
|
||||
QFile file(f.file);
|
||||
bool success = file.open(QIODevice::ReadOnly);
|
||||
if (!success) {
|
||||
qWarning() << "ERROR: Couldn't restore chat from file:" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
QDataStream in(&file);
|
||||
|
||||
qint32 version = 0;
|
||||
if (!f.oldFile) {
|
||||
// Read and check the header
|
||||
quint32 magic;
|
||||
in >> magic;
|
||||
if (magic != CHAT_FORMAT_MAGIC) {
|
||||
qWarning() << "ERROR: Chat file has bad magic:" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
QDataStream in(&file);
|
||||
|
||||
qint32 version = 0;
|
||||
if (!f.oldFile) {
|
||||
// Read and check the header
|
||||
quint32 magic;
|
||||
in >> magic;
|
||||
if (magic != CHAT_FORMAT_MAGIC) {
|
||||
qWarning() << "ERROR: Chat file has bad magic:" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the version
|
||||
in >> version;
|
||||
if (version < 1) {
|
||||
qWarning() << "ERROR: Chat file has non supported version:" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (version <= 1)
|
||||
in.setVersion(QDataStream::Qt_6_2);
|
||||
// Read the version
|
||||
in >> version;
|
||||
if (version < 1) {
|
||||
qWarning() << "ERROR: Chat file has non supported version:" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "deserializing chat" << f.file;
|
||||
if (version <= 1)
|
||||
in.setVersion(QDataStream::Qt_6_2);
|
||||
}
|
||||
|
||||
Chat *chat = new Chat;
|
||||
chat->moveToThread(qApp->thread());
|
||||
if (!chat->deserialize(in, version)) {
|
||||
qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName();
|
||||
} else {
|
||||
emit chatRestored(chat);
|
||||
}
|
||||
if (f.oldFile)
|
||||
file.remove(); // No longer storing in this directory
|
||||
file.close();
|
||||
qDebug() << "deserializing chat" << f.file;
|
||||
|
||||
Chat *chat = new Chat;
|
||||
chat->moveToThread(qApp->thread());
|
||||
if (!chat->deserialize(in, version)) {
|
||||
qWarning() << "ERROR: Couldn't deserialize chat from file:" << file.fileName();
|
||||
} else {
|
||||
emit chatRestored(chat);
|
||||
}
|
||||
if (f.oldFile)
|
||||
file.remove(); // No longer storing in this directory
|
||||
file.close();
|
||||
}
|
||||
|
||||
qint64 elapsedTime = timer.elapsed();
|
||||
@ -249,35 +245,13 @@ void ChatListModel::restoreChat(Chat *chat)
|
||||
chat->setParent(this);
|
||||
connect(chat, &Chat::nameChanged, this, &ChatListModel::nameChanged);
|
||||
|
||||
if (m_dummyChat) {
|
||||
beginResetModel();
|
||||
m_chats = QList<Chat*>({chat});
|
||||
setCurrentChat(chat);
|
||||
delete m_dummyChat;
|
||||
m_dummyChat = nullptr;
|
||||
endResetModel();
|
||||
} else {
|
||||
beginInsertRows(QModelIndex(), m_chats.size(), m_chats.size());
|
||||
m_chats.append(chat);
|
||||
endInsertRows();
|
||||
}
|
||||
beginInsertRows(QModelIndex(), m_chats.size(), m_chats.size());
|
||||
m_chats.append(chat);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void ChatListModel::chatsRestoredFinished()
|
||||
{
|
||||
if (m_dummyChat) {
|
||||
beginResetModel();
|
||||
Chat *dummy = m_dummyChat;
|
||||
m_dummyChat = nullptr;
|
||||
m_chats.clear();
|
||||
addChat();
|
||||
delete dummy;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
if (m_chats.isEmpty())
|
||||
addChat();
|
||||
|
||||
addServerChat();
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
Q_INVOKABLE void addChat()
|
||||
{
|
||||
// Don't add a new chat if we already have one
|
||||
if (m_newChat || m_dummyChat)
|
||||
if (m_newChat)
|
||||
return;
|
||||
|
||||
// Create a new chat pointer and connect it to determine when it is populated
|
||||
@ -101,18 +101,6 @@ public:
|
||||
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();
|
||||
}
|
||||
|
||||
Q_INVOKABLE void addServerChat()
|
||||
{
|
||||
// Create a new dummy chat pointer and don't connect it
|
||||
@ -252,7 +240,6 @@ private Q_SLOTS:
|
||||
|
||||
private:
|
||||
Chat* m_newChat;
|
||||
Chat* m_dummyChat;
|
||||
Chat* m_serverChat;
|
||||
Chat* m_currentChat;
|
||||
QList<Chat*> m_chats;
|
||||
|
@ -10,8 +10,7 @@
|
||||
#include <QUrl>
|
||||
|
||||
static int default_threadCount = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
||||
static bool default_saveChats = false;
|
||||
static bool default_saveChatGPTChats = true;
|
||||
static bool default_saveChatsContext = false;
|
||||
static bool default_serverChat = false;
|
||||
static QString default_userDefaultModel = "Application default";
|
||||
static bool default_forceMetal = false;
|
||||
@ -103,8 +102,7 @@ void MySettings::restoreApplicationDefaults()
|
||||
setFontSize(default_fontSize);
|
||||
setDevice(default_device);
|
||||
setThreadCount(default_threadCount);
|
||||
setSaveChats(default_saveChats);
|
||||
setSaveChatGPTChats(default_saveChatGPTChats);
|
||||
setSaveChatsContext(default_saveChatsContext);
|
||||
setServerChat(default_serverChat);
|
||||
setModelPath(defaultLocalModelsPath());
|
||||
setUserDefaultModel(default_userDefaultModel);
|
||||
@ -397,40 +395,22 @@ void MySettings::setThreadCount(int c)
|
||||
emit threadCountChanged();
|
||||
}
|
||||
|
||||
bool MySettings::saveChats() const
|
||||
bool MySettings::saveChatsContext() const
|
||||
{
|
||||
QSettings setting;
|
||||
setting.sync();
|
||||
return setting.value("saveChats", default_saveChats).toBool();
|
||||
return setting.value("saveChatsContext", default_saveChatsContext).toBool();
|
||||
}
|
||||
|
||||
void MySettings::setSaveChats(bool b)
|
||||
void MySettings::setSaveChatsContext(bool b)
|
||||
{
|
||||
if (saveChats() == b)
|
||||
if (saveChatsContext() == b)
|
||||
return;
|
||||
|
||||
QSettings setting;
|
||||
setting.setValue("saveChats", b);
|
||||
setting.setValue("saveChatsContext", b);
|
||||
setting.sync();
|
||||
emit saveChatsChanged();
|
||||
}
|
||||
|
||||
bool MySettings::saveChatGPTChats() const
|
||||
{
|
||||
QSettings setting;
|
||||
setting.sync();
|
||||
return setting.value("saveChatGPTChats", default_saveChatGPTChats).toBool();
|
||||
}
|
||||
|
||||
void MySettings::setSaveChatGPTChats(bool b)
|
||||
{
|
||||
if (saveChatGPTChats() == b)
|
||||
return;
|
||||
|
||||
QSettings setting;
|
||||
setting.setValue("saveChatGPTChats", b);
|
||||
setting.sync();
|
||||
emit saveChatGPTChatsChanged();
|
||||
emit saveChatsContextChanged();
|
||||
}
|
||||
|
||||
bool MySettings::serverChat() const
|
||||
|
@ -10,8 +10,7 @@ class MySettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int threadCount READ threadCount WRITE setThreadCount NOTIFY threadCountChanged)
|
||||
Q_PROPERTY(bool saveChats READ saveChats WRITE setSaveChats NOTIFY saveChatsChanged)
|
||||
Q_PROPERTY(bool saveChatGPTChats READ saveChatGPTChats WRITE setSaveChatGPTChats NOTIFY saveChatGPTChatsChanged)
|
||||
Q_PROPERTY(bool saveChatsContext READ saveChatsContext WRITE setSaveChatsContext NOTIFY saveChatsContextChanged)
|
||||
Q_PROPERTY(bool serverChat READ serverChat WRITE setServerChat NOTIFY serverChatChanged)
|
||||
Q_PROPERTY(QString modelPath READ modelPath WRITE setModelPath NOTIFY modelPathChanged)
|
||||
Q_PROPERTY(QString userDefaultModel READ userDefaultModel WRITE setUserDefaultModel NOTIFY userDefaultModelChanged)
|
||||
@ -64,10 +63,8 @@ public:
|
||||
// Application settings
|
||||
int threadCount() const;
|
||||
void setThreadCount(int c);
|
||||
bool saveChats() const;
|
||||
void setSaveChats(bool b);
|
||||
bool saveChatGPTChats() const;
|
||||
void setSaveChatGPTChats(bool b);
|
||||
bool saveChatsContext() const;
|
||||
void setSaveChatsContext(bool b);
|
||||
bool serverChat() const;
|
||||
void setServerChat(bool b);
|
||||
QString modelPath() const;
|
||||
@ -122,8 +119,7 @@ Q_SIGNALS:
|
||||
void promptTemplateChanged(const ModelInfo &model);
|
||||
void systemPromptChanged(const ModelInfo &model);
|
||||
void threadCountChanged();
|
||||
void saveChatsChanged();
|
||||
void saveChatGPTChatsChanged();
|
||||
void saveChatsContextChanged();
|
||||
void serverChatChanged();
|
||||
void modelPathChanged();
|
||||
void userDefaultModelChanged();
|
||||
|
@ -317,16 +317,6 @@ void Network::sendNetworkToggled(bool isActive)
|
||||
sendMixpanelEvent("network_toggled", QVector<KeyValue>{kv});
|
||||
}
|
||||
|
||||
void Network::sendSaveChatsToggled(bool isActive)
|
||||
{
|
||||
if (!MySettings::globalInstance()->networkUsageStatsActive())
|
||||
return;
|
||||
KeyValue kv;
|
||||
kv.key = QString("isActive");
|
||||
kv.value = QJsonValue(isActive);
|
||||
sendMixpanelEvent("savechats_toggled", QVector<KeyValue>{kv});
|
||||
}
|
||||
|
||||
void Network::sendNewChat(int count)
|
||||
{
|
||||
if (!MySettings::globalInstance()->networkUsageStatsActive())
|
||||
|
@ -38,7 +38,6 @@ public Q_SLOTS:
|
||||
void sendDownloadFinished(const QString &model, bool success);
|
||||
Q_INVOKABLE void sendSettingsDialog();
|
||||
Q_INVOKABLE void sendNetworkToggled(bool active);
|
||||
Q_INVOKABLE void sendSaveChatsToggled(bool active);
|
||||
Q_INVOKABLE void sendNewChat(int count);
|
||||
Q_INVOKABLE void sendRemoveChat();
|
||||
Q_INVOKABLE void sendRenameChat();
|
||||
|
@ -234,53 +234,35 @@ MySettingsTab {
|
||||
Accessible.description: ToolTip.text
|
||||
}
|
||||
Label {
|
||||
id: saveChatsLabel
|
||||
text: qsTr("Save chats to disk:")
|
||||
id: saveChatsContextLabel
|
||||
text: qsTr("Save chats context to disk:")
|
||||
color: theme.textColor
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
Layout.row: 7
|
||||
Layout.column: 0
|
||||
}
|
||||
MyCheckBox {
|
||||
id: saveChatsBox
|
||||
id: saveChatsContextBox
|
||||
Layout.row: 7
|
||||
Layout.column: 1
|
||||
checked: MySettings.saveChats
|
||||
checked: MySettings.saveChatsContext
|
||||
onClicked: {
|
||||
Network.sendSaveChatsToggled(saveChatsBox.checked);
|
||||
MySettings.saveChats = !MySettings.saveChats
|
||||
MySettings.saveChatsContext = !MySettings.saveChatsContext
|
||||
}
|
||||
ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
Label {
|
||||
id: saveChatGPTChatsLabel
|
||||
text: qsTr("Save ChatGPT chats to disk:")
|
||||
color: theme.textColor
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
Layout.row: 8
|
||||
Layout.column: 0
|
||||
}
|
||||
MyCheckBox {
|
||||
id: saveChatGPTChatsBox
|
||||
Layout.row: 8
|
||||
Layout.column: 1
|
||||
checked: MySettings.saveChatGPTChats
|
||||
onClicked: {
|
||||
MySettings.saveChatGPTChats = !MySettings.saveChatGPTChats
|
||||
}
|
||||
}
|
||||
Label {
|
||||
id: serverChatLabel
|
||||
text: qsTr("Enable API server:")
|
||||
color: theme.textColor
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
Layout.row: 9
|
||||
Layout.row: 8
|
||||
Layout.column: 0
|
||||
}
|
||||
MyCheckBox {
|
||||
id: serverChatBox
|
||||
Layout.row: 9
|
||||
Layout.row: 8
|
||||
Layout.column: 1
|
||||
checked: MySettings.serverChat
|
||||
onClicked: {
|
||||
@ -290,7 +272,7 @@ MySettingsTab {
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
Rectangle {
|
||||
Layout.row: 10
|
||||
Layout.row: 9
|
||||
Layout.column: 0
|
||||
Layout.columnSpan: 3
|
||||
Layout.fillWidth: true
|
||||
|
Loading…
Reference in New Issue
Block a user