Rendhaputra commited on
Commit
62b92d8
·
verified ·
1 Parent(s): 71fd9dd

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +77 -34
src/streamlit_app.py CHANGED
@@ -45,6 +45,7 @@ def get_active_cycle():
45
  c.execute("SELECT id, start_date FROM cycles WHERE active = 1 ORDER BY id DESC LIMIT 1")
46
  return c.fetchone()
47
 
 
48
  def get_rolling_30(cycle_id, current_temp):
49
  c = db.cursor()
50
  c.execute("SELECT raw_temp FROM daily_logs WHERE cycle_id = ? ORDER BY log_date DESC LIMIT 29", (cycle_id,))
@@ -52,15 +53,12 @@ def get_rolling_30(cycle_id, current_temp):
52
  past_temps = []
53
  for row in c.fetchall():
54
  try:
55
- # Pastikan data tidak None/kosong dan paksa menjadi angka (float)
56
  if row[0] is not None:
57
  past_temps.append(float(row[0]))
58
  except ValueError:
59
- # Jika ada data yang corrupt (misal terisi huruf/simbol), abaikan
60
  pass
 
61
  all_temps = past_temps + [float(current_temp)]
62
-
63
- # Hitung rata-rata, cegah error jika list kosong
64
  if len(all_temps) == 0:
65
  return 0.0
66
 
@@ -77,25 +75,48 @@ with st.sidebar:
77
  if active_cycle:
78
  st.success(f"Siklus Aktif: {active_cycle[1]}")
79
 
80
- # --- FITUR IMPORT CSV ---
81
  st.markdown("---")
82
  st.subheader("📤 Bulk Import Data Historis")
83
- st.caption("Gunakan CSV dengan kolom: 'Tanggal' (YYYY-MM-DD) dan 'Suhu'")
84
  uploaded_file = st.file_uploader("Pilih file CSV", type="csv")
85
 
86
  if uploaded_file is not None:
87
  try:
88
- data_import = pd.read_csv(uploaded_file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  if st.button("Konfirmasi Import Data"):
90
  count = 0
91
- for index, row in data_import.iterrows():
92
- # Cek apakah data sudah ada untuk menghindari duplikat
93
  db.execute("INSERT INTO daily_logs (cycle_id, log_date, raw_temp) VALUES (?, ?, ?)",
94
  (active_cycle[0], str(row['Tanggal']), float(row['Suhu'])))
95
  count += 1
96
  db.commit()
97
  st.success(f"✅ Berhasil mengimpor {count} data historis!")
98
  st.rerun()
 
 
99
  except Exception as e:
100
  st.error(f"Gagal memproses CSV: {e}")
101
 
@@ -113,10 +134,14 @@ with st.sidebar:
113
  db.commit()
114
  st.rerun()
115
 
116
- # MAIN AREA (Logika Prediksi Harian)
117
  if active_cycle:
118
  cycle_id, start_date_str = active_cycle
119
- start_date = datetime.date.fromisoformat(start_date_str)
 
 
 
 
120
 
121
  col1, col2 = st.columns([1, 2])
122
 
@@ -126,30 +151,48 @@ if active_cycle:
126
  temp_raw = st.number_input("Suhu Bodi Tengah (°C)", 200.0, 500.0, 350.0)
127
 
128
  if st.button("Simpan & Prediksi", type="primary"):
129
- hari_ops = (tgl_skrg - start_date).days
130
- roll30 = get_rolling_30(cycle_id, temp_raw)
131
-
132
- if model:
133
- pred_mm = float(model.predict([[hari_ops, roll30]])[0])
134
- db.execute("INSERT INTO daily_logs (cycle_id, log_date, raw_temp) VALUES (?, ?, ?)",
135
- (cycle_id, tgl_skrg.isoformat(), temp_raw))
136
- db.commit()
137
- st.session_state['hasil'] = {
138
- 'mm': pred_mm, 'hari': hari_ops, 'roll': roll30,
139
- 'sisa': max(0, int((pred_mm - 100) / 0.191))
140
- }
141
 
142
  with col2:
143
  st.subheader("📊 Visualisasi & Analisis")
144
- if 'hasil' in st.session_state:
145
- res = st.session_state['hasil']
146
- m1, m2, m3 = st.columns(3)
147
- m1.metric("Ketebalan BTA", f"{res['mm']:.1f} mm")
148
- m2.metric("Umur Operasi", f"{res['hari']} Hari")
149
- m3.metric("Est. Sisa Umur", f"{res['sisa']} Hari")
150
 
151
- # Tampilkan Grafik (akan otomatis terupdate setelah import CSV)
152
- df_hist = pd.read_sql_query(f"SELECT log_date, raw_temp FROM daily_logs WHERE cycle_id={cycle_id} ORDER BY log_date ASC", db)
153
- if not df_hist.empty:
154
- st.line_chart(df_hist.set_index('log_date'))
155
- st.write(f"Total data dalam database: **{len(df_hist)} baris**")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  c.execute("SELECT id, start_date FROM cycles WHERE active = 1 ORDER BY id DESC LIMIT 1")
46
  return c.fetchone()
47
 
48
+ # (Fungsi ini tetap disimpan sebagai cadangan/helper, meski logika utamanya sekarang menggunakan Pandas)
49
  def get_rolling_30(cycle_id, current_temp):
50
  c = db.cursor()
51
  c.execute("SELECT raw_temp FROM daily_logs WHERE cycle_id = ? ORDER BY log_date DESC LIMIT 29", (cycle_id,))
 
53
  past_temps = []
54
  for row in c.fetchall():
55
  try:
 
56
  if row[0] is not None:
57
  past_temps.append(float(row[0]))
58
  except ValueError:
 
59
  pass
60
+
61
  all_temps = past_temps + [float(current_temp)]
 
 
62
  if len(all_temps) == 0:
63
  return 0.0
64
 
 
75
  if active_cycle:
76
  st.success(f"Siklus Aktif: {active_cycle[1]}")
77
 
78
+ # --- FITUR IMPORT CSV (Versi Diperbarui) ---
79
  st.markdown("---")
80
  st.subheader("📤 Bulk Import Data Historis")
81
+ st.caption("Gunakan CSV dengan kolom: 'Tanggal' dan 'Bodi Tengah (°C)'")
82
  uploaded_file = st.file_uploader("Pilih file CSV", type="csv")
83
 
84
  if uploaded_file is not None:
85
  try:
86
+ # 1. Melewati baris judul (skiprows=1) & Penanganan Encoding
87
+ try:
88
+ data_import = pd.read_csv(uploaded_file, encoding='utf-8-sig', skiprows=1)
89
+ except UnicodeDecodeError:
90
+ uploaded_file.seek(0)
91
+ data_import = pd.read_csv(uploaded_file, encoding='latin1', skiprows=1)
92
+
93
+ # 2. Cek apakah pemisahnya ternyata titik koma (;)
94
+ if len(data_import.columns) == 1:
95
+ uploaded_file.seek(0)
96
+ data_import = pd.read_csv(uploaded_file, encoding='utf-8-sig', sep=';', skiprows=1)
97
+
98
+ # 3. Bersihkan nama kolom dari spasi
99
+ data_import.columns = data_import.columns.str.strip()
100
+
101
+ # 4. Samakan nama kolom di CSV ("Bodi Tengah (°C)") ke "Suhu"
102
+ if 'Bodi Tengah (°C)' in data_import.columns:
103
+ data_import.rename(columns={'Bodi Tengah (°C)': 'Suhu'}, inplace=True)
104
+
105
+ st.info("Preview Data yang akan diimpor:")
106
+ st.dataframe(data_import[['Tanggal', 'Suhu']].head(3))
107
+
108
  if st.button("Konfirmasi Import Data"):
109
  count = 0
110
+ # Abaikan data kosong pada kolom vital
111
+ for index, row in data_import.dropna(subset=['Tanggal', 'Suhu']).iterrows():
112
  db.execute("INSERT INTO daily_logs (cycle_id, log_date, raw_temp) VALUES (?, ?, ?)",
113
  (active_cycle[0], str(row['Tanggal']), float(row['Suhu'])))
114
  count += 1
115
  db.commit()
116
  st.success(f"✅ Berhasil mengimpor {count} data historis!")
117
  st.rerun()
118
+ except KeyError as e:
119
+ st.error(f"Kolom tidak ditemukan: {e}. Pastikan file memiliki kolom 'Tanggal' dan 'Bodi Tengah (°C)'.")
120
  except Exception as e:
121
  st.error(f"Gagal memproses CSV: {e}")
122
 
 
134
  db.commit()
135
  st.rerun()
136
 
137
+ # --- MAIN AREA (Versi Diperbarui: Otomatis Update) ---
138
  if active_cycle:
139
  cycle_id, start_date_str = active_cycle
140
+ # Pastikan start_date dikonversi dengan aman menggunakan Pandas
141
+ try:
142
+ start_date = pd.to_datetime(start_date_str).date()
143
+ except Exception:
144
+ start_date = datetime.date.fromisoformat(start_date_str)
145
 
146
  col1, col2 = st.columns([1, 2])
147
 
 
151
  temp_raw = st.number_input("Suhu Bodi Tengah (°C)", 200.0, 500.0, 350.0)
152
 
153
  if st.button("Simpan & Prediksi", type="primary"):
154
+ # Hanya menyimpan data ke DB, perhitungannya ditangani di Col2
155
+ db.execute("INSERT INTO daily_logs (cycle_id, log_date, raw_temp) VALUES (?, ?, ?)",
156
+ (cycle_id, tgl_skrg.isoformat(), temp_raw))
157
+ db.commit()
158
+ st.rerun()
 
 
 
 
 
 
 
159
 
160
  with col2:
161
  st.subheader("📊 Visualisasi & Analisis")
 
 
 
 
 
 
162
 
163
+ # Tarik semua data dari DB menggunakan Pandas
164
+ df_hist = pd.read_sql_query(f"SELECT log_date, raw_temp FROM daily_logs WHERE cycle_id={cycle_id}", db)
165
+
166
+ if not df_hist.empty and model is not None:
167
+ # Rapikan dan urutkan tanggal (antisipasi beda format CSV "MM/DD/YYYY" vs Streamlit "YYYY-MM-DD")
168
+ df_hist['log_date'] = pd.to_datetime(df_hist['log_date'], format="mixed", dayfirst=False)
169
+ df_hist = df_hist.sort_values('log_date').reset_index(drop=True)
170
+
171
+ # Ambil data hari terakhir yang ada di database
172
+ latest_row = df_hist.iloc[-1]
173
+ latest_date = latest_row['log_date'].date()
174
+
175
+ # Perhitungan Hari Operasi
176
+ hari_ops = (latest_date - start_date).days
177
+
178
+ # Hitung Rolling 30 dari Pandas
179
+ tail_30 = pd.to_numeric(df_hist['raw_temp'].tail(30), errors='coerce').dropna()
180
+ roll30 = tail_30.mean() if not tail_30.empty else 0.0
181
+
182
+ # Lakukan Prediksi Model
183
+ pred_mm = float(model.predict([[hari_ops, roll30]])[0])
184
+ sisa_hari = max(0, int((pred_mm - 100) / 0.191))
185
+
186
+ # Tampilkan ke Layar secara Otomatis
187
+ m1, m2, m3 = st.columns(3)
188
+ m1.metric("Ketebalan BTA", f"{pred_mm:.1f} mm")
189
+ m2.metric("Umur Operasi", f"{hari_ops} Hari")
190
+ m3.metric("Est. Sisa Umur", f"{sisa_hari} Hari")
191
+
192
+ # Kembalikan tipe data ke string untuk chart agar rapi
193
+ df_hist['log_date'] = df_hist['log_date'].dt.strftime('%Y-%m-%d')
194
+ st.line_chart(df_hist.set_index('log_date')['raw_temp'])
195
+ st.write(f"Total data dalam database: **{len(df_hist)} baris**")
196
+
197
+ else:
198
+ st.info("Belum ada data untuk dianalisis. Silakan input harian atau import CSV.")