SorrelC commited on
Commit
9093322
Β·
verified Β·
1 Parent(s): 041dfb0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -81
app.py CHANGED
@@ -243,7 +243,9 @@ def collect_entities_from_records(
243
  p5, l5, e5, o5, d5,
244
  p6, l6, e6, o6, d6,
245
  p7, l7, e7, o7, d7,
246
- p8, l8, e8, o8, d8
 
 
247
  ):
248
  """Collect all entities from the input fields"""
249
  builder = NetworkGraphBuilder()
@@ -258,6 +260,8 @@ def collect_entities_from_records(
258
  (p6, l6, e6, o6, d6),
259
  (p7, l7, e7, o7, d7),
260
  (p8, l8, e8, o8, d8),
 
 
261
  ]
262
 
263
  for record_id, (person, location, event, org, date) in enumerate(records, 1):
@@ -318,7 +322,7 @@ def collect_entities_from_records(
318
  </div>
319
  '''
320
 
321
- # Return summary and update all 16 dropdowns (8 source + 8 target)
322
  return (
323
  summary_html,
324
  gr.update(choices=entity_names, value=None), # source 1
@@ -337,6 +341,10 @@ def collect_entities_from_records(
337
  gr.update(choices=entity_names, value=None), # target 7
338
  gr.update(choices=entity_names, value=None), # source 8
339
  gr.update(choices=entity_names, value=None), # target 8
 
 
 
 
340
  )
341
 
342
 
@@ -349,6 +357,8 @@ def generate_network_graph(
349
  p6, l6, e6, o6, d6,
350
  p7, l7, e7, o7, d7,
351
  p8, l8, e8, o8, d8,
 
 
352
  src1, rel1, tgt1,
353
  src2, rel2, tgt2,
354
  src3, rel3, tgt3,
@@ -356,7 +366,9 @@ def generate_network_graph(
356
  src5, rel5, tgt5,
357
  src6, rel6, tgt6,
358
  src7, rel7, tgt7,
359
- src8, rel8, tgt8
 
 
360
  ):
361
  """Generate the network graph from all inputs"""
362
  try:
@@ -372,6 +384,8 @@ def generate_network_graph(
372
  (p6, l6, e6, o6, d6),
373
  (p7, l7, e7, o7, d7),
374
  (p8, l8, e8, o8, d8),
 
 
375
  ]
376
 
377
  for record_id, (person, location, event, org, date) in enumerate(records, 1):
@@ -386,7 +400,7 @@ def generate_network_graph(
386
  if date:
387
  builder.add_entity(date, 'DATE', record_id)
388
 
389
- # Process relationships (now 8 total)
390
  relationships = [
391
  (src1, rel1, tgt1),
392
  (src2, rel2, tgt2),
@@ -396,6 +410,8 @@ def generate_network_graph(
396
  (src6, rel6, tgt6),
397
  (src7, rel7, tgt7),
398
  (src8, rel8, tgt8),
 
 
399
  ]
400
 
401
  for source, rel_type, target in relationships:
@@ -420,7 +436,7 @@ def generate_network_graph(
420
  # Create visualisation
421
  graph_html, standalone_html = builder.create_pyvis_graph(G)
422
 
423
- # Create statistics
424
  stats_html = f'''
425
  <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; border: 1px solid #ddd;">
426
  <h4 style="margin: 0 0 10px 0;">πŸ“ˆ Network Statistics</h4>
@@ -474,6 +490,38 @@ def generate_network_graph(
474
 
475
  stats_html += '</div>'
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  return graph_html, stats_html
478
 
479
  except Exception as e:
@@ -501,6 +549,8 @@ def export_network_graph(
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,
@@ -508,7 +558,9 @@ def export_network_graph(
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:
@@ -524,6 +576,8 @@ def export_network_graph(
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):
@@ -548,6 +602,8 @@ def export_network_graph(
548
  (src6, rel6, tgt6),
549
  (src7, rel7, tgt7),
550
  (src8, rel8, tgt8),
 
 
551
  ]
552
 
553
  for source, rel_type, target in relationships:
@@ -601,6 +657,10 @@ def load_austen_example():
601
  "Mr. Collins", "", "Excellent Boiled Potatoes", "", "",
602
  # Record 8
603
  "Caroline Bingley", "", "", "", "",
 
 
 
 
604
  )
605
 
606
 
@@ -623,6 +683,10 @@ def load_wwii_example():
623
  "", "", "", "", "",
624
  # Record 8
625
  "", "", "", "", "",
 
 
 
 
626
  )
627
 
628
 
@@ -672,47 +736,47 @@ def create_interface():
672
 
673
  gr.HTML("<hr style='margin: 15px 0;'>")
674
 
675
- # ==================== STEP 1: ENTITY INPUT (4 per row) ====================
676
  gr.Markdown("## πŸ“ Step 1: Enter Entities")
677
 
678
  entity_inputs = []
679
 
680
- # First row: Records 1-4 (all on one line)
681
  with gr.Row():
682
- with gr.Column(scale=1, min_width=200):
683
  gr.Markdown("**Record 1**")
684
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
685
- p1 = gr.Textbox(label="", placeholder="e.g., Elizabeth Bennet", show_label=False)
686
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
687
- l1 = gr.Textbox(label="", placeholder="e.g., Longbourn", show_label=False)
688
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
689
- e1 = gr.Textbox(label="", placeholder="e.g., Meryton Ball", show_label=False)
690
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
691
- o1 = gr.Textbox(label="", placeholder="e.g., Bennet Family", show_label=False)
692
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
693
- d1 = gr.Textbox(label="", placeholder="e.g., 1811", show_label=False)
694
  entity_inputs.extend([p1, l1, e1, o1, d1])
695
 
696
- with gr.Column(scale=1, min_width=200):
697
  gr.Markdown("**Record 2**")
698
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
699
- p2 = gr.Textbox(label="", placeholder="e.g., Mr. Darcy", show_label=False)
700
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
701
- l2 = gr.Textbox(label="", placeholder="e.g., Pemberley", show_label=False)
702
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
703
- e2 = gr.Textbox(label="", placeholder="e.g., Netherfield Ball", show_label=False)
704
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
705
- o2 = gr.Textbox(label="", placeholder="e.g., Darcy Estate", show_label=False)
706
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
707
  d2 = gr.Textbox(label="", placeholder="", show_label=False)
708
  entity_inputs.extend([p2, l2, e2, o2, d2])
709
 
710
- with gr.Column(scale=1, min_width=200):
711
  gr.Markdown("**Record 3**")
712
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
713
- p3 = gr.Textbox(label="", placeholder="e.g., Jane Bennet", show_label=False)
714
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
715
- l3 = gr.Textbox(label="", placeholder="e.g., Netherfield", show_label=False)
716
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
717
  e3 = gr.Textbox(label="", placeholder="", show_label=False)
718
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
@@ -721,12 +785,12 @@ def create_interface():
721
  d3 = gr.Textbox(label="", placeholder="", show_label=False)
722
  entity_inputs.extend([p3, l3, e3, o3, d3])
723
 
724
- with gr.Column(scale=1, min_width=200):
725
  gr.Markdown("**Record 4**")
726
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
727
- p4 = gr.Textbox(label="", placeholder="e.g., Mr. Bingley", show_label=False)
728
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
729
- l4 = gr.Textbox(label="", placeholder="e.g., London", show_label=False)
730
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
731
  e4 = gr.Textbox(label="", placeholder="", show_label=False)
732
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
@@ -734,25 +798,25 @@ def create_interface():
734
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
735
  d4 = gr.Textbox(label="", placeholder="", show_label=False)
736
  entity_inputs.extend([p4, l4, e4, o4, d4])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
 
738
- # Additional records 5-8
739
- with gr.Accordion("βž• Additional Records (5-8)", open=False):
740
  with gr.Row():
741
- with gr.Column(scale=1, min_width=200):
742
- gr.Markdown("**Record 5**")
743
- gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
744
- p5 = gr.Textbox(label="", show_label=False)
745
- gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
746
- l5 = gr.Textbox(label="", show_label=False)
747
- gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
748
- e5 = gr.Textbox(label="", show_label=False)
749
- gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
750
- o5 = gr.Textbox(label="", show_label=False)
751
- gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
752
- d5 = gr.Textbox(label="", show_label=False)
753
- entity_inputs.extend([p5, l5, e5, o5, d5])
754
-
755
- with gr.Column(scale=1, min_width=200):
756
  gr.Markdown("**Record 6**")
757
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
758
  p6 = gr.Textbox(label="", show_label=False)
@@ -766,7 +830,7 @@ def create_interface():
766
  d6 = gr.Textbox(label="", show_label=False)
767
  entity_inputs.extend([p6, l6, e6, o6, d6])
768
 
769
- with gr.Column(scale=1, min_width=200):
770
  gr.Markdown("**Record 7**")
771
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
772
  p7 = gr.Textbox(label="", show_label=False)
@@ -780,7 +844,7 @@ def create_interface():
780
  d7 = gr.Textbox(label="", show_label=False)
781
  entity_inputs.extend([p7, l7, e7, o7, d7])
782
 
783
- with gr.Column(scale=1, min_width=200):
784
  gr.Markdown("**Record 8**")
785
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
786
  p8 = gr.Textbox(label="", show_label=False)
@@ -793,6 +857,34 @@ def create_interface():
793
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
794
  d8 = gr.Textbox(label="", show_label=False)
795
  entity_inputs.extend([p8, l8, e8, o8, d8])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
796
 
797
  gr.HTML("<hr style='margin: 20px 0;'>")
798
 
@@ -851,8 +943,8 @@ def create_interface():
851
  tgt5 = gr.Dropdown(label="To", choices=[])
852
  relationship_inputs.extend([src5, rel5, tgt5])
853
 
854
- # Additional relationships 6-8
855
- with gr.Accordion("βž• Additional Relationships (6-8)", open=False):
856
  with gr.Row():
857
  with gr.Column(scale=1, min_width=180):
858
  gr.Markdown("**Relationship 6**")
@@ -874,6 +966,20 @@ def create_interface():
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
 
878
  gr.HTML("<hr style='margin: 20px 0;'>")
879
 
@@ -882,7 +988,7 @@ def create_interface():
882
 
883
  generate_btn = gr.Button("🎨 Generate Network Graph", variant="primary", size="lg")
884
 
885
- # Full-width network graph with stats sidebar
886
  with gr.Row():
887
  with gr.Column(scale=3):
888
  network_plot = gr.HTML(label="Interactive Network Graph")
@@ -905,38 +1011,6 @@ def create_interface():
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;">
911
- <h4 style="color: white; margin: 0 0 15px 0;">🎨 Entity Colour Legend</h4>
912
- <div style="display: flex; flex-wrap: wrap; gap: 20px;">
913
- <span style="display: flex; align-items: center; gap: 8px; color: white;">
914
- <span style="width: 20px; height: 20px; border-radius: 50%; background-color: {ENTITY_COLOURS['PERSON']}; display: inline-block; border: 2px solid white;"></span>
915
- Person
916
- </span>
917
- <span style="display: flex; align-items: center; gap: 8px; color: white;">
918
- <span style="width: 20px; height: 20px; border-radius: 50%; background-color: {ENTITY_COLOURS['LOCATION']}; display: inline-block; border: 2px solid white;"></span>
919
- Location
920
- </span>
921
- <span style="display: flex; align-items: center; gap: 8px; color: white;">
922
- <span style="width: 20px; height: 20px; border-radius: 50%; background-color: {ENTITY_COLOURS['EVENT']}; display: inline-block; border: 2px solid white;"></span>
923
- Event
924
- </span>
925
- <span style="display: flex; align-items: center; gap: 8px; color: white;">
926
- <span style="width: 20px; height: 20px; border-radius: 50%; background-color: {ENTITY_COLOURS['ORGANIZATION']}; display: inline-block; border: 2px solid white;"></span>
927
- Organisation
928
- </span>
929
- <span style="display: flex; align-items: center; gap: 8px; color: white;">
930
- <span style="width: 20px; height: 20px; border-radius: 50%; background-color: {ENTITY_COLOURS['DATE']}; display: inline-block; border: 2px solid white;"></span>
931
- Date
932
- </span>
933
- </div>
934
- <p style="color: white; margin: 15px 0 0 0; font-size: 13px;">
935
- πŸ–±οΈ <strong>Interaction:</strong> Drag nodes to rearrange β€’ Scroll to zoom β€’ Hover for details
936
- </p>
937
- </div>
938
- """)
939
-
940
  # ==================== WIRE UP EVENTS ====================
941
 
942
  # Example buttons
@@ -952,7 +1026,7 @@ def create_interface():
952
  outputs=entity_inputs
953
  )
954
 
955
- # Collect entities - now updates 16 dropdowns (8 relationships x 2)
956
  collect_btn.click(
957
  fn=collect_entities_from_records,
958
  inputs=entity_inputs,
@@ -965,7 +1039,9 @@ def create_interface():
965
  src5, tgt5,
966
  src6, tgt6,
967
  src7, tgt7,
968
- src8, tgt8
 
 
969
  ]
970
  )
971
 
 
243
  p5, l5, e5, o5, d5,
244
  p6, l6, e6, o6, d6,
245
  p7, l7, e7, o7, d7,
246
+ p8, l8, e8, o8, d8,
247
+ p9, l9, e9, o9, d9,
248
+ p10, l10, e10, o10, d10
249
  ):
250
  """Collect all entities from the input fields"""
251
  builder = NetworkGraphBuilder()
 
260
  (p6, l6, e6, o6, d6),
261
  (p7, l7, e7, o7, d7),
262
  (p8, l8, e8, o8, d8),
263
+ (p9, l9, e9, o9, d9),
264
+ (p10, l10, e10, o10, d10),
265
  ]
266
 
267
  for record_id, (person, location, event, org, date) in enumerate(records, 1):
 
322
  </div>
323
  '''
324
 
325
+ # Return summary and update all 20 dropdowns (10 source + 10 target)
326
  return (
327
  summary_html,
328
  gr.update(choices=entity_names, value=None), # source 1
 
341
  gr.update(choices=entity_names, value=None), # target 7
342
  gr.update(choices=entity_names, value=None), # source 8
343
  gr.update(choices=entity_names, value=None), # target 8
344
+ gr.update(choices=entity_names, value=None), # source 9
345
+ gr.update(choices=entity_names, value=None), # target 9
346
+ gr.update(choices=entity_names, value=None), # source 10
347
+ gr.update(choices=entity_names, value=None), # target 10
348
  )
349
 
350
 
 
357
  p6, l6, e6, o6, d6,
358
  p7, l7, e7, o7, d7,
359
  p8, l8, e8, o8, d8,
360
+ p9, l9, e9, o9, d9,
361
+ p10, l10, e10, o10, d10,
362
  src1, rel1, tgt1,
363
  src2, rel2, tgt2,
364
  src3, rel3, tgt3,
 
366
  src5, rel5, tgt5,
367
  src6, rel6, tgt6,
368
  src7, rel7, tgt7,
369
+ src8, rel8, tgt8,
370
+ src9, rel9, tgt9,
371
+ src10, rel10, tgt10
372
  ):
373
  """Generate the network graph from all inputs"""
374
  try:
 
384
  (p6, l6, e6, o6, d6),
385
  (p7, l7, e7, o7, d7),
386
  (p8, l8, e8, o8, d8),
387
+ (p9, l9, e9, o9, d9),
388
+ (p10, l10, e10, o10, d10),
389
  ]
390
 
391
  for record_id, (person, location, event, org, date) in enumerate(records, 1):
 
400
  if date:
401
  builder.add_entity(date, 'DATE', record_id)
402
 
403
+ # Process relationships (now 10 total)
404
  relationships = [
405
  (src1, rel1, tgt1),
406
  (src2, rel2, tgt2),
 
410
  (src6, rel6, tgt6),
411
  (src7, rel7, tgt7),
412
  (src8, rel8, tgt8),
413
+ (src9, rel9, tgt9),
414
+ (src10, rel10, tgt10),
415
  ]
416
 
417
  for source, rel_type, target in relationships:
 
436
  # Create visualisation
437
  graph_html, standalone_html = builder.create_pyvis_graph(G)
438
 
439
+ # Create statistics with colour legend included
440
  stats_html = f'''
441
  <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; border: 1px solid #ddd;">
442
  <h4 style="margin: 0 0 10px 0;">πŸ“ˆ Network Statistics</h4>
 
490
 
491
  stats_html += '</div>'
492
 
493
+ # Add colour legend below stats
494
+ stats_html += f'''
495
+ <div style="background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); padding: 15px; border-radius: 10px; margin-top: 15px;">
496
+ <h4 style="color: white; margin: 0 0 12px 0; font-size: 14px;">🎨 Entity Colour Legend</h4>
497
+ <div style="display: flex; flex-direction: column; gap: 8px;">
498
+ <span style="display: flex; align-items: center; gap: 8px; color: white; font-size: 13px;">
499
+ <span style="width: 16px; height: 16px; border-radius: 50%; background-color: {ENTITY_COLOURS['PERSON']}; display: inline-block; border: 2px solid white;"></span>
500
+ Person
501
+ </span>
502
+ <span style="display: flex; align-items: center; gap: 8px; color: white; font-size: 13px;">
503
+ <span style="width: 16px; height: 16px; border-radius: 50%; background-color: {ENTITY_COLOURS['LOCATION']}; display: inline-block; border: 2px solid white;"></span>
504
+ Location
505
+ </span>
506
+ <span style="display: flex; align-items: center; gap: 8px; color: white; font-size: 13px;">
507
+ <span style="width: 16px; height: 16px; border-radius: 50%; background-color: {ENTITY_COLOURS['EVENT']}; display: inline-block; border: 2px solid white;"></span>
508
+ Event
509
+ </span>
510
+ <span style="display: flex; align-items: center; gap: 8px; color: white; font-size: 13px;">
511
+ <span style="width: 16px; height: 16px; border-radius: 50%; background-color: {ENTITY_COLOURS['ORGANIZATION']}; display: inline-block; border: 2px solid white;"></span>
512
+ Organisation
513
+ </span>
514
+ <span style="display: flex; align-items: center; gap: 8px; color: white; font-size: 13px;">
515
+ <span style="width: 16px; height: 16px; border-radius: 50%; background-color: {ENTITY_COLOURS['DATE']}; display: inline-block; border: 2px solid white;"></span>
516
+ Date
517
+ </span>
518
+ </div>
519
+ <p style="color: white; margin: 12px 0 0 0; font-size: 12px;">
520
+ πŸ–±οΈ <strong style="color: white;">Interaction:</strong> Drag nodes β€’ Scroll to zoom β€’ Hover for details
521
+ </p>
522
+ </div>
523
+ '''
524
+
525
  return graph_html, stats_html
526
 
527
  except Exception as e:
 
549
  p6, l6, e6, o6, d6,
550
  p7, l7, e7, o7, d7,
551
  p8, l8, e8, o8, d8,
552
+ p9, l9, e9, o9, d9,
553
+ p10, l10, e10, o10, d10,
554
  src1, rel1, tgt1,
555
  src2, rel2, tgt2,
556
  src3, rel3, tgt3,
 
558
  src5, rel5, tgt5,
559
  src6, rel6, tgt6,
560
  src7, rel7, tgt7,
561
+ src8, rel8, tgt8,
562
+ src9, rel9, tgt9,
563
+ src10, rel10, tgt10
564
  ):
565
  """Export the network graph as a standalone HTML file"""
566
  try:
 
576
  (p6, l6, e6, o6, d6),
577
  (p7, l7, e7, o7, d7),
578
  (p8, l8, e8, o8, d8),
579
+ (p9, l9, e9, o9, d9),
580
+ (p10, l10, e10, o10, d10),
581
  ]
582
 
583
  for record_id, (person, location, event, org, date) in enumerate(records, 1):
 
602
  (src6, rel6, tgt6),
603
  (src7, rel7, tgt7),
604
  (src8, rel8, tgt8),
605
+ (src9, rel9, tgt9),
606
+ (src10, rel10, tgt10),
607
  ]
608
 
609
  for source, rel_type, target in relationships:
 
657
  "Mr. Collins", "", "Excellent Boiled Potatoes", "", "",
658
  # Record 8
659
  "Caroline Bingley", "", "", "", "",
660
+ # Record 9
661
+ "Lydia Bennet", "", "", "", "",
662
+ # Record 10
663
+ "Lady Catherine de Bourgh", "", "", "", "",
664
  )
665
 
666
 
 
683
  "", "", "", "", "",
684
  # Record 8
685
  "", "", "", "", "",
686
+ # Record 9
687
+ "", "", "", "", "",
688
+ # Record 10
689
+ "", "", "", "", "",
690
  )
691
 
692
 
 
736
 
737
  gr.HTML("<hr style='margin: 15px 0;'>")
738
 
739
+ # ==================== STEP 1: ENTITY INPUT (5 per row) ====================
740
  gr.Markdown("## πŸ“ Step 1: Enter Entities")
741
 
742
  entity_inputs = []
743
 
744
+ # First row: Records 1-5
745
  with gr.Row():
746
+ with gr.Column(scale=1, min_width=180):
747
  gr.Markdown("**Record 1**")
748
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
749
+ p1 = gr.Textbox(label="", placeholder="e.g. Elizabeth Bennet", show_label=False)
750
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
751
+ l1 = gr.Textbox(label="", placeholder="e.g. Longbourn", show_label=False)
752
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
753
+ e1 = gr.Textbox(label="", placeholder="e.g. Meryton Ball", show_label=False)
754
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
755
+ o1 = gr.Textbox(label="", placeholder="e.g. The Militia", show_label=False)
756
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
757
+ d1 = gr.Textbox(label="", placeholder="e.g. 1812", show_label=False)
758
  entity_inputs.extend([p1, l1, e1, o1, d1])
759
 
760
+ with gr.Column(scale=1, min_width=180):
761
  gr.Markdown("**Record 2**")
762
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
763
+ p2 = gr.Textbox(label="", placeholder="e.g. Mr. Darcy", show_label=False)
764
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
765
+ l2 = gr.Textbox(label="", placeholder="e.g. Pemberley", show_label=False)
766
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
767
+ e2 = gr.Textbox(label="", placeholder="", show_label=False)
768
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
769
+ o2 = gr.Textbox(label="", placeholder="", show_label=False)
770
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
771
  d2 = gr.Textbox(label="", placeholder="", show_label=False)
772
  entity_inputs.extend([p2, l2, e2, o2, d2])
773
 
774
+ with gr.Column(scale=1, min_width=180):
775
  gr.Markdown("**Record 3**")
776
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
777
+ p3 = gr.Textbox(label="", placeholder="", show_label=False)
778
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
779
+ l3 = gr.Textbox(label="", placeholder="", show_label=False)
780
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
781
  e3 = gr.Textbox(label="", placeholder="", show_label=False)
782
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
 
785
  d3 = gr.Textbox(label="", placeholder="", show_label=False)
786
  entity_inputs.extend([p3, l3, e3, o3, d3])
787
 
788
+ with gr.Column(scale=1, min_width=180):
789
  gr.Markdown("**Record 4**")
790
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
791
+ p4 = gr.Textbox(label="", placeholder="", show_label=False)
792
  gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
793
+ l4 = gr.Textbox(label="", placeholder="", show_label=False)
794
  gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
795
  e4 = gr.Textbox(label="", placeholder="", show_label=False)
796
  gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
 
798
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
799
  d4 = gr.Textbox(label="", placeholder="", show_label=False)
800
  entity_inputs.extend([p4, l4, e4, o4, d4])
801
+
802
+ with gr.Column(scale=1, min_width=180):
803
+ gr.Markdown("**Record 5**")
804
+ gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
805
+ p5 = gr.Textbox(label="", placeholder="", show_label=False)
806
+ gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
807
+ l5 = gr.Textbox(label="", placeholder="", show_label=False)
808
+ gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
809
+ e5 = gr.Textbox(label="", placeholder="", show_label=False)
810
+ gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
811
+ o5 = gr.Textbox(label="", placeholder="", show_label=False)
812
+ gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
813
+ d5 = gr.Textbox(label="", placeholder="", show_label=False)
814
+ entity_inputs.extend([p5, l5, e5, o5, d5])
815
 
816
+ # Additional records 6-10
817
+ with gr.Accordion("βž• Additional Records (6-10)", open=False):
818
  with gr.Row():
819
+ with gr.Column(scale=1, min_width=180):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
820
  gr.Markdown("**Record 6**")
821
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
822
  p6 = gr.Textbox(label="", show_label=False)
 
830
  d6 = gr.Textbox(label="", show_label=False)
831
  entity_inputs.extend([p6, l6, e6, o6, d6])
832
 
833
+ with gr.Column(scale=1, min_width=180):
834
  gr.Markdown("**Record 7**")
835
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
836
  p7 = gr.Textbox(label="", show_label=False)
 
844
  d7 = gr.Textbox(label="", show_label=False)
845
  entity_inputs.extend([p7, l7, e7, o7, d7])
846
 
847
+ with gr.Column(scale=1, min_width=180):
848
  gr.Markdown("**Record 8**")
849
  gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
850
  p8 = gr.Textbox(label="", show_label=False)
 
857
  gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
858
  d8 = gr.Textbox(label="", show_label=False)
859
  entity_inputs.extend([p8, l8, e8, o8, d8])
860
+
861
+ with gr.Column(scale=1, min_width=180):
862
+ gr.Markdown("**Record 9**")
863
+ gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
864
+ p9 = gr.Textbox(label="", show_label=False)
865
+ gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
866
+ l9 = gr.Textbox(label="", show_label=False)
867
+ gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
868
+ e9 = gr.Textbox(label="", show_label=False)
869
+ gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
870
+ o9 = gr.Textbox(label="", show_label=False)
871
+ gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
872
+ d9 = gr.Textbox(label="", show_label=False)
873
+ entity_inputs.extend([p9, l9, e9, o9, d9])
874
+
875
+ with gr.Column(scale=1, min_width=180):
876
+ gr.Markdown("**Record 10**")
877
+ gr.HTML(create_coloured_label("Person", ENTITY_COLOURS['PERSON'], "πŸ‘€"))
878
+ p10 = gr.Textbox(label="", show_label=False)
879
+ gr.HTML(create_coloured_label("Location", ENTITY_COLOURS['LOCATION'], "πŸ“"))
880
+ l10 = gr.Textbox(label="", show_label=False)
881
+ gr.HTML(create_coloured_label("Event", ENTITY_COLOURS['EVENT'], "πŸ“…"))
882
+ e10 = gr.Textbox(label="", show_label=False)
883
+ gr.HTML(create_coloured_label("Organisation", ENTITY_COLOURS['ORGANIZATION'], "🏒"))
884
+ o10 = gr.Textbox(label="", show_label=False)
885
+ gr.HTML(create_coloured_label("Date", ENTITY_COLOURS['DATE'], "πŸ—“οΈ"))
886
+ d10 = gr.Textbox(label="", show_label=False)
887
+ entity_inputs.extend([p10, l10, e10, o10, d10])
888
 
889
  gr.HTML("<hr style='margin: 20px 0;'>")
890
 
 
943
  tgt5 = gr.Dropdown(label="To", choices=[])
944
  relationship_inputs.extend([src5, rel5, tgt5])
945
 
946
+ # Additional relationships 6-10
947
+ with gr.Accordion("βž• Additional Relationships (6-10)", open=False):
948
  with gr.Row():
949
  with gr.Column(scale=1, min_width=180):
950
  gr.Markdown("**Relationship 6**")
 
966
  rel8 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
967
  tgt8 = gr.Dropdown(label="To", choices=[])
968
  relationship_inputs.extend([src8, rel8, tgt8])
969
+
970
+ with gr.Column(scale=1, min_width=180):
971
+ gr.Markdown("**Relationship 9**")
972
+ src9 = gr.Dropdown(label="From", choices=[])
973
+ rel9 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
974
+ tgt9 = gr.Dropdown(label="To", choices=[])
975
+ relationship_inputs.extend([src9, rel9, tgt9])
976
+
977
+ with gr.Column(scale=1, min_width=180):
978
+ gr.Markdown("**Relationship 10**")
979
+ src10 = gr.Dropdown(label="From", choices=[])
980
+ rel10 = gr.Dropdown(label="Type", choices=RELATIONSHIP_TYPES, value="Related to", allow_custom_value=True)
981
+ tgt10 = gr.Dropdown(label="To", choices=[])
982
+ relationship_inputs.extend([src10, rel10, tgt10])
983
 
984
  gr.HTML("<hr style='margin: 20px 0;'>")
985
 
 
988
 
989
  generate_btn = gr.Button("🎨 Generate Network Graph", variant="primary", size="lg")
990
 
991
+ # Full-width network graph with stats sidebar (legend now included in stats)
992
  with gr.Row():
993
  with gr.Column(scale=3):
994
  network_plot = gr.HTML(label="Interactive Network Graph")
 
1011
  </div>
1012
  """)
1013
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
  # ==================== WIRE UP EVENTS ====================
1015
 
1016
  # Example buttons
 
1026
  outputs=entity_inputs
1027
  )
1028
 
1029
+ # Collect entities - now updates 20 dropdowns (10 relationships x 2)
1030
  collect_btn.click(
1031
  fn=collect_entities_from_records,
1032
  inputs=entity_inputs,
 
1039
  src5, tgt5,
1040
  src6, tgt6,
1041
  src7, tgt7,
1042
+ src8, tgt8,
1043
+ src9, tgt9,
1044
+ src10, tgt10
1045
  ]
1046
  )
1047