Spaces:
Sleeping
Sleeping
Commit ·
350eca4
1
Parent(s): 78c1ba6
Inject JS via gr.Blocks(js=) instead of inline script tags
Browse filesGradio strips script tags from gr.HTML for security. Move all
JS to the js= parameter and CSS to css= parameter on Blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
app.py
CHANGED
|
@@ -252,29 +252,29 @@ CUSTOM_HTML = """
|
|
| 252 |
</div>
|
| 253 |
</div>
|
| 254 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
<style>
|
| 259 |
-
#explorer-app { font-family: var(--font-family, 'Inter', system-ui, sans-serif); max-width: 800px; margin: 0 auto; }
|
| 260 |
-
#setup-panel { padding: 24px 0; }
|
| 261 |
-
.setup-field { margin-bottom: 16px; }
|
| 262 |
-
.setup-field label { display: block; font-size: 13px; color: #6B7280; margin-bottom: 4px; }
|
| 263 |
-
#token-input { width: 100%; padding: 8px 12px; border: 1px solid #E5E7EB; border-radius: 4px; font-family: inherit; font-size: 14px; }
|
| 264 |
-
#token-input:focus { outline: none; border-color: #4682B4; }
|
| 265 |
-
.drop-zone { border: 2px dashed #E5E7EB; border-radius: 8px; padding: 32px; text-align: center; color: #9CA3AF; cursor: pointer; transition: border-color 0.2s; }
|
| 266 |
-
.drop-zone.drag-over { border-color: #4682B4; background: #f0f7ff; }
|
| 267 |
-
.drop-zone p { margin: 0; }
|
| 268 |
-
.file-label { color: #4682B4; cursor: pointer; text-decoration: underline; }
|
| 269 |
-
#file-list { margin-top: 8px; font-size: 13px; color: #374151; text-align: left; }
|
| 270 |
-
#file-list div { padding: 2px 0; }
|
| 271 |
-
#start-btn { width: 100%; padding: 10px; background: #4682B4; color: white; border: none; border-radius: 4px; font-family: inherit; font-size: 14px; cursor: pointer; margin-top: 8px; }
|
| 272 |
-
#start-btn:disabled { background: #D1D5DB; cursor: default; }
|
| 273 |
-
#start-btn:not(:disabled):hover { background: #3a6f9a; }
|
| 274 |
-
#chat-panel { padding-top: 8px; }
|
| 275 |
-
</style>
|
| 276 |
-
<script>
|
| 277 |
-
(function() {
|
| 278 |
var API_BASE = window.location.origin;
|
| 279 |
var tokenInput = document.getElementById('token-input');
|
| 280 |
var fileInput = document.getElementById('file-input');
|
|
@@ -320,7 +320,6 @@ CUSTOM_HTML = """
|
|
| 320 |
startBtn.disabled = true;
|
| 321 |
startBtn.textContent = 'Uploading...';
|
| 322 |
|
| 323 |
-
// Step 1: Upload files to Gradio's file endpoint
|
| 324 |
var formData = new FormData();
|
| 325 |
selectedFiles.forEach(function(f) { formData.append('files', f); });
|
| 326 |
|
|
@@ -330,7 +329,6 @@ CUSTOM_HTML = """
|
|
| 330 |
})
|
| 331 |
.then(function(r) { return r.json(); })
|
| 332 |
.then(function(uploadedPaths) {
|
| 333 |
-
// Step 2: Call our setup endpoint with the server file paths
|
| 334 |
return fetch(API_BASE + '/gradio_api/call/upload', {
|
| 335 |
method: 'POST',
|
| 336 |
headers: { 'Content-Type': 'application/json' },
|
|
@@ -418,7 +416,7 @@ CUSTOM_HTML = """
|
|
| 418 |
finalHtml += '<div class="chat-stats">' + eventData.stats + '</div>';
|
| 419 |
}
|
| 420 |
if (eventData.trace_html) {
|
| 421 |
-
finalHtml += '<button class="chat-trace-toggle" onclick="this.nextElementSibling.classList.toggle(\'open\')">trace</button>';
|
| 422 |
finalHtml += '<div class="chat-trace">' + eventData.trace_html + '</div>';
|
| 423 |
}
|
| 424 |
turn.innerHTML = '<div class="chat-question">' + escapeHtml(question) + '</div>' + finalHtml;
|
|
@@ -455,12 +453,11 @@ CUSTOM_HTML = """
|
|
| 455 |
});
|
| 456 |
});
|
| 457 |
})();
|
| 458 |
-
</script>
|
| 459 |
"""
|
| 460 |
|
| 461 |
|
| 462 |
def build_app() -> gr.Blocks:
|
| 463 |
-
with gr.Blocks(title="Document Explorer") as demo:
|
| 464 |
gr.HTML(CUSTOM_HTML)
|
| 465 |
|
| 466 |
# Hidden state for file upload workspace
|
|
|
|
| 252 |
</div>
|
| 253 |
</div>
|
| 254 |
</div>
|
| 255 |
+
"""
|
| 256 |
+
|
| 257 |
+
CUSTOM_CSS = _CHAT_UI_CSS + """
|
| 258 |
+
#explorer-app { font-family: var(--font-family, 'Inter', system-ui, sans-serif); max-width: 800px; margin: 0 auto; }
|
| 259 |
+
#setup-panel { padding: 24px 0; }
|
| 260 |
+
.setup-field { margin-bottom: 16px; }
|
| 261 |
+
.setup-field label { display: block; font-size: 13px; color: #6B7280; margin-bottom: 4px; }
|
| 262 |
+
#token-input { width: 100%; padding: 8px 12px; border: 1px solid #E5E7EB; border-radius: 4px; font-family: inherit; font-size: 14px; }
|
| 263 |
+
#token-input:focus { outline: none; border-color: #4682B4; }
|
| 264 |
+
.drop-zone { border: 2px dashed #E5E7EB; border-radius: 8px; padding: 32px; text-align: center; color: #9CA3AF; cursor: pointer; transition: border-color 0.2s; }
|
| 265 |
+
.drop-zone.drag-over { border-color: #4682B4; background: #f0f7ff; }
|
| 266 |
+
.drop-zone p { margin: 0; }
|
| 267 |
+
.file-label { color: #4682B4; cursor: pointer; text-decoration: underline; }
|
| 268 |
+
#file-list { margin-top: 8px; font-size: 13px; color: #374151; text-align: left; }
|
| 269 |
+
#file-list div { padding: 2px 0; }
|
| 270 |
+
#start-btn { width: 100%; padding: 10px; background: #4682B4; color: white; border: none; border-radius: 4px; font-family: inherit; font-size: 14px; cursor: pointer; margin-top: 8px; }
|
| 271 |
+
#start-btn:disabled { background: #D1D5DB; cursor: default; }
|
| 272 |
+
#start-btn:not(:disabled):hover { background: #3a6f9a; }
|
| 273 |
+
#chat-panel { padding-top: 8px; }
|
| 274 |
+
"""
|
| 275 |
|
| 276 |
+
CUSTOM_JS = _CHAT_UI_JS + """
|
| 277 |
+
;(function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
var API_BASE = window.location.origin;
|
| 279 |
var tokenInput = document.getElementById('token-input');
|
| 280 |
var fileInput = document.getElementById('file-input');
|
|
|
|
| 320 |
startBtn.disabled = true;
|
| 321 |
startBtn.textContent = 'Uploading...';
|
| 322 |
|
|
|
|
| 323 |
var formData = new FormData();
|
| 324 |
selectedFiles.forEach(function(f) { formData.append('files', f); });
|
| 325 |
|
|
|
|
| 329 |
})
|
| 330 |
.then(function(r) { return r.json(); })
|
| 331 |
.then(function(uploadedPaths) {
|
|
|
|
| 332 |
return fetch(API_BASE + '/gradio_api/call/upload', {
|
| 333 |
method: 'POST',
|
| 334 |
headers: { 'Content-Type': 'application/json' },
|
|
|
|
| 416 |
finalHtml += '<div class="chat-stats">' + eventData.stats + '</div>';
|
| 417 |
}
|
| 418 |
if (eventData.trace_html) {
|
| 419 |
+
finalHtml += '<button class="chat-trace-toggle" onclick="this.nextElementSibling.classList.toggle(\\'open\\')">trace</button>';
|
| 420 |
finalHtml += '<div class="chat-trace">' + eventData.trace_html + '</div>';
|
| 421 |
}
|
| 422 |
turn.innerHTML = '<div class="chat-question">' + escapeHtml(question) + '</div>' + finalHtml;
|
|
|
|
| 453 |
});
|
| 454 |
});
|
| 455 |
})();
|
|
|
|
| 456 |
"""
|
| 457 |
|
| 458 |
|
| 459 |
def build_app() -> gr.Blocks:
|
| 460 |
+
with gr.Blocks(title="Document Explorer", css=CUSTOM_CSS, js=CUSTOM_JS) as demo:
|
| 461 |
gr.HTML(CUSTOM_HTML)
|
| 462 |
|
| 463 |
# Hidden state for file upload workspace
|