awacke1 commited on
Commit
b1d0519
·
verified ·
1 Parent(s): f51a852

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -0
app.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import re
5
+ import glob
6
+ import json
7
+ import base64
8
+ import zipfile
9
+ import random
10
+ import requests
11
+ import openai
12
+
13
+ from PIL import Image
14
+ from urllib.parse import quote
15
+
16
+ import streamlit as st
17
+ import streamlit.components.v1 as components
18
+
19
+ # Example base snippet: your normal Mermaid code
20
+ DEFAULT_MERMAID = r"""
21
+ flowchart LR
22
+ U((User 😎)) -- "Talk 🗣️" --> LLM[LLM Agent 🤖\nExtract Info]
23
+ click U "/?q=User%20😎" "Open 'User 😎'" "_blank"
24
+ click LLM "/?q=LLM%20Agent%20Extract%20Info" "Open LLM Agent" "_blank"
25
+
26
+ LLM -- "Query 🔍" --> HS[Hybrid Search 🔎\nVector+NER+Lexical]
27
+ click HS "/?q=Hybrid%20Search%20Vector+NER+Lexical" "Open Hybrid Search" "_blank"
28
+
29
+ HS -- "Reason 🤔" --> RE[Reasoning Engine 🛠️\nNeuralNetwork+Medical]
30
+ click RE "/?q=Reasoning%20Engine%20NeuralNetwork+Medical" "Open Reasoning" "_blank"
31
+
32
+ RE -- "Link 📡" --> KG((Knowledge Graph 📚\nOntology+GAR+RAG))
33
+ click KG "/?q=Knowledge%20Graph%20Ontology+GAR+RAG" "Open Knowledge Graph" "_blank"
34
+ """
35
+
36
+ def parse_mermaid_edges(mermaid_text: str):
37
+ """
38
+ 🍿 parse_mermaid_edges:
39
+ - Find lines like `A -- "Label" --> B`.
40
+ - Return adjacency dict: edges[A] = [(label, B), ...].
41
+ """
42
+ adjacency = {}
43
+ # Regex to match lines like: A -- "Label" --> B
44
+ edge_pattern = re.compile(r'(\S+)\s*--\s*"([^"]*)"\s*-->\s*(\S+)')
45
+
46
+ # We split the text into lines and search for edges
47
+ for line in mermaid_text.split('\n'):
48
+ match = edge_pattern.search(line.strip())
49
+ if match:
50
+ nodeA, label, nodeB = match.groups()
51
+ if nodeA not in adjacency:
52
+ adjacency[nodeA] = []
53
+ adjacency[nodeA].append((label, nodeB))
54
+
55
+ return adjacency
56
+
57
+ def build_subgraph(adjacency, start_node):
58
+ """
59
+ 🍎 build_subgraph:
60
+ - BFS or DFS from start_node to gather edges.
61
+ - For simplicity, we only gather direct edges from this node.
62
+ - If you want a multi-level downstream search, do a BFS/DFS deeper.
63
+ """
64
+ sub_edges = []
65
+ # If start_node has no adjacency, return empty
66
+ if start_node not in adjacency:
67
+ return sub_edges
68
+
69
+ # For each edge out of start_node, store it in sub_edges
70
+ for label, child in adjacency[start_node]:
71
+ sub_edges.append((start_node, label, child))
72
+
73
+ return sub_edges
74
+
75
+ def create_subgraph_mermaid(sub_edges, start_node):
76
+ """
77
+ 🍄 create_subgraph_mermaid:
78
+ - Given a list of edges in form (A, label, B),
79
+ - Return a smaller flowchart snippet that includes them.
80
+ """
81
+ # Start with the flowchart directive
82
+ sub_mermaid = "flowchart LR\n"
83
+ sub_mermaid += f" %% Subgraph for {start_node}\n"
84
+
85
+ # For each edge, build a line: NodeA -- "Label" --> NodeB
86
+ for (A, label, B) in sub_edges:
87
+ # Potentially you can keep the original styles or shapes (like U((User 😎))).
88
+ # If your original code has shapes, you can store them in a dict so A-> "U((User 😎))" etc.
89
+ sub_mermaid += f' {A} -- "{label}" --> {B}\n'
90
+
91
+ # Optionally add a comment to show the subgraph ends
92
+ sub_mermaid += f" %% End of subgraph for {start_node}\n"
93
+ return sub_mermaid
94
+
95
+ def generate_mermaid_html(mermaid_code: str) -> str:
96
+ """Tiny function to embed Mermaid code in HTML with a CDN."""
97
+ return f"""
98
+ <html>
99
+ <head>
100
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
101
+ <style>
102
+ .centered-mermaid {{
103
+ display: flex;
104
+ justify-content: center;
105
+ margin: 20px auto;
106
+ }}
107
+ .mermaid {{
108
+ max-width: 800px;
109
+ }}
110
+ </style>
111
+ </head>
112
+ <body>
113
+ <div class="mermaid centered-mermaid">
114
+ {mermaid_code}
115
+ </div>
116
+ <script>
117
+ mermaid.initialize({{ startOnLoad: true }});
118
+ </script>
119
+ </body>
120
+ </html>
121
+ """
122
+
123
+ def main():
124
+ st.set_page_config(page_title="Partial Subgraph Demo", layout="wide")
125
+ st.title("Partial Mermaid Subgraph from a Clicked Node")
126
+
127
+ # 1) Show the main diagram
128
+ st.subheader("Full Diagram:")
129
+ full_html = generate_mermaid_html(DEFAULT_MERMAID)
130
+ components.html(full_html, height=400, scrolling=True)
131
+
132
+ # 2) Build adjacency from the original code
133
+ adjacency = parse_mermaid_edges(DEFAULT_MERMAID)
134
+
135
+ # 3) See if user clicked a shape, e.g. ?q=LLM%20Agent%20Extract%20Info
136
+ query_params = st.query_params
137
+ clicked = (query_params.get('q') or [""])[0] # If present
138
+
139
+ if clicked:
140
+ # The "clicked" node might contain spaces or special chars.
141
+ # We typically match the "nodeId" from the code.
142
+ # But your code might have the real node name "LLM" or "RE", etc.
143
+ # If your node is "LLM" and the label is "LLM Agent Extract Info",
144
+ # you might need to map them.
145
+ # For simplicity, let's assume your node ID is the same as the label
146
+ # after removing spaces.
147
+ # Or if your original code uses node IDs like 'LLM' or 'U'.
148
+ # We'll show an example:
149
+
150
+ # We can guess your node ID might be "LLM" if the text includes "LLM".
151
+ # Let's try a simpler approach: you store an internal mapping
152
+ # from node ID -> label. We'll do a brute force approach:
153
+ st.info(f"User clicked shape: {clicked}")
154
+
155
+ # Suppose we want to find the adjacency key that best matches the clicked string:
156
+ # This is a naive approach:
157
+ # We'll see if 'clicked' is a substring of the adjacency's node key.
158
+ possible_keys = []
159
+ for nodeKey in adjacency.keys():
160
+ if clicked.lower().replace("%20", " ").replace("extract info", "") in nodeKey.lower():
161
+ possible_keys.append(nodeKey)
162
+ # If we found one or more possible matches, take the first
163
+ if possible_keys:
164
+ chosen_node = possible_keys[0]
165
+ # Build subgraph from adjacency
166
+ sub_edges = build_subgraph(adjacency, chosen_node)
167
+ if sub_edges:
168
+ sub_mermaid = create_subgraph_mermaid(sub_edges, chosen_node)
169
+
170
+ # Display top-centered subgraph
171
+ st.subheader(f"SearchResult Subgraph for Node: {chosen_node}")
172
+ partial_html = generate_mermaid_html(sub_mermaid)
173
+ components.html(partial_html, height=300, scrolling=False)
174
+ else:
175
+ st.warning(f"No outgoing edges from node '{chosen_node}'.")
176
+ else:
177
+ st.warning("No matching node found in adjacency for that query param.")
178
+ else:
179
+ st.info("No shape clicked, or no ?q= in the query parameters.")
180
+
181
+
182
+ if __name__ == "__main__":
183
+ main()