Spaces:
Running
Running
Update app.py
Browse files
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
|
| 409 |
-
"""Create
|
| 410 |
-
if
|
| 411 |
-
|
| 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 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
</tr>
|
| 451 |
-
</thead>
|
| 452 |
-
<tbody>
|
| 453 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
|
| 606 |
progress(0.9, desc="Creating summary...")
|
| 607 |
|
| 608 |
-
# Create summary
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
#
|
| 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 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 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 |
-
|
| 828 |
-
|
| 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 |
-
|
| 839 |
-
|
| 840 |
-
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 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=
|
| 862 |
inputs=[
|
| 863 |
text_input,
|
| 864 |
standard_entities,
|
|
@@ -866,7 +762,18 @@ def create_interface():
|
|
| 866 |
confidence_threshold,
|
| 867 |
model_dropdown
|
| 868 |
],
|
| 869 |
-
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|