| | import streamlit as st |
| | from pysd import read_vensim, read_xmile |
| | import pandas as pd |
| | import matplotlib.pyplot as plt |
| | import tempfile |
| | import os |
| | import requests |
| |
|
| | st.set_page_config(page_title="System Dynamics Simulator with Insights", layout="wide") |
| | st.title("π System Dynamics Simulator using PySD + HF Transformers") |
| | st.markdown("Upload a **.mdl** or **.xmile** file, simulate it, and gain insights using Hugging Face LLMs.") |
| |
|
| | HF_API_TOKEN = st.secrets["HF_API_TOKEN"] if "HF_API_TOKEN" in st.secrets else st.text_input("Enter Hugging Face API Token", type="password") |
| | HF_MODEL_URL = "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.1" |
| |
|
| | def ask_llm(prompt): |
| | if not HF_API_TOKEN: |
| | return "π API token required." |
| | headers = {"Authorization": f"Bearer {HF_API_TOKEN}"} |
| | payload = {"inputs": prompt} |
| | response = requests.post(HF_MODEL_URL, headers=headers, json=payload) |
| | if response.status_code == 200: |
| | return response.json()[0]["generated_text"] |
| | else: |
| | return f"β οΈ Error: {response.text}" |
| |
|
| | uploaded_file = st.file_uploader("Choose a Vensim (.mdl) or XMILE (.xmile) file", type=["mdl", "xmile"]) |
| |
|
| | if uploaded_file is not None: |
| | suffix = os.path.splitext(uploaded_file.name)[-1].lower() |
| |
|
| | with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp_file: |
| | tmp_file.write(uploaded_file.getvalue()) |
| | model_path = tmp_file.name |
| |
|
| | try: |
| | if suffix == ".mdl": |
| | model = read_vensim(model_path) |
| | elif suffix == ".xmile": |
| | model = read_xmile(model_path) |
| | else: |
| | st.error("Unsupported file format.") |
| | st.stop() |
| |
|
| | st.success("β
Model loaded successfully!") |
| | if st.button("Run Simulation"): |
| | result = model.run() |
| | st.subheader("π Simulation Output") |
| | st.dataframe(result) |
| |
|
| | st.subheader("π Plot Time-Series") |
| | selected_vars = st.multiselect("Select variables to plot", result.columns.tolist(), default=result.columns.tolist()) |
| | if selected_vars: |
| | for var in selected_vars: |
| | fig, ax = plt.subplots() |
| | ax.plot(result.index, result[var], label=var) |
| | ax.set_xlabel("Time") |
| | ax.set_ylabel(var) |
| | ax.set_title(f"{var} over Time") |
| | ax.grid(True) |
| | st.pyplot(fig) |
| |
|
| | st.subheader("π§ Ask a Question about the Model") |
| | question = st.text_area("What would you like to know about the system dynamics model?") |
| | if st.button("Get Insight from LLM"): |
| | model_info = str(model.components)[:1000] |
| | prompt = f"""The following is a system dynamics model fragment: |
| | |
| | {model_info} |
| | |
| | Question: {question} |
| | """ |
| | response = ask_llm(prompt) |
| | st.markdown(f"**Answer:**\n\n{response}") |
| |
|
| | except Exception as e: |
| | st.error(f"β Error: {str(e)}") |
| |
|
| | |