VijayPulmamidi commited on
Commit
920f674
·
verified ·
1 Parent(s): 5052850

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +7 -29
app.py CHANGED
@@ -1,6 +1,5 @@
1
  import pandas as pd
2
  import numpy as np
3
- from sklearn.ensemble import IsolationForest
4
  import gradio as gr
5
  import os
6
  import tempfile
@@ -68,16 +67,15 @@ def insert_reconciliation_to_salesforce(df, sf):
68
  return f"Inserted {inserted_count} records into Salesforce"
69
 
70
  def generate_suggestion(row):
71
- if row['deviation'] > 15:
72
  excess = row['used_quantity'] - row['planned_quantity']
73
  return f"Overuse Alert: Reduce future orders by {excess:.0f} units of {row['material_type']}."
74
- elif row['deviation'] < -15:
75
  surplus = abs(row['planned_quantity'] - row['used_quantity'])
76
  return f"Surplus Detected: {surplus:.0f} units unused. Consider reducing future orders."
77
  return "Usage as planned. No action needed."
78
 
79
  def reconcile_materials(csv_file):
80
- # Read CSV
81
  if isinstance(csv_file, str):
82
  df = pd.read_csv(csv_file)
83
  elif hasattr(csv_file, 'name'):
@@ -86,10 +84,8 @@ def reconcile_materials(csv_file):
86
  csv_file.seek(0)
87
  df = pd.read_csv(csv_file)
88
 
89
- # Normalize column names: strip spaces, lowercase
90
  df.columns = df.columns.str.strip().str.lower().str.replace(' ', '_')
91
 
92
- # Map common columns - all lowercase with underscores
93
  col_map = {
94
  'project_id': 'project_id',
95
  'material_type': 'material_type',
@@ -97,27 +93,25 @@ def reconcile_materials(csv_file):
97
  'received_quantity': 'received_quantity',
98
  'used_quantity': 'used_quantity',
99
  }
100
- # Find columns from CSV that best match expected columns
101
  mapped_cols = {}
102
  for expected_col in col_map:
103
  for actual_col in df.columns:
104
  if actual_col == expected_col:
105
  mapped_cols[expected_col] = actual_col
106
  break
107
- # Rename columns to expected names if present
108
  df.rename(columns=mapped_cols, inplace=True)
109
 
110
- # Required columns
111
  required = ['material_type', 'planned_quantity', 'received_quantity', 'used_quantity']
112
  missing = [col for col in required if col not in df.columns]
113
  if missing:
114
  return None, f"Error: Missing required column(s): {', '.join(missing)}", None, None, None, None
115
 
116
- # Convert quantities to numeric, fill missing with 0
117
  for col in ['planned_quantity', 'received_quantity', 'used_quantity']:
118
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
119
 
120
- # Compute balance and deviation
121
  df['balance_quantity'] = df['received_quantity'] - df['used_quantity']
122
  df['deviation'] = df.apply(
123
  lambda row: ((row['used_quantity'] - row['planned_quantity']) / row['planned_quantity']) * 100
@@ -125,25 +119,12 @@ def reconcile_materials(csv_file):
125
  axis=1
126
  )
127
 
128
- # Anomaly detection
129
- features = df[['planned_quantity', 'received_quantity', 'used_quantity', 'deviation']]
130
- iso_forest = IsolationForest(contamination=0.1, random_state=42)
131
- df['anomaly'] = iso_forest.fit_predict(features)
132
-
133
- # Enforce anomaly for deviation beyond 15%
134
- df.loc[df['deviation'].abs() > 15, 'anomaly'] = -1
135
-
136
- # AI Suggestions & Status
137
  df['ai_suggestion'] = df.apply(generate_suggestion, axis=1)
138
- df['reconciliation_status'] = df.apply(
139
- lambda row: 'Flagged' if abs(row['deviation']) > 15 else 'Complete',
140
- axis=1
141
- )
142
 
143
- # Insert into Salesforce (handle None for output)
144
  salesforce_result = insert_reconciliation_to_salesforce(df, sf)
145
 
146
- # Prepare output text summary
147
  output_text = f"Material Reconciliation Results\n=============================\n\n"
148
  output_text += f"{salesforce_result}\n\nDetailed Records:\n"
149
  for i, row in df.iterrows():
@@ -161,12 +142,10 @@ def reconcile_materials(csv_file):
161
  output_text += f" Reconciliation Status: {row['reconciliation_status']}\n"
162
  output_text += "-----------------------------\n"
163
 
164
- # Save file
165
  with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
166
  output_file = tmp.name
167
  df.to_csv(output_file, index=False)
168
 
169
- # Charts
170
  bar_fig = px.bar(
171
  df, x='material_type', y='deviation',
172
  color='reconciliation_status',
@@ -186,7 +165,6 @@ def reconcile_materials(csv_file):
186
  ai_summary = "\n".join([f"{row['material_type']}: {row['ai_suggestion']}" for _, row in df.iterrows()])
187
  return output_file, output_text, df, bar_fig, pie_fig, ai_summary
188
 
189
-
190
  # Gradio UI
191
  with gr.Blocks(css='button:has(span:contains("Share via Link")) { display: none !important; }') as interface:
192
  gr.Markdown("# Material Reconciliation Dashboard")
 
1
  import pandas as pd
2
  import numpy as np
 
3
  import gradio as gr
4
  import os
5
  import tempfile
 
67
  return f"Inserted {inserted_count} records into Salesforce"
68
 
69
  def generate_suggestion(row):
70
+ if row['deviation'] > 5:
71
  excess = row['used_quantity'] - row['planned_quantity']
72
  return f"Overuse Alert: Reduce future orders by {excess:.0f} units of {row['material_type']}."
73
+ elif row['deviation'] < -5:
74
  surplus = abs(row['planned_quantity'] - row['used_quantity'])
75
  return f"Surplus Detected: {surplus:.0f} units unused. Consider reducing future orders."
76
  return "Usage as planned. No action needed."
77
 
78
  def reconcile_materials(csv_file):
 
79
  if isinstance(csv_file, str):
80
  df = pd.read_csv(csv_file)
81
  elif hasattr(csv_file, 'name'):
 
84
  csv_file.seek(0)
85
  df = pd.read_csv(csv_file)
86
 
 
87
  df.columns = df.columns.str.strip().str.lower().str.replace(' ', '_')
88
 
 
89
  col_map = {
90
  'project_id': 'project_id',
91
  'material_type': 'material_type',
 
93
  'received_quantity': 'received_quantity',
94
  'used_quantity': 'used_quantity',
95
  }
96
+
97
  mapped_cols = {}
98
  for expected_col in col_map:
99
  for actual_col in df.columns:
100
  if actual_col == expected_col:
101
  mapped_cols[expected_col] = actual_col
102
  break
103
+
104
  df.rename(columns=mapped_cols, inplace=True)
105
 
 
106
  required = ['material_type', 'planned_quantity', 'received_quantity', 'used_quantity']
107
  missing = [col for col in required if col not in df.columns]
108
  if missing:
109
  return None, f"Error: Missing required column(s): {', '.join(missing)}", None, None, None, None
110
 
 
111
  for col in ['planned_quantity', 'received_quantity', 'used_quantity']:
112
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
113
 
114
+ df['used_quantity'] = df[['used_quantity', 'received_quantity']].min(axis=1)
115
  df['balance_quantity'] = df['received_quantity'] - df['used_quantity']
116
  df['deviation'] = df.apply(
117
  lambda row: ((row['used_quantity'] - row['planned_quantity']) / row['planned_quantity']) * 100
 
119
  axis=1
120
  )
121
 
122
+ df['anomaly'] = df['deviation'].apply(lambda d: -1 if abs(d) > 5 else 1)
 
 
 
 
 
 
 
 
123
  df['ai_suggestion'] = df.apply(generate_suggestion, axis=1)
124
+ df['reconciliation_status'] = df['deviation'].apply(lambda d: 'Flagged' if abs(d) > 5 else 'Complete')
 
 
 
125
 
 
126
  salesforce_result = insert_reconciliation_to_salesforce(df, sf)
127
 
 
128
  output_text = f"Material Reconciliation Results\n=============================\n\n"
129
  output_text += f"{salesforce_result}\n\nDetailed Records:\n"
130
  for i, row in df.iterrows():
 
142
  output_text += f" Reconciliation Status: {row['reconciliation_status']}\n"
143
  output_text += "-----------------------------\n"
144
 
 
145
  with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
146
  output_file = tmp.name
147
  df.to_csv(output_file, index=False)
148
 
 
149
  bar_fig = px.bar(
150
  df, x='material_type', y='deviation',
151
  color='reconciliation_status',
 
165
  ai_summary = "\n".join([f"{row['material_type']}: {row['ai_suggestion']}" for _, row in df.iterrows()])
166
  return output_file, output_text, df, bar_fig, pie_fig, ai_summary
167
 
 
168
  # Gradio UI
169
  with gr.Blocks(css='button:has(span:contains("Share via Link")) { display: none !important; }') as interface:
170
  gr.Markdown("# Material Reconciliation Dashboard")