dhani10 commited on
Commit
2e0de6b
·
verified ·
1 Parent(s): f86120e

Deploy Engine Condition Predictor

Browse files
Files changed (4) hide show
  1. Dockerfile +6 -40
  2. README.md +1 -2
  3. requirements.txt +0 -1
  4. streamlit_app.py +99 -96
Dockerfile CHANGED
@@ -1,53 +1,19 @@
1
- # Docker runtime for HF Space
2
- # # Use a slim Python base
3
- # FROM python:3.11-slim
4
-
5
- # # Basic hygiene
6
- # ENV PIP_NO_CACHE_DIR=1 # PYTHONDONTWRITEBYTECODE=1 # PYTHONUNBUFFERED=1
7
-
8
- # # Working directory
9
- # WORKDIR /app
10
-
11
- # # Copy and install Python deps first
12
- # RUN pip install scikit-learn==1.5.0
13
- # COPY requirements.txt /app/
14
-
15
- # # Install packages without dependencies to avoid conflicts
16
- # RUN pip install --upgrade pip && # pip install --no-deps -r requirements.txt && # pip install streamlit==1.39.0 pandas==2.2.2 numpy==1.26.4 scikit-learn==1.4.2 scipy==1.11.4 joblib==1.4.2 huggingface_hub==0.25.1
17
-
18
- # # Copy app code
19
- # COPY streamlit_app.py /app/
20
- # COPY README.md /app/
21
-
22
- # # Hugging Face caches
23
- # ENV HF_HOME=/tmp/huggingface
24
- # RUN mkdir -p /tmp/huggingface/hub
25
-
26
- # # Expose port
27
- # EXPOSE 7860
28
-
29
- # # Run Streamlit
30
- # CMD ["streamlit", "run", "streamlit_app.py", "--server.port=7860", "--server.address=0.0.0.0"]
31
-
32
  FROM python:3.11-slim
33
 
34
  WORKDIR /app
35
 
36
  # Install system dependencies
37
- RUN apt-get update && apt-get install -y gcc g++ && rm -rf /var/lib/apt/lists/*
 
 
 
38
 
39
  # Copy requirements
40
  COPY requirements.txt .
41
 
42
- # Install Python packages with specific versions
43
  RUN pip install --upgrade pip
44
- RUN pip install streamlit==1.39.0
45
- RUN pip install pandas==2.2.2
46
- RUN pip install numpy==1.26.4
47
- RUN pip install scikit-learn==1.5.0
48
- RUN pip install scipy==1.14.0
49
- RUN pip install joblib==1.4.2
50
- RUN pip install huggingface_hub==0.25.1
51
 
52
  # Copy app
53
  COPY streamlit_app.py .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  FROM python:3.11-slim
2
 
3
  WORKDIR /app
4
 
5
  # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ gcc \
8
+ g++ \
9
+ && rm -rf /var/lib/apt/lists/*
10
 
11
  # Copy requirements
12
  COPY requirements.txt .
13
 
14
+ # Install Python packages
15
  RUN pip install --upgrade pip
16
+ RUN pip install -r requirements.txt
 
 
 
 
 
 
17
 
18
  # Copy app
19
  COPY streamlit_app.py .
README.md CHANGED
@@ -6,5 +6,4 @@ colorTo: blue
6
  sdk: docker
7
  pinned: false
8
  ---
9
- This Space runs a Streamlit app inside a custom Docker image.
10
- If the model repo is **private**, add a Space Secret **HF_TOKEN** (read token) and restart the Space.
 
6
  sdk: docker
7
  pinned: false
8
  ---
9
+ This Space runs a Streamlit app that predicts engine condition from sensor data.
 
requirements.txt CHANGED
@@ -2,6 +2,5 @@ streamlit==1.39.0
2
  pandas==2.2.2
3
  numpy==1.26.4
4
  scikit-learn==1.5.0
5
- scipy==1.11.4
6
  joblib==1.4.2
7
  huggingface_hub==0.25.1
 
2
  pandas==2.2.2
3
  numpy==1.26.4
4
  scikit-learn==1.5.0
 
5
  joblib==1.4.2
6
  huggingface_hub==0.25.1
streamlit_app.py CHANGED
@@ -1,116 +1,119 @@
1
- # Streamlit UI that downloads a scikit-learn pipeline from HF
2
- import os, sys, logging, joblib, numpy as np, pandas as pd
 
 
 
3
  from huggingface_hub import hf_hub_download
4
- from sklearn.exceptions import InconsistentVersionWarning
5
- import warnings
6
 
7
- warnings.filterwarnings("ignore", category=InconsistentVersionWarning)
 
 
8
 
9
- # Silence noisy logs when not run via `streamlit run`
10
- if "streamlit" not in " ".join(sys.argv).lower():
11
- for name in ("streamlit.runtime.scriptrunner.script_run_context",
12
- "streamlit.runtime.scriptrunner","streamlit"):
13
- lg = logging.getLogger(name); lg.setLevel(logging.CRITICAL); lg.propagate=False; lg.disabled=True
14
 
15
- HF_MODEL_REPO = os.getenv("HF_MODEL_REPO", "dhani10/engine-condition-model")
16
- MODEL_FILE = os.getenv("MODEL_FILE", "best_engine_model.joblib")
17
- HF_TOKEN = os.getenv("HF_TOKEN") # add as Space Secret if model repo is private
18
-
19
- HF_CACHE_ROOT = os.getenv("HF_HOME", "/tmp/huggingface")
20
- os.environ["HF_HOME"] = HF_CACHE_ROOT
21
- os.environ["HF_HUB_CACHE"] = os.path.join(HF_CACHE_ROOT, "hub")
22
- os.makedirs(os.environ["HF_HUB_CACHE"], exist_ok=True)
23
-
24
- def _load_model_impl():
25
- path = hf_hub_download(
26
- repo_id=HF_MODEL_REPO,
27
- filename=MODEL_FILE,
28
- repo_type="model",
29
- token=HF_TOKEN, # None if public
30
- cache_dir=os.environ["HF_HUB_CACHE"],
31
- )
32
- return joblib.load(path)
33
-
34
- def get_expected_input_columns(clf):
35
- pre = getattr(getattr(clf, "named_steps", {}), "get", lambda *_: None)("preprocessor")
36
- if pre is not None:
37
- transformers = getattr(pre, "transformers_", getattr(pre, "transformers", []))
38
- cols = []
39
- for _, __, selected in transformers:
40
- if selected in (None, "drop"): continue
41
- if isinstance(selected, list): cols.extend(selected)
42
- elif hasattr(selected, "__iter__"): cols.extend(list(selected))
43
- cols = list(dict.fromkeys(cols))
44
- if cols: return cols
45
- fni = getattr(clf, "feature_names_in_", None)
46
- return list(fni) if fni is not None else [
47
- "engine_rpm","lub_oil_pressure","fuel_pressure",
48
- "coolant_pressure","lub_oil_temp","coolant_temp"
49
- ]
50
-
51
- def coerce_numeric_df(df: pd.DataFrame) -> pd.DataFrame:
52
- out = df.copy()
53
- for c in out.columns: out[c] = pd.to_numeric(out[c], errors="ignore")
54
- return out
55
-
56
- def predict_with_pipeline(model, X: pd.DataFrame):
57
- y = model.predict(X); p = None
58
- if hasattr(model, "predict_proba"):
59
- try:
60
- P = model.predict_proba(X); p = P[:,1] if (P.ndim==2 and P.shape[1]>=2) else P.ravel()
61
- except Exception: pass
62
- return y, p
63
 
64
  def main():
65
- import streamlit as st
66
- st.set_page_config(page_title="Engine Condition Predictor", layout="centered")
 
 
 
 
67
  st.title("Predictive Maintenance — Engine Condition")
68
- st.caption(f"Model: {HF_MODEL_REPO} {MODEL_FILE}")
 
 
 
 
 
69
 
70
- @st.cache_resource(show_spinner=True)
71
- def load_model(): return _load_model_impl()
72
 
73
- model = load_model()
74
- EXPECTED_COLS = get_expected_input_columns(model)
75
 
76
- with st.form("predict_form"):
77
  col1, col2 = st.columns(2)
 
78
  with col1:
79
- engine_rpm = st.number_input("Engine RPM", min_value=0, max_value=5000, value=1200, step=10)
80
- lub_oil_pressure = st.number_input("Lubricating Oil Pressure (bar)", value=3.0, step=0.1)
81
- fuel_pressure = st.number_input("Fuel Pressure (bar)", value=5.0, step=0.1)
 
82
  with col2:
83
- coolant_pressure = st.number_input("Coolant Pressure (bar)", value=2.0, step=0.1)
84
- lub_oil_temp = st.number_input("Lubricating Oil Temperature (°C)", value=80.0, step=0.1)
85
- coolant_temp = st.number_input("Coolant Temperature (°C)", value=75.0, step=0.1)
86
- submitted = st.form_submit_button("Predict")
 
87
 
88
  if submitted:
89
- row = pd.DataFrame({c:[np.nan] for c in EXPECTED_COLS})
90
- for k,v in {
91
- "engine_rpm":engine_rpm,"lub_oil_pressure":lub_oil_pressure,"fuel_pressure":fuel_pressure,
92
- "coolant_pressure":coolant_pressure,"lub_oil_temp":lub_oil_temp,"coolant_temp":coolant_temp
93
- }.items():
94
- if k in row.columns: row.at[0,k]=v
 
 
 
 
95
  try:
96
- X = coerce_numeric_df(row)
97
- y, p = predict_with_pipeline(model, X)
98
- pred = int(y[0])
99
- if pred==1:
100
- msg = "⚠️ Faulty Engine Detected"
101
- if p is not None: msg += f" (Confidence: {float(p[0]):.2f})"
102
- import streamlit as st; st.error(msg)
 
 
 
 
 
 
 
 
 
 
103
  else:
104
- msg = " Engine is Healthy"
105
- if p is not None: msg += f" (Confidence: {1 - float(p[0]):.2f})"
106
- import streamlit as st; st.success(msg)
107
- with st.expander("Inputs sent to the model"):
108
- st.dataframe(X)
 
 
 
 
 
 
 
109
  except Exception as e:
110
- import streamlit as st
111
- st.error(f"Prediction failed: {e}")
112
- st.write("Expected columns:", EXPECTED_COLS)
113
 
114
  if __name__ == "__main__":
115
- if "streamlit" in " ".join(sys.argv).lower(): main()
116
- else: print("Tip: run this app with: streamlit run streamlit_app.py")
 
1
+
2
+ import streamlit as st
3
+ import joblib
4
+ import pandas as pd
5
+ import numpy as np
6
  from huggingface_hub import hf_hub_download
7
+ import os
 
8
 
9
+ # Configuration
10
+ HF_MODEL_REPO = os.getenv("HF_MODEL_REPO", "dhani10/engine-condition-model")
11
+ MODEL_FILE = os.getenv("MODEL_FILE", "best_engine_model.joblib")
12
 
13
+ # Expected features (match your training data exactly)
14
+ EXPECTED_COLS = [
15
+ 'Engine rpm', 'Lub oil pressure', 'Fuel pressure',
16
+ 'Coolant pressure', 'lub oil temp', 'Coolant temp'
17
+ ]
18
 
19
+ @st.cache_resource
20
+ def load_model():
21
+ """Load the model from Hugging Face Hub"""
22
+ try:
23
+ model_path = hf_hub_download(
24
+ repo_id=HF_MODEL_REPO,
25
+ filename=MODEL_FILE,
26
+ repo_type="model",
27
+ token=os.getenv("HF_TOKEN")
28
+ )
29
+ model = joblib.load(model_path)
30
+ st.success("Model loaded successfully!")
31
+ return model
32
+ except Exception as e:
33
+ st.error(f"Failed to load model: {e}")
34
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  def main():
37
+ st.set_page_config(
38
+ page_title="Engine Condition Predictor",
39
+ layout="centered",
40
+ page_icon="🏭"
41
+ )
42
+
43
  st.title("Predictive Maintenance — Engine Condition")
44
+ st.markdown("Monitor engine health using real-time sensor data")
45
+ st.caption(f"Model: {HF_MODEL_REPO}")
46
+
47
+ # Load model
48
+ with st.spinner("Loading AI model..."):
49
+ model = load_model()
50
 
51
+ if model is None:
52
+ st.stop()
53
 
54
+ # Input form
55
+ st.header("🔧 Engine Sensor Readings")
56
 
57
+ with st.form("prediction_form"):
58
  col1, col2 = st.columns(2)
59
+
60
  with col1:
61
+ engine_rpm = st.slider("Engine RPM", 100, 2500, 1200)
62
+ lub_oil_pressure = st.slider("Lub Oil Pressure (bar)", 0.5, 7.0, 3.0, 0.1)
63
+ fuel_pressure = st.slider("Fuel Pressure (bar)", 0.5, 20.0, 6.0, 0.1)
64
+
65
  with col2:
66
+ coolant_pressure = st.slider("Coolant Pressure (bar)", 0.5, 7.0, 2.0, 0.1)
67
+ lub_oil_temp = st.slider("Lub Oil Temp (°C)", 70.0, 110.0, 80.0, 0.1)
68
+ coolant_temp = st.slider("Coolant Temp (°C)", 60.0, 100.0, 75.0, 0.1)
69
+
70
+ submitted = st.form_submit_button("Analyze Engine Condition", type="primary")
71
 
72
  if submitted:
73
+ # Create input data with EXACT column names from training
74
+ input_data = pd.DataFrame([{
75
+ 'Engine rpm': engine_rpm,
76
+ 'Lub oil pressure': lub_oil_pressure,
77
+ 'Fuel pressure': fuel_pressure,
78
+ 'Coolant pressure': coolant_pressure,
79
+ 'lub oil temp': lub_oil_temp,
80
+ 'Coolant temp': coolant_temp
81
+ }])
82
+
83
  try:
84
+ # Make prediction
85
+ prediction = model.predict(input_data)[0]
86
+ probability = model.predict_proba(input_data)[0]
87
+
88
+ # Display results
89
+ st.header("Analysis Results")
90
+
91
+ if prediction == 1:
92
+ st.error("**FAULTY ENGINE DETECTED**")
93
+ st.progress(probability[1])
94
+ st.warning(f"**Risk Probability:** {probability[1]*100:.1f}%")
95
+ st.markdown("""
96
+ **Recommended Actions:**
97
+ - Schedule immediate maintenance
98
+ - Inspect lubrication system
99
+ - Check cooling system
100
+ """)
101
  else:
102
+ st.success("**ENGINE OPERATING NORMALLY**")
103
+ st.progress(probability[0])
104
+ st.info(f"**Health Score:** {probability[0]*100:.1f}%")
105
+ st.markdown("""
106
+ **Status:** Continue routine monitoring
107
+ **Next maintenance:** As scheduled
108
+ """)
109
+
110
+ # Show input data
111
+ with st.expander("View Input Data"):
112
+ st.dataframe(input_data)
113
+
114
  except Exception as e:
115
+ st.error(f"Prediction error: {str(e)}")
116
+ st.info("Please check that the model expects the correct feature names")
 
117
 
118
  if __name__ == "__main__":
119
+ main()