AdityaRatan commited on
Commit
5e6d596
Β·
verified Β·
1 Parent(s): 4b6312a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -396
app.py CHANGED
@@ -17,25 +17,37 @@ from xgboost import XGBRegressor
17
  # Configure Gemini API
18
  GEMINI_API_KEY = os.getenv("gemini_api")
19
 
20
-
21
-
22
  genai.configure(api_key=GEMINI_API_KEY)
23
  generation_config = {
24
- "temperature": 1,
25
- "top_p": 0.95,
26
- "top_k": 64,
27
- "max_output_tokens": 8192,
28
- "response_mime_type": "text/plain",
29
  }
30
 
31
  model = genai.GenerativeModel(
32
- model_name="gemini-2.0-pro-exp-02-05",
33
- generation_config=generation_config,
34
  )
35
 
36
  chat_model = genai.GenerativeModel('"gemini-2.0-pro-exp-02-05"')
37
 
38
- # Create and save a simple model on first run
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def create_initial_model():
40
  n_samples = 1000
41
  np.random.seed(42)
@@ -86,245 +98,9 @@ def create_initial_model():
86
 
87
  return model
88
 
89
- # Enhanced CSS styling
90
- CUSTOM_CSS = '''
91
- .gradio-container {
92
- max-width: 1200px !important;
93
- margin: auto !important;
94
- padding: 20px !important;
95
- background-color: #1a1a1a !important;
96
- color: #ffffff !important;
97
- }
98
-
99
- .main-header {
100
- background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%) !important;
101
- color: white !important;
102
- padding: 30px !important;
103
- border-radius: 15px !important;
104
- margin-bottom: 30px !important;
105
- text-align: center !important;
106
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2) !important;
107
- }
108
-
109
- .app-title {
110
- font-size: 2.5em !important;
111
- font-weight: bold !important;
112
- margin-bottom: 10px !important;
113
- background: linear-gradient(90deg, #ffffff, #3498DB) !important;
114
- -webkit-background-clip: text !important;
115
- -webkit-text-fill-color: transparent !important;
116
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3) !important;
117
- }
118
-
119
- .app-subtitle {
120
- font-size: 1.3em !important;
121
- color: #89CFF0 !important;
122
- margin-bottom: 15px !important;
123
- font-weight: 500 !important;
124
- }
125
-
126
- .app-description {
127
- font-size: 1.1em !important;
128
- color: #B0C4DE !important;
129
- margin-bottom: 20px !important;
130
- line-height: 1.5 !important;
131
- }
132
-
133
- .creator-info {
134
- font-size: 1.2em !important;
135
- color: #3498DB !important;
136
- margin-top: 15px !important;
137
- padding: 10px !important;
138
- border-top: 2px solid rgba(52, 152, 219, 0.3) !important;
139
- font-style: italic !important;
140
- }
141
-
142
- # Add this to your CUSTOM_CSS string
143
-
144
- .gr-checkbox-group {
145
- background: #363636 !important;
146
- padding: 15px !important;
147
- border-radius: 10px !important;
148
- margin: 10px 0 !important;
149
- }
150
-
151
- .gr-checkbox {
152
- margin: 10px 0 !important;
153
- cursor: pointer !important;
154
- }
155
-
156
- .gr-checkbox input[type="checkbox"] {
157
- width: 20px !important;
158
- height: 20px !important;
159
- margin-right: 10px !important;
160
- cursor: pointer !important;
161
- }
162
-
163
- .gr-checkbox label {
164
- color: #ffffff !important;
165
- font-size: 1.1em !important;
166
- cursor: pointer !important;
167
- }
168
-
169
- .gr-checkbox:hover {
170
- background-color: #404040 !important;
171
- border-radius: 5px !important;
172
- transition: background-color 0.3s ease !important;
173
- }
174
-
175
- .gr-checkbox input[type="checkbox"]:checked + label {
176
- color: #3498DB !important;
177
- font-weight: bold !important;
178
- }
179
-
180
-
181
-
182
-
183
-
184
- .status-box {
185
- background: #363636 !important;
186
- border-left: 4px solid #3498DB !important;
187
- padding: 15px !important;
188
- margin: 10px 0 !important;
189
- border-radius: 0 5px 5px 0 !important;
190
- color: #ffffff !important;
191
- }
192
-
193
- .chart-container {
194
- background: #2d2d2d !important;
195
- padding: 20px !important;
196
- border-radius: 10px !important;
197
- box-shadow: 0 2px 4px rgba(0,0,0,0.2) !important;
198
- color: #ffffff !important;
199
- }
200
-
201
- .chat-container {
202
- height: 400px !important;
203
- overflow-y: auto !important;
204
- border: 1px solid #404040 !important;
205
- border-radius: 10px !important;
206
- padding: 15px !important;
207
- background: #2d2d2d !important;
208
- color: #ffffff !important;
209
- }
210
-
211
- .file-format-help {
212
- background: #363636 !important;
213
- padding: 15px !important;
214
- border-radius: 10px !important;
215
- margin-top: 20px !important;
216
- border-left: 4px solid #3498DB !important;
217
- }
218
-
219
- .file-instructions {
220
- color: #89CFF0 !important;
221
- font-size: 0.9em !important;
222
- margin-top: 5px !important;
223
- font-style: italic !important;
224
- line-height: 1.4 !important;
225
- }
226
-
227
- .file-upload {
228
- border: 2px dashed #404040 !important;
229
- border-radius: 10px !important;
230
- padding: 20px !important;
231
- text-align: center !important;
232
- background: #2d2d2d !important;
233
- color: #ffffff !important;
234
- transition: all 0.3s ease !important;
235
- margin-bottom: 10px !important;
236
- }
237
-
238
- .file-upload:hover {
239
- border-color: #3498DB !important;
240
- background: #363636 !important;
241
- }
242
-
243
- .file-upload.drag-enter {
244
- border-color: #3498DB !important;
245
- background: #363636 !important;
246
- transform: scale(1.02) !important;
247
- }
248
-
249
- .file-upload .upload-label {
250
- font-size: 1.1em !important;
251
- font-weight: 500 !important;
252
- margin-bottom: 10px !important;
253
- }
254
-
255
- .result-box {
256
- background: #363636 !important;
257
- border: 1px solid #404040 !important;
258
- border-radius: 10px !important;
259
- padding: 20px !important;
260
- margin-top: 15px !important;
261
- color: #ffffff !important;
262
- }
263
-
264
- .tab-content {
265
- background: #2d2d2d !important;
266
- padding: 20px !important;
267
- border-radius: 10px !important;
268
- box-shadow: 0 2px 4px rgba(0,0,0,0.2) !important;
269
- color: #ffffff !important;
270
- }
271
-
272
- input, select, textarea {
273
- background: #363636 !important;
274
- color: #ffffff !important;
275
- border: 1px solid #404040 !important;
276
- }
277
-
278
- input:focus, select:focus, textarea:focus {
279
- border-color: #3498DB !important;
280
- box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2) !important;
281
- }
282
-
283
- .action-button {
284
- background: #3498DB !important;
285
- color: white !important;
286
- border: none !important;
287
- padding: 10px 20px !important;
288
- border-radius: 5px !important;
289
- cursor: pointer !important;
290
- transition: all 0.3s ease !important;
291
- }
292
-
293
- .action-button:hover {
294
- background: #2980B9 !important;
295
- transform: translateY(-2px) !important;
296
- box-shadow: 0 4px 8px rgba(0,0,0,0.2) !important;
297
- }
298
-
299
- .footer {
300
- text-align: center !important;
301
- padding: 20px !important;
302
- margin-top: 40px !important;
303
- border-top: 1px solid #404040 !important;
304
- color: #888888 !important;
305
- }
306
- '''
307
-
308
- class SupplyChainState:
309
- def __init__(self):
310
- self.sales_df = None
311
- self.supplier_df = None
312
- self.text_data = None
313
- self.chat_history = []
314
- self.analysis_results = {}
315
- self.freight_predictions = []
316
-
317
- try:
318
- self.freight_model = create_initial_model()
319
- except Exception as e:
320
- print(f"Warning: Could not create freight prediction model: {e}")
321
- self.freight_model = None
322
-
323
  def process_uploaded_data(state, sales_file, supplier_file, text_data):
324
- """Process uploaded files and store in state"""
325
  try:
326
  if sales_file is not None:
327
- # Check sales file extension
328
  file_ext = os.path.splitext(sales_file.name)[1].lower()
329
  if file_ext not in ['.xlsx', '.xls', '.csv']:
330
  return '❌ Error: Sales data must be in Excel (.xlsx, .xls) or CSV format'
@@ -338,7 +114,6 @@ def process_uploaded_data(state, sales_file, supplier_file, text_data):
338
  return f'❌ Error reading sales data: {str(e)}'
339
 
340
  if supplier_file is not None:
341
- # Check supplier file extension
342
  file_ext = os.path.splitext(supplier_file.name)[1].lower()
343
  if file_ext not in ['.xlsx', '.xls', '.csv']:
344
  return '❌ Error: Supplier data must be in Excel (.xlsx, .xls) or CSV format'
@@ -355,10 +130,8 @@ def process_uploaded_data(state, sales_file, supplier_file, text_data):
355
  return "βœ… Data processed successfully"
356
  except Exception as e:
357
  return f'❌ Error processing data: {str(e)}'
358
-
359
 
360
  def perform_demand_forecasting(state):
361
- """Perform demand forecasting using Gemini"""
362
  if state.sales_df is None:
363
  return "Error: No sales data provided", None, "Please upload sales data first"
364
 
@@ -394,7 +167,6 @@ def perform_demand_forecasting(state):
394
  return f"❌ Error in demand forecasting: {str(e)}", None, "Analysis failed"
395
 
396
  def perform_risk_assessment(state):
397
- """Perform risk assessment using Gemini"""
398
  if state.supplier_df is None:
399
  return "Error: No supplier data provided", None, "Please upload supplier data first"
400
 
@@ -432,15 +204,10 @@ def perform_risk_assessment(state):
432
  except Exception as e:
433
  return f"❌ Error in risk assessment: {str(e)}", None, "Assessment failed"
434
 
435
-
436
  def perform_inventory_optimization(state):
437
- """Perform inventory optimization analysis"""
438
  if state.sales_df is None:
439
  return "Error: No sales data provided", None, "Please upload sales data first"
440
 
441
- if model is None:
442
- return "AI features are currently disabled. Please check your API key configuration.", None, "AI Disabled"
443
-
444
  try:
445
  inventory_summary = state.sales_df.describe().to_string()
446
  prompt = f"""Analyze the following inventory data and provide:
@@ -460,7 +227,6 @@ def perform_inventory_optimization(state):
460
  response = model.generate_content(prompt)
461
  analysis_text = response.text
462
 
463
- # Create inventory level visualization
464
  fig = go.Figure()
465
 
466
  if 'quantity' in state.sales_df.columns:
@@ -487,13 +253,9 @@ def perform_inventory_optimization(state):
487
  return f"❌ Error in inventory optimization: {str(e)}", None, "Analysis failed"
488
 
489
  def perform_supplier_performance(state):
490
- """Analyze supplier performance"""
491
  if state.supplier_df is None:
492
  return "Error: No supplier data provided", None, "Please upload supplier data first"
493
 
494
- if model is None:
495
- return "AI features are currently disabled. Please check your API key configuration.", None, "AI Disabled"
496
-
497
  try:
498
  supplier_summary = state.supplier_df.describe().to_string()
499
  prompt = f"""Analyze supplier performance based on:
@@ -513,12 +275,10 @@ def perform_supplier_performance(state):
513
  response = model.generate_content(prompt)
514
  analysis_text = response.text
515
 
516
- # Create supplier performance visualization
517
  if 'performance_score' in state.supplier_df.columns:
518
  fig = px.box(state.supplier_df, y='performance_score',
519
  title='Supplier Performance Distribution')
520
  else:
521
- # Create a sample visualization if performance_score is not available
522
  fig = go.Figure(data=[
523
  go.Bar(name='On-Time Delivery', x=['Supplier A', 'Supplier B', 'Supplier C'],
524
  y=[95, 87, 92]),
@@ -541,15 +301,10 @@ def perform_supplier_performance(state):
541
  return f"❌ Error in supplier performance analysis: {str(e)}", None, "Analysis failed"
542
 
543
  def perform_sustainability_analysis(state):
544
- """Analyze sustainability metrics"""
545
  if state.supplier_df is None and state.sales_df is None:
546
  return "Error: No data provided", None, "Please upload data first"
547
 
548
- if model is None:
549
- return "AI features are currently disabled. Please check your API key configuration.", None, "AI Disabled"
550
-
551
  try:
552
- # Combine available data for analysis
553
  data_summary = ""
554
  if state.supplier_df is not None:
555
  data_summary += f"Supplier Data Summary:\n{state.supplier_df.describe().to_string()}\n\n"
@@ -574,10 +329,8 @@ def perform_sustainability_analysis(state):
574
  response = model.generate_content(prompt)
575
  analysis_text = response.text
576
 
577
- # Create sustainability visualization
578
  fig = go.Figure()
579
 
580
- # Example sustainability metrics
581
  categories = ['Carbon Emissions', 'Water Usage', 'Waste Reduction',
582
  'Energy Efficiency', 'Green Transportation']
583
  current_scores = [75, 82, 68, 90, 60]
@@ -615,12 +368,10 @@ def perform_sustainability_analysis(state):
615
  return analysis_text, fig, "βœ… Sustainability analysis completed"
616
  except Exception as e:
617
  return f"❌ Error in sustainability analysis: {str(e)}", None, "Analysis failed"
618
-
619
 
620
  def predict_freight_cost(state, weight, line_item_value, cost_per_kg,
621
- shipment_mode, air_charter_weight, ocean_weight, truck_weight,
622
- air_charter_value, ocean_value, truck_value):
623
- """Predict freight cost using the model"""
624
  if state.freight_model is None:
625
  return "Error: Freight prediction model not loaded"
626
 
@@ -644,7 +395,6 @@ def predict_freight_cost(state, weight, line_item_value, cost_per_kg,
644
  return f"Error making prediction: {str(e)}"
645
 
646
  def chat_with_navigator(state, message):
647
- """Handle chat interactions"""
648
  try:
649
  context = "Available data and analysis:\n"
650
  if state.sales_df is not None:
@@ -684,7 +434,6 @@ def chat_with_navigator(state, message):
684
  return [{"role": "assistant", "content": f"Error: {str(e)}"}]
685
 
686
  def generate_pdf_report(state, analysis_options):
687
- """Generate PDF report with analysis results"""
688
  try:
689
  temp_dir = tempfile.mkdtemp()
690
  pdf_path = os.path.join(temp_dir, "supply_chain_report.pdf")
@@ -693,6 +442,7 @@ def generate_pdf_report(state, analysis_options):
693
  styles = getSampleStyleSheet()
694
  story = []
695
 
 
696
  title_style = ParagraphStyle(
697
  'CustomTitle',
698
  parent=styles['Heading1'],
@@ -708,11 +458,6 @@ def generate_pdf_report(state, analysis_options):
708
  story.append(Paragraph(f"Generated on: {timestamp}", styles['Normal']))
709
  story.append(Spacer(1, 20))
710
 
711
- story.append(Paragraph("Executive Summary", styles['Heading2']))
712
- summary_text = "This report provides a comprehensive analysis of supply chain data, including demand forecasting, risk assessment, and optimization recommendations."
713
- story.append(Paragraph(summary_text, styles['Normal']))
714
- story.append(Spacer(1, 20))
715
-
716
  if state.analysis_results:
717
  for analysis_type, results in state.analysis_results.items():
718
  if analysis_type in analysis_options:
@@ -760,12 +505,10 @@ def generate_pdf_report(state, analysis_options):
760
  return None
761
 
762
  def run_analyses(state, choices, sales_file, supplier_file, text_data):
763
- """Run selected analyses"""
764
  results = []
765
  figures = []
766
  status_messages = []
767
 
768
- # Process data first
769
  process_status = process_uploaded_data(state, sales_file, supplier_file, text_data)
770
  if "Error" in process_status:
771
  return process_status, None, process_status
@@ -819,106 +562,12 @@ def run_analyses(state, choices, sales_file, supplier_file, text_data):
819
  return combined_results, final_figure, combined_status
820
 
821
  def predict_and_store_freight(state, *args):
822
- """Predict freight cost and store the result"""
823
  result = predict_freight_cost(state, *args)
824
  if isinstance(result, (int, float)):
825
  state.freight_predictions.append(result)
826
  return result
827
 
828
-
829
- CUSTOM_CSS = """
830
- /* Horizontal tabs layout */
831
- .tabs {
832
- display: flex !important;
833
- flex-direction: column !important;
834
- gap: 1rem !important;
835
- }
836
-
837
- .tabs > .tab-nav {
838
- display: flex !important;
839
- flex-direction: row !important;
840
- gap: 0.5rem !important;
841
- padding: 0.5rem !important;
842
- background: #f8f9fa !important;
843
- border-radius: 8px !important;
844
- border-bottom: 2px solid #e9ecef !important;
845
- }
846
-
847
- .tabs > .tab-nav > button {
848
- flex: 1 !important;
849
- padding: 0.75rem 1rem !important;
850
- border-radius: 6px !important;
851
- border: none !important;
852
- background: transparent !important;
853
- color: #495057 !important;
854
- font-weight: 500 !important;
855
- transition: all 0.2s ease !important;
856
- }
857
-
858
- .tabs > .tab-nav > button.selected {
859
- background: white !important;
860
- color: #228be6 !important;
861
- box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
862
- }
863
-
864
- .tab-content {
865
- padding: 1.5rem !important;
866
- background: white !important;
867
- border-radius: 8px !important;
868
- box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important;
869
- }
870
-
871
- /* Additional styling */
872
- .main-header {
873
- background: linear-gradient(135deg, #0061a8 0%, #003459 100%);
874
- padding: 2rem;
875
- color: white;
876
- border-radius: 8px;
877
- margin-bottom: 2rem;
878
- }
879
-
880
- .app-title {
881
- font-size: 2.5rem !important;
882
- margin-bottom: 0.5rem !important;
883
- }
884
-
885
- .app-subtitle {
886
- opacity: 0.9;
887
- margin-bottom: 1rem !important;
888
- }
889
-
890
- .action-button {
891
- background: #228be6 !important;
892
- border-radius: 6px !important;
893
- transition: all 0.2s ease !important;
894
- }
895
-
896
- .action-button:hover {
897
- transform: translateY(-2px) !important;
898
- box-shadow: 0 4px 8px rgba(34, 139, 230, 0.2) !important;
899
- }
900
-
901
- .file-upload {
902
- border: 2px dashed #e9ecef !important;
903
- border-radius: 8px !important;
904
- padding: 1rem !important;
905
- }
906
-
907
- .result-box {
908
- background: #f8f9fa !important;
909
- border-radius: 6px !important;
910
- padding: 1rem !important;
911
- }
912
-
913
- .chart-container {
914
- background: black !important;
915
- border-radius: 8px !important;
916
- box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important;
917
- }
918
- """
919
-
920
  def create_interface():
921
- """Create Gradio interface with enhanced UI"""
922
  state = SupplyChainState()
923
 
924
  with gr.Blocks(css=CUSTOM_CSS, title="SupplyChainAI Navigator") as demo:
@@ -1001,10 +650,10 @@ def create_interface():
1001
  label="Visualization",
1002
  elem_classes="chart-container"
1003
  )
1004
- processing_status = gr.Textbox( # Changed from raw_output
1005
- label="Processing Status",
1006
- elem_classes="status-box"
1007
- )
1008
 
1009
  # Cost Prediction Tab
1010
  with gr.Tab("πŸ’° Cost Prediction", elem_classes="tab-content"):
@@ -1065,6 +714,17 @@ def create_interface():
1065
 
1066
  # Report Tab
1067
  with gr.Tab("πŸ“‘ Report", elem_classes="tab-content"):
 
 
 
 
 
 
 
 
 
 
 
1068
  report_button = gr.Button(
1069
  "πŸ“„ Generate Report",
1070
  variant="primary",
@@ -1075,28 +735,19 @@ def create_interface():
1075
  )
1076
 
1077
  # Event Handlers
1078
- def update_mode_inputs(mode):
1079
- return {
1080
- air_inputs: gr.update(visible=mode=="✈️ Air"),
1081
- ocean_inputs: gr.update(visible=mode=="🚒 Ocean"),
1082
- truck_inputs: gr.update(visible=mode=="πŸš› Truck")
1083
- }
1084
-
1085
  upload_button.click(
1086
  fn=lambda *args: process_uploaded_data(state, *args),
1087
  inputs=[sales_data_upload, supplier_data_upload, text_input_area],
1088
- outputs=[upload_status]
1089
- )
1090
 
1091
  analyze_button.click(
1092
  fn=lambda choices, sales, supplier, text: run_analyses(state, choices, sales, supplier, text),
1093
  inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
1094
- outputs=[analysis_output, plot_output, processing_status] # Updated output
1095
  )
1096
 
1097
-
1098
  predict_button.click(
1099
- fn=lambda *args: predict_freight_cost(state, *args),
1100
  inputs=[weight, line_item_value, shipment_mode],
1101
  outputs=[freight_result]
1102
  )
@@ -1108,17 +759,17 @@ def create_interface():
1108
  )
1109
 
1110
  report_button.click(
1111
- fn=lambda: generate_report(state),
 
1112
  outputs=[report_download]
1113
  )
1114
 
1115
  return demo
1116
 
1117
- # Update the launch parameters in __main__:
1118
  if __name__ == "__main__":
1119
  demo = create_interface()
1120
  demo.launch(
1121
- server_name="0.0.0.0", # Add this line
1122
- server_port=7860, # Add this line
1123
  debug=True
1124
  )
 
17
  # Configure Gemini API
18
  GEMINI_API_KEY = os.getenv("gemini_api")
19
 
 
 
20
  genai.configure(api_key=GEMINI_API_KEY)
21
  generation_config = {
22
+ "temperature": 1,
23
+ "top_p": 0.95,
24
+ "top_k": 64,
25
+ "max_output_tokens": 8192,
26
+ "response_mime_type": "text/plain",
27
  }
28
 
29
  model = genai.GenerativeModel(
30
+ model_name="gemini-2.0-pro-exp-02-05",
31
+ generation_config=generation_config,
32
  )
33
 
34
  chat_model = genai.GenerativeModel('"gemini-2.0-pro-exp-02-05"')
35
 
36
+ class SupplyChainState:
37
+ def __init__(self):
38
+ self.sales_df = None
39
+ self.supplier_df = None
40
+ self.text_data = None
41
+ self.chat_history = []
42
+ self.analysis_results = {}
43
+ self.freight_predictions = []
44
+
45
+ try:
46
+ self.freight_model = create_initial_model()
47
+ except Exception as e:
48
+ print(f"Warning: Could not create freight prediction model: {e}")
49
+ self.freight_model = None
50
+
51
  def create_initial_model():
52
  n_samples = 1000
53
  np.random.seed(42)
 
98
 
99
  return model
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  def process_uploaded_data(state, sales_file, supplier_file, text_data):
 
102
  try:
103
  if sales_file is not None:
 
104
  file_ext = os.path.splitext(sales_file.name)[1].lower()
105
  if file_ext not in ['.xlsx', '.xls', '.csv']:
106
  return '❌ Error: Sales data must be in Excel (.xlsx, .xls) or CSV format'
 
114
  return f'❌ Error reading sales data: {str(e)}'
115
 
116
  if supplier_file is not None:
 
117
  file_ext = os.path.splitext(supplier_file.name)[1].lower()
118
  if file_ext not in ['.xlsx', '.xls', '.csv']:
119
  return '❌ Error: Supplier data must be in Excel (.xlsx, .xls) or CSV format'
 
130
  return "βœ… Data processed successfully"
131
  except Exception as e:
132
  return f'❌ Error processing data: {str(e)}'
 
133
 
134
  def perform_demand_forecasting(state):
 
135
  if state.sales_df is None:
136
  return "Error: No sales data provided", None, "Please upload sales data first"
137
 
 
167
  return f"❌ Error in demand forecasting: {str(e)}", None, "Analysis failed"
168
 
169
  def perform_risk_assessment(state):
 
170
  if state.supplier_df is None:
171
  return "Error: No supplier data provided", None, "Please upload supplier data first"
172
 
 
204
  except Exception as e:
205
  return f"❌ Error in risk assessment: {str(e)}", None, "Assessment failed"
206
 
 
207
  def perform_inventory_optimization(state):
 
208
  if state.sales_df is None:
209
  return "Error: No sales data provided", None, "Please upload sales data first"
210
 
 
 
 
211
  try:
212
  inventory_summary = state.sales_df.describe().to_string()
213
  prompt = f"""Analyze the following inventory data and provide:
 
227
  response = model.generate_content(prompt)
228
  analysis_text = response.text
229
 
 
230
  fig = go.Figure()
231
 
232
  if 'quantity' in state.sales_df.columns:
 
253
  return f"❌ Error in inventory optimization: {str(e)}", None, "Analysis failed"
254
 
255
  def perform_supplier_performance(state):
 
256
  if state.supplier_df is None:
257
  return "Error: No supplier data provided", None, "Please upload supplier data first"
258
 
 
 
 
259
  try:
260
  supplier_summary = state.supplier_df.describe().to_string()
261
  prompt = f"""Analyze supplier performance based on:
 
275
  response = model.generate_content(prompt)
276
  analysis_text = response.text
277
 
 
278
  if 'performance_score' in state.supplier_df.columns:
279
  fig = px.box(state.supplier_df, y='performance_score',
280
  title='Supplier Performance Distribution')
281
  else:
 
282
  fig = go.Figure(data=[
283
  go.Bar(name='On-Time Delivery', x=['Supplier A', 'Supplier B', 'Supplier C'],
284
  y=[95, 87, 92]),
 
301
  return f"❌ Error in supplier performance analysis: {str(e)}", None, "Analysis failed"
302
 
303
  def perform_sustainability_analysis(state):
 
304
  if state.supplier_df is None and state.sales_df is None:
305
  return "Error: No data provided", None, "Please upload data first"
306
 
 
 
 
307
  try:
 
308
  data_summary = ""
309
  if state.supplier_df is not None:
310
  data_summary += f"Supplier Data Summary:\n{state.supplier_df.describe().to_string()}\n\n"
 
329
  response = model.generate_content(prompt)
330
  analysis_text = response.text
331
 
 
332
  fig = go.Figure()
333
 
 
334
  categories = ['Carbon Emissions', 'Water Usage', 'Waste Reduction',
335
  'Energy Efficiency', 'Green Transportation']
336
  current_scores = [75, 82, 68, 90, 60]
 
368
  return analysis_text, fig, "βœ… Sustainability analysis completed"
369
  except Exception as e:
370
  return f"❌ Error in sustainability analysis: {str(e)}", None, "Analysis failed"
 
371
 
372
  def predict_freight_cost(state, weight, line_item_value, cost_per_kg,
373
+ shipment_mode, air_charter_weight=0, ocean_weight=0, truck_weight=0,
374
+ air_charter_value=0, ocean_value=0, truck_value=0):
 
375
  if state.freight_model is None:
376
  return "Error: Freight prediction model not loaded"
377
 
 
395
  return f"Error making prediction: {str(e)}"
396
 
397
  def chat_with_navigator(state, message):
 
398
  try:
399
  context = "Available data and analysis:\n"
400
  if state.sales_df is not None:
 
434
  return [{"role": "assistant", "content": f"Error: {str(e)}"}]
435
 
436
  def generate_pdf_report(state, analysis_options):
 
437
  try:
438
  temp_dir = tempfile.mkdtemp()
439
  pdf_path = os.path.join(temp_dir, "supply_chain_report.pdf")
 
442
  styles = getSampleStyleSheet()
443
  story = []
444
 
445
+ # Create custom title style
446
  title_style = ParagraphStyle(
447
  'CustomTitle',
448
  parent=styles['Heading1'],
 
458
  story.append(Paragraph(f"Generated on: {timestamp}", styles['Normal']))
459
  story.append(Spacer(1, 20))
460
 
 
 
 
 
 
461
  if state.analysis_results:
462
  for analysis_type, results in state.analysis_results.items():
463
  if analysis_type in analysis_options:
 
505
  return None
506
 
507
  def run_analyses(state, choices, sales_file, supplier_file, text_data):
 
508
  results = []
509
  figures = []
510
  status_messages = []
511
 
 
512
  process_status = process_uploaded_data(state, sales_file, supplier_file, text_data)
513
  if "Error" in process_status:
514
  return process_status, None, process_status
 
562
  return combined_results, final_figure, combined_status
563
 
564
  def predict_and_store_freight(state, *args):
 
565
  result = predict_freight_cost(state, *args)
566
  if isinstance(result, (int, float)):
567
  state.freight_predictions.append(result)
568
  return result
569
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  def create_interface():
 
571
  state = SupplyChainState()
572
 
573
  with gr.Blocks(css=CUSTOM_CSS, title="SupplyChainAI Navigator") as demo:
 
650
  label="Visualization",
651
  elem_classes="chart-container"
652
  )
653
+ processing_status = gr.Textbox(
654
+ label="Processing Status",
655
+ elem_classes="status-box"
656
+ )
657
 
658
  # Cost Prediction Tab
659
  with gr.Tab("πŸ’° Cost Prediction", elem_classes="tab-content"):
 
714
 
715
  # Report Tab
716
  with gr.Tab("πŸ“‘ Report", elem_classes="tab-content"):
717
+ report_options = gr.CheckboxGroup(
718
+ choices=[
719
+ "πŸ“ˆ Demand Forecasting",
720
+ "⚠️ Risk Assessment",
721
+ "πŸ“¦ Inventory Optimization",
722
+ "🀝 Supplier Performance",
723
+ "🌿 Sustainability Analysis"
724
+ ],
725
+ label="Select sections to include",
726
+ value=[]
727
+ )
728
  report_button = gr.Button(
729
  "πŸ“„ Generate Report",
730
  variant="primary",
 
735
  )
736
 
737
  # Event Handlers
 
 
 
 
 
 
 
738
  upload_button.click(
739
  fn=lambda *args: process_uploaded_data(state, *args),
740
  inputs=[sales_data_upload, supplier_data_upload, text_input_area],
741
+ outputs=[upload_status])
 
742
 
743
  analyze_button.click(
744
  fn=lambda choices, sales, supplier, text: run_analyses(state, choices, sales, supplier, text),
745
  inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
746
+ outputs=[analysis_output, plot_output, processing_status]
747
  )
748
 
 
749
  predict_button.click(
750
+ fn=lambda *args: predict_and_store_freight(state, *args),
751
  inputs=[weight, line_item_value, shipment_mode],
752
  outputs=[freight_result]
753
  )
 
759
  )
760
 
761
  report_button.click(
762
+ fn=lambda options: generate_pdf_report(state, options),
763
+ inputs=[report_options],
764
  outputs=[report_download]
765
  )
766
 
767
  return demo
768
 
 
769
  if __name__ == "__main__":
770
  demo = create_interface()
771
  demo.launch(
772
+ server_name="0.0.0.0",
773
+ server_port=7860,
774
  debug=True
775
  )