Spaces:
Sleeping
Sleeping
# app.py - FactoryRAG+: Smart Chatbot with Role-Based Assistant, Dashboard, PDF, and Digital Twin | |
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from sentence_transformers import SentenceTransformer | |
from transformers import pipeline | |
from sklearn.ensemble import IsolationForest | |
import base64 | |
from io import BytesIO | |
from fpdf import FPDF | |
st.set_page_config(page_title="FactoryRAG+ - Smart Sensor Twin", layout="wide") | |
st.title("π FactoryRAG+: Smart Dashboard with AI Monitoring, PDF Reporting & Digital Twin") | |
# Load models | |
EMBED_MODEL = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') | |
GEN_MODEL = pipeline('text2text-generation', model='google/flan-t5-base') | |
# Upload data | |
uploaded_file = st.sidebar.file_uploader("π Upload your condition monitoring CSV", type=["csv"]) | |
if uploaded_file: | |
df = pd.read_csv(uploaded_file) | |
numeric_cols = df.select_dtypes(include=np.number).columns.tolist() | |
st.success("β Data loaded successfully!") | |
st.subheader("π Sensor Snapshot") | |
st.dataframe(df.head()) | |
# --- Multi-signal Dashboard --- | |
st.subheader("π Sensor Dashboard") | |
selected_cols = st.multiselect("Select signals to visualize", numeric_cols, default=numeric_cols[:3]) | |
fig, ax = plt.subplots(len(selected_cols), 1, figsize=(8, 2 * len(selected_cols))) | |
if len(selected_cols) == 1: | |
ax = [ax] | |
for i, col in enumerate(selected_cols): | |
ax[i].plot(df[col], label=col) | |
ax[i].set_ylabel(col) | |
ax[i].legend() | |
st.pyplot(fig) | |
# --- Convert Logs to Chunks --- | |
def convert_to_chunks(df): | |
chunks = [] | |
for idx, row in df.iterrows(): | |
sentence = f"[Log {idx}] " + ", ".join([f"{col}: {row[col]:.2f}" for col in numeric_cols]) | |
chunks.append(sentence) | |
return chunks | |
# Ensure initialization | |
if 'chunks' not in st.session_state or 'embeddings' not in st.session_state: | |
chunks = convert_to_chunks(df) | |
embeddings = EMBED_MODEL.encode(chunks) | |
st.session_state.chunks = chunks | |
st.session_state.embeddings = embeddings | |
# --- Anomaly Detection --- | |
st.subheader("π¨ Anomaly Detection (Isolation Forest)") | |
iso = IsolationForest(contamination=0.02) | |
anomaly_labels = iso.fit_predict(df[numeric_cols]) | |
df['anomaly'] = ['β' if x == -1 else '' for x in anomaly_labels] | |
st.dataframe(df[df['anomaly'] == 'β'].head(5)) | |
# --- Digital Twin Summary --- | |
st.subheader("π§ͺ Digital Twin Summary") | |
twin_report = "" | |
for col in selected_cols: | |
max_v = df[col].max() | |
min_v = df[col].min() | |
mean_v = df[col].mean() | |
twin_report += f"{col}\nβ Max: {max_v:.2f}, Min: {min_v:.2f}, Avg: {mean_v:.2f}\n\n" | |
st.code(twin_report) | |
# --- PDF Export --- | |
st.subheader("π€ Export Digital Twin Report as PDF") | |
pdf = FPDF() | |
pdf.add_page() | |
pdf.set_font("Arial", size=12) | |
pdf.multi_cell(0, 10, f"FactoryRAG+ Digital Twin Report\n\nSelected Signals: {', '.join(selected_cols)}\n\n" + twin_report) | |
pdf_bytes = pdf.output(dest='S').encode('latin1') | |
b64 = base64.b64encode(pdf_bytes).decode() | |
href = f'<a href="data:application/octet-stream;base64,{b64}" download="digital_twin_report.pdf">π Download PDF Report</a>' | |
st.markdown(href, unsafe_allow_html=True) | |
# --- Role-based Factory Assistant --- | |
st.subheader("π¬ Factory Assistant Chat") | |
roles = { | |
"Operator": "You are a machine operator. Provide practical insights and safety warnings.", | |
"Maintenance": "You are a maintenance technician. Suggest inspections and likely causes of sensor anomalies.", | |
"Engineer": "You are a control systems engineer. Offer analytical interpretations and system-level advice." | |
} | |
role = st.selectbox("π€ Choose your role: Operator, Maintenance, or Engineer", list(roles.keys())) | |
if 'chat_history' not in st.session_state: | |
st.session_state.chat_history = [] | |
user_input = st.text_input("Ask FactoryGPT anything (based on uploaded sensor logs):", key="chat_input") | |
if user_input: | |
query_vec = EMBED_MODEL.encode([user_input])[0] | |
sims = np.dot(st.session_state.embeddings, query_vec) | |
top_idxs = np.argsort(sims)[-3:][::-1] | |
context = "\n".join([st.session_state.chunks[i] for i in top_idxs]) | |
system_prompt = roles[role] | |
full_prompt = f"{system_prompt}\n\nSensor Context:\n{context}\n\nUser Question: {user_input}" | |
reply = GEN_MODEL(full_prompt, max_length=256)[0]['generated_text'] | |
st.session_state.chat_history.append(("You", user_input)) | |
st.session_state.chat_history.append((f"{role} - FactoryGPT", reply)) | |
for speaker, msg in st.session_state.chat_history[-10:]: | |
st.markdown(f"**{speaker}:** {msg}") | |
else: | |
st.info("π Upload a sensor log CSV file to explore digital twin analysis, chatbot Q&A, waveform charts, anomaly detection, and PDF export.") | |