diff --git a/py/api/__init__.py b/py/api/__init__.py
index 2495df7..457565d 100644
--- a/py/api/__init__.py
+++ b/py/api/__init__.py
@@ -199,8 +199,9 @@ class PromptManagerAPI(
)
except Exception as e:
+ self.logger.exception("Failed to load web UI")
return web.Response(
- text=f"
Error
Failed to load web UI: {str(e)}
",
+ text="Error
Failed to load web UI. Check server logs for details.
",
content_type="text/html",
status=500,
)
@@ -232,8 +233,9 @@ class PromptManagerAPI(
)
except Exception as e:
+ self.logger.exception("Failed to load gallery")
return web.Response(
- text=f"Error
Failed to load gallery: {str(e)}
",
+ text="Error
Failed to load gallery. Check server logs for details.
",
content_type="text/html",
status=500,
)
@@ -265,8 +267,9 @@ class PromptManagerAPI(
)
except Exception as e:
+ self.logger.exception("Failed to load admin UI")
return web.Response(
- text=f"Error
Failed to load admin UI: {str(e)}
",
+ text="Error
Failed to load admin UI. Check server logs for details.
",
content_type="text/html",
status=500,
)
@@ -298,8 +301,9 @@ class PromptManagerAPI(
)
except Exception as e:
+ self.logger.exception("Failed to load gallery")
return web.Response(
- text=f"Error
Failed to load gallery: {str(e)}
",
+ text="Error
Failed to load gallery. Check server logs for details.
",
content_type="text/html",
status=500,
)
diff --git a/py/api/admin.py b/py/api/admin.py
index 09de150..f96d9c3 100644
--- a/py/api/admin.py
+++ b/py/api/admin.py
@@ -1116,9 +1116,8 @@ class AdminRoutesMixin:
yield f"data: {json.dumps({'type': 'complete', 'processed': processed_count, 'found': found_count, 'added': added_count, 'linked': linked_count})}\n\n"
except Exception as e:
- self.logger.error(f"Scan error: {e}")
- self.logger.error(f"Scan error traceback: {traceback.format_exc()}")
- yield f"data: {json.dumps({'type': 'error', 'message': str(e)})}\n\n"
+ self.logger.exception("Scan error")
+ yield f"data: {json.dumps({'type': 'error', 'message': 'An internal error occurred. Check server logs for details.'})}\n\n"
response = web.StreamResponse(
status=200,
diff --git a/py/api/autotag_routes.py b/py/api/autotag_routes.py
index 2864570..5b95679 100644
--- a/py/api/autotag_routes.py
+++ b/py/api/autotag_routes.py
@@ -93,8 +93,8 @@ class AutotagRoutesMixin:
yield f"data: {json.dumps({'type': 'error', 'message': 'Download failed'})}\n\n"
except Exception as e:
- self.logger.error(f"Download model error: {e}")
- yield f"data: {json.dumps({'type': 'error', 'message': str(e)})}\n\n"
+ self.logger.exception("Download model error")
+ yield f"data: {json.dumps({'type': 'error', 'message': 'An internal error occurred. Check server logs for details.'})}\n\n"
response = web.StreamResponse(
status=200,
@@ -274,8 +274,8 @@ class AutotagRoutesMixin:
self.logger.error(f"AutoTag error: {e}")
import traceback
- self.logger.error(f"AutoTag traceback: {traceback.format_exc()}")
- yield f"data: {json.dumps({'type': 'error', 'message': str(e)})}\n\n"
+ self.logger.exception("AutoTag error")
+ yield f"data: {json.dumps({'type': 'error', 'message': 'An internal error occurred. Check server logs for details.'})}\n\n"
response = web.StreamResponse(
status=200,
diff --git a/py/api/images.py b/py/api/images.py
index 599acaf..2c2da5b 100644
--- a/py/api/images.py
+++ b/py/api/images.py
@@ -817,11 +817,12 @@ class ImageRoutesMixin:
)
except Exception as e:
+ self.logger.exception("Thumbnail generation failed")
await send_progress(
"error",
{
- "error": str(e),
- "message": f"Thumbnail generation failed: {str(e)}",
+ "error": "An internal error occurred",
+ "message": "Thumbnail generation failed. Check server logs for details.",
},
)
diff --git a/web/js/admin.js b/web/js/admin.js
index 11f0b5e..60106e3 100644
--- a/web/js/admin.js
+++ b/web/js/admin.js
@@ -2539,19 +2539,28 @@ Seed: ${this.currentMetadata.seed || 'Unknown'}`;
showFullPrompt(type) {
if (!this.currentMetadata) return;
-
+
const prompt = type === 'positive' ? this.currentMetadata.positivePrompt : this.currentMetadata.negativePrompt;
+ const safePrompt = this.escapeHtml(prompt);
+ const safeType = this.escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
const newWindow = window.open('', '_blank');
- newWindow.document.write(`
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
- ${prompt}
-
-
-
- `);
+ const doc = newWindow.document;
+ doc.open();
+ doc.write('' + safeType + ' Prompt');
+ doc.close();
+ doc.body.style.cssText = 'background:#111;color:#fff;font-family:monospace;padding:20px;';
+ const h2 = doc.createElement('h2');
+ h2.textContent = type.charAt(0).toUpperCase() + type.slice(1) + ' Prompt';
+ doc.body.appendChild(h2);
+ const pre = doc.createElement('pre');
+ pre.style.cssText = 'background:#222;padding:15px;border-radius:5px;white-space:pre-wrap;line-height:1.5;';
+ pre.textContent = prompt;
+ doc.body.appendChild(pre);
+ const btn = doc.createElement('button');
+ btn.textContent = 'Copy to Clipboard';
+ btn.style.cssText = 'margin-top:20px;padding:10px 20px;background:#444;color:#fff;border:none;border-radius:5px;cursor:pointer;';
+ btn.addEventListener('click', () => { navigator.clipboard.writeText(pre.textContent).then(() => alert('Copied!')); });
+ doc.body.appendChild(btn);
}
showWorkflowData() {
@@ -3182,17 +3191,25 @@ Seed: ${this.currentMetadata.seed || 'Unknown'}`;
showFullPrompt(type) {
if (this.currentMetadata) {
const prompt = type === 'positive' ? this.currentMetadata.positivePrompt : this.currentMetadata.negativePrompt;
+ const safeType = this.escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
const newWindow = window.open('', '_blank');
- newWindow.document.write(`
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
- ${prompt}
-
-
-
- `);
+ const doc = newWindow.document;
+ doc.open();
+ doc.write('' + safeType + ' Prompt');
+ doc.close();
+ doc.body.style.cssText = 'background:#111;color:#fff;font-family:monospace;padding:20px;';
+ const h2 = doc.createElement('h2');
+ h2.textContent = type.charAt(0).toUpperCase() + type.slice(1) + ' Prompt';
+ doc.body.appendChild(h2);
+ const pre = doc.createElement('pre');
+ pre.style.cssText = 'background:#222;padding:15px;border-radius:5px;white-space:pre-wrap;line-height:1.5;';
+ pre.textContent = prompt;
+ doc.body.appendChild(pre);
+ const btn = doc.createElement('button');
+ btn.textContent = 'Copy to Clipboard';
+ btn.style.cssText = 'margin-top:20px;padding:10px 20px;background:#444;color:#fff;border:none;border-radius:5px;cursor:pointer;';
+ btn.addEventListener('click', () => { navigator.clipboard.writeText(pre.textContent).then(() => alert('Copied!')); });
+ doc.body.appendChild(btn);
}
}
diff --git a/web/js/gallery.js b/web/js/gallery.js
index 0d4e54b..2f6d0cf 100644
--- a/web/js/gallery.js
+++ b/web/js/gallery.js
@@ -1197,17 +1197,25 @@
showFullPrompt(type) {
if (this.currentMetadata) {
const prompt = type === 'positive' ? this.currentMetadata.positivePrompt : this.currentMetadata.negativePrompt;
+ const safeType = this.escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
const newWindow = window.open('', '_blank');
- newWindow.document.write(`
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
- ${prompt}
-
-
-
- `);
+ const doc = newWindow.document;
+ doc.open();
+ doc.write('' + safeType + ' Prompt');
+ doc.close();
+ doc.body.style.cssText = 'background:#111;color:#fff;font-family:monospace;padding:20px;';
+ const h2 = doc.createElement('h2');
+ h2.textContent = type.charAt(0).toUpperCase() + type.slice(1) + ' Prompt';
+ doc.body.appendChild(h2);
+ const pre = doc.createElement('pre');
+ pre.style.cssText = 'background:#222;padding:15px;border-radius:5px;white-space:pre-wrap;line-height:1.5;';
+ pre.textContent = prompt;
+ doc.body.appendChild(pre);
+ const btn = doc.createElement('button');
+ btn.textContent = 'Copy to Clipboard';
+ btn.style.cssText = 'margin-top:20px;padding:10px 20px;background:#444;color:#fff;border:none;border-radius:5px;cursor:pointer;';
+ btn.addEventListener('click', () => { navigator.clipboard.writeText(pre.textContent).then(() => alert('Copied!')); });
+ doc.body.appendChild(btn);
}
}
diff --git a/web/metadata.html b/web/metadata.html
index 294d578..930a65e 100644
--- a/web/metadata.html
+++ b/web/metadata.html
@@ -477,20 +477,34 @@ Seed: ${currentWorkflowData.seed || 'Unknown'}`;
};
}
+ function escapeHtml(text) {
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+ }
+
function showFullPrompt(type) {
if (currentWorkflowData) {
const prompt = type === 'positive' ? currentWorkflowData.positivePrompt : currentWorkflowData.negativePrompt;
+ const safeType = escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
const newWindow = window.open('', '_blank');
- newWindow.document.write(`
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
-
- ${type.charAt(0).toUpperCase() + type.slice(1)} Prompt
- ${prompt}
-
-
-
- `);
+ const doc = newWindow.document;
+ doc.open();
+ doc.write('' + safeType + ' Prompt');
+ doc.close();
+ doc.body.style.cssText = 'background:#111;color:#fff;font-family:monospace;padding:20px;';
+ const h2 = doc.createElement('h2');
+ h2.textContent = type.charAt(0).toUpperCase() + type.slice(1) + ' Prompt';
+ doc.body.appendChild(h2);
+ const pre = doc.createElement('pre');
+ pre.style.cssText = 'background:#222;padding:15px;border-radius:5px;white-space:pre-wrap;line-height:1.5;';
+ pre.textContent = prompt;
+ doc.body.appendChild(pre);
+ const btn = doc.createElement('button');
+ btn.textContent = 'Copy to Clipboard';
+ btn.style.cssText = 'margin-top:20px;padding:10px 20px;background:#444;color:#fff;border:none;border-radius:5px;cursor:pointer;';
+ btn.addEventListener('click', function() { navigator.clipboard.writeText(pre.textContent).then(function() { alert('Copied!'); }); });
+ doc.body.appendChild(btn);
}
}