Spaces:
Sleeping
Sleeping
| #!/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() | |