awacke1's picture
Create app.py
b1d0519 verified
raw
history blame
6.72 kB
#!/usr/bin/env python3
import os
import re
import glob
import json
import base64
import zipfile
import random
import requests
import openai
from PIL import Image
from urllib.parse import quote
import streamlit as st
import streamlit.components.v1 as components
# Example base snippet: your normal Mermaid code
DEFAULT_MERMAID = r"""
flowchart LR
U((User ๐Ÿ˜Ž)) -- "Talk ๐Ÿ—ฃ๏ธ" --> LLM[LLM Agent ๐Ÿค–\nExtract Info]
click U "/?q=User%20๐Ÿ˜Ž" "Open 'User ๐Ÿ˜Ž'" "_blank"
click LLM "/?q=LLM%20Agent%20Extract%20Info" "Open LLM Agent" "_blank"
LLM -- "Query ๐Ÿ”" --> HS[Hybrid Search ๐Ÿ”Ž\nVector+NER+Lexical]
click HS "/?q=Hybrid%20Search%20Vector+NER+Lexical" "Open Hybrid Search" "_blank"
HS -- "Reason ๐Ÿค”" --> RE[Reasoning Engine ๐Ÿ› ๏ธ\nNeuralNetwork+Medical]
click RE "/?q=Reasoning%20Engine%20NeuralNetwork+Medical" "Open Reasoning" "_blank"
RE -- "Link ๐Ÿ“ก" --> KG((Knowledge Graph ๐Ÿ“š\nOntology+GAR+RAG))
click KG "/?q=Knowledge%20Graph%20Ontology+GAR+RAG" "Open Knowledge Graph" "_blank"
"""
def parse_mermaid_edges(mermaid_text: str):
"""
๐Ÿฟ parse_mermaid_edges:
- Find lines like `A -- "Label" --> B`.
- Return adjacency dict: edges[A] = [(label, B), ...].
"""
adjacency = {}
# Regex to match lines like: A -- "Label" --> B
edge_pattern = re.compile(r'(\S+)\s*--\s*"([^"]*)"\s*-->\s*(\S+)')
# We split the text into lines and search for edges
for line in mermaid_text.split('\n'):
match = edge_pattern.search(line.strip())
if match:
nodeA, label, nodeB = match.groups()
if nodeA not in adjacency:
adjacency[nodeA] = []
adjacency[nodeA].append((label, nodeB))
return adjacency
def build_subgraph(adjacency, start_node):
"""
๐ŸŽ build_subgraph:
- BFS or DFS from start_node to gather edges.
- For simplicity, we only gather direct edges from this node.
- If you want a multi-level downstream search, do a BFS/DFS deeper.
"""
sub_edges = []
# If start_node has no adjacency, return empty
if start_node not in adjacency:
return sub_edges
# For each edge out of start_node, store it in sub_edges
for label, child in adjacency[start_node]:
sub_edges.append((start_node, label, child))
return sub_edges
def create_subgraph_mermaid(sub_edges, start_node):
"""
๐Ÿ„ create_subgraph_mermaid:
- Given a list of edges in form (A, label, B),
- Return a smaller flowchart snippet that includes them.
"""
# Start with the flowchart directive
sub_mermaid = "flowchart LR\n"
sub_mermaid += f" %% Subgraph for {start_node}\n"
# For each edge, build a line: NodeA -- "Label" --> NodeB
for (A, label, B) in sub_edges:
# Potentially you can keep the original styles or shapes (like U((User ๐Ÿ˜Ž))).
# If your original code has shapes, you can store them in a dict so A-> "U((User ๐Ÿ˜Ž))" etc.
sub_mermaid += f' {A} -- "{label}" --> {B}\n'
# Optionally add a comment to show the subgraph ends
sub_mermaid += f" %% End of subgraph for {start_node}\n"
return sub_mermaid
def generate_mermaid_html(mermaid_code: str) -> str:
"""Tiny function to embed Mermaid code in HTML with a CDN."""
return f"""
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<style>
.centered-mermaid {{
display: flex;
justify-content: center;
margin: 20px auto;
}}
.mermaid {{
max-width: 800px;
}}
</style>
</head>
<body>
<div class="mermaid centered-mermaid">
{mermaid_code}
</div>
<script>
mermaid.initialize({{ startOnLoad: true }});
</script>
</body>
</html>
"""
def main():
st.set_page_config(page_title="Partial Subgraph Demo", layout="wide")
st.title("Partial Mermaid Subgraph from a Clicked Node")
# 1) Show the main diagram
st.subheader("Full Diagram:")
full_html = generate_mermaid_html(DEFAULT_MERMAID)
components.html(full_html, height=400, scrolling=True)
# 2) Build adjacency from the original code
adjacency = parse_mermaid_edges(DEFAULT_MERMAID)
# 3) See if user clicked a shape, e.g. ?q=LLM%20Agent%20Extract%20Info
query_params = st.query_params
clicked = (query_params.get('q') or [""])[0] # If present
if clicked:
# The "clicked" node might contain spaces or special chars.
# We typically match the "nodeId" from the code.
# But your code might have the real node name "LLM" or "RE", etc.
# If your node is "LLM" and the label is "LLM Agent Extract Info",
# you might need to map them.
# For simplicity, let's assume your node ID is the same as the label
# after removing spaces.
# Or if your original code uses node IDs like 'LLM' or 'U'.
# We'll show an example:
# We can guess your node ID might be "LLM" if the text includes "LLM".
# Let's try a simpler approach: you store an internal mapping
# from node ID -> label. We'll do a brute force approach:
st.info(f"User clicked shape: {clicked}")
# Suppose we want to find the adjacency key that best matches the clicked string:
# This is a naive approach:
# We'll see if 'clicked' is a substring of the adjacency's node key.
possible_keys = []
for nodeKey in adjacency.keys():
if clicked.lower().replace("%20", " ").replace("extract info", "") in nodeKey.lower():
possible_keys.append(nodeKey)
# If we found one or more possible matches, take the first
if possible_keys:
chosen_node = possible_keys[0]
# Build subgraph from adjacency
sub_edges = build_subgraph(adjacency, chosen_node)
if sub_edges:
sub_mermaid = create_subgraph_mermaid(sub_edges, chosen_node)
# Display top-centered subgraph
st.subheader(f"SearchResult Subgraph for Node: {chosen_node}")
partial_html = generate_mermaid_html(sub_mermaid)
components.html(partial_html, height=300, scrolling=False)
else:
st.warning(f"No outgoing edges from node '{chosen_node}'.")
else:
st.warning("No matching node found in adjacency for that query param.")
else:
st.info("No shape clicked, or no ?q= in the query parameters.")
if __name__ == "__main__":
main()