diff --git a/static/css/chat.css b/static/css/chat.css
index dcca39c..d91e250 100644
--- a/static/css/chat.css
+++ b/static/css/chat.css
@@ -1011,6 +1011,7 @@ body.loading #version,
#scrolling,
#import,
#export,
+#dump,
#clear,
#upload,
#add,
@@ -1170,6 +1171,7 @@ label[for="reasoning-tokens"] {
#scrolling,
#import,
#export,
+#dump,
#clear {
position: unset !important;
}
@@ -1210,6 +1212,15 @@ label[for="reasoning-tokens"] {
background-image: url(icons/export.svg);
}
+#dump {
+ background-image: url(icons/dump.svg);
+}
+
+#dump.loading {
+ animation: rotating 1.2s linear infinite;
+ background-image: url(icons/spinner.svg);
+}
+
#clear {
background-image: url(icons/trash.svg);
}
diff --git a/static/css/icons/dump.svg b/static/css/icons/dump.svg
new file mode 100644
index 0000000..dec3380
--- /dev/null
+++ b/static/css/icons/dump.svg
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/static/index.html b/static/index.html
index ee43108..84d4f37 100644
--- a/static/index.html
+++ b/static/index.html
@@ -99,6 +99,7 @@
+
diff --git a/static/js/chat.js b/static/js/chat.js
index 44fe6c3..152dc9d 100644
--- a/static/js/chat.js
+++ b/static/js/chat.js
@@ -37,6 +37,7 @@
$scrolling = document.getElementById("scrolling"),
$export = document.getElementById("export"),
$import = document.getElementById("import"),
+ $dump = document.getElementById("dump"),
$clear = document.getElementById("clear"),
$authentication = document.getElementById("authentication"),
$authError = document.getElementById("auth-error"),
@@ -72,6 +73,7 @@
isResizing = false,
scrollResize = false,
isUploading = false,
+ isDumping = false,
totalCost = 0;
function updateTotalCost() {
@@ -1085,15 +1087,7 @@
return true;
}
- function generate(cancel = false, noPush = false) {
- if (abortNow() && cancel) {
- return;
- }
-
- if (autoScrolling) {
- setFollowTail(true);
- }
-
+ function buildRequest(noPush = false) {
let temperature = parseFloat($temperature.value);
if (Number.isNaN(temperature) || temperature < 0 || temperature > 2) {
@@ -1127,11 +1121,7 @@
pushMessage();
}
- const controller = new AbortController();
-
- $chat.classList.add("completing");
-
- const body = {
+ return {
prompt: $prompt.value,
model: $model.value,
temperature: temperature,
@@ -1150,6 +1140,22 @@
},
messages: messages.map(message => message.getData()).filter(Boolean),
};
+ }
+
+ function generate(cancel = false, noPush = false) {
+ if (abortNow() && cancel) {
+ return;
+ }
+
+ if (autoScrolling) {
+ setFollowTail(true);
+ }
+
+ const body = buildRequest(noPush);
+
+ const controller = new AbortController();
+
+ $chat.classList.add("completing");
let message, generationID, stopTimeout;
@@ -1995,6 +2001,42 @@
restore();
});
+ $dump.addEventListener("click", async () => {
+ if (isDumping) {
+ return;
+ }
+
+ isDumping = true;
+
+ $dump.classList.add("loading");
+
+ const body = buildRequest(true);
+
+ try {
+ const response = await fetch("/-/dump", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(body),
+ });
+
+ const json = await response.json();
+
+ if (!response.ok) {
+ throw new Error(json?.error || response.statusText);
+ }
+
+ download("request.json", "application/json", JSON.stringify(json.request, null, 4));
+ } catch (err) {
+ notify(err);
+ }
+
+ $dump.classList.remove("loading");
+
+ isDumping = false;
+ });
+
$scrolling.addEventListener("click", () => {
autoScrolling = !autoScrolling;