SorrelC commited on
Commit
a05d7f2
Β·
verified Β·
1 Parent(s): 9709aea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -248
app.py CHANGED
@@ -405,124 +405,88 @@ def create_shared_entity_html(entity, entity_colors):
405
  f'title="SHARED: {tooltip}">'
406
  f'{entity["text"]} 🀝</span>')
407
 
408
- def create_entity_table_gradio_tabs(entities, entity_colors):
409
- """Create Gradio tabs for entity results"""
410
- if not entities:
411
- return "No entities found."
412
-
413
- # Share overlapping entities
414
- shared_entities = find_overlapping_entities(entities)
415
-
416
- # Group entities by type
417
- entity_groups = {}
418
- for entity in shared_entities:
419
- if entity.get('is_shared', False):
420
- key = 'SHARED_ENTITIES'
421
- else:
422
- key = entity['label']
423
 
424
- if key not in entity_groups:
425
- entity_groups[key] = []
426
- entity_groups[key].append(entity)
427
-
428
- if not entity_groups:
429
- return "No entities found."
430
-
431
- # Create content for each tab
432
- tab_contents = {}
433
-
434
- for entity_type, entities_of_type in entity_groups.items():
435
- if entity_type == 'SHARED_ENTITIES':
436
- colour = '#666666'
437
- header = f"🀝 Shared Entities ({len(entities_of_type)} found)"
 
 
 
 
438
 
439
- # Create table for shared entities
440
- table_html = f"""
441
- <div style="margin: 15px 0;">
442
- <h4 style="color: {colour}; margin-bottom: 15px;">{header}</h4>
443
- <table style="width: 100%; border-collapse: collapse; border: 1px solid #ddd;">
444
- <thead>
445
- <tr style="background-color: {colour}; color: white;">
446
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Entity Text</th>
447
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">All Labels</th>
448
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Sources</th>
449
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Count</th>
450
- </tr>
451
- </thead>
452
- <tbody>
453
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
 
455
- for entity in entities_of_type:
456
- labels_text = " | ".join(entity['labels'])
457
- sources_text = " | ".join(entity['sources'])
458
-
459
- table_html += f"""
460
- <tr style="background-color: #fff;">
461
- <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">{entity['text']}</td>
462
- <td style="padding: 10px; border: 1px solid #ddd;">{labels_text}</td>
463
- <td style="padding: 10px; border: 1px solid #ddd;">{sources_text}</td>
464
- <td style="padding: 10px; border: 1px solid #ddd; text-align: center;">
465
- <span style='background-color: #28a745; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px;'>
466
- {entity['entity_count']}
467
- </span>
468
- </td>
469
- </tr>
470
- """
471
-
472
- table_html += "</tbody></table></div>"
473
- tab_contents[f"🀝 SHARED ({len(entities_of_type)})"] = table_html
474
-
475
- else:
476
- colour = entity_colors.get(entity_type.upper(), '#f0f0f0')
477
- # Determine if it's common or custom
478
- is_standard = entity_type in STANDARD_ENTITIES
479
- icon = "🎯" if is_standard else "✨"
480
- source_text = "Common NER" if is_standard else "Custom GLiNER"
481
- header = f"{icon} {source_text} - {entity_type} ({len(entities_of_type)} found)"
482
-
483
- # Create table for this entity type
484
- table_html = f"""
485
- <div style="margin: 15px 0;">
486
- <h4 style="color: {colour}; margin-bottom: 15px;">{header}</h4>
487
- <table style="width: 100%; border-collapse: collapse; border: 1px solid #ddd;">
488
- <thead>
489
- <tr style="background-color: {colour}; color: white;">
490
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Entity Text</th>
491
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Confidence</th>
492
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Type</th>
493
- <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Source</th>
494
- </tr>
495
- </thead>
496
- <tbody>
497
  """
498
-
499
- # Sort by confidence score
500
- entities_of_type.sort(key=lambda x: x.get('confidence', 0), reverse=True)
501
-
502
- for entity in entities_of_type:
503
- confidence = entity.get('confidence', 0.0)
504
- confidence_colour = "#28a745" if confidence > 0.7 else "#ffc107" if confidence > 0.4 else "#dc3545"
505
- source = entity.get('source', 'Unknown')
506
- source_badge = f"<span style='background-color: #007bff; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px;'>{source}</span>"
507
-
508
- table_html += f"""
509
- <tr style="background-color: #fff;">
510
- <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">{entity['text']}</td>
511
- <td style="padding: 10px; border: 1px solid #ddd;">
512
- <span style="color: {confidence_colour}; font-weight: bold;">
513
- {confidence:.3f}
514
- </span>
515
- </td>
516
- <td style="padding: 10px; border: 1px solid #ddd;">{entity['label']}</td>
517
- <td style="padding: 10px; border: 1px solid #ddd;">{source_badge}</td>
518
- </tr>
519
- """
520
-
521
- table_html += "</tbody></table></div>"
522
- tab_label = f"{icon} {entity_type} ({len(entities_of_type)})"
523
- tab_contents[tab_label] = table_html
524
 
525
- return tab_contents
 
526
 
527
  def create_legend_html(entity_colors, standard_entities, custom_entities):
528
  """Create a legend showing entity colours"""
@@ -559,7 +523,7 @@ ner_manager = HybridNERManager()
559
  def process_text(text, standard_entities, custom_entities_str, confidence_threshold, selected_model, progress=gr.Progress()):
560
  """Main processing function for Gradio interface with progress tracking"""
561
  if not text.strip():
562
- return "❌ Please enter some text to analyse", "", {}
563
 
564
  progress(0.1, desc="Initialising...")
565
 
@@ -572,7 +536,7 @@ def process_text(text, standard_entities, custom_entities_str, confidence_thresh
572
  selected_standard = [entity for entity in standard_entities if entity]
573
 
574
  if not selected_standard and not custom_entities:
575
- return "❌ Please select at least one common entity type OR enter custom entity types", "", {}
576
 
577
  progress(0.2, desc="Loading models...")
578
 
@@ -591,7 +555,7 @@ def process_text(text, standard_entities, custom_entities_str, confidence_thresh
591
  all_entities.extend(custom_entity_results)
592
 
593
  if not all_entities:
594
- return "❌ No entities found. Try lowering the confidence threshold or using different entity types.", "", {}
595
 
596
  progress(0.8, desc="Processing results...")
597
 
@@ -601,14 +565,26 @@ def process_text(text, standard_entities, custom_entities_str, confidence_thresh
601
  # Create outputs
602
  legend_html = create_legend_html(entity_colors, selected_standard, custom_entities)
603
  highlighted_html = create_highlighted_html(text, all_entities, entity_colors)
604
- tab_contents = create_entity_table_gradio_tabs(all_entities, entity_colors)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
 
606
  progress(0.9, desc="Creating summary...")
607
 
608
- # Create summary with shared entities terminology
609
- # Note: Shared entities are those found by BOTH common NER models AND custom GLiNER
610
  total_entities = len(all_entities)
611
- shared_entities = find_overlapping_entities(all_entities)
612
  final_count = len(shared_entities)
613
  shared_count = sum(1 for e in shared_entities if e.get('is_shared', False))
614
 
@@ -622,7 +598,29 @@ def process_text(text, standard_entities, custom_entities_str, confidence_thresh
622
 
623
  progress(1.0, desc="Complete!")
624
 
625
- return summary, legend_html + highlighted_html, tab_contents
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
 
627
  # Create Gradio interface
628
  def create_interface():
@@ -723,142 +721,40 @@ def create_interface():
723
  with gr.Row():
724
  highlighted_output = gr.HTML(label="Highlighted Text")
725
 
726
- # Create dynamic tabs for results
727
- results_tabs = gr.State({})
728
-
729
- def update_tabs(tab_contents):
730
- """Update the results tabs based on the analysis"""
731
- if not tab_contents or not isinstance(tab_contents, dict):
732
- return {gr.HTML("No results to display"): gr.update(visible=True)}
733
-
734
- # Create tabs dynamically
735
- tab_components = {}
736
- for tab_name, content in tab_contents.items():
737
- tab_components[tab_name] = gr.HTML(content)
738
-
739
- return tab_components
740
-
741
- # Results section with tabs
742
  with gr.Row():
743
  with gr.Column():
744
  gr.Markdown("### πŸ“‹ Detailed Results")
745
 
746
- # We'll update this section dynamically
747
- results_container = gr.HTML(label="Results")
748
-
749
- # Function to process and display results
750
- def process_and_display(text, standard_entities, custom_entities, confidence_threshold, selected_model):
751
- # Get results from main processing function
752
- summary, highlighted, tab_contents = process_text(
753
- text, standard_entities, custom_entities, confidence_threshold, selected_model
754
- )
755
-
756
- # Create tabs HTML manually since Gradio dynamic tabs are complex
757
- if isinstance(tab_contents, dict) and tab_contents:
758
- # Generate unique IDs to avoid conflicts
759
- import time
760
- timestamp = str(int(time.time() * 1000))
761
-
762
- tabs_html = f"""
763
- <div style="margin: 20px 0;" id="tab-container-{timestamp}">
764
- <div style="border-bottom: 2px solid #ddd; margin-bottom: 20px;">
765
- """
766
-
767
- # Create tab buttons
768
- tab_names = list(tab_contents.keys())
769
- for i, tab_name in enumerate(tab_names):
770
- active_style = "background-color: #f8f9fa; border-bottom: 3px solid #4ECDC4;" if i == 0 else "background-color: #fff;"
771
- default_bg = '#f8f9fa' if i == 0 else '#fff'
772
- tabs_html += f"""
773
- <button onclick="showResultTab{timestamp}('{i}')" id="result-tab-{timestamp}-{i}"
774
- style="padding: 12px 24px; margin-right: 5px; border: 1px solid #ddd;
775
- border-bottom: none; cursor: pointer; font-weight: bold; {active_style}
776
- transition: all 0.3s ease;"
777
- onmouseover="this.style.backgroundColor='#e9ecef'"
778
- onmouseout="this.style.backgroundColor='{default_bg}'">
779
- {tab_name}
780
- </button>
781
- """
782
-
783
- tabs_html += "</div>"
784
-
785
- # Create tab content
786
- for i, (tab_name, content) in enumerate(tab_contents.items()):
787
- display_style = "display: block;" if i == 0 else "display: none;"
788
- tabs_html += f"""
789
- <div id="result-content-{timestamp}-{i}" style="{display_style}">
790
- {content}
791
- </div>
792
- """
793
-
794
- # Add JavaScript for tab switching with unique function name
795
- tabs_html += f"""
796
- <script>
797
- function showResultTab{timestamp}(tabIndex) {{
798
- console.log('Tab clicked:', tabIndex);
799
-
800
- // Hide all content for this specific tab container
801
- var contents = document.querySelectorAll('[id^="result-content-{timestamp}-"]');
802
- contents.forEach(function(content) {{
803
- content.style.display = 'none';
804
- }});
805
-
806
- // Reset all tab styles for this specific tab container
807
- var tabs = document.querySelectorAll('[id^="result-tab-{timestamp}-"]');
808
- tabs.forEach(function(tab) {{
809
- tab.style.backgroundColor = '#fff';
810
- tab.style.borderBottom = 'none';
811
- }});
812
-
813
- // Show selected content
814
- var targetContent = document.getElementById('result-content-{timestamp}-' + tabIndex);
815
- if (targetContent) {{
816
- targetContent.style.display = 'block';
817
- }}
818
-
819
- // Highlight selected tab
820
- var activeTab = document.getElementById('result-tab-{timestamp}-' + tabIndex);
821
- if (activeTab) {{
822
- activeTab.style.backgroundColor = '#f8f9fa';
823
- activeTab.style.borderBottom = '3px solid #4ECDC4';
824
- }}
825
- }}
826
 
827
- // Ensure tabs are clickable after DOM load
828
- document.addEventListener('DOMContentLoaded', function() {{
829
- var tabs = document.querySelectorAll('[id^="result-tab-{timestamp}-"]');
830
- tabs.forEach(function(tab, index) {{
831
- tab.addEventListener('click', function(e) {{
832
- e.preventDefault();
833
- showResultTab{timestamp}(index.toString());
834
- }});
835
- }});
836
- }});
837
 
838
- // Also try immediate setup in case DOM is already loaded
839
- setTimeout(function() {{
840
- var tabs = document.querySelectorAll('[id^="result-tab-{timestamp}-"]');
841
- tabs.forEach(function(tab, index) {{
842
- tab.onclick = function(e) {{
843
- e.preventDefault();
844
- showResultTab{timestamp}(index.toString());
845
- return false;
846
- }};
847
- }});
848
- }}, 100);
849
- </script>
850
- </div>
851
- """
852
-
853
- results_display = tabs_html
854
- else:
855
- results_display = str(tab_contents) if tab_contents else "No results to display"
856
-
857
- return summary, highlighted, results_display
858
 
859
  # Connect the button to the processing function
860
  analyse_btn.click(
861
- fn=process_and_display,
862
  inputs=[
863
  text_input,
864
  standard_entities,
@@ -866,7 +762,18 @@ def create_interface():
866
  confidence_threshold,
867
  model_dropdown
868
  ],
869
- outputs=[summary_output, highlighted_output, results_container]
 
 
 
 
 
 
 
 
 
 
 
870
  )
871
 
872
  # Add examples
 
405
  f'title="SHARED: {tooltip}">'
406
  f'{entity["text"]} 🀝</span>')
407
 
408
+ def create_entity_table_html(entities_of_type, entity_type, colour, is_shared=False):
409
+ """Create HTML table for a specific entity type"""
410
+ if is_shared:
411
+ header = f"🀝 Shared Entities ({len(entities_of_type)} found)"
 
 
 
 
 
 
 
 
 
 
 
412
 
413
+ table_html = f"""
414
+ <div style="margin: 15px 0;">
415
+ <h4 style="color: {colour}; margin-bottom: 15px;">{header}</h4>
416
+ <table style="width: 100%; border-collapse: collapse; border: 1px solid #ddd;">
417
+ <thead>
418
+ <tr style="background-color: {colour}; color: white;">
419
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Entity Text</th>
420
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">All Labels</th>
421
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Sources</th>
422
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Count</th>
423
+ </tr>
424
+ </thead>
425
+ <tbody>
426
+ """
427
+
428
+ for entity in entities_of_type:
429
+ labels_text = " | ".join(entity['labels'])
430
+ sources_text = " | ".join(entity['sources'])
431
 
432
+ table_html += f"""
433
+ <tr style="background-color: #fff;">
434
+ <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">{entity['text']}</td>
435
+ <td style="padding: 10px; border: 1px solid #ddd;">{labels_text}</td>
436
+ <td style="padding: 10px; border: 1px solid #ddd;">{sources_text}</td>
437
+ <td style="padding: 10px; border: 1px solid #ddd; text-align: center;">
438
+ <span style='background-color: #28a745; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px;'>
439
+ {entity['entity_count']}
440
+ </span>
441
+ </td>
442
+ </tr>
 
 
 
443
  """
444
+ else:
445
+ # Determine if it's common or custom
446
+ is_standard = entity_type in STANDARD_ENTITIES
447
+ icon = "🎯" if is_standard else "✨"
448
+ source_text = "Common NER" if is_standard else "Custom GLiNER"
449
+ header = f"{icon} {source_text} - {entity_type} ({len(entities_of_type)} found)"
450
+
451
+ table_html = f"""
452
+ <div style="margin: 15px 0;">
453
+ <h4 style="color: {colour}; margin-bottom: 15px;">{header}</h4>
454
+ <table style="width: 100%; border-collapse: collapse; border: 1px solid #ddd;">
455
+ <thead>
456
+ <tr style="background-color: {colour}; color: white;">
457
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Entity Text</th>
458
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Confidence</th>
459
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Type</th>
460
+ <th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Source</th>
461
+ </tr>
462
+ </thead>
463
+ <tbody>
464
+ """
465
+
466
+ # Sort by confidence score
467
+ entities_of_type.sort(key=lambda x: x.get('confidence', 0), reverse=True)
468
+
469
+ for entity in entities_of_type:
470
+ confidence = entity.get('confidence', 0.0)
471
+ confidence_colour = "#28a745" if confidence > 0.7 else "#ffc107" if confidence > 0.4 else "#dc3545"
472
+ source = entity.get('source', 'Unknown')
473
+ source_badge = f"<span style='background-color: #007bff; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px;'>{source}</span>"
474
 
475
+ table_html += f"""
476
+ <tr style="background-color: #fff;">
477
+ <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">{entity['text']}</td>
478
+ <td style="padding: 10px; border: 1px solid #ddd;">
479
+ <span style="color: {confidence_colour}; font-weight: bold;">
480
+ {confidence:.3f}
481
+ </span>
482
+ </td>
483
+ <td style="padding: 10px; border: 1px solid #ddd;">{entity['label']}</td>
484
+ <td style="padding: 10px; border: 1px solid #ddd;">{source_badge}</td>
485
+ </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
+ table_html += "</tbody></table></div>"
489
+ return table_html
490
 
491
  def create_legend_html(entity_colors, standard_entities, custom_entities):
492
  """Create a legend showing entity colours"""
 
523
  def process_text(text, standard_entities, custom_entities_str, confidence_threshold, selected_model, progress=gr.Progress()):
524
  """Main processing function for Gradio interface with progress tracking"""
525
  if not text.strip():
526
+ return "❌ Please enter some text to analyse", "", None, None, None, None, None, None, None, None
527
 
528
  progress(0.1, desc="Initialising...")
529
 
 
536
  selected_standard = [entity for entity in standard_entities if entity]
537
 
538
  if not selected_standard and not custom_entities:
539
+ return "❌ Please select at least one common entity type OR enter custom entity types", "", None, None, None, None, None, None, None, None
540
 
541
  progress(0.2, desc="Loading models...")
542
 
 
555
  all_entities.extend(custom_entity_results)
556
 
557
  if not all_entities:
558
+ return "❌ No entities found. Try lowering the confidence threshold or using different entity types.", "", None, None, None, None, None, None, None, None
559
 
560
  progress(0.8, desc="Processing results...")
561
 
 
565
  # Create outputs
566
  legend_html = create_legend_html(entity_colors, selected_standard, custom_entities)
567
  highlighted_html = create_highlighted_html(text, all_entities, entity_colors)
568
+
569
+ # Share overlapping entities
570
+ shared_entities = find_overlapping_entities(all_entities)
571
+
572
+ # Group entities by type
573
+ entity_groups = {}
574
+ for entity in shared_entities:
575
+ if entity.get('is_shared', False):
576
+ key = 'SHARED_ENTITIES'
577
+ else:
578
+ key = entity['label']
579
+
580
+ if key not in entity_groups:
581
+ entity_groups[key] = []
582
+ entity_groups[key].append(entity)
583
 
584
  progress(0.9, desc="Creating summary...")
585
 
586
+ # Create summary
 
587
  total_entities = len(all_entities)
 
588
  final_count = len(shared_entities)
589
  shared_count = sum(1 for e in shared_entities if e.get('is_shared', False))
590
 
 
598
 
599
  progress(1.0, desc="Complete!")
600
 
601
+ # Create HTML tables for each entity type
602
+ tables = {}
603
+
604
+ # Create table for shared entities if any
605
+ if 'SHARED_ENTITIES' in entity_groups:
606
+ tables['shared'] = create_entity_table_html(entity_groups['SHARED_ENTITIES'], 'SHARED_ENTITIES', '#666666', is_shared=True)
607
+ else:
608
+ tables['shared'] = None
609
+
610
+ # Create tables for other entity types (up to 7 for the interface)
611
+ entity_types = [k for k in entity_groups.keys() if k != 'SHARED_ENTITIES']
612
+ for i in range(7):
613
+ if i < len(entity_types):
614
+ entity_type = entity_types[i]
615
+ colour = entity_colors.get(entity_type.upper(), '#f0f0f0')
616
+ tables[f'tab{i+1}'] = create_entity_table_html(entity_groups[entity_type], entity_type, colour)
617
+ else:
618
+ tables[f'tab{i+1}'] = None
619
+
620
+ return (summary, legend_html + highlighted_html,
621
+ tables.get('shared'), tables.get('tab1'), tables.get('tab2'),
622
+ tables.get('tab3'), tables.get('tab4'), tables.get('tab5'),
623
+ tables.get('tab6'), tables.get('tab7'))
624
 
625
  # Create Gradio interface
626
  def create_interface():
 
721
  with gr.Row():
722
  highlighted_output = gr.HTML(label="Highlighted Text")
723
 
724
+ # Results section with native Gradio tabs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
725
  with gr.Row():
726
  with gr.Column():
727
  gr.Markdown("### πŸ“‹ Detailed Results")
728
 
729
+ with gr.Tabs() as results_tabs:
730
+ # Pre-create tabs for different entity types
731
+ with gr.Tab("🀝 Shared", visible=False) as shared_tab:
732
+ shared_output = gr.HTML()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
 
734
+ with gr.Tab("Entity Type 1", visible=False) as tab1:
735
+ tab1_output = gr.HTML()
 
 
 
 
 
 
 
 
736
 
737
+ with gr.Tab("Entity Type 2", visible=False) as tab2:
738
+ tab2_output = gr.HTML()
739
+
740
+ with gr.Tab("Entity Type 3", visible=False) as tab3:
741
+ tab3_output = gr.HTML()
742
+
743
+ with gr.Tab("Entity Type 4", visible=False) as tab4:
744
+ tab4_output = gr.HTML()
745
+
746
+ with gr.Tab("Entity Type 5", visible=False) as tab5:
747
+ tab5_output = gr.HTML()
748
+
749
+ with gr.Tab("Entity Type 6", visible=False) as tab6:
750
+ tab6_output = gr.HTML()
751
+
752
+ with gr.Tab("Entity Type 7", visible=False) as tab7:
753
+ tab7_output = gr.HTML()
 
 
 
754
 
755
  # Connect the button to the processing function
756
  analyse_btn.click(
757
+ fn=process_text,
758
  inputs=[
759
  text_input,
760
  standard_entities,
 
762
  confidence_threshold,
763
  model_dropdown
764
  ],
765
+ outputs=[
766
+ summary_output,
767
+ highlighted_output,
768
+ shared_output,
769
+ tab1_output,
770
+ tab2_output,
771
+ tab3_output,
772
+ tab4_output,
773
+ tab5_output,
774
+ tab6_output,
775
+ tab7_output
776
+ ]
777
  )
778
 
779
  # Add examples