-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
863 lines (726 loc) · 40.3 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
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
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
# This is the final version with agraph as d3-graph was not very versatile and had responsive rendering issues on the modbile.
import streamlit as st
import json
import networkx as nx
from streamlit_agraph import agraph, Node, Edge, Config
from typing import Dict, List, Optional, Union, Tuple
import os
from gtts import gTTS
import os
from io import BytesIO
# Add this near the top of the file, with other helper functions
def display_shloka_content(shloka, chapter_num):
"""Helper function to display shloka content with audio controls"""
# Sanskrit Text Section
shloka_text = shloka.get('sanskrit_text', '')
if shloka_text:
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Sanskrit",
key=f"sanskrit_theme_{chapter_num}_{shloka['shloka_number']}"):
audio_file = generate_audio(
shloka_text,
filename=f"sanskrit_{chapter_num}_{shloka['shloka_number']}.mp3",
lang='hi'
)
st.audio(audio_file, format="audio/mp3")
with col2:
st.markdown("**Sanskrit Text:**")
st.text(shloka_text)
# English sections
if 'transliteration' in shloka:
# Create English text without transliteration
english_text = f"Meaning: {shloka.get('meaning', '')}\n\n"
if 'interpretation' in shloka:
english_text += f"Interpretation: {shloka['interpretation']}\n\n"
if 'life_application' in shloka:
english_text += f"Life Application: {shloka['life_application']}"
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Explanation",
key=f"english_theme_{chapter_num}_{shloka['shloka_number']}"):
audio_file = generate_audio(
english_text,
filename=f"english_{chapter_num}_{shloka['shloka_number']}.mp3",
lang='en'
)
st.audio(audio_file, format="audio/mp3")
# Display text sections
with col2:
if 'transliteration' in shloka:
st.markdown("**Transliteration:**")
st.write(shloka['transliteration'])
st.markdown("**Meaning:**")
st.write(shloka.get('meaning', ''))
if 'interpretation' in shloka:
st.markdown("**Interpretation:**")
st.write(shloka['interpretation'])
if 'life_application' in shloka:
st.markdown("**Life Application:**")
st.write(shloka['life_application'])
# Function to generate audio from text
def generate_audio(text: str, filename: str = "shloka.mp3", lang: str = 'hi'):
"""
Generate audio from text with language support and loading spinner
lang can be 'hi' for Hindi or 'en' for English
For Indian English accent, we use 'en-IN'
Returns audio data as bytes
"""
with st.spinner('Generating audio, please wait...'):
if lang == 'en':
lang = 'en-IN' # Use Indian English accent
# Create a BytesIO object to store audio in memory
audio_bytes = BytesIO()
tts = gTTS(text=text, lang=lang)
tts.write_to_fp(audio_bytes)
audio_bytes.seek(0) # Reset pointer to beginning of buffer
return audio_bytes
def create_node(id: str, label: str, node_type: str) -> Node:
"""Helper function to create nodes with consistent styling"""
type_to_style = {
'problem': {'color': '#FFD700', 'size': 30, 'shape': 'dot'}, # Yellow
'chapter': {'color': '#87CEEB', 'size': 25, 'shape': 'dot'}, # Sky blue
'shloka': {'color': '#F08080', 'size': 20, 'shape': 'dot'}, # Light coral
'theme': {'color': '#90EE90', 'size': 35, 'shape': 'dot'}, # Light green
'character': {'color': '#FFD700', 'size': 30, 'shape': 'dot'}, # Changed from 'circularImage' to 'dot'
'event': {'color': '#87CEEB', 'size': 25, 'shape': 'dot'} # Sky blue
}
style = type_to_style.get(node_type, {'color': '#FFFFFF', 'size': 25, 'shape': 'dot'})
return Node(
id=id,
label=label,
size=style['size'],
shape=style['shape'],
color=style['color']
)
def create_edge(source: str, target: str, label: str = "") -> Edge:
"""Helper function to create edges with consistent styling"""
return Edge(
source=source,
target=target,
label=label,
color="#666666",
smooth={'type': 'curvedCW', 'roundness': 0.2}
)
def create_agraph_config() -> Config:
"""Create consistent agraph configuration for graph visualization"""
config = Config(
# Basic display configuration
width="100%", # Responsive width that fills container
height=600, # Fixed height in pixels
directed=True, # Show directed edges with arrows
# Physics simulation settings for node positioning
physics={
'enabled': True, # Enable physics simulation
'solver': 'forceAtlas2Based', # Use ForceAtlas2 algorithm for layout
'forceAtlas2Based': {
'gravitationalConstant': -2000, # Strength of node repulsion (-ve for repulsion)
'centralGravity': 0.5, # Pull towards center (0=no pull, 1=strong)
'springLength': 200, # Desired length of edges
'springConstant': 0.05, # Edge elasticity (higher=stiffer)
'damping': 0.4, # Reduces node oscillation (0=no damping, 1=full)
'avoidOverlap': 0.5 # Node spacing (0=allow overlap, 1=no overlap)
},
'stabilization': {
'enabled': True, # Stabilize network before displaying
'iterations': 2000, # Max iterations for stabilization
'updateInterval': 25, # Reduced for smoother initial render
'onlyDynamicEdges': False,# Stabilize all edges
'fit': True, # Scale to fit container
'initialSteps': 1000 # Minimum steps before first render
},
'minVelocity': 0.75, # Minimum velocity for simulation
'maxVelocity': 30, # Maximum velocity for simulation
},
# Node and edge behavior
hierarchical=False, # Don't use hierarchical layout
nodeHighlightBehavior=True, # Enable node highlighting on hover
node={
'labelProperty': 'label', # Node property to use as label
'size': 500, # Base node size
'highlightStrokeColor': 'black', # Color when node is highlighted
'scaling': { # Node size scaling
'min': 10,
'max': 30
}
},
# Edge (link) configuration
link={
'labelProperty': 'label', # Edge property to use as label
'renderLabel': True, # Show edge labels
'strokeWidth': 1.5, # Edge line thickness
'smooth': { # Edge curve settings
'enabled': True,
'type': 'curvedCW'
}
},
# Visual styling
highlightColor="#F7A7A6", # Color used for highlighting
collapsible=True, # Allow collapsing of nodes
# Layout configuration
layout={
'hierarchical': False, # Disable hierarchical layout
'improvedLayout': True, # Use improved layout algorithm
'randomSeed': 42, # Consistent layout between renders
'clusterThreshold': 150, # Distance threshold for clustering
},
# Container styling
style={ # CSS styling for graph container
'border': '2px solid #ddd',
'border-radius': '8px',
'background': '#f8f9fa',
'margin': '10px 0',
'padding': '10px'
}
)
return config
class GitaGraphRAG:
def __init__(self):
self.current_dir = os.path.dirname(os.path.abspath(__file__))
self.data_path = os.path.join(self.current_dir, 'data', 'bhagavad_gita_complete.json')
self.data = self._load_data()
self.G = nx.Graph()
self.build_knowledge_graph()
def _load_data(self) -> Optional[Dict]:
"""Load the Bhagavad Gita JSON data"""
try:
with open(self.data_path, 'r', encoding='utf-8') as f:
data = json.load(f)
return data
except Exception as e:
st.error(f"Error loading data: {str(e)}")
return None
def build_knowledge_graph(self) -> None:
"""Build the knowledge graph from the loaded data"""
if not self.data:
return
# Add problem nodes first
if 'problem_solutions_map' in self.data:
for problem, details in self.data['problem_solutions_map'].items():
problem_id = f"Problem_{problem}"
self.G.add_node(problem_id,
type='problem',
name=problem,
description=details['description'])
# Add references as edges to chapters/shlokas
for ref in details['references']:
shloka_id = f"Shloka_{ref['chapter']}_{ref['shloka']}"
chapter_id = f"Chapter_{ref['chapter']}"
# Add edges to both chapter and shloka
self.G.add_edge(problem_id, chapter_id)
self.G.add_edge(problem_id, shloka_id)
# Add chapter nodes
if 'chapters' in self.data:
for chapter in self.data['chapters']:
chapter_id = f"Chapter_{chapter['number']}"
node_attrs = {
'type': 'chapter',
'name': chapter.get('name', ''),
'number': chapter.get('number', 0),
'summary': chapter.get('summary', ''),
'main_theme': chapter.get('main_theme', '')
}
self.G.add_node(chapter_id, **node_attrs)
# Add shloka nodes
for shloka in chapter.get('shlokas', []):
shloka_id = f"Shloka_{chapter['number']}_{shloka['shloka_number']}"
self.G.add_node(shloka_id,
type='shloka',
sanskrit_text=shloka.get('sanskrit_text', ''),
meaning=shloka.get('meaning', ''),
interpretation=shloka.get('interpretation', ''))
self.G.add_edge(chapter_id, shloka_id)
def get_problem_solutions(self, problem: str) -> Optional[Dict]:
"""Get solutions for a specific problem"""
if 'problem_solutions_map' in self.data:
return self.data['problem_solutions_map'].get(problem)
return None
def get_shloka_by_reference(self, chapter: int, shloka: int) -> Optional[Dict]:
"""Get shloka details by chapter and shloka number"""
if 'chapters' in self.data:
chapter_data = next((ch for ch in self.data['chapters']
if ch['number'] == chapter), None)
if chapter_data:
return next((sh for sh in chapter_data.get('shlokas', [])
if sh['shloka_number'] == shloka), None)
return None
def visualize_chapter_graph(self, node_id: str) -> Tuple[List[Node], List[Edge]]:
"""Create agraph visualization of the graph for a specific node"""
nodes = []
edges = []
seen_nodes = set() # To prevent duplicate nodes
# Create subgraph for the selected node
subgraph = nx.ego_graph(self.G, node_id, radius=1)
# Add nodes
for node in subgraph.nodes():
if node not in seen_nodes:
node_data = self.G.nodes[node]
node_type = node_data['type']
label = f"{node_data.get('name', '')} {node.split('_')[-1]}"
nodes.append(create_node(node, label, node_type))
seen_nodes.add(node)
# Add edges
for source, target in subgraph.edges():
edges.append(create_edge(source, target))
return nodes, edges
def visualize_theme_relationships(self, selected_theme: str, related_chapters: list) -> Tuple[List[Node], List[Edge]]:
"""Create agraph visualization showing relationships between theme, chapters, and shlokas"""
nodes = []
edges = []
seen_nodes = set()
# Add theme node
theme_id = f"Theme_{selected_theme}"
nodes.append(create_node(theme_id, selected_theme, 'theme'))
seen_nodes.add(theme_id)
# Add related chapters and shlokas
for chapter in related_chapters:
chapter_id = f"Chapter_{chapter['number']}"
if chapter_id not in seen_nodes:
nodes.append(create_node(
chapter_id,
f"Chapter {chapter['number']}: {chapter['name']}",
'chapter'
))
seen_nodes.add(chapter_id)
edges.append(create_edge(theme_id, chapter_id, "contains"))
# Add relevant shlokas
for shloka in chapter.get('shlokas', []):
if any(kw.lower() in selected_theme.lower() for kw in shloka.get('keywords', [])):
shloka_id = f"Shloka_{chapter['number']}_{shloka['shloka_number']}"
if shloka_id not in seen_nodes:
nodes.append(create_node(
shloka_id,
f"Shloka {shloka['shloka_number']}",
'shloka'
))
seen_nodes.add(shloka_id)
edges.append(create_edge(chapter_id, shloka_id, "contains"))
edges.append(create_edge(theme_id, shloka_id, "references"))
return nodes, edges
def display_chapter_insights(self):
"""Display chapter insights with character-centric relationships."""
st.header("Ontology of Characters")
# Move chapter selection to main content area with horizontal radio buttons
chapters = self.data.get("chapters", [])
if not chapters:
st.error("No chapters found in the data.")
return
selected_chapter_num = st.radio(
"Select Chapter",
[chapter["number"] for chapter in chapters],
format_func=lambda x: f"Chapter {x}",
horizontal=True # Makes the radio buttons appear horizontally
)
selected_chapter = next(
(chapter for chapter in chapters if chapter["number"] == selected_chapter_num),
None
)
if not selected_chapter:
st.error("Invalid chapter selected.")
return
# Display chapter information in expander
with st.expander(f"Chapter {selected_chapter['number']}: {selected_chapter['name']}"):
st.markdown("### Summary")
st.write(selected_chapter.get("summary", "No summary available."))
st.markdown("### Character Relationship Graph")
# Create character relationship graph
nodes = []
edges = []
seen_nodes = set()
key_events = selected_chapter.get("key_events", [])
for event in key_events:
event_id = f"Event_{event['event']}"
if event_id not in seen_nodes:
nodes.append(create_node(event_id, event['event'], 'event'))
seen_nodes.add(event_id)
for char in event['characters']:
char_id = f"Character_{char}"
if char_id not in seen_nodes:
nodes.append(create_node(char_id, char, 'character'))
seen_nodes.add(char_id)
edges.append(create_edge(char_id, event_id))
for shloka_num in event['shlokas']:
shloka_id = f"Shloka_{selected_chapter_num}_{shloka_num}"
if shloka_id not in seen_nodes:
nodes.append(create_node(shloka_id, f"Shloka {shloka_num}", 'shloka'))
seen_nodes.add(shloka_id)
edges.append(create_edge(event_id, shloka_id))
# Display Character Details
st.markdown("### Character Details")
# Get all unique characters from events
unique_characters = set()
for event in key_events:
unique_characters.update(event['characters'])
for char in unique_characters:
with st.expander(f"{char}", expanded=False):
# Display character description
char_info = next((c for c in selected_chapter.get('characters', [])
if c['name'] == char), None)
if char_info:
st.markdown("**Description:**")
st.write(char_info['description'])
# Find events involving this character
char_events = [event for event in key_events if char in event['characters']]
if char_events:
st.markdown("**Associated Events and Teachings:**")
for event_index, event in enumerate(char_events):
st.markdown(f"### {event['event']}")
for shloka_index, shloka_num in enumerate(event['shlokas']):
shloka = next((s for s in selected_chapter['shlokas']
if s['shloka_number'] == shloka_num), None)
if shloka:
st.markdown(f"#### Shloka {shloka_num}")
# Sanskrit Text Section
shloka_text = shloka.get('sanskrit_text', '')
if shloka_text:
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Sanskrit",
key=f"sanskrit_{selected_chapter_num}_{char}_{event_index}_{shloka_index}"):
audio_file = generate_audio(
shloka_text,
filename=f"sanskrit_{selected_chapter_num}_{shloka_num}.mp3",
lang='hi'
)
st.audio(audio_file, format="audio/mp3")
with col2:
st.markdown("**Sanskrit Text:**")
st.text(shloka_text)
# English Sections
if 'transliteration' in shloka:
# Create English text without transliteration
english_text = f"Meaning: {shloka.get('meaning', '')}\n\n"
if 'interpretation' in shloka:
english_text += f"Interpretation: {shloka['interpretation']}\n\n"
if 'life_application' in shloka:
english_text += f"Life Application: {shloka['life_application']}"
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Explanation",
key=f"english_{selected_chapter_num}_{char}_{event_index}_{shloka_index}"):
audio_file = generate_audio(
english_text,
filename=f"english_{selected_chapter_num}_{shloka_num}.mp3",
lang='en'
)
st.audio(audio_file, format="audio/mp3")
# Display text sections
with col2:
if 'transliteration' in shloka:
st.markdown("**Transliteration:**")
st.write(shloka['transliteration'])
st.markdown("**Meaning:**")
st.write(shloka['meaning'])
if 'interpretation' in shloka:
st.markdown("**Interpretation:**")
st.write(shloka['interpretation'])
if 'life_application' in shloka:
st.markdown("**Life Application:**")
st.write(shloka['life_application'])
# Display character relationships
char_relationships = [
rel for rel in selected_chapter.get('character_relationships', [])
if char in rel['from'] or char in rel['to']
]
if char_relationships:
st.markdown("**Character Relationships:**")
for rel in char_relationships:
st.markdown(f"- {rel['description']}")
# Display the graph
config = create_agraph_config()
agraph(nodes=nodes, edges=edges, config=config)
def get_themes_from_chapters(data):
"""Extract all unique themes from chapters with their shloka counts"""
theme_counts = {}
for chapter in data['chapters']:
# Get themes from both main_theme and philosophical_aspects
themes = set()
if 'main_theme' in chapter:
themes.add(chapter['main_theme'])
if 'philosophical_aspects' in chapter:
themes.update(chapter['philosophical_aspects'])
# Count relevant shlokas for each theme
for theme in themes:
if theme not in theme_counts:
theme_counts[theme] = 0
# Count shlokas that have keywords matching the theme
theme_counts[theme] += len([
shloka for shloka in chapter.get('shlokas', [])
if any(kw.lower() in theme.lower() for kw in shloka.get('keywords', []))
])
# Sort themes by shloka count in descending order
sorted_themes = sorted(
theme_counts.items(),
key=lambda x: x[1],
reverse=True
)
# Return list of tuples (theme, count)
return sorted_themes
def find_chapters_by_theme(data, theme):
"""Find all chapters that contain a specific theme"""
matching_chapters = []
for chapter in data['chapters']:
if ('main_theme' in chapter and theme in chapter['main_theme']) or \
('philosophical_aspects' in chapter and theme in chapter['philosophical_aspects']):
matching_chapters.append(chapter)
return matching_chapters
def main():
st.set_page_config(page_title="Bhagavad Gita Knowledge Graph", layout="wide")
st.title("Bhagavad Gita Knowledge Graph")
# Initialize the RAG system
rag = GitaGraphRAG()
if not rag.data:
st.error("Failed to load Bhagavad Gita data.")
return
# Sidebar for navigation
st.sidebar.title("Navigation")
view_option = st.sidebar.selectbox(
"Select View",
["Chapter Topology", "Ontologies of Wisdom ", "Philosophical Themes Triples","Ontology of Characters"]
)
if view_option == "Chapter Topology":
st.header("Chapter Topology")
# Move chapter selection to main content area with horizontal radio buttons
chapter_numbers = [ch['number'] for ch in rag.data['chapters']]
selected_chapter_num = st.radio(
"Select Chapter",
sorted(chapter_numbers),
format_func=lambda x: f"Chapter {x}",
horizontal=True # Makes the radio buttons appear horizontally
)
# Get selected chapter data
chapter_data = next((ch for ch in rag.data['chapters']
if ch['number'] == selected_chapter_num), None)
if chapter_data:
st.subheader(f"Chapter {selected_chapter_num}: {chapter_data['name']}")
# Create two tabs
content_tab, graph_tab = st.tabs(["Chapter Content", "Knowledge Graph"])
with content_tab:
# Summary first
st.markdown("### Summary")
st.write(chapter_data['summary'])
# Display shlokas
st.markdown("### Shlokas")
for shloka in chapter_data.get('shlokas', []):
with st.expander(f"Shloka {shloka['shloka_number']}"):
# Extract Sanskrit text
shloka_text = shloka.get('sanskrit_text', '')
# Add Play buttons in columns
if shloka_text:
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Sanskrit",
key=f"sanskrit_ch_{selected_chapter_num}_{shloka['shloka_number']}"):
audio_file = generate_audio(
shloka_text,
filename=f"sanskrit_{selected_chapter_num}_{shloka['shloka_number']}.mp3",
lang='hi'
)
st.audio(audio_file, format="audio/mp3")
with col2:
st.markdown("**Sanskrit Text:**")
st.text(shloka_text)
# English sections
if 'transliteration' in shloka:
# Create English text without transliteration
english_text = f"Meaning: {shloka.get('meaning', '')}\n\n"
if 'interpretation' in shloka:
english_text += f"Interpretation: {shloka['interpretation']}\n\n"
if 'life_application' in shloka:
english_text += f"Life Application: {shloka['life_application']}"
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Explanation",
key=f"english_ch_{selected_chapter_num}_{shloka['shloka_number']}"):
audio_file = generate_audio(
english_text,
filename=f"english_{selected_chapter_num}_{shloka['shloka_number']}.mp3",
lang='en'
)
st.audio(audio_file, format="audio/mp3")
# Display text sections
with col2:
if 'transliteration' in shloka:
st.markdown("**Transliteration:**")
st.write(shloka['transliteration'])
st.markdown("**Meaning:**")
st.write(shloka['meaning'])
if 'interpretation' in shloka:
st.markdown("**Interpretation:**")
st.write(shloka['interpretation'])
if 'life_application' in shloka:
st.markdown("**Life Application:**")
st.write(shloka['life_application'])
with graph_tab:
st.markdown("### Chapter Knowledge Graph")
# Force initial render with a state variable
if 'first_render' not in st.session_state:
st.session_state.first_render = True
# Force rerun on first render
st.rerun()
# Create the graph
nodes, edges = rag.visualize_chapter_graph(f"Chapter_{selected_chapter_num}")
config = create_agraph_config()
agraph(nodes=nodes, edges=edges, config=config)
# Clear the first render flag
if st.session_state.first_render:
st.session_state.first_render = False
elif view_option == "Ontologies of Wisdom ":
st.header("Knowledge Pathways from Bhagavad Gita for Wisdom of Life")
# Convert dropdown to horizontal radio buttons
problems = list(rag.data['problem_solutions_map'].keys())
selected_problem = st.radio(
"Select a problem to explore solutions",
problems,
format_func=lambda x: x.replace('_', ' ').title(),
horizontal=True # This makes the radio buttons appear horizontally
)
if selected_problem:
problem_data = rag.data['problem_solutions_map'][selected_problem]
# Display problem description
st.subheader("Description")
st.write(problem_data['description'])
# Display relevant shlokas first
st.subheader("Relevant Shlokas")
for ref in problem_data['references']:
shloka = rag.get_shloka_by_reference(ref['chapter'], ref['shloka'])
if shloka:
with st.expander(f"Chapter {ref['chapter']}, Shloka {ref['shloka']}"):
shloka_text = shloka.get('sanskrit_text', '')
# Add Play buttons in columns for Sanskrit
if shloka_text:
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Sanskrit",
key=f"sanskrit_wisdom_{ref['chapter']}_{ref['shloka']}"):
audio_file = generate_audio(
shloka_text,
filename=f"sanskrit_{ref['chapter']}_{ref['shloka']}.mp3",
lang='hi'
)
st.audio(audio_file, format="audio/mp3")
with col2:
st.markdown("**Sanskrit Text:**")
st.text(shloka_text)
# English sections
if 'transliteration' in shloka:
# Create English text without transliteration
english_text = f"Meaning: {shloka.get('meaning', '')}\n\n"
if 'interpretation' in shloka:
english_text += f"Interpretation: {shloka['interpretation']}\n\n"
if 'life_application' in shloka:
english_text += f"Life Application: {shloka['life_application']}"
col1, col2 = st.columns([1, 4])
with col1:
if st.button("🔊 Explanation",
key=f"english_wisdom_{ref['chapter']}_{ref['shloka']}"):
audio_file = generate_audio(
english_text,
filename=f"english_{ref['chapter']}_{ref['shloka']}.mp3",
lang='en'
)
st.audio(audio_file, format="audio/mp3")
# Display text sections
with col2:
if 'transliteration' in shloka:
st.markdown("**Transliteration:**")
st.write(shloka['transliteration'])
st.markdown("**Meaning:**")
st.write(shloka['meaning'])
if 'interpretation' in shloka:
st.markdown("**Interpretation:**")
st.write(shloka['interpretation'])
if 'life_application' in shloka:
st.markdown("**Life Application:**")
st.write(shloka['life_application'])
# Add separator before graph
st.markdown("---")
# Display the problem-solution graph at the bottom
st.subheader("Problem-Solution Graph")
problem_id = f"Problem_{selected_problem}"
nodes, edges = rag.visualize_chapter_graph(problem_id)
config = create_agraph_config()
agraph(nodes=nodes, edges=edges, config=config)
elif view_option == "Philosophical Themes Triples":
st.header("Philosophical Themes Navigator")
# Get sorted themes with counts
theme_data = get_themes_from_chapters(rag.data)
# Create display format for selectbox
theme_options = [theme for theme, _ in theme_data]
theme_format = {theme: f"{theme} ({count} shlokas)"
for theme, count in theme_data}
# Move theme selection to main content area with a searchable dropdown
col1, col2 = st.columns([2, 1]) # Create two columns for better layout
with col1:
selected_theme = st.selectbox(
"Select a Theme to Explore",
theme_options,
format_func=lambda x: theme_format[x],
key="theme_selector"
)
if selected_theme:
st.subheader(f"Exploring: {selected_theme}")
# Theme Statistics using metrics
related_chapters = find_chapters_by_theme(rag.data, selected_theme)
total_shlokas = sum(len([s for s in ch.get('shlokas', [])
if any(kw.lower() in selected_theme.lower()
for kw in s.get('keywords', []))])
for ch in related_chapters)
col1, col2 = st.columns(2)
with col1:
st.metric(
label="📚 Related Chapters",
value=len(related_chapters)
)
with col2:
st.metric(
label="🕉️ Relevant Shlokas",
value=total_shlokas
)
# Create tabs for Chapters and Theme Relationships
chapters_tab, relationships_tab = st.tabs(["Related Chapters", "Theme Relationships"])
with chapters_tab:
if related_chapters:
for chapter in related_chapters:
st.markdown(f"### Chapter {chapter['number']}: {chapter['name']}")
# Summary in a collapsible section
with st.expander("Chapter Summary & Themes", expanded=False):
st.markdown("#### Summary")
st.write(chapter['summary'])
# Main Theme with markdown styling
st.markdown("#### Main Theme")
st.markdown(f"🎯 ***{chapter['main_theme']}***")
# Philosophical aspects with decorative markdown
if 'philosophical_aspects' in chapter:
st.markdown("#### Philosophical Aspects")
for aspect in chapter['philosophical_aspects']:
st.markdown(f"✨ :blue[{aspect}]")
# Show relevant shlokas directly (not in an expander)
if 'shlokas' in chapter:
relevant_shlokas = [
shloka for shloka in chapter['shlokas']
if any(kw.lower() in selected_theme.lower()
for kw in shloka.get('keywords', []))
]
if relevant_shlokas:
st.markdown("#### Relevant Shlokas")
for shloka in relevant_shlokas:
st.markdown(f"**Shloka {shloka['shloka_number']}**")
display_shloka_content(shloka, chapter['number'])
st.markdown("---") # Add separator between shlokas
st.markdown("---") # Add separator between chapters
with relationships_tab:
st.markdown("### Theme Relationships")
# Create tabs for each chapter's relationship graph
chapter_tabs = st.tabs([f"Chapter {chapter['number']}" for chapter in related_chapters])
# Display each chapter's relationship graph in its own tab
for tab, chapter in zip(chapter_tabs, related_chapters):
with tab:
st.markdown(f"#### {chapter['name']}")
nodes, edges = rag.visualize_theme_relationships(selected_theme, [chapter])
config = create_agraph_config()
agraph(nodes=nodes, edges=edges, config=config)
if view_option == "Ontology of Characters":
rag.display_chapter_insights()
if __name__ == "__main__":
main()