Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import plotly.graph_objects as go
|
| 5 |
+
from datetime import datetime
|
| 6 |
+
|
| 7 |
+
# Fault classification logic
|
| 8 |
+
def classify_fault(temperature, vibration, humidity, power, pressure):
|
| 9 |
+
"""Classify device status based on sensor readings"""
|
| 10 |
+
|
| 11 |
+
# Define thresholds
|
| 12 |
+
temp_normal = (15, 35)
|
| 13 |
+
vib_normal = (0, 50)
|
| 14 |
+
humidity_normal = (30, 70)
|
| 15 |
+
power_normal = (80, 120)
|
| 16 |
+
pressure_normal = (950, 1050)
|
| 17 |
+
|
| 18 |
+
faults = []
|
| 19 |
+
severity_score = 0
|
| 20 |
+
|
| 21 |
+
# Check temperature
|
| 22 |
+
if temperature < temp_normal[0] or temperature > temp_normal[1]:
|
| 23 |
+
if temperature < temp_normal[0] - 10 or temperature > temp_normal[1] + 10:
|
| 24 |
+
faults.append("❌ **CRITICAL**: Temperature out of range")
|
| 25 |
+
severity_score += 3
|
| 26 |
+
else:
|
| 27 |
+
faults.append("⚠️ **WARNING**: Temperature abnormal")
|
| 28 |
+
severity_score += 1
|
| 29 |
+
|
| 30 |
+
# Check vibration
|
| 31 |
+
if vibration > vib_normal[1]:
|
| 32 |
+
if vibration > vib_normal[1] * 1.5:
|
| 33 |
+
faults.append("❌ **CRITICAL**: Excessive vibration detected")
|
| 34 |
+
severity_score += 3
|
| 35 |
+
else:
|
| 36 |
+
faults.append("⚠️ **WARNING**: Elevated vibration")
|
| 37 |
+
severity_score += 1
|
| 38 |
+
|
| 39 |
+
# Check humidity
|
| 40 |
+
if humidity < humidity_normal[0] or humidity > humidity_normal[1]:
|
| 41 |
+
faults.append("⚠️ **WARNING**: Humidity out of optimal range")
|
| 42 |
+
severity_score += 1
|
| 43 |
+
|
| 44 |
+
# Check power
|
| 45 |
+
if power < power_normal[0] or power > power_normal[1]:
|
| 46 |
+
if power < power_normal[0] * 0.7 or power > power_normal[1] * 1.3:
|
| 47 |
+
faults.append("❌ **CRITICAL**: Power consumption anomaly")
|
| 48 |
+
severity_score += 3
|
| 49 |
+
else:
|
| 50 |
+
faults.append("⚠️ **WARNING**: Power consumption unusual")
|
| 51 |
+
severity_score += 1
|
| 52 |
+
|
| 53 |
+
# Check pressure
|
| 54 |
+
if pressure < pressure_normal[0] or pressure > pressure_normal[1]:
|
| 55 |
+
faults.append("⚠️ **WARNING**: Pressure deviation detected")
|
| 56 |
+
severity_score += 1
|
| 57 |
+
|
| 58 |
+
# Determine overall status
|
| 59 |
+
if severity_score == 0:
|
| 60 |
+
status = "✅ NORMAL"
|
| 61 |
+
color = "green"
|
| 62 |
+
recommendation = "Device operating within normal parameters. Continue routine monitoring."
|
| 63 |
+
elif severity_score <= 3:
|
| 64 |
+
status = "⚠️ WARNING"
|
| 65 |
+
color = "orange"
|
| 66 |
+
recommendation = "Schedule inspection. Monitor closely for further degradation."
|
| 67 |
+
else:
|
| 68 |
+
status = "❌ FAILURE"
|
| 69 |
+
color = "red"
|
| 70 |
+
recommendation = "IMMEDIATE ACTION REQUIRED. Stop device and perform maintenance."
|
| 71 |
+
|
| 72 |
+
# Create gauge chart
|
| 73 |
+
fig = go.Figure(go.Indicator(
|
| 74 |
+
mode="gauge+number+delta",
|
| 75 |
+
value=severity_score,
|
| 76 |
+
domain={'x': [0, 1], 'y': [0, 1]},
|
| 77 |
+
title={'text': "Fault Severity Score"},
|
| 78 |
+
delta={'reference': 0},
|
| 79 |
+
gauge={
|
| 80 |
+
'axis': {'range': [None, 10]},
|
| 81 |
+
'bar': {'color': color},
|
| 82 |
+
'steps': [
|
| 83 |
+
{'range': [0, 3], 'color': "lightgreen"},
|
| 84 |
+
{'range': [3, 6], 'color': "lightyellow"},
|
| 85 |
+
{'range': [6, 10], 'color': "lightcoral"}],
|
| 86 |
+
'threshold': {
|
| 87 |
+
'line': {'color': "red", 'width': 4},
|
| 88 |
+
'thickness': 0.75,
|
| 89 |
+
'value': 7}}))
|
| 90 |
+
|
| 91 |
+
fig.update_layout(height=300)
|
| 92 |
+
|
| 93 |
+
# Generate report
|
| 94 |
+
report = f"## {status}\n\n"
|
| 95 |
+
report += f"**Timestamp**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
| 96 |
+
report += f"**Severity Score**: {severity_score}/10\n\n"
|
| 97 |
+
|
| 98 |
+
if faults:
|
| 99 |
+
report += "### Detected Issues:\n"
|
| 100 |
+
for fault in faults:
|
| 101 |
+
report += f"- {fault}\n"
|
| 102 |
+
else:
|
| 103 |
+
report += "### ✅ No Issues Detected\n"
|
| 104 |
+
|
| 105 |
+
report += f"\n### Recommendation:\n{recommendation}\n\n"
|
| 106 |
+
report += "---\n**Sensor Readings:**\n"
|
| 107 |
+
report += f"- Temperature: {temperature}°C\n"
|
| 108 |
+
report += f"- Vibration: {vibration} Hz\n"
|
| 109 |
+
report += f"- Humidity: {humidity}%\n"
|
| 110 |
+
report += f"- Power: {power} W\n"
|
| 111 |
+
report += f"- Pressure: {pressure} hPa\n"
|
| 112 |
+
|
| 113 |
+
return fig, report
|
| 114 |
+
|
| 115 |
+
def classify_from_csv(file):
|
| 116 |
+
"""Process CSV file with sensor data"""
|
| 117 |
+
if file is None:
|
| 118 |
+
return None, "Please upload a CSV file"
|
| 119 |
+
|
| 120 |
+
try:
|
| 121 |
+
df = pd.read_csv(file.name)
|
| 122 |
+
|
| 123 |
+
# Check required columns
|
| 124 |
+
required = ['temperature', 'vibration', 'humidity', 'power', 'pressure']
|
| 125 |
+
if not all(col in df.columns for col in required):
|
| 126 |
+
return None, f"⚠️ Missing columns. Required: {', '.join(required)}"
|
| 127 |
+
|
| 128 |
+
# Process last row
|
| 129 |
+
last_row = df.iloc[-1]
|
| 130 |
+
return classify_fault(
|
| 131 |
+
last_row['temperature'],
|
| 132 |
+
last_row['vibration'],
|
| 133 |
+
last_row['humidity'],
|
| 134 |
+
last_row['power'],
|
| 135 |
+
last_row['pressure']
|
| 136 |
+
)
|
| 137 |
+
except Exception as e:
|
| 138 |
+
return None, f"❌ Error processing file: {str(e)}"
|
| 139 |
+
|
| 140 |
+
# Create Gradio interface
|
| 141 |
+
with gr.Blocks(title="Device Fault Classifier - Anktechsol", theme=gr.themes.Soft()) as demo:
|
| 142 |
+
gr.Markdown("""
|
| 143 |
+
# 🔧 IoT Device Fault Classifier
|
| 144 |
+
### by **Anktechsol** - AI + IoT Experts
|
| 145 |
+
|
| 146 |
+
Intelligent fault detection and classification for industrial IoT devices using AI-powered sensor analysis.
|
| 147 |
+
Identify device failures before they cause downtime!
|
| 148 |
+
""")
|
| 149 |
+
|
| 150 |
+
with gr.Tabs():
|
| 151 |
+
with gr.Tab("📊 Manual Input"):
|
| 152 |
+
with gr.Row():
|
| 153 |
+
with gr.Column():
|
| 154 |
+
temp_input = gr.Slider(0, 100, value=25, label="Temperature (°C)")
|
| 155 |
+
vib_input = gr.Slider(0, 150, value=30, label="Vibration (Hz)")
|
| 156 |
+
humid_input = gr.Slider(0, 100, value=50, label="Humidity (%)")
|
| 157 |
+
power_input = gr.Slider(0, 200, value=100, label="Power (W)")
|
| 158 |
+
pressure_input = gr.Slider(800, 1200, value=1013, label="Pressure (hPa)")
|
| 159 |
+
classify_btn = gr.Button("🔍 Classify Status", variant="primary", size="lg")
|
| 160 |
+
gr.Markdown("""
|
| 161 |
+
---
|
| 162 |
+
### 🔗 Resources
|
| 163 |
+
- [Anktechsol](https://anktechsol.com)
|
| 164 |
+
- [More Tools](https://huggingface.co/anktechsol)
|
| 165 |
+
""")
|
| 166 |
+
|
| 167 |
+
with gr.Column():
|
| 168 |
+
gauge_plot = gr.Plot(label="Severity Gauge")
|
| 169 |
+
report_output = gr.Markdown()
|
| 170 |
+
|
| 171 |
+
classify_btn.click(
|
| 172 |
+
fn=classify_fault,
|
| 173 |
+
inputs=[temp_input, vib_input, humid_input, power_input, pressure_input],
|
| 174 |
+
outputs=[gauge_plot, report_output]
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
with gr.Tab("📄 CSV Upload"):
|
| 178 |
+
gr.Markdown("""
|
| 179 |
+
Upload a CSV file with columns: `temperature`, `vibration`, `humidity`, `power`, `pressure`
|
| 180 |
+
|
| 181 |
+
The classifier will analyze the most recent reading.
|
| 182 |
+
""")
|
| 183 |
+
with gr.Row():
|
| 184 |
+
csv_input = gr.File(label="Upload Sensor Data CSV", file_types=[".csv"])
|
| 185 |
+
with gr.Row():
|
| 186 |
+
csv_gauge = gr.Plot(label="Severity Gauge")
|
| 187 |
+
with gr.Row():
|
| 188 |
+
csv_report = gr.Markdown()
|
| 189 |
+
|
| 190 |
+
csv_input.change(
|
| 191 |
+
fn=classify_from_csv,
|
| 192 |
+
inputs=[csv_input],
|
| 193 |
+
outputs=[csv_gauge, csv_report]
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
# Auto-load demo
|
| 197 |
+
demo.load(
|
| 198 |
+
fn=lambda: classify_fault(25, 30, 50, 100, 1013),
|
| 199 |
+
outputs=[gauge_plot, report_output]
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
if __name__ == "__main__":
|
| 203 |
+
demo.launch()
|