返回提交历史
Modified
g4f/gui/client/css/style.css
+10
-4
Modified
g4f/gui/client/html/index.html
+5
-6
Modified
g4f/gui/client/js/chat.v1.js
+42
-2
XFEstudio/gpt4free
Add export / import conversations
95b1b8c0
代码差异
3 个文件
+57
-12
@@ -15,7 +15,7 @@
15
15
margin: auto;
16
16
display: flex;
17
17
flex-direction: column;
18
gap: 16px;
18
gap: var(--inner-gap);
19
19
max-width: 200px;
20
20
padding: var(--section-gap);
21
21
overflow: none;
@@ -183,7 +183,8 @@ body {
183
183
.conversations {
184
184
display: flex;
185
185
flex-direction: column;
186
gap: 16px;
186
gap: var(--inner-gap);
187
padding: var(--inner-gap);
187
188
}
188
189
189
190
.conversations .title {
@@ -573,7 +574,7 @@ label[for="camera"] {
573
574
height: fit-content;
574
575
display: flex;
575
576
align-items: center;
576
gap: 16px;
577
gap: var(--inner-gap);
577
578
}
578
579
579
580
.field .about {
@@ -657,10 +658,15 @@ select {
657
658
font-size: 14px;
658
659
}
659
660
661
.bottom_buttons button a {
662
color: var(--colour-3);
663
font-weight: 500;
664
}
665
660
666
.conversations .top {
661
667
display: flex;
662
668
flex-direction: column;
663
gap: 16px;
669
gap: var(--inner-gap);
664
670
overflow: auto;
665
671
}
666
672
@@ -94,11 +94,10 @@
94
94
<i class="fa-regular fa-trash"></i>
95
95
<span>Clear Conversations</span>
96
96
</button>
97
<div class="info">
98
<i class="fa-brands fa-telegram"></i>
99
<span class="convo-title">tele ~ <a href="https://t.me/g4f_official">@g4f_official</a>
100
</span>
101
</div>
97
<button onclick="save_storage()">
98
<i class="fa-solid fa-download"></i>
99
<a href="" onclick="return false;">Export Conversations</a>
100
</button>
102
101
<div class="info">
103
102
<i class="fa-brands fa-github"></i>
104
103
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@gpt4free</a>
@@ -161,7 +160,7 @@
161
160
<option value="gemini-pro">gemini-pro</option>
162
161
<option value="">----</option>
163
162
</select>
164
<select name="model2" id="model2" class="hidden">
163
<select name="model2" id="model2" class="hidden"></select>
165
164
</div>
166
165
<div class="field">
167
166
<select name="jailbreak" id="jailbreak" style="display: none;">
@@ -913,8 +913,21 @@ fileInput.addEventListener('change', async (event) => {
913
913
}
914
914
fileInput.dataset.type = type
915
915
const reader = new FileReader();
916
reader.addEventListener('load', (event) => {
916
reader.addEventListener('load', async (event) => {
917
917
fileInput.dataset.text = event.target.result;
918
if (type == "json") {
919
const data = JSON.parse(event.target.result);
920
if ("g4f" in data.options) {
921
Object.keys(data).forEach(key => {
922
if (key != "options" && !localStorage.getItem(key)) {
923
appStorage.setItem(key, JSON.stringify(data[key]));
924
}
925
});
926
fileInput.value = "";
927
delete fileInput.dataset.text;
928
await load_conversations();
929
}
930
}
918
931
});
919
932
reader.readAsText(fileInput.files[0]);
920
933
} else {
@@ -953,4 +966,31 @@ async function load_provider_models() {
953
966
modelSelect.classList.remove("hidden");
954
967
}
955
968
};
956
providerSelect.addEventListener("change", load_provider_models)
969
providerSelect.addEventListener("change", load_provider_models)
970
971
function save_storage() {
972
let filename = new Date().toLocaleString()
973
filename += ".json"
974
let data = {"options": {"g4f": ""}};
975
for (let i = 0; i < appStorage.length; i++){
976
let key = appStorage.key(i);
977
let item = appStorage.getItem(key);
978
if (key.startsWith("conversation:")) {
979
data[key] = JSON.parse(item);
980
} else {
981
data["options"][key] = item;
982
}
983
}
984
data = JSON.stringify(data, null, 4);
985
const blob = new Blob([data], {type: 'text/csv'});
986
if(window.navigator.msSaveOrOpenBlob) {
987
window.navigator.msSaveBlob(blob, filename);
988
} else{
989
const elem = window.document.createElement('a');
990
elem.href = window.URL.createObjectURL(blob);
991
elem.download = filename;
992
document.body.appendChild(elem);
993
elem.click();
994
document.body.removeChild(elem);
995
}
996
}