entropy25 commited on
Commit
b35d1f5
Β·
verified Β·
1 Parent(s): d9f1c12

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +142 -86
app.py CHANGED
@@ -7,7 +7,7 @@ from datetime import datetime, timedelta
7
  import google.generativeai as genai
8
 
9
  # Page config
10
- st.set_page_config(page_title="Production Monitor", page_icon="🏭", layout="wide")
11
 
12
  @st.cache_resource
13
  def init_ai():
@@ -27,12 +27,10 @@ def load_data(file):
27
  def get_material_stats(df):
28
  stats = {}
29
  total = df['weight_kg'].sum()
30
-
31
  total_work_days = df['date'].nunique()
32
 
33
  for material in df['material_type'].unique():
34
  data = df[df['material_type'] == material]
35
-
36
  work_days = data['date'].nunique()
37
  daily_avg = data.groupby('date')['weight_kg'].sum().mean()
38
 
@@ -54,56 +52,58 @@ def get_material_stats(df):
54
 
55
  return stats
56
 
57
- def display_material_overview(stats):
58
- st.subheader("πŸ“‹ Material Overview")
59
-
60
-
61
- materials = [k for k in stats.keys() if k != '_total_']
62
-
63
-
64
- cols = st.columns(4)
65
-
66
-
67
- for i, material in enumerate(materials):
68
- if i < 3:
69
- info = stats[material]
70
- with cols[i]:
71
- st.metric(
72
- label=material.replace('_', ' ').title(),
73
- value=f"{info['total']:,.0f} kg",
74
- delta=f"{info['percentage']:.1f}% of total"
75
- )
76
- st.caption(f"Daily avg: {info['daily_avg']:,.0f} kg")
77
- st.caption(f"Work days: {info['work_days']} days")
 
78
 
 
 
 
79
 
80
- total_info = stats['_total_']
81
- with cols[3]:
82
- st.metric(
83
- label="Total Production",
84
- value=f"{total_info['total']:,.0f} kg",
85
- delta="100% of total"
86
- )
87
- st.caption(f"Daily avg: {total_info['daily_avg']:,.0f} kg")
88
- st.caption(f"Work days: {total_info['work_days']} days")
89
-
90
- def create_trend_chart(df, time_period='daily', material_filter=None):
91
- if material_filter:
92
- df = df[df['material_type'].isin(material_filter)]
93
 
94
  if time_period == 'daily':
95
  grouped = df.groupby(['date', 'material_type'])['weight_kg'].sum().reset_index()
96
  fig = px.line(grouped, x='date', y='weight_kg', color='material_type',
97
- title='Daily Production Trend')
98
- elif time_period == 'shift':
99
- grouped = df.groupby(['date', 'shift', 'material_type'])['weight_kg'].sum().reset_index()
100
- fig = px.bar(grouped, x='date', y='weight_kg', color='shift',
101
- facet_col='material_type', title='Production by Shift')
102
- else: # weekly
103
  df['week'] = df['date'].dt.isocalendar().week
104
- grouped = df.groupby(['week', 'material_type'])['weight_kg'].sum().reset_index()
105
- fig = px.bar(grouped, x='week', y='weight_kg', color='material_type',
106
- title='Weekly Production')
 
 
 
 
 
 
 
 
 
 
107
 
108
  fig.update_layout(height=400)
109
  return fig
@@ -129,7 +129,7 @@ def query_ai(model, stats, question):
129
 
130
  context = f"""Production Data Summary:
131
  {chr(10).join([f"- {mat.title()}: {info['total']:,.0f}kg ({info['percentage']:.1f}%)"
132
- for mat, info in stats.items()])}
133
 
134
  Question: {question}
135
  Answer concisely based on the data:"""
@@ -161,11 +161,13 @@ def main():
161
  df = load_data(uploaded_file)
162
  stats = get_material_stats(df)
163
 
164
- # Material cards
165
  st.subheader("πŸ“‹ Material Overview")
166
- cols = st.columns(len(stats))
167
 
168
- for i, (material, info) in enumerate(stats.items()):
 
 
169
  with cols[i]:
170
  st.metric(
171
  label=material.replace('_', ' ').title(),
@@ -173,33 +175,87 @@ def main():
173
  delta=f"{info['percentage']:.1f}% of total"
174
  )
175
  st.caption(f"Daily avg: {info['daily_avg']:,.0f} kg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  # Chart controls
178
- st.subheader("πŸ“ˆ Trends")
179
- col1, col2 = st.columns([3, 1])
180
-
181
- with col2:
182
- time_view = st.selectbox("Time View", ["daily", "weekly", "shift"])
183
- materials = st.multiselect(
184
- "Materials",
185
- options=list(stats.keys()),
186
- default=list(stats.keys())
 
 
 
 
 
187
  )
188
 
189
- with col1:
190
- if materials:
191
- chart = create_trend_chart(df, time_view, materials)
192
- st.plotly_chart(chart, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
- # Shift analysis
 
 
 
 
 
 
 
195
  if 'shift' in df.columns:
196
  st.subheader("πŸŒ“ Shift Analysis")
197
- shift_data = df.groupby(['shift', 'material_type'])['weight_kg'].sum().reset_index()
198
- shift_chart = px.bar(shift_data, x='shift', y='weight_kg', color='material_type',
199
- title='Production by Shift')
200
- st.plotly_chart(shift_chart, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
- # Anomaly detection
203
  st.subheader("⚠️ Quality Check")
204
  outliers = detect_outliers(df)
205
 
@@ -208,7 +264,7 @@ def main():
208
  with alert_cols[i]:
209
  if info['count'] > 0:
210
  st.warning(f"**{material.title()}**: {info['count']} outliers")
211
- st.caption(f"Normal: {info['range']}")
212
  else:
213
  st.success(f"**{material.title()}**: All normal")
214
 
@@ -217,35 +273,35 @@ def main():
217
  st.subheader("πŸ€– AI Insights")
218
 
219
  # Quick questions
220
- quick_q = [
221
  "What's the production trend?",
222
  "Which material is most consistent?",
223
  "Any efficiency recommendations?"
224
  ]
225
 
226
- cols = st.columns(len(quick_q))
227
- for i, q in enumerate(quick_q):
228
  with cols[i]:
229
- if st.button(q, key=f"q{i}"):
230
  answer = query_ai(model, stats, q)
231
  st.info(answer)
232
 
233
  # Custom question
234
- custom_q = st.text_input("Ask anything about your data:")
235
- if custom_q:
236
- if st.button("Ask"):
237
- answer = query_ai(model, stats, custom_q)
238
- st.success(f"**Q:** {custom_q}")
239
- st.write(f"**A:** {answer}")
240
 
241
  else:
242
- st.info("πŸ“ Upload your production data to start")
243
  st.markdown("""
244
- **Expected format (TSV):**
245
- - `date`: MM/DD/YYYY
246
- - `weight_kg`: Production weight
247
- - `material_type`: Material category
248
- - `shift`: day/night (optional)
249
  """)
250
 
251
  if __name__ == "__main__":
 
7
  import google.generativeai as genai
8
 
9
  # Page config
10
+ st.set_page_config(page_title="Production Data Monitor Platform – Nilsen Service & Consulting AS", page_icon="🏭", layout="wide")
11
 
12
  @st.cache_resource
13
  def init_ai():
 
27
  def get_material_stats(df):
28
  stats = {}
29
  total = df['weight_kg'].sum()
 
30
  total_work_days = df['date'].nunique()
31
 
32
  for material in df['material_type'].unique():
33
  data = df[df['material_type'] == material]
 
34
  work_days = data['date'].nunique()
35
  daily_avg = data.groupby('date')['weight_kg'].sum().mean()
36
 
 
52
 
53
  return stats
54
 
55
+ def create_total_production_chart(df, time_period='daily'):
56
+ """Create total production trend chart"""
57
+ if time_period == 'daily':
58
+ grouped = df.groupby('date')['weight_kg'].sum().reset_index()
59
+ fig = px.line(grouped, x='date', y='weight_kg',
60
+ title='πŸ“Š Total Production Trend',
61
+ labels={'weight_kg': 'Weight (kg)', 'date': 'Date'})
62
+ elif time_period == 'weekly':
63
+ df['week'] = df['date'].dt.isocalendar().week
64
+ df['year'] = df['date'].dt.year
65
+ grouped = df.groupby(['year', 'week'])['weight_kg'].sum().reset_index()
66
+ grouped['week_label'] = grouped['year'].astype(str) + '-W' + grouped['week'].astype(str)
67
+ fig = px.bar(grouped, x='week_label', y='weight_kg',
68
+ title='πŸ“Š Total Production Trend (Weekly)',
69
+ labels={'weight_kg': 'Weight (kg)', 'week_label': 'Week'})
70
+ else: # monthly
71
+ df['month'] = df['date'].dt.to_period('M')
72
+ grouped = df.groupby('month')['weight_kg'].sum().reset_index()
73
+ grouped['month'] = grouped['month'].astype(str)
74
+ fig = px.bar(grouped, x='month', y='weight_kg',
75
+ title='πŸ“Š Total Production Trend (Monthly)',
76
+ labels={'weight_kg': 'Weight (kg)', 'month': 'Month'})
77
 
78
+ fig.update_layout(height=400, showlegend=False)
79
+ fig.update_traces(line_color='#1f77b4' if time_period == 'daily' else None)
80
+ return fig
81
 
82
+ def create_materials_trend_chart(df, time_period='daily', selected_materials=None):
83
+ """Create individual materials trend chart"""
84
+ if selected_materials:
85
+ df = df[df['material_type'].isin(selected_materials)]
 
 
 
 
 
 
 
 
 
86
 
87
  if time_period == 'daily':
88
  grouped = df.groupby(['date', 'material_type'])['weight_kg'].sum().reset_index()
89
  fig = px.line(grouped, x='date', y='weight_kg', color='material_type',
90
+ title='🏷️ Materials Production Trends',
91
+ labels={'weight_kg': 'Weight (kg)', 'date': 'Date', 'material_type': 'Material'})
92
+ elif time_period == 'weekly':
 
 
 
93
  df['week'] = df['date'].dt.isocalendar().week
94
+ df['year'] = df['date'].dt.year
95
+ grouped = df.groupby(['year', 'week', 'material_type'])['weight_kg'].sum().reset_index()
96
+ grouped['week_label'] = grouped['year'].astype(str) + '-W' + grouped['week'].astype(str)
97
+ fig = px.bar(grouped, x='week_label', y='weight_kg', color='material_type',
98
+ title='🏷️ Materials Production Trends (Weekly)',
99
+ labels={'weight_kg': 'Weight (kg)', 'week_label': 'Week', 'material_type': 'Material'})
100
+ else: # monthly
101
+ df['month'] = df['date'].dt.to_period('M')
102
+ grouped = df.groupby(['month', 'material_type'])['weight_kg'].sum().reset_index()
103
+ grouped['month'] = grouped['month'].astype(str)
104
+ fig = px.bar(grouped, x='month', y='weight_kg', color='material_type',
105
+ title='🏷️ Materials Production Trends (Monthly)',
106
+ labels={'weight_kg': 'Weight (kg)', 'month': 'Month', 'material_type': 'Material'})
107
 
108
  fig.update_layout(height=400)
109
  return fig
 
129
 
130
  context = f"""Production Data Summary:
131
  {chr(10).join([f"- {mat.title()}: {info['total']:,.0f}kg ({info['percentage']:.1f}%)"
132
+ for mat, info in stats.items() if mat != '_total_'])}
133
 
134
  Question: {question}
135
  Answer concisely based on the data:"""
 
161
  df = load_data(uploaded_file)
162
  stats = get_material_stats(df)
163
 
164
+ # Material Overview
165
  st.subheader("πŸ“‹ Material Overview")
166
+ materials = [k for k in stats.keys() if k != '_total_']
167
 
168
+ cols = st.columns(4)
169
+ for i, material in enumerate(materials[:3]):
170
+ info = stats[material]
171
  with cols[i]:
172
  st.metric(
173
  label=material.replace('_', ' ').title(),
 
175
  delta=f"{info['percentage']:.1f}% of total"
176
  )
177
  st.caption(f"Daily avg: {info['daily_avg']:,.0f} kg")
178
+ st.caption(f"Work days: {info['work_days']} days")
179
+
180
+ # Total production metric
181
+ total_info = stats['_total_']
182
+ with cols[3]:
183
+ st.metric(
184
+ label="Total Production",
185
+ value=f"{total_info['total']:,.0f} kg",
186
+ delta="100% of total"
187
+ )
188
+ st.caption(f"Daily avg: {total_info['daily_avg']:,.0f} kg")
189
+ st.caption(f"Work days: {total_info['work_days']} days")
190
+
191
+ # Production Trends Section
192
+ st.subheader("πŸ“ˆ Production Trends")
193
 
194
  # Chart controls
195
+ col_ctrl1, col_ctrl2, col_ctrl3 = st.columns([2, 2, 3])
196
+
197
+ with col_ctrl1:
198
+ time_view = st.selectbox("Time Period", ["daily", "weekly", "monthly"])
199
+
200
+ with col_ctrl2:
201
+ chart_type = st.selectbox("View Type", ["both", "total_only", "materials_only"])
202
+
203
+ with col_ctrl3:
204
+ selected_materials = st.multiselect(
205
+ "Select Materials",
206
+ options=materials,
207
+ default=materials,
208
+ help="Choose which materials to display in trends"
209
  )
210
 
211
+ # Display charts based on selection
212
+ if chart_type == "both":
213
+ chart_col1, chart_col2 = st.columns(2)
214
+
215
+ with chart_col1:
216
+ total_chart = create_total_production_chart(df, time_view)
217
+ st.plotly_chart(total_chart, use_container_width=True)
218
+
219
+ with chart_col2:
220
+ if selected_materials:
221
+ materials_chart = create_materials_trend_chart(df, time_view, selected_materials)
222
+ st.plotly_chart(materials_chart, use_container_width=True)
223
+ else:
224
+ st.info("Please select materials to display trends")
225
+
226
+ elif chart_type == "total_only":
227
+ total_chart = create_total_production_chart(df, time_view)
228
+ st.plotly_chart(total_chart, use_container_width=True)
229
 
230
+ else: # materials_only
231
+ if selected_materials:
232
+ materials_chart = create_materials_trend_chart(df, time_view, selected_materials)
233
+ st.plotly_chart(materials_chart, use_container_width=True)
234
+ else:
235
+ st.info("Please select materials to display trends")
236
+
237
+ # Shift Analysis
238
  if 'shift' in df.columns:
239
  st.subheader("πŸŒ“ Shift Analysis")
240
+
241
+ shift_col1, shift_col2 = st.columns(2)
242
+
243
+ with shift_col1:
244
+ # Shift comparison by material
245
+ shift_data = df.groupby(['shift', 'material_type'])['weight_kg'].sum().reset_index()
246
+ shift_chart = px.bar(shift_data, x='shift', y='weight_kg', color='material_type',
247
+ title='Production by Shift and Material',
248
+ labels={'weight_kg': 'Weight (kg)', 'shift': 'Shift', 'material_type': 'Material'})
249
+ st.plotly_chart(shift_chart, use_container_width=True)
250
+
251
+ with shift_col2:
252
+ # Total production by shift
253
+ shift_total = df.groupby('shift')['weight_kg'].sum().reset_index()
254
+ shift_total_chart = px.pie(shift_total, values='weight_kg', names='shift',
255
+ title='Total Production Distribution by Shift')
256
+ st.plotly_chart(shift_total_chart, use_container_width=True)
257
 
258
+ # Quality Check
259
  st.subheader("⚠️ Quality Check")
260
  outliers = detect_outliers(df)
261
 
 
264
  with alert_cols[i]:
265
  if info['count'] > 0:
266
  st.warning(f"**{material.title()}**: {info['count']} outliers")
267
+ st.caption(f"Normal range: {info['range']}")
268
  else:
269
  st.success(f"**{material.title()}**: All normal")
270
 
 
273
  st.subheader("πŸ€– AI Insights")
274
 
275
  # Quick questions
276
+ quick_questions = [
277
  "What's the production trend?",
278
  "Which material is most consistent?",
279
  "Any efficiency recommendations?"
280
  ]
281
 
282
+ cols = st.columns(len(quick_questions))
283
+ for i, q in enumerate(quick_questions):
284
  with cols[i]:
285
+ if st.button(q, key=f"quick_q_{i}"):
286
  answer = query_ai(model, stats, q)
287
  st.info(answer)
288
 
289
  # Custom question
290
+ custom_question = st.text_input("Ask anything about your production data:")
291
+ if custom_question:
292
+ if st.button("Ask AI"):
293
+ answer = query_ai(model, stats, custom_question)
294
+ st.success(f"**Question:** {custom_question}")
295
+ st.write(f"**Answer:** {answer}")
296
 
297
  else:
298
+ st.info("πŸ“ Upload your production data to start analysis")
299
  st.markdown("""
300
+ **Expected CSV format:**
301
+ - `date`: MM/DD/YYYY format
302
+ - `weight_kg`: Production weight in kilograms
303
+ - `material_type`: Material category/type
304
+ - `shift`: day/night shift (optional)
305
  """)
306
 
307
  if __name__ == "__main__":