diff --git a/index.css b/index.css
index da6acf9e..203fbf61 100644
--- a/index.css
+++ b/index.css
@@ -356,6 +356,14 @@ text.drag {
font-weight: bold;
}
+button.ui-button:disabled {
+ filter: brightness(0.95);
+}
+
+button.ui-button:disabled:hover {
+ cursor: default;
+}
+
.ui-dialog,
#optionsContainer {
user-select: none;
@@ -2378,6 +2386,15 @@ svg.button {
margin-left: 0.25em;
}
+@keyframes clockwiseBorderPulse {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
@media print {
div,
canvas {
diff --git a/index.html b/index.html
index 4c70d664..b2c55863 100644
--- a/index.html
+++ b/index.html
@@ -8065,7 +8065,7 @@
-
+
diff --git a/modules/ui/ai-generator.js b/modules/ui/ai-generator.js
index a0dbc0a6..c28efc8a 100644
--- a/modules/ui/ai-generator.js
+++ b/modules/ui/ai-generator.js
@@ -54,18 +54,24 @@ function geneateWithAi(defaultPrompt, onApply) {
try {
button.disabled = true;
- byId("aiGeneratorResult").disabled = true;
+ const resultArea = byId("aiGeneratorResult");
+ resultArea.value = "";
+ resultArea.disabled = true;
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
- headers: {"Content-Type": "application/json", Authorization: `Bearer ${key}`},
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${key}`
+ },
body: JSON.stringify({
model,
messages: [
{role: "system", content: SYSTEM_MESSAGE},
{role: "user", content: prompt}
],
- temperature: 1.2
+ temperature: 1.2,
+ stream: true // Enable streaming
})
});
@@ -74,9 +80,32 @@ function geneateWithAi(defaultPrompt, onApply) {
throw new Error(json?.error?.message || "Failed to generate");
}
- const {choices} = await response.json();
- const result = choices[0].message.content;
- byId("aiGeneratorResult").value = result;
+ const reader = response.body.getReader();
+ const decoder = new TextDecoder("utf-8");
+ let buffer = "";
+
+ while (true) {
+ const {done, value} = await reader.read();
+ if (done) break;
+
+ buffer += decoder.decode(value, {stream: true});
+ const lines = buffer.split("\n");
+
+ for (let i = 0; i < lines.length - 1; i++) {
+ const line = lines[i].trim();
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
+ try {
+ const jsonData = JSON.parse(line.slice(6));
+ const content = jsonData.choices[0].delta.content;
+ if (content) resultArea.value += content;
+ } catch (jsonError) {
+ console.warn("Failed to parse JSON:", jsonError, "Line:", line);
+ }
+ }
+ }
+
+ buffer = lines[lines.length - 1];
+ }
} catch (error) {
return tip(error.message, true, "error", 4000);
} finally {
diff --git a/versioning.js b/versioning.js
index 71c28183..da0012fb 100644
--- a/versioning.js
+++ b/versioning.js
@@ -1,7 +1,7 @@
"use strict";
// version and caching control
-const version = "1.99.08"; // generator version, update each time
+const version = "1.99.09"; // generator version, update each time
{
document.title += " v" + version;