Update app.py
Browse files
app.py
CHANGED
@@ -16,6 +16,7 @@ import torch
|
|
16 |
import gc
|
17 |
from diskcache import Cache
|
18 |
from transformers import AutoTokenizer
|
|
|
19 |
|
20 |
# ==================== CONFIGURATION ====================
|
21 |
# Configure logging
|
@@ -313,12 +314,18 @@ class ClinicalOversightApp:
|
|
313 |
cleaned = self.text_processor.clean_response(message.content)
|
314 |
if cleaned:
|
315 |
full_response += cleaned + " "
|
316 |
-
yield {
|
|
|
|
|
|
|
317 |
elif isinstance(chunk, str) and chunk.strip():
|
318 |
cleaned = self.text_processor.clean_response(chunk)
|
319 |
if cleaned:
|
320 |
full_response += cleaned + " "
|
321 |
-
yield {
|
|
|
|
|
|
|
322 |
|
323 |
def analyze(self, message: str, history: List[dict], files: List) -> Generator[tuple, None, None]:
|
324 |
"""Main analysis pipeline with proper output formatting"""
|
@@ -329,11 +336,13 @@ class ClinicalOversightApp:
|
|
329 |
|
330 |
try:
|
331 |
# Add user message to history
|
332 |
-
chatbot_output.append({
|
|
|
|
|
|
|
333 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
334 |
|
335 |
# Process uploaded files
|
336 |
-
.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 0
|
337 |
extracted = []
|
338 |
file_hash_value = ""
|
339 |
|
@@ -354,7 +363,10 @@ class ClinicalOversightApp:
|
|
354 |
extracted.append({"error": f"Error processing file: {str(e)}"})
|
355 |
|
356 |
file_hash_value = get_file_hash(files[0].name) if files else ""
|
357 |
-
chatbot_output.append({
|
|
|
|
|
|
|
358 |
progress_text = self._update_progress(len(files), len(files), "Files processed")
|
359 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
360 |
|
@@ -373,7 +385,7 @@ are found, state 'No missed diagnoses identified'.
|
|
373 |
Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
374 |
{chunk[:1200]}
|
375 |
"""
|
376 |
-
chatbot_output.append({"role": "assistant", "content": ""})
|
377 |
progress_text = self._update_progress(chunk_idx, len(chunks), "Analyzing")
|
378 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
379 |
|
@@ -403,10 +415,16 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
403 |
|
404 |
except Exception as e:
|
405 |
logger.error(f"Analysis error: {e}")
|
406 |
-
chatbot_output.append({
|
|
|
|
|
|
|
407 |
final_summary = f"Error occurred: {str(e)}"
|
408 |
progress_text = {"visible": False}
|
409 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
|
|
|
|
|
|
410 |
|
411 |
def _update_progress(self, current: int, total: int, stage: str = "") -> Dict[str, Any]:
|
412 |
"""Format progress update for UI"""
|
@@ -414,7 +432,7 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
414 |
return {"value": progress, "visible": True}
|
415 |
|
416 |
def create_interface(self):
|
417 |
-
"""Create Gradio interface with ChatGPT-like design"""
|
418 |
css = """
|
419 |
body, .gradio-container {
|
420 |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
@@ -428,18 +446,23 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
428 |
}
|
429 |
.chat-container {
|
430 |
background: var(--chat-bg);
|
431 |
-
border-radius:
|
432 |
-
padding:
|
433 |
height: 80vh;
|
434 |
overflow-y: auto;
|
435 |
-
box-shadow: 0
|
|
|
436 |
}
|
437 |
.message {
|
438 |
-
margin:
|
439 |
padding: 12px 16px;
|
440 |
border-radius: 12px;
|
441 |
max-width: 80%;
|
442 |
-
transition: all 0.
|
|
|
|
|
|
|
|
|
443 |
}
|
444 |
.message.user {
|
445 |
background: #007bff;
|
@@ -450,14 +473,22 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
450 |
background: var(--message-bg);
|
451 |
color: var(--text-color);
|
452 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
.input-container {
|
454 |
display: flex;
|
455 |
align-items: center;
|
456 |
margin-top: 20px;
|
457 |
background: var(--chat-bg);
|
458 |
-
padding:
|
459 |
-
border-radius:
|
460 |
-
box-shadow: 0
|
|
|
|
|
461 |
}
|
462 |
.input-textbox {
|
463 |
flex-grow: 1;
|
@@ -465,31 +496,39 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
465 |
background: transparent;
|
466 |
color: var(--text-color);
|
467 |
outline: none;
|
|
|
468 |
}
|
469 |
.send-btn {
|
470 |
background: #007bff;
|
471 |
color: white;
|
472 |
border: none;
|
473 |
border-radius: 20px;
|
474 |
-
padding:
|
475 |
-
margin-left:
|
|
|
476 |
}
|
477 |
.send-btn:hover {
|
478 |
background: #0056b3;
|
479 |
}
|
480 |
.sidebar {
|
481 |
background: var(--sidebar-bg);
|
482 |
-
padding:
|
483 |
-
border-radius:
|
484 |
margin-top: 20px;
|
485 |
-
box-shadow: 0
|
|
|
|
|
486 |
}
|
487 |
.sidebar-hidden {
|
488 |
-
|
|
|
|
|
|
|
|
|
489 |
}
|
490 |
.header {
|
491 |
text-align: center;
|
492 |
-
margin-bottom:
|
493 |
}
|
494 |
.theme-toggle {
|
495 |
position: absolute;
|
@@ -500,13 +539,28 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
500 |
border: none;
|
501 |
border-radius: 20px;
|
502 |
padding: 8px 16px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
503 |
}
|
504 |
:root {
|
505 |
--background: #ffffff;
|
506 |
--text-color: #333333;
|
507 |
-
--chat-bg: #
|
508 |
--message-bg: #e5e5ea;
|
509 |
-
--sidebar-bg: #
|
510 |
}
|
511 |
@media (prefers-color-scheme: dark) {
|
512 |
:root {
|
@@ -519,19 +573,26 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
519 |
}
|
520 |
@media (max-width: 600px) {
|
521 |
.gradio-container {
|
522 |
-
padding:
|
523 |
}
|
524 |
.chat-container {
|
525 |
height: 70vh;
|
526 |
}
|
527 |
.input-container {
|
528 |
flex-direction: column;
|
529 |
-
gap:
|
|
|
530 |
}
|
531 |
.send-btn {
|
532 |
width: 100%;
|
533 |
margin-left: 0;
|
534 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
535 |
}
|
536 |
"""
|
537 |
|
@@ -541,10 +602,11 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
541 |
const isDark = root.style.getPropertyValue('--background') === '#1e2a44';
|
542 |
root.style.setProperty('--background', isDark ? '#ffffff' : '#1e2a44');
|
543 |
root.style.setProperty('--text-color', isDark ? '#333333' : '#ffffff');
|
544 |
-
root.style.setProperty('--chat-bg', isDark ? '#
|
545 |
root.style.setProperty('--message-bg', isDark ? '#e5e5ea' : '#3e4c6a');
|
546 |
-
root.style.setProperty('--sidebar-bg', isDark ? '#
|
547 |
localStorage.setItem('theme', isDark ? 'light' : 'dark');
|
|
|
548 |
}
|
549 |
|
550 |
function toggleSidebar() {
|
@@ -556,6 +618,7 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
556 |
const savedTheme = localStorage.getItem('theme');
|
557 |
if (savedTheme === 'dark') toggleTheme();
|
558 |
document.querySelector('.sidebar').classList.add('sidebar-hidden');
|
|
|
559 |
});
|
560 |
"""
|
561 |
|
@@ -568,7 +631,7 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
568 |
</p>
|
569 |
</div>
|
570 |
""")
|
571 |
-
gr.Button("
|
572 |
None, None, None, _js="toggleTheme"
|
573 |
)
|
574 |
|
@@ -578,27 +641,30 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
578 |
height="100%",
|
579 |
show_copy_button=True,
|
580 |
type="messages",
|
581 |
-
elem_classes="chatbot"
|
|
|
582 |
)
|
|
|
583 |
|
584 |
with gr.Row():
|
585 |
-
gr.Button("
|
586 |
None, None, None, _js="toggleSidebar"
|
587 |
)
|
588 |
|
589 |
with gr.Column(elem_classes="sidebar"):
|
|
|
590 |
file_upload = gr.File(
|
591 |
file_types=[".pdf", ".csv", ".xls", ".xlsx"],
|
592 |
file_count="multiple",
|
593 |
-
label="
|
594 |
)
|
595 |
-
gr.Markdown("### π Summary
|
596 |
final_summary = gr.Markdown(
|
597 |
"Analysis results will appear here..."
|
598 |
)
|
599 |
-
gr.Markdown("###
|
600 |
download_output = gr.File(
|
601 |
-
label="
|
602 |
visible=False,
|
603 |
interactive=False
|
604 |
)
|
@@ -623,18 +689,40 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
|
623 |
interactive=False
|
624 |
)
|
625 |
|
|
|
|
|
|
|
|
|
|
|
|
|
626 |
send_btn.click(
|
|
|
|
|
|
|
|
|
627 |
self.analyze,
|
628 |
inputs=[msg_input, chatbot, file_upload],
|
629 |
outputs=[chatbot, download_output, final_summary, progress_text],
|
630 |
show_progress="hidden"
|
|
|
|
|
|
|
|
|
631 |
)
|
632 |
|
633 |
msg_input.submit(
|
|
|
|
|
|
|
|
|
634 |
self.analyze,
|
635 |
inputs=[msg_input, chatbot, file_upload],
|
636 |
outputs=[chatbot, download_output, final_summary, progress_text],
|
637 |
show_progress="hidden"
|
|
|
|
|
|
|
|
|
638 |
)
|
639 |
|
640 |
app.load(
|
|
|
16 |
import gc
|
17 |
from diskcache import Cache
|
18 |
from transformers import AutoTokenizer
|
19 |
+
from datetime import datetime
|
20 |
|
21 |
# ==================== CONFIGURATION ====================
|
22 |
# Configure logging
|
|
|
314 |
cleaned = self.text_processor.clean_response(message.content)
|
315 |
if cleaned:
|
316 |
full_response += cleaned + " "
|
317 |
+
yield {
|
318 |
+
"role": "assistant",
|
319 |
+
"content": f"β
{cleaned} [{datetime.now().strftime('%H:%M:%S')}]"
|
320 |
+
}
|
321 |
elif isinstance(chunk, str) and chunk.strip():
|
322 |
cleaned = self.text_processor.clean_response(chunk)
|
323 |
if cleaned:
|
324 |
full_response += cleaned + " "
|
325 |
+
yield {
|
326 |
+
"role": "assistant",
|
327 |
+
"content": f"β
{cleaned} [{datetime.now().strftime('%H:%M:%S')}]"
|
328 |
+
}
|
329 |
|
330 |
def analyze(self, message: str, history: List[dict], files: List) -> Generator[tuple, None, None]:
|
331 |
"""Main analysis pipeline with proper output formatting"""
|
|
|
336 |
|
337 |
try:
|
338 |
# Add user message to history
|
339 |
+
chatbot_output.append({
|
340 |
+
"role": "user",
|
341 |
+
"content": f"{message} [{datetime.now().strftime('%H:%M:%S')}]"
|
342 |
+
})
|
343 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
344 |
|
345 |
# Process uploaded files
|
|
|
346 |
extracted = []
|
347 |
file_hash_value = ""
|
348 |
|
|
|
363 |
extracted.append({"error": f"Error processing file: {str(e)}"})
|
364 |
|
365 |
file_hash_value = get_file_hash(files[0].name) if files else ""
|
366 |
+
chatbot_output.append({
|
367 |
+
"role": "assistant",
|
368 |
+
"content": f"β
File processing complete [{datetime.now().strftime('%H:%M:%S')}]"
|
369 |
+
})
|
370 |
progress_text = self._update_progress(len(files), len(files), "Files processed")
|
371 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
372 |
|
|
|
385 |
Patient Record (Chunk {chunk_idx}/{len(chunks)}):
|
386 |
{chunk[:1200]}
|
387 |
"""
|
388 |
+
chatbot_output.append({"role": "assistant", "content": "β³ Analyzing..."})
|
389 |
progress_text = self._update_progress(chunk_idx, len(chunks), "Analyzing")
|
390 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
391 |
|
|
|
415 |
|
416 |
except Exception as e:
|
417 |
logger.error(f"Analysis error: {e}")
|
418 |
+
chatbot_output.append({
|
419 |
+
"role": "assistant",
|
420 |
+
"content": f"β Error: {str(e)} [{datetime.now().strftime('%H:%M:%S')}]"
|
421 |
+
})
|
422 |
final_summary = f"Error occurred: {str(e)}"
|
423 |
progress_text = {"visible": False}
|
424 |
yield (chatbot_output, download_output, final_summary, progress_text)
|
425 |
+
finally:
|
426 |
+
torch.cuda.empty_cache()
|
427 |
+
gc.collect()
|
428 |
|
429 |
def _update_progress(self, current: int, total: int, stage: str = "") -> Dict[str, Any]:
|
430 |
"""Format progress update for UI"""
|
|
|
432 |
return {"value": progress, "visible": True}
|
433 |
|
434 |
def create_interface(self):
|
435 |
+
"""Create Gradio interface with refined ChatGPT-like design"""
|
436 |
css = """
|
437 |
body, .gradio-container {
|
438 |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
446 |
}
|
447 |
.chat-container {
|
448 |
background: var(--chat-bg);
|
449 |
+
border-radius: 16px;
|
450 |
+
padding: 24px;
|
451 |
height: 80vh;
|
452 |
overflow-y: auto;
|
453 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
454 |
+
position: relative;
|
455 |
}
|
456 |
.message {
|
457 |
+
margin: 12px 0;
|
458 |
padding: 12px 16px;
|
459 |
border-radius: 12px;
|
460 |
max-width: 80%;
|
461 |
+
transition: all 0.3s ease;
|
462 |
+
position: relative;
|
463 |
+
}
|
464 |
+
.message:hover {
|
465 |
+
transform: translateY(-2px);
|
466 |
}
|
467 |
.message.user {
|
468 |
background: #007bff;
|
|
|
473 |
background: var(--message-bg);
|
474 |
color: var(--text-color);
|
475 |
}
|
476 |
+
.message-timestamp {
|
477 |
+
font-size: 0.75em;
|
478 |
+
opacity: 0.7;
|
479 |
+
margin-top: 4px;
|
480 |
+
text-align: right;
|
481 |
+
}
|
482 |
.input-container {
|
483 |
display: flex;
|
484 |
align-items: center;
|
485 |
margin-top: 20px;
|
486 |
background: var(--chat-bg);
|
487 |
+
padding: 12px 24px;
|
488 |
+
border-radius: 30px;
|
489 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
490 |
+
position: sticky;
|
491 |
+
bottom: 0;
|
492 |
}
|
493 |
.input-textbox {
|
494 |
flex-grow: 1;
|
|
|
496 |
background: transparent;
|
497 |
color: var(--text-color);
|
498 |
outline: none;
|
499 |
+
font-size: 1em;
|
500 |
}
|
501 |
.send-btn {
|
502 |
background: #007bff;
|
503 |
color: white;
|
504 |
border: none;
|
505 |
border-radius: 20px;
|
506 |
+
padding: 10px 20px;
|
507 |
+
margin-left: 12px;
|
508 |
+
transition: background 0.2s ease;
|
509 |
}
|
510 |
.send-btn:hover {
|
511 |
background: #0056b3;
|
512 |
}
|
513 |
.sidebar {
|
514 |
background: var(--sidebar-bg);
|
515 |
+
padding: 24px;
|
516 |
+
border-radius: 16px;
|
517 |
margin-top: 20px;
|
518 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
519 |
+
transition: transform 0.3s ease;
|
520 |
+
transform: translateX(0);
|
521 |
}
|
522 |
.sidebar-hidden {
|
523 |
+
transform: translateX(100%);
|
524 |
+
position: absolute;
|
525 |
+
right: 0;
|
526 |
+
top: 100px;
|
527 |
+
width: 300px;
|
528 |
}
|
529 |
.header {
|
530 |
text-align: center;
|
531 |
+
margin-bottom: 24px;
|
532 |
}
|
533 |
.theme-toggle {
|
534 |
position: absolute;
|
|
|
539 |
border: none;
|
540 |
border-radius: 20px;
|
541 |
padding: 8px 16px;
|
542 |
+
display: flex;
|
543 |
+
align-items: center;
|
544 |
+
gap: 8px;
|
545 |
+
}
|
546 |
+
.loading-spinner {
|
547 |
+
position: absolute;
|
548 |
+
bottom: 80px;
|
549 |
+
left: 50%;
|
550 |
+
transform: translateX(-50%);
|
551 |
+
font-size: 1.2em;
|
552 |
+
animation: spin 1s linear infinite;
|
553 |
+
}
|
554 |
+
@keyframes spin {
|
555 |
+
0% { transform: translateX(-50%) rotate(0deg); }
|
556 |
+
100% { transform: translateX(-50%) rotate(360deg); }
|
557 |
}
|
558 |
:root {
|
559 |
--background: #ffffff;
|
560 |
--text-color: #333333;
|
561 |
+
--chat-bg: #f9fafb;
|
562 |
--message-bg: #e5e5ea;
|
563 |
+
--sidebar-bg: #f1f3f5;
|
564 |
}
|
565 |
@media (prefers-color-scheme: dark) {
|
566 |
:root {
|
|
|
573 |
}
|
574 |
@media (max-width: 600px) {
|
575 |
.gradio-container {
|
576 |
+
padding: 12px;
|
577 |
}
|
578 |
.chat-container {
|
579 |
height: 70vh;
|
580 |
}
|
581 |
.input-container {
|
582 |
flex-direction: column;
|
583 |
+
gap: 12px;
|
584 |
+
padding: 12px;
|
585 |
}
|
586 |
.send-btn {
|
587 |
width: 100%;
|
588 |
margin-left: 0;
|
589 |
}
|
590 |
+
.sidebar {
|
591 |
+
width: 100%;
|
592 |
+
}
|
593 |
+
.sidebar-hidden {
|
594 |
+
transform: translateX(100%);
|
595 |
+
}
|
596 |
}
|
597 |
"""
|
598 |
|
|
|
602 |
const isDark = root.style.getPropertyValue('--background') === '#1e2a44';
|
603 |
root.style.setProperty('--background', isDark ? '#ffffff' : '#1e2a44');
|
604 |
root.style.setProperty('--text-color', isDark ? '#333333' : '#ffffff');
|
605 |
+
root.style.setProperty('--chat-bg', isDark ? '#f9fafb' : '#2d3b55');
|
606 |
root.style.setProperty('--message-bg', isDark ? '#e5e5ea' : '#3e4c6a');
|
607 |
+
root.style.setProperty('--sidebar-bg', isDark ? '#f1f3f5' : '#2a3650');
|
608 |
localStorage.setItem('theme', isDark ? 'light' : 'dark');
|
609 |
+
document.querySelector('.theme-toggle').innerHTML = isDark ? 'π Dark Mode' : 'βοΈ Light Mode';
|
610 |
}
|
611 |
|
612 |
function toggleSidebar() {
|
|
|
618 |
const savedTheme = localStorage.getItem('theme');
|
619 |
if (savedTheme === 'dark') toggleTheme();
|
620 |
document.querySelector('.sidebar').classList.add('sidebar-hidden');
|
621 |
+
document.querySelector('.theme-toggle').innerHTML = savedTheme === 'dark' ? 'βοΈ Light Mode' : 'π Dark Mode';
|
622 |
});
|
623 |
"""
|
624 |
|
|
|
631 |
</p>
|
632 |
</div>
|
633 |
""")
|
634 |
+
gr.Button("π Dark Mode", elem_classes="theme-toggle").click(
|
635 |
None, None, None, _js="toggleTheme"
|
636 |
)
|
637 |
|
|
|
641 |
height="100%",
|
642 |
show_copy_button=True,
|
643 |
type="messages",
|
644 |
+
elem_classes="chatbot",
|
645 |
+
render_markdown=True
|
646 |
)
|
647 |
+
gr.HTML("<div class='loading-spinner' style='display: none;'>β³</div>")
|
648 |
|
649 |
with gr.Row():
|
650 |
+
gr.Button("π Tools", variant="secondary").click(
|
651 |
None, None, None, _js="toggleSidebar"
|
652 |
)
|
653 |
|
654 |
with gr.Column(elem_classes="sidebar"):
|
655 |
+
gr.Markdown("### π Upload Records")
|
656 |
file_upload = gr.File(
|
657 |
file_types=[".pdf", ".csv", ".xls", ".xlsx"],
|
658 |
file_count="multiple",
|
659 |
+
label="Patient Records"
|
660 |
)
|
661 |
+
gr.Markdown("### π Analysis Summary")
|
662 |
final_summary = gr.Markdown(
|
663 |
"Analysis results will appear here..."
|
664 |
)
|
665 |
+
gr.Markdown("### π Full Report")
|
666 |
download_output = gr.File(
|
667 |
+
label="Download Report",
|
668 |
visible=False,
|
669 |
interactive=False
|
670 |
)
|
|
|
689 |
interactive=False
|
690 |
)
|
691 |
|
692 |
+
def show_loading_spinner():
|
693 |
+
return gr.update(value="<div class='loading-spinner'>β³</div>", visible=True)
|
694 |
+
|
695 |
+
def hide_loading_spinner():
|
696 |
+
return gr.update(value="<div class='loading-spinner' style='display: none;'>β³</div>", visible=False)
|
697 |
+
|
698 |
send_btn.click(
|
699 |
+
show_loading_spinner,
|
700 |
+
outputs=[chatbot],
|
701 |
+
_js="() => { document.querySelector('.loading-spinner').style.display = 'block'; }"
|
702 |
+
).then(
|
703 |
self.analyze,
|
704 |
inputs=[msg_input, chatbot, file_upload],
|
705 |
outputs=[chatbot, download_output, final_summary, progress_text],
|
706 |
show_progress="hidden"
|
707 |
+
).then(
|
708 |
+
hide_loading_spinner,
|
709 |
+
outputs=[chatbot],
|
710 |
+
_js="() => { document.querySelector('.loading-spinner').style.display = 'none'; }"
|
711 |
)
|
712 |
|
713 |
msg_input.submit(
|
714 |
+
show_loading_spinner,
|
715 |
+
outputs=[chatbot],
|
716 |
+
_js="() => { document.querySelector('.loading-spinner').style.display = 'block'; }"
|
717 |
+
).then(
|
718 |
self.analyze,
|
719 |
inputs=[msg_input, chatbot, file_upload],
|
720 |
outputs=[chatbot, download_output, final_summary, progress_text],
|
721 |
show_progress="hidden"
|
722 |
+
).then(
|
723 |
+
hide_loading_spinner,
|
724 |
+
outputs=[chatbot],
|
725 |
+
_js="() => { document.querySelector('.loading-spinner').style.display = 'none'; }"
|
726 |
)
|
727 |
|
728 |
app.load(
|