ginipick commited on
Commit
46324f5
Β·
verified Β·
1 Parent(s): a9aa021

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +265 -35
app.py CHANGED
@@ -8,26 +8,145 @@ import spacy
8
  from spacy import displacy
9
  from spacy.tokens import Span
10
  import random
11
- from tqdm import tqdm
 
12
 
13
  # Constants
14
  TITLE = "🌐 GraphMind: Phi-3 Instruct Graph Explorer"
15
  SUBTITLE = "✨ Extract and visualize knowledge graphs from any text in multiple languages"
16
 
17
- # Custom CSS for styling
18
  CUSTOM_CSS = """
19
  .gradio-container {
20
  font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
 
21
  }
22
  .gr-button-primary {
23
- background-color: #6366f1 !important;
 
 
 
 
 
 
 
 
24
  }
25
  .gr-button-secondary {
26
- border-color: #6366f1 !important;
27
- color: #6366f1 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
  """
30
 
 
 
 
 
 
 
 
31
  # Color utilities
32
  def get_random_light_color():
33
  r = random.randint(140, 255)
@@ -107,7 +226,13 @@ def create_custom_entity_viz(data, full_text):
107
  }
108
 
109
  html = displacy.render(doc, style="span", options=options)
110
- return html
 
 
 
 
 
 
111
 
112
  def create_graph(json_data):
113
  G = nx.Graph()
@@ -122,8 +247,8 @@ def create_graph(json_data):
122
 
123
  # Create network visualization
124
  nt = Network(
125
- width="720px",
126
- height="600px",
127
  directed=True,
128
  notebook=False,
129
  bgcolor="#f8fafc",
@@ -159,7 +284,7 @@ def create_graph(json_data):
159
  html = nt.generate_html()
160
  html = html.replace("'", '"')
161
 
162
- return f"""<iframe style="width: 100%; height: 620px; margin: 0 auto; border-radius: 8px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);"
163
  name="result" allow="midi; geolocation; microphone; camera; display-capture; encrypted-media;"
164
  sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-popups
165
  allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
@@ -169,6 +294,22 @@ def process_and_visualize(text, model, progress=gr.Progress()):
169
  if not text or not model:
170
  raise gr.Error("⚠️ Both text and model must be provided.")
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  progress(0, desc="Starting extraction...")
173
  json_data = extract(text, model)
174
 
@@ -182,6 +323,20 @@ def process_and_visualize(text, model, progress=gr.Progress()):
182
  edge_count = len(json_data["edges"])
183
  stats = f"πŸ“Š Extracted {node_count} entities and {edge_count} relationships"
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  progress(1.0, desc="Complete!")
186
  return graph_html, entities_viz, json_data, stats
187
 
@@ -206,56 +361,116 @@ EXAMPLES = [
206
  ν‰λ‹¨μ˜ ν˜Έν‰μ„ λ°›μ•˜λ‹€.""")]
207
  ]
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  def create_ui():
 
 
 
210
  with gr.Blocks(css=CUSTOM_CSS, title=TITLE) as demo:
211
- # Header
212
- gr.Markdown(f"# {TITLE}")
213
- gr.Markdown(f"{SUBTITLE}")
 
 
 
 
 
214
 
 
215
  with gr.Row():
216
- gr.Markdown("🌍 **Multilingual Support Available** πŸ”€")
217
-
218
- # Main interface
219
- with gr.Row():
220
- # Input column
221
- with gr.Column(scale=1):
222
  input_model = gr.Dropdown(
223
  MODEL_LIST,
224
  label="πŸ€– Select Model",
225
  info="Choose a model to process your text",
226
- value=MODEL_LIST[0] if MODEL_LIST else None
 
227
  )
228
 
229
  input_text = gr.TextArea(
230
  label="πŸ“ Input Text",
231
  info="Enter text in any language to extract a knowledge graph",
232
  placeholder="Enter text here...",
233
- lines=10
 
 
234
  )
235
 
236
  with gr.Row():
237
  submit_button = gr.Button("πŸš€ Extract & Visualize", variant="primary", scale=2)
238
  clear_button = gr.Button("πŸ”„ Clear", variant="secondary", scale=1)
239
 
 
 
 
 
 
 
240
  gr.Examples(
241
  examples=EXAMPLES,
242
  inputs=input_text,
243
- label="πŸ“š Example Texts (English & Korean)"
 
244
  )
245
 
246
- stats_output = gr.Markdown("", label="πŸ” Analysis Results")
247
-
248
- # Output column
249
- with gr.Column(scale=1):
250
- with gr.Tab("🧩 Knowledge Graph"):
251
- output_graph = gr.HTML(label="")
252
-
253
- with gr.Tab("🏷️ Entities"):
254
- output_entity_viz = gr.HTML(label="")
255
-
256
- with gr.Tab("πŸ“Š JSON Data"):
257
  output_json = gr.JSON(label="")
 
 
 
 
 
 
 
 
258
 
 
 
 
259
  # Functionality
260
  submit_button.click(
261
  fn=process_and_visualize,
@@ -269,10 +484,25 @@ def create_ui():
269
  outputs=[output_graph, output_entity_viz, output_json, stats_output]
270
  )
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  # Footer
273
- gr.Markdown("---")
274
- gr.Markdown("πŸ“‹ **Instructions:** Enter text in any language, select a model, and click 'Extract & Visualize' to generate a knowledge graph.")
275
- gr.Markdown("πŸ› οΈ Powered by Phi-3 Instruct Graph | Emergent Methods")
 
276
 
277
  return demo
278
 
 
8
  from spacy import displacy
9
  from spacy.tokens import Span
10
  import random
11
+ import os
12
+ import pickle
13
 
14
  # Constants
15
  TITLE = "🌐 GraphMind: Phi-3 Instruct Graph Explorer"
16
  SUBTITLE = "✨ Extract and visualize knowledge graphs from any text in multiple languages"
17
 
18
+ # Enhanced Custom CSS for styling with improved visuals
19
  CUSTOM_CSS = """
20
  .gradio-container {
21
  font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
22
+ background: linear-gradient(to bottom, #f9fafb, #f3f4f6);
23
  }
24
  .gr-button-primary {
25
+ background-color: #4f46e5 !important;
26
+ border: none !important;
27
+ color: white !important;
28
+ border-radius: 8px !important;
29
+ }
30
+ .gr-button-primary:hover {
31
+ background-color: #4338ca !important;
32
+ transform: translateY(-1px);
33
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
34
  }
35
  .gr-button-secondary {
36
+ border-color: #4f46e5 !important;
37
+ color: #4f46e5 !important;
38
+ border-radius: 8px !important;
39
+ }
40
+ .gr-button-secondary:hover {
41
+ background-color: #eef2ff !important;
42
+ transform: translateY(-1px);
43
+ }
44
+ .gr-box, .gr-input, .gr-textarea, .gr-dropdown {
45
+ border-radius: 8px !important;
46
+ border: 1px solid #e5e7eb !important;
47
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
48
+ }
49
+ .gr-padded {
50
+ padding: 16px !important;
51
+ }
52
+ .gr-form {
53
+ border: none !important;
54
+ background: transparent !important;
55
+ }
56
+ .gr-input:focus, .gr-textarea:focus, .gr-dropdown:focus {
57
+ border-color: #4f46e5 !important;
58
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2) !important;
59
+ }
60
+ .gr-panel {
61
+ border-radius: 12px !important;
62
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
63
+ background-color: white !important;
64
+ }
65
+ .gr-heading {
66
+ font-weight: 700 !important;
67
+ color: #111827 !important;
68
+ }
69
+ .gr-examples-table {
70
+ border-radius: 8px !important;
71
+ overflow: hidden !important;
72
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06) !important;
73
+ }
74
+ .gr-prose p {
75
+ margin-bottom: 0.75rem !important;
76
+ color: #4b5563 !important;
77
+ }
78
+ .gr-prose h1, .gr-prose h2, .gr-prose h3 {
79
+ font-weight: 700 !important;
80
+ color: #111827 !important;
81
+ }
82
+ .gr-tab {
83
+ border-radius: 8px 8px 0 0 !important;
84
+ }
85
+ .gr-tab-selected {
86
+ border-color: #4f46e5 !important;
87
+ color: #4f46e5 !important;
88
+ font-weight: 600 !important;
89
+ }
90
+ .visualization-container {
91
+ min-height: 600px !important;
92
+ margin-top: 2rem !important;
93
+ margin-bottom: 2rem !important;
94
+ border-radius: 16px !important;
95
+ overflow: hidden !important;
96
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1) !important;
97
+ }
98
+ .sidebar-container {
99
+ background-color: white !important;
100
+ border-radius: 12px !important;
101
+ padding: 16px !important;
102
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
103
+ }
104
+ .app-title {
105
+ background: linear-gradient(90deg, #4f46e5, #8b5cf6) !important;
106
+ -webkit-background-clip: text !important;
107
+ -webkit-text-fill-color: transparent !important;
108
+ font-weight: 800 !important;
109
+ font-size: 2.25rem !important;
110
+ margin-bottom: 0.5rem !important;
111
+ }
112
+ .app-subtitle {
113
+ color: #6b7280 !important;
114
+ font-size: 1.25rem !important;
115
+ margin-bottom: 2rem !important;
116
+ }
117
+ .graph-iframe iframe {
118
+ width: 100% !important;
119
+ height: 700px !important;
120
+ border-radius: 12px !important;
121
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
122
+ }
123
+ .results-container {
124
+ background-color: #f8fafc !important;
125
+ padding: 20px !important;
126
+ border-radius: 12px !important;
127
+ margin-top: 1rem !important;
128
+ margin-bottom: 1rem !important;
129
+ border: 1px solid #e2e8f0 !important;
130
+ }
131
+ .language-badge {
132
+ display: inline-block !important;
133
+ background-color: #4f46e5 !important;
134
+ color: white !important;
135
+ padding: 4px 12px !important;
136
+ border-radius: 16px !important;
137
+ font-weight: 600 !important;
138
+ font-size: 0.875rem !important;
139
+ margin-right: 8px !important;
140
  }
141
  """
142
 
143
+ # Cache directory and file paths
144
+ CACHE_DIR = "cache"
145
+ EXAMPLE_CACHE_FILE = os.path.join(CACHE_DIR, "first_example_cache.pkl")
146
+
147
+ # Create cache directory if it doesn't exist
148
+ os.makedirs(CACHE_DIR, exist_ok=True)
149
+
150
  # Color utilities
151
  def get_random_light_color():
152
  r = random.randint(140, 255)
 
226
  }
227
 
228
  html = displacy.render(doc, style="span", options=options)
229
+ # Add custom styling to the entity visualization
230
+ styled_html = f"""
231
+ <div style="padding: 20px; border-radius: 12px; background-color: white; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);">
232
+ {html}
233
+ </div>
234
+ """
235
+ return styled_html
236
 
237
  def create_graph(json_data):
238
  G = nx.Graph()
 
247
 
248
  # Create network visualization
249
  nt = Network(
250
+ width="100%",
251
+ height="700px",
252
  directed=True,
253
  notebook=False,
254
  bgcolor="#f8fafc",
 
284
  html = nt.generate_html()
285
  html = html.replace("'", '"')
286
 
287
+ return f"""<iframe style="width: 100%; height: 700px; margin: 0 auto; border-radius: 12px; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);"
288
  name="result" allow="midi; geolocation; microphone; camera; display-capture; encrypted-media;"
289
  sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-popups
290
  allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
 
294
  if not text or not model:
295
  raise gr.Error("⚠️ Both text and model must be provided.")
296
 
297
+ # Check if we're processing the first example for caching
298
+ is_first_example = text == EXAMPLES[0][0]
299
+
300
+ # Try to load from cache if it's the first example
301
+ if is_first_example and os.path.exists(EXAMPLE_CACHE_FILE):
302
+ try:
303
+ progress(0.3, desc="Loading from cache...")
304
+ with open(EXAMPLE_CACHE_FILE, 'rb') as f:
305
+ cache_data = pickle.load(f)
306
+
307
+ progress(1.0, desc="Loaded from cache!")
308
+ return cache_data["graph_html"], cache_data["entities_viz"], cache_data["json_data"], cache_data["stats"]
309
+ except Exception as e:
310
+ print(f"Cache loading error: {str(e)}")
311
+ # Continue with normal processing if cache fails
312
+
313
  progress(0, desc="Starting extraction...")
314
  json_data = extract(text, model)
315
 
 
323
  edge_count = len(json_data["edges"])
324
  stats = f"πŸ“Š Extracted {node_count} entities and {edge_count} relationships"
325
 
326
+ # Save to cache if it's the first example
327
+ if is_first_example:
328
+ try:
329
+ cache_data = {
330
+ "graph_html": graph_html,
331
+ "entities_viz": entities_viz,
332
+ "json_data": json_data,
333
+ "stats": stats
334
+ }
335
+ with open(EXAMPLE_CACHE_FILE, 'wb') as f:
336
+ pickle.dump(cache_data, f)
337
+ except Exception as e:
338
+ print(f"Cache saving error: {str(e)}")
339
+
340
  progress(1.0, desc="Complete!")
341
  return graph_html, entities_viz, json_data, stats
342
 
 
361
  ν‰λ‹¨μ˜ ν˜Έν‰μ„ λ°›μ•˜λ‹€.""")]
362
  ]
363
 
364
+ # Function to preprocess the first example when the app starts
365
+ def generate_first_example_cache():
366
+ """Generate cache for the first example if it doesn't exist"""
367
+ if not os.path.exists(EXAMPLE_CACHE_FILE):
368
+ print("Generating cache for first example...")
369
+ try:
370
+ text = EXAMPLES[0][0]
371
+ model = MODEL_LIST[0] if MODEL_LIST else None
372
+
373
+ if model:
374
+ # Extract data
375
+ json_data = extract(text, model)
376
+ entities_viz = create_custom_entity_viz(json_data, text)
377
+ graph_html = create_graph(json_data)
378
+
379
+ node_count = len(json_data["nodes"])
380
+ edge_count = len(json_data["edges"])
381
+ stats = f"πŸ“Š Extracted {node_count} entities and {edge_count} relationships"
382
+
383
+ # Save to cache
384
+ cache_data = {
385
+ "graph_html": graph_html,
386
+ "entities_viz": entities_viz,
387
+ "json_data": json_data,
388
+ "stats": stats
389
+ }
390
+ with open(EXAMPLE_CACHE_FILE, 'wb') as f:
391
+ pickle.dump(cache_data, f)
392
+
393
+ print("First example cache generated successfully")
394
+ return cache_data
395
+ except Exception as e:
396
+ print(f"Error generating first example cache: {str(e)}")
397
+ else:
398
+ print("First example cache already exists")
399
+ try:
400
+ with open(EXAMPLE_CACHE_FILE, 'rb') as f:
401
+ return pickle.load(f)
402
+ except Exception as e:
403
+ print(f"Error loading existing cache: {str(e)}")
404
+
405
+ return None
406
+
407
  def create_ui():
408
+ # Try to generate/load the first example cache
409
+ first_example_cache = generate_first_example_cache()
410
+
411
  with gr.Blocks(css=CUSTOM_CSS, title=TITLE) as demo:
412
+ # Header with enhanced styling
413
+ with gr.Row(elem_classes=["header-container"]):
414
+ with gr.Column():
415
+ gr.Markdown(f"<h1 class='app-title'>{TITLE}</h1>")
416
+ gr.Markdown(f"<p class='app-subtitle'>{SUBTITLE}</p>")
417
+
418
+ with gr.Row():
419
+ gr.Markdown("<span class='language-badge'>English</span><span class='language-badge'>Korean</span><span class='language-badge'>+ More</span>")
420
 
421
+ # Main content area - redesigned layout
422
  with gr.Row():
423
+ # Left panel - Input controls
424
+ with gr.Column(scale=1, elem_classes=["sidebar-container"]):
 
 
 
 
425
  input_model = gr.Dropdown(
426
  MODEL_LIST,
427
  label="πŸ€– Select Model",
428
  info="Choose a model to process your text",
429
+ value=MODEL_LIST[0] if MODEL_LIST else None,
430
+ elem_classes=["control-item"]
431
  )
432
 
433
  input_text = gr.TextArea(
434
  label="πŸ“ Input Text",
435
  info="Enter text in any language to extract a knowledge graph",
436
  placeholder="Enter text here...",
437
+ lines=8,
438
+ value=EXAMPLES[0][0], # Pre-fill with first example
439
+ elem_classes=["control-item"]
440
  )
441
 
442
  with gr.Row():
443
  submit_button = gr.Button("πŸš€ Extract & Visualize", variant="primary", scale=2)
444
  clear_button = gr.Button("πŸ”„ Clear", variant="secondary", scale=1)
445
 
446
+ # Statistics will appear here
447
+ stats_output = gr.Markdown("", label="πŸ” Analysis Results", elem_classes=["results-container"])
448
+
449
+ # Right panel - Examples moved to right side
450
+ with gr.Column(scale=1, elem_classes=["sidebar-container"]):
451
+ gr.Markdown("<h3>πŸ“š Example Texts</h3>")
452
  gr.Examples(
453
  examples=EXAMPLES,
454
  inputs=input_text,
455
+ label="",
456
+ elem_classes=["examples-panel"]
457
  )
458
 
459
+ # JSON output moved to right side as well
460
+ with gr.Accordion("πŸ“Š JSON Data", open=False):
 
 
 
 
 
 
 
 
 
461
  output_json = gr.JSON(label="")
462
+
463
+ # Full width visualization area at the bottom
464
+ with gr.Row(elem_classes=["visualization-container"]):
465
+ with gr.Column():
466
+ # Tab container for visualizations
467
+ with gr.Tabs():
468
+ with gr.Tab("🧩 Knowledge Graph"):
469
+ output_graph = gr.HTML(label="", elem_classes=["graph-iframe"])
470
 
471
+ with gr.Tab("🏷️ Entity Recognition"):
472
+ output_entity_viz = gr.HTML(label="")
473
+
474
  # Functionality
475
  submit_button.click(
476
  fn=process_and_visualize,
 
484
  outputs=[output_graph, output_entity_viz, output_json, stats_output]
485
  )
486
 
487
+ # Set initial values from cache if available
488
+ if first_example_cache:
489
+ # Use this to set initial values when the app loads
490
+ demo.load(
491
+ lambda: [
492
+ first_example_cache["graph_html"],
493
+ first_example_cache["entities_viz"],
494
+ first_example_cache["json_data"],
495
+ first_example_cache["stats"]
496
+ ],
497
+ inputs=None,
498
+ outputs=[output_graph, output_entity_viz, output_json, stats_output]
499
+ )
500
+
501
  # Footer
502
+ with gr.Row(elem_classes=["footer-container"]):
503
+ gr.Markdown("---")
504
+ gr.Markdown("πŸ“‹ **Instructions:** Enter text in any language, select a model, and click 'Extract & Visualize' to generate a knowledge graph.")
505
+ gr.Markdown("πŸ› οΈ Powered by Phi-3 Instruct Graph | Emergent Methods")
506
 
507
  return demo
508