SHELLAPANDIANGANHUNGING commited on
Commit
de17a01
·
verified ·
1 Parent(s): 50317c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -95
app.py CHANGED
@@ -2,8 +2,9 @@ import gradio as gr
2
  import pandas as pd
3
  import numpy as np
4
 
5
- # ================= LOAD DATA — AMBIL TEKANAN & WAKTU TERAKHIR =================
6
  last_pressure = 85.0
 
7
  last_time = "–"
8
 
9
  try:
@@ -11,15 +12,17 @@ try:
11
  df.columns = df.columns.str.replace("Â", "", regex=False)
12
  for col in df.select_dtypes(include='object').columns:
13
  df[col] = df[col].astype(str).str.replace("Â", "", regex=False)
 
14
  df['Time'] = pd.to_datetime(df['Time'], errors='coerce')
15
  df = df.dropna(subset=['Time'])
16
 
17
  if not df.empty:
18
- last_row = df.sort_values('Time').iloc[-1]
19
  last_pressure = float(last_row['Pressure']) if pd.notna(last_row.get('Pressure')) else 85.0
20
- last_time = last_row['Time'].strftime("%H:%M")
 
21
  except Exception as e:
22
- pass
23
 
24
  # ================= BATAS AMAN (SESUAI STANDAR OPERASIONAL) =================
25
  red_low = 70.0
@@ -32,157 +35,145 @@ def get_safe_fill_range(last_p):
32
  upper = min(last_p + 10, amber_high - 0.5)
33
  return round(lower, 1), round(upper, 1)
34
 
35
- # ================= CUSTOM CSS — (TETAP SAMA SEPERTI ANDA INGINKAN) =================
36
  custom_css = """
37
  body, .gradio-container {
38
  background: #000000 !important;
39
  color: #FFFFFF !important;
40
  font-family: 'Segoe UI', system-ui, sans-serif;
41
- margin: 0;
42
- padding: 0;
43
  }
44
  .gradio-container {
45
  max-width: 100% !important;
46
- height: 100vh !important;
47
- display: flex;
48
- flex-direction: column;
49
- align-items: center;
50
- justify-content: flex-start;
51
  }
52
  #title-box {
53
  background: #003A8F;
54
  color: white;
55
- padding: 16px 32px;
56
  border-radius: 12px;
57
- margin-bottom: 32px;
58
  text-align: center;
59
- width: 100%;
60
- max-width: 800px;
61
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
62
  }
63
  #title-box h1 {
64
  margin: 0;
65
- font-size: 28px;
66
  font-weight: 700;
67
  }
68
- .form-section {
69
  display: flex;
70
  flex-direction: column;
71
- align-items: flex-start;
72
  width: 100%;
73
- max-width: 800px;
 
74
  gap: 24px;
75
  }
76
- .control-row {
77
- display: flex;
78
- gap: 24px;
79
- width: 100%;
80
- align-items: center;
81
- }
82
- .control-row > div {
83
- flex: 1;
84
- min-width: 200px;
85
- }
86
- .gradio-html, .output-area {
87
- width: 100%;
88
- max-width: 800px;
89
  background: #121212;
90
  border: 1px solid #333;
91
  border-radius: 12px;
92
- padding: 24px;
93
- margin-top: 16px;
 
94
  font-size: 18px;
95
- line-height: 1.6;
96
- }
97
- .output-area h3 {
98
- color: #FFD100;
99
- margin: 16px 0 12px 0;
100
- font-size: 22px;
101
- font-weight: 600;
102
- }
103
- .output-area p {
104
- margin: 10px 0;
105
- }
106
- .output-area .safe {
107
- color: #00FF00;
108
- font-weight: bold;
109
- }
110
- .output-area .caution {
111
- color: #FFA500;
112
- font-weight: bold;
113
- }
114
- .output-area .danger {
115
- color: #FF0000;
116
- font-weight: bold;
117
  }
118
  .gr-button {
119
  background: #003A8F !important;
120
  color: white !important;
121
  font-weight: bold;
122
  font-size: 18px !important;
123
- padding: 12px 32px !important;
124
  border-radius: 8px !important;
125
  border: none !important;
126
- width: auto !important;
127
- margin-top: 12px;
128
  }
129
  .gr-button:hover {
130
  background: #002D6B !important;
131
- transform: scale(1.03);
132
- box-shadow: 0 4px 12px rgba(0, 58, 143, 0.4);
133
  }
134
  label {
135
  color: #CCCCCC !important;
136
  font-size: 18px !important;
137
  font-weight: 500;
138
  }
139
- input, select {
140
- font-size: 18px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
142
  """
143
 
144
- # ================= GRADIO LAYOUT (TETAP SAMA) =================
145
- with gr.Blocks(title="Michelin Mining Tyre Analytics — Objective 6", css=custom_css) as demo:
146
  gr.HTML("""
147
  <div id="title-box">
148
  <h1>Michelin Mining Tyre Simulation Pressure</h1>
149
  </div>
150
  """)
151
 
152
- with gr.Column(elem_classes="form-section"):
153
- with gr.Row(elem_classes="control-row"):
154
- temperature = gr.Slider(
155
- label="Suhu Saat Ini (°C)",
156
- minimum=40,
157
- maximum=70,
158
- value=54,
159
- step=0.5,
160
- interactive=True
161
- )
162
- tyre_type = gr.Radio(
163
- choices=["10 (Depan)", "11 (Belakang)"],
164
- label="Jenis Ban",
165
- value="10 (Depan)",
166
- interactive=True
167
- )
168
-
169
- last_info = gr.Markdown(f"Tekanan Terakhir: {last_pressure} psi | Jam: {last_time}")
170
 
171
  btn_submit = gr.Button("Submit", elem_classes="gr-button")
172
  output = gr.HTML(elem_classes="output-area")
173
 
174
- # ================= LOGIKA SIMULASI — DIPERBAIKI REKOMENDASINYA =================
175
- def simulate(tyre_str, temp):
176
- # Interpolasi tekanan ideal
 
 
 
 
 
177
  ideal = 85.0 + 0.42 * (temp - 54.0)
178
  ideal = round(ideal, 1)
179
 
180
- # Ambil batas aman
181
  lower_safe, upper_safe = get_safe_fill_range(last_pressure)
182
 
183
- # Hitung selisih operasional (untuk penjelasan)
184
- max_add = round(amber_high - last_pressure, 1) # maks boleh tambah tanpa kena amber
185
- max_sub = round(last_pressure - amber_low, 1) # maks boleh kurangi tanpa kena amber
186
 
187
  # Status
188
  if ideal < red_low:
@@ -196,24 +187,24 @@ with gr.Blocks(title="Michelin Mining Tyre Analytics — Objective 6", css=custo
196
  else:
197
  status = '<span class="safe">Dalam zona aman</span>'
198
 
199
- # REKOMENDASI YANG ANDA INGINKAN EKSPLISIT & OPERASIONAL
200
  rec_html = f"""
201
  <h3>Hasil Simulasi</h3>
202
  <p>Ideal Tekanan pada {temp}°C: {ideal} psi</p>
203
  <p>Status: {status}</p>
204
  <hr>
205
  <h3>Rekomendasi Isi Ulang</h3>
206
- <p>Berdasarkan tekanan terakhir <strong>{last_pressure} psi</strong> (pukul {last_time}):</p>
207
  <p class="safe">Isi tekanan antara <strong>{lower_safe} – {upper_safe} psi</strong></p>
208
  <p>Maksimal penambahan: <strong>+{min(10.0, max_add):.1f} psi</strong> (agar tidak melebihi {amber_high} psi)</p>
209
  <p>Maksimal pengurangan: <strong>−{min(10.0, max_sub):.1f} psi</strong> (agar tidak turun di bawah {amber_low} psi)</p>
210
  <p class="caution">Jangan isi kurang dari {amber_low} psi (batas Amber bawah)</p>
211
  <p class="caution">Jangan isi lebih dari {amber_high} psi (batas Amber atas)</p>
212
  <p class="danger">Hindari tekanan di bawah {red_low} psi atau di atas {red_high} psi (zona Red)</p>
213
- <p style="margin-top:16px;"><em>Catatan: Rekomendasi menjaga margin aman minimal 0.5 psi dari zona Amber.</em></p>
214
  """
215
  return rec_html
216
 
217
- btn_submit.click(simulate, inputs=[tyre_type, temperature], outputs=output)
218
 
219
  demo.launch()
 
2
  import pandas as pd
3
  import numpy as np
4
 
5
+ # ================= LOAD DATA — AMBIL TEKANAN, SUHU & WAKTU TERAKHIR =================
6
  last_pressure = 85.0
7
+ last_temperature = 54.0
8
  last_time = "–"
9
 
10
  try:
 
12
  df.columns = df.columns.str.replace("Â", "", regex=False)
13
  for col in df.select_dtypes(include='object').columns:
14
  df[col] = df[col].astype(str).str.replace("Â", "", regex=False)
15
+
16
  df['Time'] = pd.to_datetime(df['Time'], errors='coerce')
17
  df = df.dropna(subset=['Time'])
18
 
19
  if not df.empty:
20
+ last_row = df.sort_values('Time', ascending=False).iloc[0]
21
  last_pressure = float(last_row['Pressure']) if pd.notna(last_row.get('Pressure')) else 85.0
22
+ last_temperature = float(last_row['Temperature']) if pd.notna(last_row.get('Temperature')) else 54.0
23
+ last_time = last_row['Time'].strftime("%Y-%m-%d %H:%M")
24
  except Exception as e:
25
+ pass # tetap pakai default jika gagal
26
 
27
  # ================= BATAS AMAN (SESUAI STANDAR OPERASIONAL) =================
28
  red_low = 70.0
 
35
  upper = min(last_p + 10, amber_high - 0.5)
36
  return round(lower, 1), round(upper, 1)
37
 
38
+ # ================= CUSTOM CSS — Tengah, Wide, Bersih =================
39
  custom_css = """
40
  body, .gradio-container {
41
  background: #000000 !important;
42
  color: #FFFFFF !important;
43
  font-family: 'Segoe UI', system-ui, sans-serif;
 
 
44
  }
45
  .gradio-container {
46
  max-width: 100% !important;
47
+ padding: 20px !important;
 
 
 
 
48
  }
49
  #title-box {
50
  background: #003A8F;
51
  color: white;
52
+ padding: 18px 32px;
53
  border-radius: 12px;
54
+ margin: 20px auto 30px auto;
55
  text-align: center;
56
+ width: fit-content;
57
+ min-width: 500px;
58
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
59
  }
60
  #title-box h1 {
61
  margin: 0;
62
+ font-size: 26px;
63
  font-weight: 700;
64
  }
65
+ .center-section {
66
  display: flex;
67
  flex-direction: column;
68
+ align-items: center;
69
  width: 100%;
70
+ max-width: 700px;
71
+ margin: 0 auto;
72
  gap: 24px;
73
  }
74
+ .info-card {
 
 
 
 
 
 
 
 
 
 
 
 
75
  background: #121212;
76
  border: 1px solid #333;
77
  border-radius: 12px;
78
+ padding: 20px;
79
+ width: 100%;
80
+ text-align: center;
81
  font-size: 18px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
83
  .gr-button {
84
  background: #003A8F !important;
85
  color: white !important;
86
  font-weight: bold;
87
  font-size: 18px !important;
88
+ padding: 12px 36px !important;
89
  border-radius: 8px !important;
90
  border: none !important;
91
+ margin-top: 8px;
 
92
  }
93
  .gr-button:hover {
94
  background: #002D6B !important;
95
+ transform: translateY(-1px);
96
+ box-shadow: 0 4px 10px rgba(0, 58, 143, 0.4);
97
  }
98
  label {
99
  color: #CCCCCC !important;
100
  font-size: 18px !important;
101
  font-weight: 500;
102
  }
103
+ .output-area {
104
+ background: #121212;
105
+ border: 1px solid #333;
106
+ border-radius: 12px;
107
+ padding: 26px;
108
+ width: 100%;
109
+ font-size: 18px;
110
+ line-height: 1.6;
111
+ margin-top: 10px;
112
+ }
113
+ .output-area h3 {
114
+ color: #FFD100;
115
+ margin: 18px 0 12px 0;
116
+ font-size: 22px;
117
+ font-weight: 600;
118
+ }
119
+ .output-area p {
120
+ margin: 10px 0;
121
+ }
122
+ .output-area .safe { color: #00FF00; font-weight: bold; }
123
+ .output-area .caution { color: #FFA500; font-weight: bold; }
124
+ .output-area .danger { color: #FF0000; font-weight: bold; }
125
+ .footer {
126
+ margin-top: 24px;
127
+ color: #888;
128
+ font-size: 15px;
129
+ text-align: center;
130
+ width: 100%;
131
  }
132
  """
133
 
134
+ # ================= GRADIO — MODE WIDE, UI TENGAH =================
135
+ with gr.Blocks(title="Michelin Mining Tyre Analytics — Objective 6", css=custom_css, mode="wide") as demo:
136
  gr.HTML("""
137
  <div id="title-box">
138
  <h1>Michelin Mining Tyre Simulation Pressure</h1>
139
  </div>
140
  """)
141
 
142
+ with gr.Column(elem_classes="center-section"):
143
+ # Info data terakhir
144
+ gr.HTML(f"""
145
+ <div class="info-card">
146
+ <p><strong>Data Terakhir:</strong> {last_time}</p>
147
+ <p>Suhu: <strong>{last_temperature} °C</strong> | Tekanan: <strong>{last_pressure} psi</strong></p>
148
+ </div>
149
+ """)
150
+
151
+ # Input: hanya jenis ban
152
+ tyre_type = gr.Radio(
153
+ choices=["10 (Depan)", "11 (Belakang)"],
154
+ label="Pilih Jenis Ban",
155
+ value="10 (Depan)",
156
+ interactive=True
157
+ )
 
 
158
 
159
  btn_submit = gr.Button("Submit", elem_classes="gr-button")
160
  output = gr.HTML(elem_classes="output-area")
161
 
162
+ # Footer
163
+ gr.HTML('<div class="footer">Michelin Mining Tyre Analytics</div>')
164
+
165
+ # ================= LOGIKA SIMULASI — TANPA INPUT SUHU (Pakai last_temperature) =================
166
+ def simulate(tyre_str):
167
+ # Gunakan suhu terakhir dari data — tidak ada input manual
168
+ temp = last_temperature
169
+ # Interpolasi ideal pressure
170
  ideal = 85.0 + 0.42 * (temp - 54.0)
171
  ideal = round(ideal, 1)
172
 
 
173
  lower_safe, upper_safe = get_safe_fill_range(last_pressure)
174
 
175
+ max_add = round(amber_high - last_pressure, 1)
176
+ max_sub = round(last_pressure - amber_low, 1)
 
177
 
178
  # Status
179
  if ideal < red_low:
 
187
  else:
188
  status = '<span class="safe">Dalam zona aman</span>'
189
 
190
+ # Rekomendasi fokus pada last_pressure & batas amber/red
191
  rec_html = f"""
192
  <h3>Hasil Simulasi</h3>
193
  <p>Ideal Tekanan pada {temp}°C: {ideal} psi</p>
194
  <p>Status: {status}</p>
195
  <hr>
196
  <h3>Rekomendasi Isi Ulang</h3>
197
+ <p>Berdasarkan tekanan terakhir <strong>{last_pressure} psi</strong> ({last_time}):</p>
198
  <p class="safe">Isi tekanan antara <strong>{lower_safe} – {upper_safe} psi</strong></p>
199
  <p>Maksimal penambahan: <strong>+{min(10.0, max_add):.1f} psi</strong> (agar tidak melebihi {amber_high} psi)</p>
200
  <p>Maksimal pengurangan: <strong>−{min(10.0, max_sub):.1f} psi</strong> (agar tidak turun di bawah {amber_low} psi)</p>
201
  <p class="caution">Jangan isi kurang dari {amber_low} psi (batas Amber bawah)</p>
202
  <p class="caution">Jangan isi lebih dari {amber_high} psi (batas Amber atas)</p>
203
  <p class="danger">Hindari tekanan di bawah {red_low} psi atau di atas {red_high} psi (zona Red)</p>
204
+ <p style="margin-top:16px;"><em>Catatan: Rekomendasi mempertahankan margin aman minimal 0.5 psi dari zona Amber.</em></p>
205
  """
206
  return rec_html
207
 
208
+ btn_submit.click(simulate, inputs=[tyre_type], outputs=output)
209
 
210
  demo.launch()