Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Support data sync #494

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ ipcMain.handle("save-proxy-setting", async (event, args) => {
});
});

ipcMain.handle("save-proxy-and-restart", async () => {
ipcMain.handle("restart-app", async () => {
app.relaunch();
app.exit();
return "";
Expand Down
160 changes: 118 additions & 42 deletions src/components/ChatSetting.vue
qcgm1978 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<v-list-item>
<v-list-item-title>{{ $t("chat.name") }}</v-list-item-title>
<v-btn
color="primary"
variant="outlined"
Expand All @@ -11,69 +12,142 @@
variant="outlined"
:text="$t('chat.downloadAllChatHistory')"
@click="downloadJson"
style="margin-left: 10px"
style="margin: 10px"
></v-btn>
</v-list-item>
<v-list-item>
<v-list-item-title>{{ $t("proxy.fullSet") }}</v-list-item-title>
<v-btn
color="primary"
variant="outlined"
:text="$t('chat.backupToLocal')"
@click="downloadDataJson"
style="margin: 10px 10px 0 0; float: left"
></v-btn>
<!-- <pre v-if="jsonData">{{ jsonData }}</pre> -->
<v-file-input
color="primary"
variant="outlined"
:label="$t('chat.restoreFromLocal')"
@change="readJson"
style="width: 400px"
></v-file-input>
</v-list-item>
<ConfirmModal ref="confirmModal" />
<v-snackbar
v-model="snackbar.show"
:timeout="snackbar.timeout"
:color="snackbar.color"
>
{{ snackbar.text }}
</v-snackbar>
</template>

<script setup>
import { ref } from "vue";
import { ref, reactive } from "vue";
import { useStore } from "vuex";
import i18n from "@/i18n";
const electron = window.require("electron");
const ipcRenderer = electron.ipcRenderer;
import ConfirmModal from "@/components/ConfirmModal.vue";
import bots from "@/bots";

const emit = defineEmits(["close-dialog"]);
const confirmModal = ref();
const store = useStore();
const jsonData = ref(null);
const snackbar = reactive({
show: false,
text: "",
timeout: 1500,
color: "success",
});
const readJson = async (event) => {
const reader = new FileReader();
reader.onload = (evt) => {
const value = JSON.parse(evt.target.result);
jsonData.value = value;
reload(value);
};
reader.readAsText(event.target.files[0]);
};
async function reload(value) {
const load = i18n.global.t("proxy.saveAndApply");
const result = await confirmModal.value.showModal("", `${load}?`);
if (result) {
Object.keys(value).map((d) => (localStorage[d] = value[d]));
await ipcRenderer.invoke("restart-app");
}
}

// This function downloads the chat history as a JSON file.

const downloadJson = () => {
const messages = get_messages();
if (!messages) {
console.error("chatall-messages not found in localStorage");
return;
}

// Create an array of messages from the chat history.
const content = "history";
download_by_link(messages, content);
};
function get_messages() {
// Get the chat history from localStorage.
const chatallMessages = localStorage.getItem("chatall-messages");
if (!chatallMessages) {
console.error("chatall-messages not found in localStorage");
return;
}

const chats = JSON.parse(chatallMessages)?.chats ?? [];

// Create an array of messages from the chat history.
const messages = chats
.filter((d) => !d.hide)
.map((chat) => ({
// The title of the chat.
title: chat.title,
// The messages in the chat.
messages: chat.messages
.filter((d) => !d.hide)
.reduce((arr, message) => {
const t = message.type;
const content = message.content;
if (t == "prompt") {
arr.push({
prompt: content,
responses: [],
});
} else {
const botClassname = message.className;
const bot = bots.getBotByClassName(botClassname);
const botName = bot.getFullname();
arr.at(-1).responses.push({
content,
botName,
botClassname,
botModel: message.model,
highlight: message.highlight,
});
}
return arr;
}, []),
}));

// Create a blob that contains the JSON data.
// The space parameter specifies the indentation of nested objects in the string representation.
const blob = new Blob([JSON.stringify({ chats: messages }, null, 2)], {
try {
// Create an array of messages from the chat history.
const messages = chats
.filter((d) => !d.hide)
.map((chat) => ({
// The title of the chat.
title: chat.title,
// The messages in the chat.
messages: chat.messages
.filter((d) => !d.hide)
.reduce((arr, message) => {
const t = message.type;
const content = message.content;
if (t == "prompt") {
arr.push({
prompt: content,
responses: [],
});
} else {
const botClassname = message.className;
const bot = bots.getBotByClassName(botClassname);
const botName = bot.getFullname();
arr.at(-1).responses.push({
content,
botName,
botClassname,
botModel: message.model,
highlight: message.highlight,
});
}
return arr;
}, []),
}));
return messages;
} catch (e) {
// debugger;
}
}
const downloadDataJson = () => {
const content = "data";
const messages = localStorage;
download_by_link(messages, content);
};
// Create a blob that contains the JSON data.
// The space parameter specifies the indentation of nested objects in the string representation.
function download_by_link(messages, name) {
const blob = new Blob([JSON.stringify(messages, null, 2)], {
// The type of the blob.
type: "application/json",
});
Expand All @@ -88,7 +162,7 @@ const downloadJson = () => {
const hour = String(date.getHours()).padStart(2, "0");
const minute = String(date.getMinutes()).padStart(2, "0");
const second = String(date.getSeconds()).padStart(2, "0");
const fileName = `chatall-history-${year}${month}${day}-${hour}${minute}${second}`;
const fileName = `chatall-${name}-${year}${month}${day}-${hour}${minute}${second}`;

const a = document.createElement("a");
a.href = url;
Expand All @@ -103,7 +177,8 @@ const downloadJson = () => {

// Revoke the URL for the blob.
URL.revokeObjectURL(url);
};
}

async function deleteChats() {
const confirm = await confirmModal.value.showModal(
"",
Expand All @@ -115,3 +190,4 @@ async function deleteChats() {
}
}
</script>
@/utils/storage
2 changes: 1 addition & 1 deletion src/components/ProxySetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ async function saveAndActive() {
);
if (result) {
await onlySave();
await ipcRenderer.invoke("save-proxy-and-restart");
await ipcRenderer.invoke("restart-app");
}
}

Expand Down
6 changes: 1 addition & 5 deletions src/components/SettingsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
<v-tabs v-model="tab" direction="vertical" color="primary">
<v-tab value="general">{{ $t("settings.general") }}</v-tab>
<v-tab value="proxy">{{ $t("proxy.name") }}</v-tab>
<v-tab value="chat">{{ $t("chat.name") }}</v-tab>
<v-tab
v-for="(setting, index) in botSettings"
:key="index"
Expand Down Expand Up @@ -59,16 +58,13 @@
@update:model-value="setCurrentMode($event)"
></v-select>
</v-list-item>
<component :is="chat" @close-dialog="closeDialog"></component>
</div>

<div v-if="tab == 'proxy'">
<component :is="proxy"></component>
</div>

<div v-if="tab == 'chat'">
<component :is="chat" @close-dialog="closeDialog"></component>
</div>

<template v-for="(setting, index) in botSettings" :key="index">
<component
v-if="tab == index"
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
"newChat": "New Chat",
"deleteAllChatHistory": "Delete All Chat History",
"downloadAllChatHistory": "Save All Chat History",
"confirmDeleteAllChatHistory": "Are you sure you want to delete all chat history? This action cannot be undone."
"confirmDeleteAllChatHistory": "Are you sure you want to delete all chat history? This action cannot be undone.",
"backupToLocal": "Backup all data to local",
"restoreFromLocal": "Restore from backup"
},
"bot": {
"creatingConversation": "Creating conversation...",
Expand Down
7 changes: 5 additions & 2 deletions src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
"newChat": "新对话",
"deleteAllChatHistory": "删除所有对话记录",
"downloadAllChatHistory": "保存所有对话记录",
"confirmDeleteAllChatHistory": "你确定要删除所有对话记录吗?此操作无法撤消。"
"confirmDeleteAllChatHistory": "你确定要删除所有对话记录吗?此操作无法撤消。",
"backupToLocal": "备份所有数据到本地",
"restoreFromLocal": "从备份恢复"
},
"bot": {
"creatingConversation": "创建新对话...",
Expand Down Expand Up @@ -253,7 +255,8 @@
"itemsPerPageAll": "全部"
},
"input": {
"clear": "清除"
"clear": "清除",
"prependAction": "预设操作"
qcgm1978 marked this conversation as resolved.
Show resolved Hide resolved
}
},
"10": "10",
Expand Down