| 
							 | 
						import streamlit as st | 
					
					
						
						| 
							 | 
						from PIL import Image | 
					
					
						
						| 
							 | 
						import matplotlib.pyplot as plt | 
					
					
						
						| 
							 | 
						import networkx as nx | 
					
					
						
						| 
							 | 
						import json | 
					
					
						
						| 
							 | 
						from transformers import AutoModelForCausalLM, AutoTokenizer | 
					
					
						
						| 
							 | 
						import torch | 
					
					
						
						| 
							 | 
						torch.cuda.empty_cache() | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						import os | 
					
					
						
						| 
							 | 
						import numpy as np | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						from download_models import download_all | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						if not os.path.exists("P&ID-Symbols-3/train/_annotations.coco.json"): | 
					
					
						
						| 
							 | 
						    with st.spinner("Downloading required files (models & datasets)..."): | 
					
					
						
						| 
							 | 
						        download_all() | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						from pipeline.detector import detect_symbols_and_lines | 
					
					
						
						| 
							 | 
						from pipeline.graph_builder import build_graph | 
					
					
						
						| 
							 | 
						from pipeline.gnn_model import run_gnn | 
					
					
						
						| 
							 | 
						from pipeline.agent import generate_agent_actions | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						st.set_page_config(layout="wide") | 
					
					
						
						| 
							 | 
						st.title(" Agentic Predictive Maintenance (P&ID Graph + GNN)") | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						if "G" not in st.session_state: | 
					
					
						
						| 
							 | 
						    st.session_state.G = None | 
					
					
						
						| 
							 | 
						if "feature_map" not in st.session_state: | 
					
					
						
						| 
							 | 
						    st.session_state.feature_map = {} | 
					
					
						
						| 
							 | 
						if "scores" not in st.session_state: | 
					
					
						
						| 
							 | 
						    st.session_state.scores = {} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						st.subheader("Upload or Select a P&ID Drawing") | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						local_dataset_dir = "P&ID-Symbols-3/P&ID-Symbols-3/test" | 
					
					
						
						| 
							 | 
						image_files = [] | 
					
					
						
						| 
							 | 
						if os.path.exists(local_dataset_dir): | 
					
					
						
						| 
							 | 
						    image_files = [f for f in os.listdir(local_dataset_dir) if f.lower().endswith((".png", ".jpg", ".jpeg"))] | 
					
					
						
						| 
							 | 
						else: | 
					
					
						
						| 
							 | 
						    st.warning(f"Dataset folder not found: {local_dataset_dir}. Please run download_models.py to download it.") | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						selected_image = st.selectbox("Select a sample from P&ID-Symbols-3:", ["-- Select an example --"] + image_files) | 
					
					
						
						| 
							 | 
						uploaded_file = st.file_uploader("...Or upload your own P&ID image", type=["png", "jpg", "jpeg"]) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						image = None | 
					
					
						
						| 
							 | 
						image_source = "" | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						if selected_image and selected_image != "-- Select an example --": | 
					
					
						
						| 
							 | 
						    image_path = os.path.join(local_dataset_dir, selected_image) | 
					
					
						
						| 
							 | 
						    image = Image.open(image_path) | 
					
					
						
						| 
							 | 
						    image_source = f"Sample from dataset: {selected_image}" | 
					
					
						
						| 
							 | 
						elif uploaded_file: | 
					
					
						
						| 
							 | 
						    image = Image.open(uploaded_file) | 
					
					
						
						| 
							 | 
						    image_source = f"Uploaded: {uploaded_file.name}" | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						if image: | 
					
					
						
						| 
							 | 
						    st.image(image, caption=image_source, use_column_width=True) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if st.button(" Run Detection and Analysis"): | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        detections, annotations, class_names = detect_symbols_and_lines(image) | 
					
					
						
						| 
							 | 
						        graph = build_graph(image, detections, annotations, class_names) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        st.info("Running anomaly detection on the graph (simulated for now)...") | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        fig, feature_map, red_nodes, central_node, scores, G = run_gnn() | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        st.session_state.G = G | 
					
					
						
						| 
							 | 
						        st.session_state.feature_map = feature_map | 
					
					
						
						| 
							 | 
						        st.session_state.scores = scores | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        st.pyplot(fig) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        actions = generate_agent_actions(fig, feature_map, red_nodes, central_node, scores) | 
					
					
						
						| 
							 | 
						        for action in actions: | 
					
					
						
						| 
							 | 
						            st.write(action) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						@st.cache_resource | 
					
					
						
						| 
							 | 
						def load_deepseek_model(): | 
					
					
						
						| 
							 | 
						    model_name = "deepseek-ai/deepseek-coder-1.3b-instruct"   | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						    tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) | 
					
					
						
						| 
							 | 
						    '''model = AutoModelForCausalLM.from_pretrained( | 
					
					
						
						| 
							 | 
						        model_name, | 
					
					
						
						| 
							 | 
						        torch_dtype=torch.float16, | 
					
					
						
						| 
							 | 
						        device_map="auto", | 
					
					
						
						| 
							 | 
						        trust_remote_code=True''' | 
					
					
						
						| 
							 | 
						    model = AutoModelForCausalLM.from_pretrained( | 
					
					
						
						| 
							 | 
						        model_name, | 
					
					
						
						| 
							 | 
						        torch_dtype=torch.float16, | 
					
					
						
						| 
							 | 
						        device_map="cpu", | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        trust_remote_code=True | 
					
					
						
						| 
							 | 
						    ) | 
					
					
						
						| 
							 | 
						    return model, tokenizer | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						st.subheader(" Ask Questions About the Graph (DeepSeek Local)") | 
					
					
						
						| 
							 | 
						user_query = st.chat_input("Ask a question about the graph...") | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						if user_query: | 
					
					
						
						| 
							 | 
						    G = st.session_state.get("G") | 
					
					
						
						| 
							 | 
						    feature_map = st.session_state.get("feature_map", {}) | 
					
					
						
						| 
							 | 
						    scores = st.session_state.get("scores", []) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if G is not None and feature_map and len(scores) > 0: | 
					
					
						
						| 
							 | 
						        graph_data = { | 
					
					
						
						| 
							 | 
						            "nodes": [ | 
					
					
						
						| 
							 | 
						                { | 
					
					
						
						| 
							 | 
						                    "id": str(i), | 
					
					
						
						| 
							 | 
						                    "label": feature_map[i] if i < len(feature_map) else f"Node {i}", | 
					
					
						
						| 
							 | 
						                    "score": float(scores[i]) if i < len(scores) else 0.0 | 
					
					
						
						| 
							 | 
						                } | 
					
					
						
						| 
							 | 
						                for i in G.nodes() | 
					
					
						
						| 
							 | 
						            ], | 
					
					
						
						| 
							 | 
						            "edges": [ | 
					
					
						
						| 
							 | 
						                {"source": str(u), "target": str(v)} | 
					
					
						
						| 
							 | 
						                for u, v in G.edges() | 
					
					
						
						| 
							 | 
						            ] | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        prompt = ( | 
					
					
						
						| 
							 | 
						            "You are an expert graph analyst. Analyze this P&ID graph and answer the question.\n\n" | 
					
					
						
						| 
							 | 
						            "### Graph Data:\n" | 
					
					
						
						| 
							 | 
						            f"{json.dumps(graph_data, indent=2)}\n\n" | 
					
					
						
						| 
							 | 
						            "### Question:\n" | 
					
					
						
						| 
							 | 
						            f"{user_query}\n\n" | 
					
					
						
						| 
							 | 
						            "### Answer:\n" | 
					
					
						
						| 
							 | 
						        ) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        try: | 
					
					
						
						| 
							 | 
						            with st.spinner("Thinking (via DeepSeek Local)..."): | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                model, tokenizer = load_deepseek_model() | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                inputs = tokenizer(prompt, return_tensors="pt").to(model.device) | 
					
					
						
						| 
							 | 
						                outputs = model.generate( | 
					
					
						
						| 
							 | 
						                    **inputs, | 
					
					
						
						| 
							 | 
						                    max_new_tokens=128, | 
					
					
						
						| 
							 | 
						                    temperature=0.7, | 
					
					
						
						| 
							 | 
						                    do_sample=True | 
					
					
						
						| 
							 | 
						                ) | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                answer = tokenizer.decode(outputs[0], skip_special_tokens=True) | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                answer = answer[len(prompt):].strip() | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						                st.markdown(f"**DeepSeek:** {answer}") | 
					
					
						
						| 
							 | 
						                 | 
					
					
						
						| 
							 | 
						        except Exception as e: | 
					
					
						
						| 
							 | 
						            st.error(f"DeepSeek error: {e}") | 
					
					
						
						| 
							 | 
						            st.error("Make sure you have enough GPU memory (8GB+ recommended for 7B model)") | 
					
					
						
						| 
							 | 
						    else: | 
					
					
						
						| 
							 | 
						        st.warning("Graph or scores are not ready yet.") | 
					
					
						
						| 
							 | 
						
 |