Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,6 +2,8 @@ import gradio as gr
|
|
| 2 |
import networkx as nx
|
| 3 |
from pyvis.network import Network
|
| 4 |
import base64
|
|
|
|
|
|
|
| 5 |
|
| 6 |
# Entity type colours (matching your NER tool)
|
| 7 |
# Updated for better distinction between Person, Location, and Event
|
|
@@ -88,9 +90,9 @@ class NetworkGraphBuilder:
|
|
| 88 |
return G
|
| 89 |
|
| 90 |
def create_pyvis_graph(self, G):
|
| 91 |
-
"""Create interactive PyVis visualisation"""
|
| 92 |
if len(G.nodes) == 0:
|
| 93 |
-
return None
|
| 94 |
|
| 95 |
# Create PyVis network with dark theme
|
| 96 |
net = Network(
|
|
@@ -213,6 +215,9 @@ class NetworkGraphBuilder:
|
|
| 213 |
# Generate HTML
|
| 214 |
html = net.generate_html()
|
| 215 |
|
|
|
|
|
|
|
|
|
|
| 216 |
# Encode as base64 data URI for iframe src
|
| 217 |
html_bytes = html.encode('utf-8')
|
| 218 |
b64_html = base64.b64encode(html_bytes).decode('utf-8')
|
|
@@ -227,7 +232,7 @@ class NetworkGraphBuilder:
|
|
| 227 |
></iframe>
|
| 228 |
'''
|
| 229 |
|
| 230 |
-
return iframe_html
|
| 231 |
|
| 232 |
|
| 233 |
def collect_entities_from_records(
|
|
@@ -413,7 +418,7 @@ def generate_network_graph(
|
|
| 413 |
return empty_html, "β **No entities to display.** Please enter entities in Step 1 first."
|
| 414 |
|
| 415 |
# Create visualisation
|
| 416 |
-
graph_html = builder.create_pyvis_graph(G)
|
| 417 |
|
| 418 |
# Create statistics
|
| 419 |
stats_html = f'''
|
|
@@ -487,6 +492,96 @@ def generate_network_graph(
|
|
| 487 |
return error_html, f"β Error: {str(e)}"
|
| 488 |
|
| 489 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
def load_austen_example():
|
| 491 |
"""Load the Jane Austen Pride and Prejudice example"""
|
| 492 |
return (
|
|
@@ -509,12 +604,6 @@ def load_austen_example():
|
|
| 509 |
)
|
| 510 |
|
| 511 |
|
| 512 |
-
def load_austen_example_extra():
|
| 513 |
-
"""Return additional Austen characters for records 5-8 area - but we handle in main example"""
|
| 514 |
-
# This is handled by main example now
|
| 515 |
-
pass
|
| 516 |
-
|
| 517 |
-
|
| 518 |
def load_wwii_example():
|
| 519 |
"""Load a WWII history example"""
|
| 520 |
return (
|
|
@@ -563,9 +652,10 @@ def create_interface():
|
|
| 563 |
### How to use this tool:
|
| 564 |
1. **π Enter entities** in the records below (or load an example to get started)
|
| 565 |
2. **βοΈ Click "Process Entities"** to collect and prepare all entities for relationships
|
| 566 |
-
3. **π€ Define relationships** between entities using the dropdowns
|
| 567 |
4. **π¨ Click "Generate Network Graph"** to visualise
|
| 568 |
5. **ποΈ Explore** - drag nodes to rearrange, scroll to zoom, hover for details
|
|
|
|
| 569 |
""")
|
| 570 |
|
| 571 |
gr.HTML("""
|
|
@@ -720,7 +810,7 @@ def create_interface():
|
|
| 720 |
|
| 721 |
# ==================== STEP 3: RELATIONSHIPS (Grid) ====================
|
| 722 |
gr.Markdown("## π€ Step 3: Define Relationships")
|
| 723 |
-
gr.Markdown("*Select entities from the dropdowns to create connections (click 'Process Entities' first)
|
| 724 |
|
| 725 |
# Relationship inputs in a grid (5 columns for first 5)
|
| 726 |
relationship_inputs = []
|
|
@@ -729,35 +819,35 @@ def create_interface():
|
|
| 729 |
with gr.Column(scale=1, min_width=180):
|
| 730 |
gr.Markdown("**Relationship 1**")
|
| 731 |
src1 = gr.Dropdown(label="From", choices=[])
|
| 732 |
-
rel1 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 733 |
tgt1 = gr.Dropdown(label="To", choices=[])
|
| 734 |
relationship_inputs.extend([src1, rel1, tgt1])
|
| 735 |
|
| 736 |
with gr.Column(scale=1, min_width=180):
|
| 737 |
gr.Markdown("**Relationship 2**")
|
| 738 |
src2 = gr.Dropdown(label="From", choices=[])
|
| 739 |
-
rel2 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 740 |
tgt2 = gr.Dropdown(label="To", choices=[])
|
| 741 |
relationship_inputs.extend([src2, rel2, tgt2])
|
| 742 |
|
| 743 |
with gr.Column(scale=1, min_width=180):
|
| 744 |
gr.Markdown("**Relationship 3**")
|
| 745 |
src3 = gr.Dropdown(label="From", choices=[])
|
| 746 |
-
rel3 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 747 |
tgt3 = gr.Dropdown(label="To", choices=[])
|
| 748 |
relationship_inputs.extend([src3, rel3, tgt3])
|
| 749 |
|
| 750 |
with gr.Column(scale=1, min_width=180):
|
| 751 |
gr.Markdown("**Relationship 4**")
|
| 752 |
src4 = gr.Dropdown(label="From", choices=[])
|
| 753 |
-
rel4 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 754 |
tgt4 = gr.Dropdown(label="To", choices=[])
|
| 755 |
relationship_inputs.extend([src4, rel4, tgt4])
|
| 756 |
|
| 757 |
with gr.Column(scale=1, min_width=180):
|
| 758 |
gr.Markdown("**Relationship 5**")
|
| 759 |
src5 = gr.Dropdown(label="From", choices=[])
|
| 760 |
-
rel5 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 761 |
tgt5 = gr.Dropdown(label="To", choices=[])
|
| 762 |
relationship_inputs.extend([src5, rel5, tgt5])
|
| 763 |
|
|
@@ -767,21 +857,21 @@ def create_interface():
|
|
| 767 |
with gr.Column(scale=1, min_width=180):
|
| 768 |
gr.Markdown("**Relationship 6**")
|
| 769 |
src6 = gr.Dropdown(label="From", choices=[])
|
| 770 |
-
rel6 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 771 |
tgt6 = gr.Dropdown(label="To", choices=[])
|
| 772 |
relationship_inputs.extend([src6, rel6, tgt6])
|
| 773 |
|
| 774 |
with gr.Column(scale=1, min_width=180):
|
| 775 |
gr.Markdown("**Relationship 7**")
|
| 776 |
src7 = gr.Dropdown(label="From", choices=[])
|
| 777 |
-
rel7 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 778 |
tgt7 = gr.Dropdown(label="To", choices=[])
|
| 779 |
relationship_inputs.extend([src7, rel7, tgt7])
|
| 780 |
|
| 781 |
with gr.Column(scale=1, min_width=180):
|
| 782 |
gr.Markdown("**Relationship 8**")
|
| 783 |
src8 = gr.Dropdown(label="From", choices=[])
|
| 784 |
-
rel8 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to")
|
| 785 |
tgt8 = gr.Dropdown(label="To", choices=[])
|
| 786 |
relationship_inputs.extend([src8, rel8, tgt8])
|
| 787 |
|
|
@@ -799,6 +889,22 @@ def create_interface():
|
|
| 799 |
with gr.Column(scale=1):
|
| 800 |
network_stats = gr.HTML()
|
| 801 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
# Colour legend
|
| 803 |
gr.HTML(f"""
|
| 804 |
<div style="background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); padding: 20px; border-radius: 10px; margin-top: 20px;">
|
|
@@ -863,7 +969,7 @@ def create_interface():
|
|
| 863 |
]
|
| 864 |
)
|
| 865 |
|
| 866 |
-
# Generate graph
|
| 867 |
all_inputs = entity_inputs + relationship_inputs
|
| 868 |
generate_btn.click(
|
| 869 |
fn=generate_network_graph,
|
|
@@ -871,6 +977,13 @@ def create_interface():
|
|
| 871 |
outputs=[network_plot, network_stats]
|
| 872 |
)
|
| 873 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 874 |
# Model Information & Documentation section
|
| 875 |
gr.HTML("""
|
| 876 |
<hr style="margin: 40px 0 20px 0;">
|
|
|
|
| 2 |
import networkx as nx
|
| 3 |
from pyvis.network import Network
|
| 4 |
import base64
|
| 5 |
+
import tempfile
|
| 6 |
+
import os
|
| 7 |
|
| 8 |
# Entity type colours (matching your NER tool)
|
| 9 |
# Updated for better distinction between Person, Location, and Event
|
|
|
|
| 90 |
return G
|
| 91 |
|
| 92 |
def create_pyvis_graph(self, G):
|
| 93 |
+
"""Create interactive PyVis visualisation. Returns (iframe_html, standalone_html)"""
|
| 94 |
if len(G.nodes) == 0:
|
| 95 |
+
return None, None
|
| 96 |
|
| 97 |
# Create PyVis network with dark theme
|
| 98 |
net = Network(
|
|
|
|
| 215 |
# Generate HTML
|
| 216 |
html = net.generate_html()
|
| 217 |
|
| 218 |
+
# Store standalone HTML for export
|
| 219 |
+
standalone_html = html
|
| 220 |
+
|
| 221 |
# Encode as base64 data URI for iframe src
|
| 222 |
html_bytes = html.encode('utf-8')
|
| 223 |
b64_html = base64.b64encode(html_bytes).decode('utf-8')
|
|
|
|
| 232 |
></iframe>
|
| 233 |
'''
|
| 234 |
|
| 235 |
+
return iframe_html, standalone_html
|
| 236 |
|
| 237 |
|
| 238 |
def collect_entities_from_records(
|
|
|
|
| 418 |
return empty_html, "β **No entities to display.** Please enter entities in Step 1 first."
|
| 419 |
|
| 420 |
# Create visualisation
|
| 421 |
+
graph_html, standalone_html = builder.create_pyvis_graph(G)
|
| 422 |
|
| 423 |
# Create statistics
|
| 424 |
stats_html = f'''
|
|
|
|
| 492 |
return error_html, f"β Error: {str(e)}"
|
| 493 |
|
| 494 |
|
| 495 |
+
def export_network_graph(
|
| 496 |
+
p1, l1, e1, o1, d1,
|
| 497 |
+
p2, l2, e2, o2, d2,
|
| 498 |
+
p3, l3, e3, o3, d3,
|
| 499 |
+
p4, l4, e4, o4, d4,
|
| 500 |
+
p5, l5, e5, o5, d5,
|
| 501 |
+
p6, l6, e6, o6, d6,
|
| 502 |
+
p7, l7, e7, o7, d7,
|
| 503 |
+
p8, l8, e8, o8, d8,
|
| 504 |
+
src1, rel1, tgt1,
|
| 505 |
+
src2, rel2, tgt2,
|
| 506 |
+
src3, rel3, tgt3,
|
| 507 |
+
src4, rel4, tgt4,
|
| 508 |
+
src5, rel5, tgt5,
|
| 509 |
+
src6, rel6, tgt6,
|
| 510 |
+
src7, rel7, tgt7,
|
| 511 |
+
src8, rel8, tgt8
|
| 512 |
+
):
|
| 513 |
+
"""Export the network graph as a standalone HTML file"""
|
| 514 |
+
try:
|
| 515 |
+
builder = NetworkGraphBuilder()
|
| 516 |
+
|
| 517 |
+
# Process each record
|
| 518 |
+
records = [
|
| 519 |
+
(p1, l1, e1, o1, d1),
|
| 520 |
+
(p2, l2, e2, o2, d2),
|
| 521 |
+
(p3, l3, e3, o3, d3),
|
| 522 |
+
(p4, l4, e4, o4, d4),
|
| 523 |
+
(p5, l5, e5, o5, d5),
|
| 524 |
+
(p6, l6, e6, o6, d6),
|
| 525 |
+
(p7, l7, e7, o7, d7),
|
| 526 |
+
(p8, l8, e8, o8, d8),
|
| 527 |
+
]
|
| 528 |
+
|
| 529 |
+
for record_id, (person, location, event, org, date) in enumerate(records, 1):
|
| 530 |
+
if person:
|
| 531 |
+
builder.add_entity(person, 'PERSON', record_id)
|
| 532 |
+
if location:
|
| 533 |
+
builder.add_entity(location, 'LOCATION', record_id)
|
| 534 |
+
if event:
|
| 535 |
+
builder.add_entity(event, 'EVENT', record_id)
|
| 536 |
+
if org:
|
| 537 |
+
builder.add_entity(org, 'ORGANIZATION', record_id)
|
| 538 |
+
if date:
|
| 539 |
+
builder.add_entity(date, 'DATE', record_id)
|
| 540 |
+
|
| 541 |
+
# Process relationships
|
| 542 |
+
relationships = [
|
| 543 |
+
(src1, rel1, tgt1),
|
| 544 |
+
(src2, rel2, tgt2),
|
| 545 |
+
(src3, rel3, tgt3),
|
| 546 |
+
(src4, rel4, tgt4),
|
| 547 |
+
(src5, rel5, tgt5),
|
| 548 |
+
(src6, rel6, tgt6),
|
| 549 |
+
(src7, rel7, tgt7),
|
| 550 |
+
(src8, rel8, tgt8),
|
| 551 |
+
]
|
| 552 |
+
|
| 553 |
+
for source, rel_type, target in relationships:
|
| 554 |
+
if source and target:
|
| 555 |
+
builder.add_relationship(source, target, rel_type)
|
| 556 |
+
|
| 557 |
+
# Build graph
|
| 558 |
+
G = builder.build_graph()
|
| 559 |
+
|
| 560 |
+
if len(G.nodes) == 0:
|
| 561 |
+
return None
|
| 562 |
+
|
| 563 |
+
# Create visualisation
|
| 564 |
+
_, standalone_html = builder.create_pyvis_graph(G)
|
| 565 |
+
|
| 566 |
+
# Save standalone HTML to a temporary file for download
|
| 567 |
+
if standalone_html:
|
| 568 |
+
export_file = tempfile.NamedTemporaryFile(
|
| 569 |
+
mode='w',
|
| 570 |
+
suffix='.html',
|
| 571 |
+
prefix='network_graph_',
|
| 572 |
+
delete=False,
|
| 573 |
+
encoding='utf-8'
|
| 574 |
+
)
|
| 575 |
+
export_file.write(standalone_html)
|
| 576 |
+
export_file.close()
|
| 577 |
+
return export_file.name
|
| 578 |
+
|
| 579 |
+
return None
|
| 580 |
+
|
| 581 |
+
except Exception as e:
|
| 582 |
+
return None
|
| 583 |
+
|
| 584 |
+
|
| 585 |
def load_austen_example():
|
| 586 |
"""Load the Jane Austen Pride and Prejudice example"""
|
| 587 |
return (
|
|
|
|
| 604 |
)
|
| 605 |
|
| 606 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
def load_wwii_example():
|
| 608 |
"""Load a WWII history example"""
|
| 609 |
return (
|
|
|
|
| 652 |
### How to use this tool:
|
| 653 |
1. **π Enter entities** in the records below (or load an example to get started)
|
| 654 |
2. **βοΈ Click "Process Entities"** to collect and prepare all entities for relationships
|
| 655 |
+
3. **π€ Define relationships** between entities using the dropdowns (or type your own relationship type)
|
| 656 |
4. **π¨ Click "Generate Network Graph"** to visualise
|
| 657 |
5. **ποΈ Explore** - drag nodes to rearrange, scroll to zoom, hover for details
|
| 658 |
+
6. **πΎ Export (optional)** - click "Export as HTML" to download your graph as an interactive file
|
| 659 |
""")
|
| 660 |
|
| 661 |
gr.HTML("""
|
|
|
|
| 810 |
|
| 811 |
# ==================== STEP 3: RELATIONSHIPS (Grid) ====================
|
| 812 |
gr.Markdown("## π€ Step 3: Define Relationships")
|
| 813 |
+
gr.Markdown("*Select entities from the dropdowns to create connections (click 'Process Entities' first). You can also type your own relationship type.*")
|
| 814 |
|
| 815 |
# Relationship inputs in a grid (5 columns for first 5)
|
| 816 |
relationship_inputs = []
|
|
|
|
| 819 |
with gr.Column(scale=1, min_width=180):
|
| 820 |
gr.Markdown("**Relationship 1**")
|
| 821 |
src1 = gr.Dropdown(label="From", choices=[])
|
| 822 |
+
rel1 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 823 |
tgt1 = gr.Dropdown(label="To", choices=[])
|
| 824 |
relationship_inputs.extend([src1, rel1, tgt1])
|
| 825 |
|
| 826 |
with gr.Column(scale=1, min_width=180):
|
| 827 |
gr.Markdown("**Relationship 2**")
|
| 828 |
src2 = gr.Dropdown(label="From", choices=[])
|
| 829 |
+
rel2 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 830 |
tgt2 = gr.Dropdown(label="To", choices=[])
|
| 831 |
relationship_inputs.extend([src2, rel2, tgt2])
|
| 832 |
|
| 833 |
with gr.Column(scale=1, min_width=180):
|
| 834 |
gr.Markdown("**Relationship 3**")
|
| 835 |
src3 = gr.Dropdown(label="From", choices=[])
|
| 836 |
+
rel3 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 837 |
tgt3 = gr.Dropdown(label="To", choices=[])
|
| 838 |
relationship_inputs.extend([src3, rel3, tgt3])
|
| 839 |
|
| 840 |
with gr.Column(scale=1, min_width=180):
|
| 841 |
gr.Markdown("**Relationship 4**")
|
| 842 |
src4 = gr.Dropdown(label="From", choices=[])
|
| 843 |
+
rel4 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 844 |
tgt4 = gr.Dropdown(label="To", choices=[])
|
| 845 |
relationship_inputs.extend([src4, rel4, tgt4])
|
| 846 |
|
| 847 |
with gr.Column(scale=1, min_width=180):
|
| 848 |
gr.Markdown("**Relationship 5**")
|
| 849 |
src5 = gr.Dropdown(label="From", choices=[])
|
| 850 |
+
rel5 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 851 |
tgt5 = gr.Dropdown(label="To", choices=[])
|
| 852 |
relationship_inputs.extend([src5, rel5, tgt5])
|
| 853 |
|
|
|
|
| 857 |
with gr.Column(scale=1, min_width=180):
|
| 858 |
gr.Markdown("**Relationship 6**")
|
| 859 |
src6 = gr.Dropdown(label="From", choices=[])
|
| 860 |
+
rel6 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 861 |
tgt6 = gr.Dropdown(label="To", choices=[])
|
| 862 |
relationship_inputs.extend([src6, rel6, tgt6])
|
| 863 |
|
| 864 |
with gr.Column(scale=1, min_width=180):
|
| 865 |
gr.Markdown("**Relationship 7**")
|
| 866 |
src7 = gr.Dropdown(label="From", choices=[])
|
| 867 |
+
rel7 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 868 |
tgt7 = gr.Dropdown(label="To", choices=[])
|
| 869 |
relationship_inputs.extend([src7, rel7, tgt7])
|
| 870 |
|
| 871 |
with gr.Column(scale=1, min_width=180):
|
| 872 |
gr.Markdown("**Relationship 8**")
|
| 873 |
src8 = gr.Dropdown(label="From", choices=[])
|
| 874 |
+
rel8 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
|
| 875 |
tgt8 = gr.Dropdown(label="To", choices=[])
|
| 876 |
relationship_inputs.extend([src8, rel8, tgt8])
|
| 877 |
|
|
|
|
| 889 |
with gr.Column(scale=1):
|
| 890 |
network_stats = gr.HTML()
|
| 891 |
|
| 892 |
+
# Export section
|
| 893 |
+
gr.Markdown("### πΎ Export Your Graph")
|
| 894 |
+
gr.Markdown("*Generate a graph first, then click export to download*")
|
| 895 |
+
with gr.Row():
|
| 896 |
+
export_btn = gr.Button("πΎ Export as HTML", variant="secondary", size="sm")
|
| 897 |
+
export_file = gr.File(
|
| 898 |
+
label="Download Interactive HTML",
|
| 899 |
+
file_types=[".html"],
|
| 900 |
+
interactive=False
|
| 901 |
+
)
|
| 902 |
+
gr.HTML("""
|
| 903 |
+
<div style="background-color: #e8f4f8; border: 1px solid #bee5eb; border-radius: 8px; padding: 12px; margin: 10px 0;">
|
| 904 |
+
<span style="color: #0c5460;">π‘ The exported HTML file is fully interactive β open it in any web browser to explore your network!</span>
|
| 905 |
+
</div>
|
| 906 |
+
""")
|
| 907 |
+
|
| 908 |
# Colour legend
|
| 909 |
gr.HTML(f"""
|
| 910 |
<div style="background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); padding: 20px; border-radius: 10px; margin-top: 20px;">
|
|
|
|
| 969 |
]
|
| 970 |
)
|
| 971 |
|
| 972 |
+
# Generate graph - outputs the visualisation and stats
|
| 973 |
all_inputs = entity_inputs + relationship_inputs
|
| 974 |
generate_btn.click(
|
| 975 |
fn=generate_network_graph,
|
|
|
|
| 977 |
outputs=[network_plot, network_stats]
|
| 978 |
)
|
| 979 |
|
| 980 |
+
# Export graph - separate button for downloading
|
| 981 |
+
export_btn.click(
|
| 982 |
+
fn=export_network_graph,
|
| 983 |
+
inputs=all_inputs,
|
| 984 |
+
outputs=[export_file]
|
| 985 |
+
)
|
| 986 |
+
|
| 987 |
# Model Information & Documentation section
|
| 988 |
gr.HTML("""
|
| 989 |
<hr style="margin: 40px 0 20px 0;">
|