Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -27,17 +27,18 @@ def main():
|
|
27 |
["RAG comparison demonstration", "Knowledge graph visualization", "Ontology structure analysis", "Entity exploration", "Semantic path visualization", "Inference tracking", "Detailed comparative analysis"]
|
28 |
)
|
29 |
|
30 |
-
|
|
|
31 |
run_rag_demo()
|
32 |
-
elif page == "Knowledge
|
33 |
run_knowledge_graph_visualization()
|
34 |
-
elif page == "Ontology
|
35 |
run_ontology_structure_analysis()
|
36 |
-
elif page == "Entity
|
37 |
run_entity_exploration()
|
38 |
-
elif page == "Semantic
|
39 |
run_semantic_path_visualization()
|
40 |
-
elif page == "Inference
|
41 |
run_reasoning_trace()
|
42 |
elif page == "Detailed comparative analysis":
|
43 |
run_detailed_comparison()
|
@@ -69,15 +70,15 @@ def run_rag_demo():
|
|
69 |
)
|
70 |
vector_answer = vector_response.choices[0].message.content
|
71 |
|
72 |
-
st.markdown("####
|
73 |
st.write(vector_answer)
|
74 |
|
75 |
-
st.markdown("####
|
76 |
for i, doc in enumerate(vector_docs):
|
77 |
with st.expander(f"Source {i+1}"):
|
78 |
st.code(doc.page_content)
|
79 |
|
80 |
-
#
|
81 |
with col2:
|
82 |
st.subheader("Ontology RAG")
|
83 |
result = semantic_retriever.retrieve_with_paths(query, k=k_val)
|
@@ -93,18 +94,18 @@ def run_rag_demo():
|
|
93 |
)
|
94 |
enhanced_answer = enhanced_response.choices[0].message.content
|
95 |
|
96 |
-
st.markdown("####
|
97 |
st.write(enhanced_answer)
|
98 |
|
99 |
-
st.markdown("####
|
100 |
for i, doc in enumerate(retrieved_docs):
|
101 |
source = doc.metadata.get("source", "unknown")
|
102 |
label = {
|
103 |
-
"ontology": "Ontology
|
104 |
-
"text": "Text
|
105 |
-
"ontology_context": "Semantic
|
106 |
-
"semantic_path": "Relationship
|
107 |
-
}.get(source, f"
|
108 |
with st.expander(f"{label} {i+1}"):
|
109 |
st.markdown(doc.page_content)
|
110 |
|
@@ -120,38 +121,38 @@ def run_rag_demo():
|
|
120 |
st.markdown("""
|
121 |
The above comparison demonstrates several key advantages of ontology-enhanced RAG:
|
122 |
|
123 |
-
1. **
|
124 |
|
125 |
-
2. **Multi-hop
|
126 |
|
127 |
-
3. **Context
|
128 |
|
129 |
-
4.
|
130 |
|
131 |
-
Try more complex queries that require understanding
|
132 |
""")
|
133 |
|
134 |
def run_knowledge_graph_visualization():
|
135 |
st.title("Knowledge Graph Visualization")
|
136 |
|
137 |
-
# Check if there is a
|
138 |
central_entity = st.session_state.get('central_entity', None)
|
139 |
|
140 |
-
#
|
141 |
display_graph_visualization(knowledge_graph, central_entity=central_entity, max_distance=2)
|
142 |
|
143 |
-
# Get and display
|
144 |
graph_stats = knowledge_graph.get_graph_statistics()
|
145 |
if graph_stats:
|
146 |
-
st.subheader("
|
147 |
|
148 |
col1, col2, col3, col4 = st.columns(4)
|
149 |
-
col1.metric("
|
150 |
-
col2.metric("
|
151 |
-
col3.metric("
|
152 |
-
col4.metric("
|
153 |
|
154 |
-
# Display
|
155 |
if "central_nodes" in graph_stats and graph_stats["central_nodes"]:
|
156 |
st.subheader("Central Nodes (by Betweenness Centrality)")
|
157 |
central_nodes = graph_stats["central_nodes"]["betweenness"]
|
@@ -167,7 +168,7 @@ def run_knowledge_graph_visualization():
|
|
167 |
nodes_df.append({
|
168 |
"ID": node_id,
|
169 |
"Name": name,
|
170 |
-
"
|
171 |
"Centrality": node_info["centrality"]
|
172 |
})
|
173 |
|
@@ -176,11 +177,11 @@ def run_knowledge_graph_visualization():
|
|
176 |
def run_ontology_structure_analysis():
|
177 |
st.title("Ontology Structure Analysis")
|
178 |
|
179 |
-
# Use
|
180 |
display_ontology_stats(ontology_manager)
|
181 |
|
182 |
-
# Add
|
183 |
-
st.subheader("
|
184 |
|
185 |
# Get class hierarchy data
|
186 |
class_hierarchy = ontology_manager.get_class_hierarchy()
|
@@ -196,19 +197,41 @@ def run_ontology_structure_analysis():
|
|
196 |
G.add_node(child)
|
197 |
G.add_edge(parent, child)
|
198 |
|
199 |
-
# Check if there are enough nodes to create
|
200 |
if len(G.nodes) > 1:
|
201 |
# Generate HTML visualization using knowledge graph class
|
202 |
kg = KnowledgeGraph(ontology_manager)
|
|
|
|
|
203 |
html = kg.generate_html_visualization(
|
204 |
include_classes=True,
|
205 |
include_instances=False,
|
206 |
max_distance=5,
|
207 |
-
layout_algorithm="hierarchical"
|
208 |
)
|
209 |
|
210 |
-
#
|
211 |
render_html_in_streamlit(html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
|
213 |
def run_entity_exploration():
|
214 |
st.title("Entity Exploration")
|
@@ -221,8 +244,8 @@ def run_entity_exploration():
|
|
221 |
# Remove duplicates and sort
|
222 |
entities = sorted(set(entities))
|
223 |
|
224 |
-
# Create a
|
225 |
-
selected_entity = st.selectbox("Select
|
226 |
|
227 |
if selected_entity:
|
228 |
# Get entity information
|
@@ -232,13 +255,13 @@ def run_entity_exploration():
|
|
232 |
display_entity_details(entity_info, ontology_manager)
|
233 |
|
234 |
# Set this entity as the central entity (for knowledge graph visualization)
|
235 |
-
if st.button("View this
|
236 |
st.session_state.central_entity = selected_entity
|
237 |
st.rerun()
|
238 |
|
239 |
# Get and display entity neighbors
|
240 |
st.subheader("Entity Neighborhood")
|
241 |
-
max_distance = st.slider("Maximum
|
242 |
|
243 |
neighborhood = knowledge_graph.get_entity_neighborhood(
|
244 |
selected_entity,
|
@@ -252,7 +275,7 @@ def run_entity_exploration():
|
|
252 |
neighbors_at_distance = [n for n in neighborhood["neighbors"] if n["distance"] == distance]
|
253 |
|
254 |
if neighbors_at_distance:
|
255 |
-
with st.expander(f"Neighbors at
|
256 |
for neighbor in neighbors_at_distance:
|
257 |
st.markdown(f"**{neighbor['id']}** ({neighbor.get('class_type', 'unknown')})")
|
258 |
|
@@ -278,16 +301,16 @@ def run_semantic_path_visualization():
|
|
278 |
col1, col2 = st.columns(2)
|
279 |
|
280 |
with col1:
|
281 |
-
source_entity = st.selectbox("Select
|
282 |
|
283 |
with col2:
|
284 |
-
target_entity = st.selectbox("Select
|
285 |
|
286 |
if source_entity and target_entity and source_entity != target_entity:
|
287 |
# Provide a maximum path length option
|
288 |
-
max_length = st.slider("Maximum
|
289 |
|
290 |
-
# Find
|
291 |
paths = knowledge_graph.find_paths_between_entities(
|
292 |
source_entity,
|
293 |
target_entity,
|
@@ -295,15 +318,15 @@ def run_semantic_path_visualization():
|
|
295 |
)
|
296 |
|
297 |
if paths:
|
298 |
-
st.success(f"Found {len(paths)} paths
|
299 |
|
300 |
# Create expanders for each path
|
301 |
for i, path in enumerate(paths):
|
302 |
-
# Calculate path length and relationship
|
303 |
path_length = len(path)
|
304 |
rel_types = [edge["type"] for edge in path]
|
305 |
|
306 |
-
with st.expander(f"
|
307 |
# Create a text description of the path
|
308 |
path_text = []
|
309 |
entities_in_path = []
|
@@ -316,7 +339,7 @@ def run_semantic_path_visualization():
|
|
316 |
entities_in_path.append(source)
|
317 |
entities_in_path.append(target)
|
318 |
|
319 |
-
# Get entity information to get a
|
320 |
source_info = ontology_manager.get_entity_info(source)
|
321 |
target_info = ontology_manager.get_entity_info(target)
|
322 |
|
@@ -344,13 +367,13 @@ def run_semantic_path_visualization():
|
|
344 |
# Display path visualization
|
345 |
visualize_path(path_info, ontology_manager)
|
346 |
else:
|
347 |
-
st.warning(f"No
|
348 |
|
349 |
def run_reasoning_trace():
|
350 |
-
st.title("
|
351 |
|
352 |
if not st.session_state.get("query") or not st.session_state.get("retrieved_docs") or not st.session_state.get("answer"):
|
353 |
-
st.warning("Please run a query on the RAG comparison page first to generate
|
354 |
return
|
355 |
|
356 |
# Get data from session state
|
@@ -358,11 +381,11 @@ def run_reasoning_trace():
|
|
358 |
retrieved_docs = st.session_state.retrieved_docs
|
359 |
answer = st.session_state.answer
|
360 |
|
361 |
-
# Show
|
362 |
display_reasoning_trace(query, retrieved_docs, answer, ontology_manager)
|
363 |
|
364 |
def run_detailed_comparison():
|
365 |
-
st.title("Detailed
|
366 |
|
367 |
# Add comparison query options
|
368 |
comparison_queries = [
|
@@ -374,7 +397,7 @@ def run_detailed_comparison():
|
|
374 |
]
|
375 |
|
376 |
selected_query = st.selectbox(
|
377 |
-
"Select
|
378 |
comparison_queries,
|
379 |
index=0
|
380 |
)
|
@@ -386,8 +409,8 @@ def run_detailed_comparison():
|
|
386 |
else:
|
387 |
query = selected_query
|
388 |
|
389 |
-
if st.button("Compare RAG
|
390 |
-
with st.spinner("
|
391 |
# Start timing
|
392 |
import time
|
393 |
start_time = time.time()
|
@@ -406,10 +429,10 @@ def run_detailed_comparison():
|
|
406 |
vector_answer = vector_response.choices[0].message.content
|
407 |
vector_time = time.time() - start_time
|
408 |
|
409 |
-
# Reset
|
410 |
start_time = time.time()
|
411 |
|
412 |
-
# Run
|
413 |
result = semantic_retriever.retrieve_with_paths(query, k=k_val)
|
414 |
retrieved_docs = result["documents"]
|
415 |
enhanced_context = "\n\n".join([doc.page_content for doc in retrieved_docs])
|
@@ -424,59 +447,59 @@ def run_detailed_comparison():
|
|
424 |
enhanced_answer = enhanced_response.choices[0].message.content
|
425 |
enhanced_time = time.time() - start_time
|
426 |
|
427 |
-
# Save
|
428 |
st.session_state.query = query
|
429 |
st.session_state.retrieved_docs = retrieved_docs
|
430 |
st.session_state.answer = enhanced_answer
|
431 |
|
432 |
-
# Display
|
433 |
-
st.subheader("Comparison
|
434 |
|
435 |
-
# Use tabs to show
|
436 |
-
tab1, tab2, tab3, tab4 = st.tabs(["Answer Comparison", "Performance
|
437 |
|
438 |
with tab1:
|
439 |
col1, col2 = st.columns(2)
|
440 |
|
441 |
with col1:
|
442 |
-
st.markdown("#### Traditional RAG
|
443 |
st.write(vector_answer)
|
444 |
|
445 |
with col2:
|
446 |
-
st.markdown("#### Ontology
|
447 |
st.write(enhanced_answer)
|
448 |
|
449 |
with tab2:
|
450 |
-
# Performance
|
451 |
col1, col2 = st.columns(2)
|
452 |
|
453 |
with col1:
|
454 |
-
st.metric("Traditional RAG
|
455 |
|
456 |
-
# Calculate text
|
457 |
vector_tokens = len(vector_context.split())
|
458 |
-
st.metric("
|
459 |
|
460 |
-
st.metric("
|
461 |
|
462 |
with col2:
|
463 |
-
st.metric("Ontology
|
464 |
|
465 |
-
# Calculate text
|
466 |
enhanced_tokens = len(enhanced_context.split())
|
467 |
-
st.metric("
|
468 |
|
469 |
-
st.metric("
|
470 |
|
471 |
-
# Add
|
472 |
import pandas as pd
|
473 |
import plotly.express as px
|
474 |
|
475 |
# Performance comparison chart
|
476 |
performance_data = {
|
477 |
-
"Metrics": ["Response
|
478 |
"Traditional RAG": [vector_time, vector_tokens, len(vector_docs)],
|
479 |
-
"Ontology
|
480 |
}
|
481 |
|
482 |
df = pd.DataFrame(performance_data)
|
@@ -484,31 +507,31 @@ def run_detailed_comparison():
|
|
484 |
# Plotly bar chart
|
485 |
fig = px.bar(
|
486 |
df,
|
487 |
-
x="
|
488 |
-
y=["Traditional RAG", "Ontology
|
489 |
barmode="group",
|
490 |
-
title="Performance
|
491 |
-
labels={"value": "
|
492 |
)
|
493 |
|
494 |
-
st.plotly_chart(fig)
|
495 |
|
496 |
with tab3:
|
497 |
-
#
|
498 |
-
traditional_sources = ["Traditional
|
499 |
|
500 |
enhanced_sources = []
|
501 |
for doc in retrieved_docs:
|
502 |
source = doc.metadata.get("source", "unknown")
|
503 |
label = {
|
504 |
-
"ontology": "Ontology
|
505 |
-
"text": "Text
|
506 |
-
"ontology_context": "Semantic
|
507 |
-
"semantic_path": "Relationship
|
508 |
-
}.get(source, "
|
509 |
enhanced_sources.append(label)
|
510 |
|
511 |
-
# Create
|
512 |
source_counts = {}
|
513 |
for source in enhanced_sources:
|
514 |
if source in source_counts:
|
@@ -517,32 +540,32 @@ def run_detailed_comparison():
|
|
517 |
source_counts[source] = 1
|
518 |
|
519 |
source_df = pd.DataFrame({
|
520 |
-
"Source
|
521 |
-
"
|
522 |
})
|
523 |
|
524 |
fig = px.pie(
|
525 |
source_df,
|
526 |
-
values="
|
527 |
-
names="Source
|
528 |
-
title="Ontology-
|
529 |
)
|
530 |
|
531 |
-
st.plotly_chart(fig)
|
532 |
|
533 |
-
# Show
|
534 |
-
st.subheader("Relationship
|
535 |
st.markdown("""
|
536 |
Ontology-enhanced methods leverage multiple sources of knowledge to construct more comprehensive answers. The figure above shows the distribution of different sources.
|
537 |
|
538 |
-
In particular, semantic context and
|
539 |
""")
|
540 |
|
541 |
with tab4:
|
542 |
-
#
|
543 |
-
st.subheader("
|
544 |
|
545 |
-
# Create
|
546 |
def evaluate_context(docs):
|
547 |
metrics = {
|
548 |
"Direct Relevance": 0,
|
@@ -556,18 +579,18 @@ def run_detailed_comparison():
|
|
556 |
|
557 |
# Direct Relevance - Based on Keywords
|
558 |
if any(kw in content.lower() for kw in query.lower().split()):
|
559 |
-
metrics["
|
560 |
|
561 |
# Semantic richness - based on text length
|
562 |
-
metrics["
|
563 |
|
564 |
-
# Structural information - from
|
565 |
if hasattr(doc, "metadata") and doc.metadata.get("source") in ["ontology", "ontology_context"]:
|
566 |
metrics["Structure Information"] += 1
|
567 |
|
568 |
# Relationship information - from path
|
569 |
if hasattr(doc, "metadata") and doc.metadata.get("source") == "semantic_path":
|
570 |
-
metrics["
|
571 |
|
572 |
# Standardization
|
573 |
for key in metrics:
|
@@ -575,109 +598,113 @@ def run_detailed_comparison():
|
|
575 |
|
576 |
return metrics
|
577 |
|
578 |
-
# Evaluate
|
579 |
vector_metrics = evaluate_context(vector_docs)
|
580 |
enhanced_metrics = evaluate_context(retrieved_docs)
|
581 |
|
582 |
-
# Create
|
583 |
metrics_df = pd.DataFrame({
|
584 |
"metrics": list(vector_metrics.keys()),
|
585 |
"Traditional RAG": list(vector_metrics.values()),
|
586 |
-
"Ontology
|
587 |
})
|
588 |
|
589 |
# Convert data to Plotly radar chart format
|
590 |
fig = px.line_polar(
|
591 |
metrics_df,
|
592 |
-
r=["Traditional RAG", "Ontology
|
593 |
-
theta="
|
594 |
line_close=True,
|
595 |
range_r=[0, 10],
|
596 |
-
title="
|
597 |
)
|
598 |
|
599 |
-
st.plotly_chart(fig)
|
600 |
|
601 |
st.markdown("""
|
602 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
603 |
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
|
618 |
-
|
619 |
-
|
620 |
st.markdown("""
|
621 |
-
|
622 |
-
|
623 |
-
-
|
624 |
-
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
-
|
|
|
|
|
|
|
|
|
|
|
631 |
""")
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
st.markdown("""
|
636 |
-
|
637 |
-
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
""")
|
648 |
-
|
649 |
-
# Add usage scenario suggestions
|
650 |
-
with st.expander("Applicable scenarios"):
|
651 |
-
st.markdown("""
|
652 |
-
### Traditional RAG applicable scenarios
|
653 |
-
|
654 |
-
- Simple fact-finding
|
655 |
-
- Unstructured document retrieval
|
656 |
-
- Applications with high response time requirements
|
657 |
-
- When the document content is clear and direct
|
658 |
-
|
659 |
-
### Applicable scenarios for Ontology Enhanced RAG
|
660 |
-
|
661 |
-
- Complex knowledge association query
|
662 |
-
- Problems that require understanding of relationships between entities
|
663 |
-
- Applications that require cross-domain reasoning
|
664 |
-
- Enterprise Knowledge Management System
|
665 |
-
- Reasoning scenarios that require high accuracy and consistency
|
666 |
-
- Applications that require implicit knowledge discovery
|
667 |
-
""")
|
668 |
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
### Enterprise Knowledge Management
|
673 |
-
Ontology-enhanced RAG systems can help enterprises effectively organize and access their knowledge assets, connect information in different departments and systems, and provide more comprehensive business insights.
|
674 |
-
|
675 |
-
### Product development decision support
|
676 |
-
By understanding the relationship between customer feedback, product features, and market data, the system can provide more valuable support for product development decisions.
|
677 |
-
|
678 |
-
### Complex compliance query
|
679 |
-
In compliance problems that require consideration of multiple rules and relationships, ontology-enhanced RAG can provide rule-based reasoning, ensuring that recommendations comply with all applicable policies and regulations.
|
680 |
-
|
681 |
-
### Diagnostics and Troubleshooting
|
682 |
-
In technical support and troubleshooting scenarios, the system can connect symptoms, causes, and solutions to provide more accurate diagnoses through multi-hop reasoning.
|
683 |
-
""")
|
|
|
27 |
["RAG comparison demonstration", "Knowledge graph visualization", "Ontology structure analysis", "Entity exploration", "Semantic path visualization", "Inference tracking", "Detailed comparative analysis"]
|
28 |
)
|
29 |
|
30 |
+
# 修正條件判斷,使其與選項名稱一致
|
31 |
+
if page == "RAG comparison demonstration":
|
32 |
run_rag_demo()
|
33 |
+
elif page == "Knowledge graph visualization":
|
34 |
run_knowledge_graph_visualization()
|
35 |
+
elif page == "Ontology structure analysis":
|
36 |
run_ontology_structure_analysis()
|
37 |
+
elif page == "Entity exploration":
|
38 |
run_entity_exploration()
|
39 |
+
elif page == "Semantic path visualization":
|
40 |
run_semantic_path_visualization()
|
41 |
+
elif page == "Inference tracking":
|
42 |
run_reasoning_trace()
|
43 |
elif page == "Detailed comparative analysis":
|
44 |
run_detailed_comparison()
|
|
|
70 |
)
|
71 |
vector_answer = vector_response.choices[0].message.content
|
72 |
|
73 |
+
st.markdown("#### Answer")
|
74 |
st.write(vector_answer)
|
75 |
|
76 |
+
st.markdown("#### Retrieved Context")
|
77 |
for i, doc in enumerate(vector_docs):
|
78 |
with st.expander(f"Source {i+1}"):
|
79 |
st.code(doc.page_content)
|
80 |
|
81 |
+
# Ontology RAG
|
82 |
with col2:
|
83 |
st.subheader("Ontology RAG")
|
84 |
result = semantic_retriever.retrieve_with_paths(query, k=k_val)
|
|
|
94 |
)
|
95 |
enhanced_answer = enhanced_response.choices[0].message.content
|
96 |
|
97 |
+
st.markdown("#### Answer")
|
98 |
st.write(enhanced_answer)
|
99 |
|
100 |
+
st.markdown("#### Retrieved Context")
|
101 |
for i, doc in enumerate(retrieved_docs):
|
102 |
source = doc.metadata.get("source", "unknown")
|
103 |
label = {
|
104 |
+
"ontology": "Ontology Context",
|
105 |
+
"text": "Text Context",
|
106 |
+
"ontology_context": "Semantic Context",
|
107 |
+
"semantic_path": "Relationship Path"
|
108 |
+
}.get(source, f"Source")
|
109 |
with st.expander(f"{label} {i+1}"):
|
110 |
st.markdown(doc.page_content)
|
111 |
|
|
|
121 |
st.markdown("""
|
122 |
The above comparison demonstrates several key advantages of ontology-enhanced RAG:
|
123 |
|
124 |
+
1. **Structural Awareness**: The ontology-enhanced approach understands the relationships between entities, not just their textual similarity.
|
125 |
|
126 |
+
2. **Multi-hop Reasoning**: By using the knowledge graph structure, the enhanced approach can connect information across multiple relationship hops.
|
127 |
|
128 |
+
3. **Context Enrichment**: The ontology provides additional context about entity types, properties, and relationships that isn't explicit in the text.
|
129 |
|
130 |
+
4. **Inference Capabilities**: The structured knowledge allows for logical inferences that vector similarity alone cannot achieve.
|
131 |
|
132 |
+
Try more complex queries that require understanding relationships to see the differences more clearly!
|
133 |
""")
|
134 |
|
135 |
def run_knowledge_graph_visualization():
|
136 |
st.title("Knowledge Graph Visualization")
|
137 |
|
138 |
+
# Check if there is a central entity selected
|
139 |
central_entity = st.session_state.get('central_entity', None)
|
140 |
|
141 |
+
# Call visualization function
|
142 |
display_graph_visualization(knowledge_graph, central_entity=central_entity, max_distance=2)
|
143 |
|
144 |
+
# Get and display graph statistics
|
145 |
graph_stats = knowledge_graph.get_graph_statistics()
|
146 |
if graph_stats:
|
147 |
+
st.subheader("Graph Statistics")
|
148 |
|
149 |
col1, col2, col3, col4 = st.columns(4)
|
150 |
+
col1.metric("Nodes", graph_stats.get("node_count", 0))
|
151 |
+
col2.metric("Edges", graph_stats.get("edge_count", 0))
|
152 |
+
col3.metric("Classes", graph_stats.get("class_count", 0))
|
153 |
+
col4.metric("Instances", graph_stats.get("instance_count", 0))
|
154 |
|
155 |
+
# Display central nodes
|
156 |
if "central_nodes" in graph_stats and graph_stats["central_nodes"]:
|
157 |
st.subheader("Central Nodes (by Betweenness Centrality)")
|
158 |
central_nodes = graph_stats["central_nodes"]["betweenness"]
|
|
|
168 |
nodes_df.append({
|
169 |
"ID": node_id,
|
170 |
"Name": name,
|
171 |
+
"Type": node_class,
|
172 |
"Centrality": node_info["centrality"]
|
173 |
})
|
174 |
|
|
|
177 |
def run_ontology_structure_analysis():
|
178 |
st.title("Ontology Structure Analysis")
|
179 |
|
180 |
+
# Use ontology statistics display function
|
181 |
display_ontology_stats(ontology_manager)
|
182 |
|
183 |
+
# Add class hierarchy visualization
|
184 |
+
st.subheader("Class Hierarchy")
|
185 |
|
186 |
# Get class hierarchy data
|
187 |
class_hierarchy = ontology_manager.get_class_hierarchy()
|
|
|
197 |
G.add_node(child)
|
198 |
G.add_edge(parent, child)
|
199 |
|
200 |
+
# Check if there are enough nodes to create visualization
|
201 |
if len(G.nodes) > 1:
|
202 |
# Generate HTML visualization using knowledge graph class
|
203 |
kg = KnowledgeGraph(ontology_manager)
|
204 |
+
|
205 |
+
# Use built-in layout algorithm
|
206 |
html = kg.generate_html_visualization(
|
207 |
include_classes=True,
|
208 |
include_instances=False,
|
209 |
max_distance=5,
|
210 |
+
layout_algorithm="hierarchical" # Use the built-in hierarchical layout
|
211 |
)
|
212 |
|
213 |
+
# Render HTML
|
214 |
render_html_in_streamlit(html)
|
215 |
+
|
216 |
+
# Add extra tree view for each root node
|
217 |
+
with st.expander("Node Tree View", expanded=False):
|
218 |
+
# Find root nodes (nodes without parent nodes)
|
219 |
+
roots = [n for n in G.nodes() if G.in_degree(n) == 0]
|
220 |
+
|
221 |
+
# Display tree structure for each root node
|
222 |
+
for root in roots:
|
223 |
+
st.markdown(f"### Root Node: {root}")
|
224 |
+
|
225 |
+
# Recursively display child nodes
|
226 |
+
def display_tree(node, depth=0):
|
227 |
+
children = list(G.successors(node))
|
228 |
+
if children:
|
229 |
+
for child in sorted(children):
|
230 |
+
st.markdown(" " * depth * 4 + f"- {child}")
|
231 |
+
display_tree(child, depth + 1)
|
232 |
+
|
233 |
+
display_tree(root)
|
234 |
+
st.markdown("---")
|
235 |
|
236 |
def run_entity_exploration():
|
237 |
st.title("Entity Exploration")
|
|
|
244 |
# Remove duplicates and sort
|
245 |
entities = sorted(set(entities))
|
246 |
|
247 |
+
# Create a dropdown selection box
|
248 |
+
selected_entity = st.selectbox("Select Entity", entities)
|
249 |
|
250 |
if selected_entity:
|
251 |
# Get entity information
|
|
|
255 |
display_entity_details(entity_info, ontology_manager)
|
256 |
|
257 |
# Set this entity as the central entity (for knowledge graph visualization)
|
258 |
+
if st.button("View this Entity in the Knowledge Graph"):
|
259 |
st.session_state.central_entity = selected_entity
|
260 |
st.rerun()
|
261 |
|
262 |
# Get and display entity neighbors
|
263 |
st.subheader("Entity Neighborhood")
|
264 |
+
max_distance = st.slider("Maximum Neighborhood Distance", 1, 3, 1)
|
265 |
|
266 |
neighborhood = knowledge_graph.get_entity_neighborhood(
|
267 |
selected_entity,
|
|
|
275 |
neighbors_at_distance = [n for n in neighborhood["neighbors"] if n["distance"] == distance]
|
276 |
|
277 |
if neighbors_at_distance:
|
278 |
+
with st.expander(f"Neighbors at Distance {distance} ({len(neighbors_at_distance)})"):
|
279 |
for neighbor in neighbors_at_distance:
|
280 |
st.markdown(f"**{neighbor['id']}** ({neighbor.get('class_type', 'unknown')})")
|
281 |
|
|
|
301 |
col1, col2 = st.columns(2)
|
302 |
|
303 |
with col1:
|
304 |
+
source_entity = st.selectbox("Select Source Entity", entities, key="source")
|
305 |
|
306 |
with col2:
|
307 |
+
target_entity = st.selectbox("Select Target Entity", entities, key="target")
|
308 |
|
309 |
if source_entity and target_entity and source_entity != target_entity:
|
310 |
# Provide a maximum path length option
|
311 |
+
max_length = st.slider("Maximum Path Length", 1, 5, 3)
|
312 |
|
313 |
+
# Find paths
|
314 |
paths = knowledge_graph.find_paths_between_entities(
|
315 |
source_entity,
|
316 |
target_entity,
|
|
|
318 |
)
|
319 |
|
320 |
if paths:
|
321 |
+
st.success(f"Found {len(paths)} paths!")
|
322 |
|
323 |
# Create expanders for each path
|
324 |
for i, path in enumerate(paths):
|
325 |
+
# Calculate path length and relationship types
|
326 |
path_length = len(path)
|
327 |
rel_types = [edge["type"] for edge in path]
|
328 |
|
329 |
+
with st.expander(f"Path {i+1} (Length: {path_length}, Relations: {', '.join(rel_types)})", expanded=(i==0)):
|
330 |
# Create a text description of the path
|
331 |
path_text = []
|
332 |
entities_in_path = []
|
|
|
339 |
entities_in_path.append(source)
|
340 |
entities_in_path.append(target)
|
341 |
|
342 |
+
# Get entity information to get a readable name
|
343 |
source_info = ontology_manager.get_entity_info(source)
|
344 |
target_info = ontology_manager.get_entity_info(target)
|
345 |
|
|
|
367 |
# Display path visualization
|
368 |
visualize_path(path_info, ontology_manager)
|
369 |
else:
|
370 |
+
st.warning(f"No paths of length {max_length} or shorter were found between these entities.")
|
371 |
|
372 |
def run_reasoning_trace():
|
373 |
+
st.title("Reasoning Trace Visualization")
|
374 |
|
375 |
if not st.session_state.get("query") or not st.session_state.get("retrieved_docs") or not st.session_state.get("answer"):
|
376 |
+
st.warning("Please run a query on the RAG comparison page first to generate reasoning trace data.")
|
377 |
return
|
378 |
|
379 |
# Get data from session state
|
|
|
381 |
retrieved_docs = st.session_state.retrieved_docs
|
382 |
answer = st.session_state.answer
|
383 |
|
384 |
+
# Show reasoning trace
|
385 |
display_reasoning_trace(query, retrieved_docs, answer, ontology_manager)
|
386 |
|
387 |
def run_detailed_comparison():
|
388 |
+
st.title("Detailed Comparison of RAG Methods")
|
389 |
|
390 |
# Add comparison query options
|
391 |
comparison_queries = [
|
|
|
397 |
]
|
398 |
|
399 |
selected_query = st.selectbox(
|
400 |
+
"Select Comparison Query",
|
401 |
comparison_queries,
|
402 |
index=0
|
403 |
)
|
|
|
409 |
else:
|
410 |
query = selected_query
|
411 |
|
412 |
+
if st.button("Compare RAG Methods"):
|
413 |
+
with st.spinner("Running detailed comparison..."):
|
414 |
# Start timing
|
415 |
import time
|
416 |
start_time = time.time()
|
|
|
429 |
vector_answer = vector_response.choices[0].message.content
|
430 |
vector_time = time.time() - start_time
|
431 |
|
432 |
+
# Reset timer
|
433 |
start_time = time.time()
|
434 |
|
435 |
+
# Run ontology-enhanced RAG
|
436 |
result = semantic_retriever.retrieve_with_paths(query, k=k_val)
|
437 |
retrieved_docs = result["documents"]
|
438 |
enhanced_context = "\n\n".join([doc.page_content for doc in retrieved_docs])
|
|
|
447 |
enhanced_answer = enhanced_response.choices[0].message.content
|
448 |
enhanced_time = time.time() - start_time
|
449 |
|
450 |
+
# Save results for visualization
|
451 |
st.session_state.query = query
|
452 |
st.session_state.retrieved_docs = retrieved_docs
|
453 |
st.session_state.answer = enhanced_answer
|
454 |
|
455 |
+
# Display comparison results
|
456 |
+
st.subheader("Comparison Results")
|
457 |
|
458 |
+
# Use tabs to show different aspects of comparison
|
459 |
+
tab1, tab2, tab3, tab4 = st.tabs(["Answer Comparison", "Performance Metrics", "Retrieval Source Comparison", "Context Quality"])
|
460 |
|
461 |
with tab1:
|
462 |
col1, col2 = st.columns(2)
|
463 |
|
464 |
with col1:
|
465 |
+
st.markdown("#### Traditional RAG Answer")
|
466 |
st.write(vector_answer)
|
467 |
|
468 |
with col2:
|
469 |
+
st.markdown("#### Ontology-Enhanced RAG Answer")
|
470 |
st.write(enhanced_answer)
|
471 |
|
472 |
with tab2:
|
473 |
+
# Performance metrics
|
474 |
col1, col2 = st.columns(2)
|
475 |
|
476 |
with col1:
|
477 |
+
st.metric("Traditional RAG Response Time", f"{vector_time:.2f} seconds")
|
478 |
|
479 |
+
# Calculate text metrics
|
480 |
vector_tokens = len(vector_context.split())
|
481 |
+
st.metric("Retrieved Context Tokens", vector_tokens)
|
482 |
|
483 |
+
st.metric("Retrieved Documents", len(vector_docs))
|
484 |
|
485 |
with col2:
|
486 |
+
st.metric("Ontology-Enhanced RAG Response Time", f"{enhanced_time:.2f} seconds")
|
487 |
|
488 |
+
# Calculate text metrics
|
489 |
enhanced_tokens = len(enhanced_context.split())
|
490 |
+
st.metric("Retrieved Context Tokens", enhanced_tokens)
|
491 |
|
492 |
+
st.metric("Retrieved Documents", len(retrieved_docs))
|
493 |
|
494 |
+
# Add chart
|
495 |
import pandas as pd
|
496 |
import plotly.express as px
|
497 |
|
498 |
# Performance comparison chart
|
499 |
performance_data = {
|
500 |
+
"Metrics": ["Response Time (seconds)", "Context Tokens", "Retrieved Documents"],
|
501 |
"Traditional RAG": [vector_time, vector_tokens, len(vector_docs)],
|
502 |
+
"Ontology-Enhanced RAG": [enhanced_time, enhanced_tokens, len(retrieved_docs)]
|
503 |
}
|
504 |
|
505 |
df = pd.DataFrame(performance_data)
|
|
|
507 |
# Plotly bar chart
|
508 |
fig = px.bar(
|
509 |
df,
|
510 |
+
x="Metrics", # Fixed column name
|
511 |
+
y=["Traditional RAG", "Ontology-Enhanced RAG"],
|
512 |
barmode="group",
|
513 |
+
title="Performance Metrics Comparison",
|
514 |
+
labels={"value": "Value", "variable": "RAG Method"}
|
515 |
)
|
516 |
|
517 |
+
st.plotly_chart(fig, use_container_width=True)
|
518 |
|
519 |
with tab3:
|
520 |
+
# Retrieval source comparison
|
521 |
+
traditional_sources = ["Traditional Vector Retrieval"] * len(vector_docs)
|
522 |
|
523 |
enhanced_sources = []
|
524 |
for doc in retrieved_docs:
|
525 |
source = doc.metadata.get("source", "unknown")
|
526 |
label = {
|
527 |
+
"ontology": "Ontology Context",
|
528 |
+
"text": "Text Context",
|
529 |
+
"ontology_context": "Semantic Context",
|
530 |
+
"semantic_path": "Relationship Path"
|
531 |
+
}.get(source, "Unknown Source")
|
532 |
enhanced_sources.append(label)
|
533 |
|
534 |
+
# Create source distribution chart
|
535 |
source_counts = {}
|
536 |
for source in enhanced_sources:
|
537 |
if source in source_counts:
|
|
|
540 |
source_counts[source] = 1
|
541 |
|
542 |
source_df = pd.DataFrame({
|
543 |
+
"Source Type": list(source_counts.keys()),
|
544 |
+
"Document Count": list(source_counts.values())
|
545 |
})
|
546 |
|
547 |
fig = px.pie(
|
548 |
source_df,
|
549 |
+
values="Document Count",
|
550 |
+
names="Source Type",
|
551 |
+
title="Ontology-Enhanced RAG Retrieval Source Distribution"
|
552 |
)
|
553 |
|
554 |
+
st.plotly_chart(fig, use_container_width=True)
|
555 |
|
556 |
+
# Show source-answer relationship
|
557 |
+
st.subheader("Relationship Between Sources and Answer")
|
558 |
st.markdown("""
|
559 |
Ontology-enhanced methods leverage multiple sources of knowledge to construct more comprehensive answers. The figure above shows the distribution of different sources.
|
560 |
|
561 |
+
In particular, semantic context and relationship paths provide knowledge that cannot be captured by traditional vector retrieval, enabling the system to connect concepts and perform multi-hop reasoning.
|
562 |
""")
|
563 |
|
564 |
with tab4:
|
565 |
+
# Context quality assessment
|
566 |
+
st.subheader("Context Quality Assessment")
|
567 |
|
568 |
+
# Create evaluation function (simplified)
|
569 |
def evaluate_context(docs):
|
570 |
metrics = {
|
571 |
"Direct Relevance": 0,
|
|
|
579 |
|
580 |
# Direct Relevance - Based on Keywords
|
581 |
if any(kw in content.lower() for kw in query.lower().split()):
|
582 |
+
metrics["Direct Relevance"] += 1 # Fixed key name
|
583 |
|
584 |
# Semantic richness - based on text length
|
585 |
+
metrics["Semantic Richness"] += min(1, len(content.split()) / 50) # Fixed key name
|
586 |
|
587 |
+
# Structural information - from ontology
|
588 |
if hasattr(doc, "metadata") and doc.metadata.get("source") in ["ontology", "ontology_context"]:
|
589 |
metrics["Structure Information"] += 1
|
590 |
|
591 |
# Relationship information - from path
|
592 |
if hasattr(doc, "metadata") and doc.metadata.get("source") == "semantic_path":
|
593 |
+
metrics["Relationship Information"] += 1 # Fixed key name
|
594 |
|
595 |
# Standardization
|
596 |
for key in metrics:
|
|
|
598 |
|
599 |
return metrics
|
600 |
|
601 |
+
# Evaluate both methods
|
602 |
vector_metrics = evaluate_context(vector_docs)
|
603 |
enhanced_metrics = evaluate_context(retrieved_docs)
|
604 |
|
605 |
+
# Create comparative radar chart
|
606 |
metrics_df = pd.DataFrame({
|
607 |
"metrics": list(vector_metrics.keys()),
|
608 |
"Traditional RAG": list(vector_metrics.values()),
|
609 |
+
"Ontology-Enhanced RAG": list(enhanced_metrics.values())
|
610 |
})
|
611 |
|
612 |
# Convert data to Plotly radar chart format
|
613 |
fig = px.line_polar(
|
614 |
metrics_df,
|
615 |
+
r=["Traditional RAG", "Ontology-Enhanced RAG"],
|
616 |
+
theta="metrics", # Fixed column name
|
617 |
line_close=True,
|
618 |
range_r=[0, 10],
|
619 |
+
title="Context Quality Comparison"
|
620 |
)
|
621 |
|
622 |
+
st.plotly_chart(fig, use_container_width=True)
|
623 |
|
624 |
st.markdown("""
|
625 |
+
The figure above shows a comparison of the two RAG methods in terms of context quality. Ontology-enhanced RAG performs better in multiple dimensions:
|
626 |
+
|
627 |
+
1. **Direct Relevance**: The degree of relevance between the retrieved content and the query
|
628 |
+
2. **Semantic Richness**: Information density and richness of the retrieval context
|
629 |
+
3. **Structural Information**: Structured knowledge of entity types, attributes, and relationships
|
630 |
+
4. **Relationship Information**: Explicit relationships and connection paths between entities
|
631 |
+
|
632 |
+
The advantage of ontology-enhanced RAG is that it can retrieve structured knowledge and relational information, which are missing in traditional RAG methods.
|
633 |
+
""")
|
634 |
+
|
635 |
+
# Display detailed analysis section
|
636 |
+
st.subheader("Method Effectiveness Analysis")
|
637 |
+
|
638 |
+
with st.expander("Comparison of Advantages and Disadvantages", expanded=True):
|
639 |
+
col1, col2 = st.columns(2)
|
640 |
|
641 |
+
with col1:
|
642 |
+
st.markdown("#### Traditional RAG")
|
643 |
+
st.markdown("""
|
644 |
+
**Advantages**:
|
645 |
+
- Simple implementation and light computational burden
|
646 |
+
- Works well with unstructured text
|
647 |
+
- Response times are usually faster
|
648 |
+
|
649 |
+
**Disadvantages**:
|
650 |
+
- Unable to capture relationships between entities
|
651 |
+
- Lack of context for structured knowledge
|
652 |
+
- Difficult to perform multi-hop reasoning
|
653 |
+
- Retrieval is mainly based on text similarity
|
654 |
+
""")
|
655 |
|
656 |
+
with col2:
|
657 |
+
st.markdown("#### Ontology Enhanced RAG")
|
658 |
+
st.markdown("""
|
659 |
+
**Advantages**:
|
660 |
+
- Ability to understand relationships and connections between entities
|
661 |
+
- Provides rich structured knowledge context
|
662 |
+
- Support multi-hop reasoning and path discovery
|
663 |
+
- Combining vector similarity and semantic relationship
|
664 |
+
|
665 |
+
**Disadvantages**:
|
666 |
+
- Higher implementation complexity
|
667 |
+
- Need to maintain the ontology model
|
668 |
+
- The computational overhead is relatively high
|
669 |
+
- Retrieval and inference times may be longer
|
670 |
+
""")
|
671 |
|
672 |
+
# Add usage scenario suggestions
|
673 |
+
with st.expander("Applicable Scenarios"):
|
674 |
st.markdown("""
|
675 |
+
### Traditional RAG Applicable Scenarios
|
676 |
+
|
677 |
+
- Simple fact-finding
|
678 |
+
- Unstructured document retrieval
|
679 |
+
- Applications with high response time requirements
|
680 |
+
- When the document content is clear and direct
|
681 |
+
|
682 |
+
### Applicable Scenarios for Ontology Enhanced RAG
|
683 |
+
|
684 |
+
- Complex knowledge association query
|
685 |
+
- Problems that require understanding of relationships between entities
|
686 |
+
- Applications that require cross-domain reasoning
|
687 |
+
- Enterprise Knowledge Management System
|
688 |
+
- Reasoning scenarios that require high accuracy and consistency
|
689 |
+
- Applications that require implicit knowledge discovery
|
690 |
""")
|
691 |
+
|
692 |
+
# Add practical application examples
|
693 |
+
with st.expander("Application Case Studies"):
|
694 |
st.markdown("""
|
695 |
+
### Enterprise Knowledge Management
|
696 |
+
Ontology-enhanced RAG systems can help enterprises effectively organize and access their knowledge assets, connect information in different departments and systems, and provide more comprehensive business insights.
|
697 |
+
|
698 |
+
### Product Development Decision Support
|
699 |
+
By understanding the relationship between customer feedback, product features, and market data, the system can provide more valuable support for product development decisions.
|
700 |
+
|
701 |
+
### Complex Compliance Queries
|
702 |
+
In compliance problems that require consideration of multiple rules and relationships, ontology-enhanced RAG can provide rule-based reasoning, ensuring that recommendations comply with all applicable policies and regulations.
|
703 |
+
|
704 |
+
### Diagnostics and Troubleshooting
|
705 |
+
In technical support and troubleshooting scenarios, the system can connect symptoms, causes, and solutions to provide more accurate diagnoses through multi-hop reasoning.
|
706 |
""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
707 |
|
708 |
+
if __name__ == "__main__":
|
709 |
+
main()
|
710 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|