AdityaRatan commited on
Commit
505b3b7
Β·
verified Β·
1 Parent(s): 607d0eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +404 -196
app.py CHANGED
@@ -11,20 +11,107 @@ import plotly.graph_objects as go
11
  import tempfile
12
  import os
13
  from datetime import datetime
 
14
 
15
- # Configure Gemini API (replace with actual key in production)
16
- GEMINI_API_KEY = os.getenv("gemini_api")
 
 
 
17
  genai.configure(api_key=GEMINI_API_KEY)
18
- model = genai.GenerativeModel('gemini-pro')
19
- chat_model = genai.GenerativeModel('gemini-pro')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- # Load the XGBoost model
22
- model_path = "optimized_xgboost_model.pkl"
23
- freight_model = None
24
- try:
25
- freight_model = joblib.load(model_path)
26
- except:
27
- print(f"Warning: Could not load freight prediction model from {model_path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  class SupplyChainState:
30
  def __init__(self):
@@ -35,12 +122,19 @@ class SupplyChainState:
35
  self.analysis_results = {}
36
  self.freight_predictions = []
37
 
38
- def predict_freight_cost(
39
- weight, line_item_value, cost_per_kg,
40
- shipment_mode, air_charter_weight, ocean_weight, truck_weight,
41
- air_charter_value, ocean_value, truck_value
42
- ):
43
- if freight_model is None:
 
 
 
 
 
 
 
44
  return "Error: Freight prediction model not loaded"
45
 
46
  features = {
@@ -57,13 +151,13 @@ def predict_freight_cost(
57
  input_data = pd.DataFrame([features])
58
 
59
  try:
60
- prediction = freight_model.predict(input_data)
61
- return round(prediction[0], 2)
62
  except Exception as e:
63
  return f"Error making prediction: {str(e)}"
64
 
65
  def process_uploaded_data(state, sales_file, supplier_file, text_data):
66
- """Process uploaded files and return DataFrames"""
67
  try:
68
  if sales_file is not None:
69
  state.sales_df = pd.read_csv(sales_file.name)
@@ -72,9 +166,9 @@ def process_uploaded_data(state, sales_file, supplier_file, text_data):
72
  state.supplier_df = pd.read_excel(supplier_file.name)
73
 
74
  state.text_data = text_data
75
- return "Data processed successfully"
76
  except Exception as e:
77
- return f'Error processing data: {str(e)}'
78
 
79
  def perform_demand_forecasting(state):
80
  """Perform demand forecasting using Gemini"""
@@ -95,11 +189,20 @@ def perform_demand_forecasting(state):
95
 
96
  response = model.generate_content(prompt)
97
  analysis_text = response.text
 
 
98
  fig = px.line(state.sales_df, title='Historical Sales Data and Forecast')
 
 
 
 
 
 
 
99
 
100
- return analysis_text, fig, "Analysis completed successfully"
101
  except Exception as e:
102
- return f"Error in demand forecasting: {str(e)}", None, "Analysis failed"
103
 
104
  def perform_risk_assessment(state):
105
  """Perform risk assessment using Gemini"""
@@ -123,11 +226,20 @@ def perform_risk_assessment(state):
123
 
124
  response = model.generate_content(prompt)
125
  analysis_text = response.text
 
 
126
  fig = px.scatter(state.supplier_df, title='Supplier Risk Assessment')
 
 
 
 
 
 
 
127
 
128
- return analysis_text, fig, "Risk assessment completed"
129
  except Exception as e:
130
- return f"Error in risk assessment: {str(e)}", None, "Assessment failed"
131
 
132
  def chat_with_navigator(state, message):
133
  """Handle chat interactions with the SupplyChainAI Navigator"""
@@ -141,7 +253,7 @@ def chat_with_navigator(state, message):
141
  if state.text_data:
142
  context += "- Additional context from text data\n"
143
  if state.freight_predictions:
144
- context += f"- Recent freight cost predictions: {state.freight_predictions[-5:]}\n"
145
 
146
  # Add analysis results
147
  if state.analysis_results:
@@ -181,18 +293,26 @@ def generate_pdf_report(state, analysis_options):
181
  styles = getSampleStyleSheet()
182
  story = []
183
 
 
184
  title_style = ParagraphStyle(
185
  'CustomTitle',
186
  parent=styles['Heading1'],
187
  fontSize=24,
188
- spaceAfter=30
 
189
  )
 
 
 
 
190
  story.append(Paragraph("SupplyChainAI Navigator Report", title_style))
191
  story.append(Spacer(1, 12))
192
 
193
- story.append(Paragraph(f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
194
- styles["Normal"]))
195
- story.append(Spacer(1, 12))
 
 
196
 
197
  # Analysis results
198
  for analysis_type, results in state.analysis_results.items():
@@ -213,8 +333,27 @@ def generate_pdf_report(state, analysis_options):
213
  if state.freight_predictions:
214
  story.append(Paragraph("Recent Freight Cost Predictions", styles['Heading2']))
215
  story.append(Spacer(1, 12))
216
- for pred in state.freight_predictions[-5:]:
217
- story.append(Paragraph(f"Predicted Cost: ${pred}", styles['Normal']))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  story.append(Spacer(1, 20))
219
 
220
  # Chat history
@@ -225,200 +364,271 @@ def generate_pdf_report(state, analysis_options):
225
  story.append(Paragraph(f"{msg_type.title()}: {msg}", styles['Normal']))
226
  story.append(Spacer(1, 6))
227
 
 
228
  doc.build(story)
229
  return pdf_path
230
  except Exception as e:
 
231
  return None
232
 
233
  def create_interface():
234
- """Create Gradio interface"""
235
  state = SupplyChainState()
236
 
237
- # Tooltip explanations
238
- tooltips = {
239
- "Weight (kg)": "The total weight of the shipment in kilograms (1-10,000 kg).",
240
- "Line Item Value": "The total value of the line item in USD (1-1,000,000 USD).",
241
- "Cost per Kilogram": "The cost incurred per kilogram for the shipment in USD (0-500 USD).",
242
- "Air Charter Weight": "Weight of the shipment when using Air Charter as the mode (0-10,000 kg).",
243
- "Ocean Weight": "Weight of the shipment when using Ocean as the mode (0-10,000 kg).",
244
- "Truck Weight": "Weight of the shipment when using Truck as the mode (0-10,000 kg).",
245
- "Air Charter Line Item Value": "Value of the shipment when using Air Charter as the mode (0-1,000,000 USD).",
246
- "Ocean Line Item Value": "Value of the shipment when using Ocean as the mode (0-1,000,000 USD).",
247
- "Truck Line Item Value": "Value of the shipment when using Truck as the mode (0-1,000,000 USD)."
248
- }
249
-
250
- with gr.Blocks(title="SupplyChainAI Navigator by Aditya Ratan") as demo:
251
- gr.Markdown("# SupplyChainAI Navigator")
252
-
253
- with gr.Tab("Data Upload"):
254
- sales_data_upload = gr.File(
255
- file_types=[".csv"],
256
- label="Upload Sales Data (CSV)"
257
- )
258
- supplier_data_upload = gr.File(
259
- file_types=[".xlsx", ".xls"],
260
- label="Upload Supplier Data (Excel)"
261
- )
262
- text_input_area = gr.Textbox(
263
- label="Paste Additional Context (e.g., News Articles, Market Updates)",
264
- lines=5
265
- )
266
- upload_status = gr.Textbox(label="Upload Status")
267
- upload_button = gr.Button("Process Uploaded Data")
268
-
269
- with gr.Tab("Analysis Selection"):
270
- analysis_options = gr.CheckboxGroup(
271
- choices=["Demand Forecasting", "Risk Assessment",
272
- "Inventory Optimization", "Supplier Performance Analysis",
273
- "Sustainability Analysis"],
274
- label="Select Analysis Options"
275
- )
276
- analyze_button = gr.Button("Run Analysis")
277
-
278
- with gr.Tab("Results & Insights"):
279
- analysis_output = gr.Textbox(label="Analysis Results")
280
- plot_output = gr.Plot(label="Visualization")
281
- raw_output = gr.Textbox(label="Processing Status")
282
-
283
- with gr.Tab("Freight Cost Prediction"):
284
  gr.Markdown("""
285
- ### Freight Cost Prediction Tool
286
- Predict shipping costs based on shipment details and mode of transport.
 
287
  """)
288
-
289
- with gr.Row():
290
- shipment_mode = gr.Dropdown(
291
- choices=["Air", "Ocean", "Truck"],
292
- label="Shipment Mode",
293
- info="Select the mode of shipment"
294
- )
295
-
296
- with gr.Row():
297
- weight = gr.Slider(
298
- label="Weight (kg)", minimum=1, maximum=10000, step=1, value=1000,
299
- info=tooltips["Weight (kg)"]
300
- )
301
- line_item_value = gr.Slider(
302
- label="Line Item Value", minimum=1, maximum=1000000, step=1, value=10000,
303
- info=tooltips["Line Item Value"]
304
- )
305
- cost_per_kg = gr.Slider(
306
- label="Cost per Kilogram", minimum=0, maximum=500, step=0.1, value=50,
307
- info=tooltips["Cost per Kilogram"]
 
 
 
 
 
 
 
 
 
308
  )
 
 
 
 
 
 
 
 
 
 
 
309
 
310
- with gr.Row():
311
- air_charter_weight = gr.Slider(
312
- label="Air Charter Weight", minimum=0, maximum=10000, step=1,
313
- visible=False, value=0, info=tooltips["Air Charter Weight"]
314
- )
315
- ocean_weight = gr.Slider(
316
- label="Ocean Weight", minimum=0, maximum=10000, step=1,
317
- visible=False, value=0, info=tooltips["Ocean Weight"]
 
 
 
 
 
 
318
  )
319
- truck_weight = gr.Slider(
320
- label="Truck Weight", minimum=0, maximum=10000, step=1,
321
- visible=False, value=0, info=tooltips["Truck Weight"]
 
 
322
  )
323
 
324
- with gr.Row():
325
- air_charter_value = gr.Slider(
326
- label="Air Charter Line Item Value", minimum=0, maximum=1000000, step=1,
327
- visible=False, value=0, info=tooltips["Air Charter Line Item Value"]
328
- )
329
- ocean_value = gr.Slider(
330
- label="Ocean Line Item Value", minimum=0, maximum=1000000, step=1,
331
- visible=False, value=0, info=tooltips["Ocean Line Item Value"]
332
- )
333
- truck_value = gr.Slider(
334
- label="Truck Line Item Value", minimum=0, maximum=1000000, step=1,
335
- visible=False, value=0, info=tooltips["Truck Line Item Value"]
 
 
 
 
 
336
  )
337
 
338
- predict_button = gr.Button("Predict Freight Cost")
339
- freight_result = gr.Number(label="Predicted Freight Cost (USD)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
- with gr.Tab("Chat"):
342
- chatbot = gr.Chatbot(label="Chat with SupplyChainAI Navigator")
343
- msg = gr.Textbox(label="Type your message")
344
- chat_button = gr.Button("Send")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
 
346
- with gr.Tab("Report Generation"):
347
- report_button = gr.Button("Generate PDF Report")
348
- report_download = gr.File(label="Download PDF Report")
349
-
350
- # Update visibility of freight prediction inputs based on shipment mode
351
- def update_freight_inputs_visibility(mode):
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  return {
353
- air_charter_weight: gr.update(visible=(mode == "Air")),
354
- ocean_weight: gr.update(visible=(mode == "Ocean")),
355
- truck_weight: gr.update(visible=(mode == "Truck")),
356
- air_charter_value: gr.update(visible=(mode == "Air")),
357
- ocean_value: gr.update(visible=(mode == "Ocean")),
358
- truck_value: gr.update(visible=(mode == "Truck")),
359
  }
360
-
361
- # Connect all event handlers
362
- # 1. Data Upload
363
  upload_button.click(
364
  fn=lambda *args: process_uploaded_data(state, *args),
365
  inputs=[sales_data_upload, supplier_data_upload, text_input_area],
366
  outputs=[upload_status]
367
  )
368
 
369
- # 2. Analysis
370
- def run_analyses(analysis_choices, sales_file, supplier_file, text_data):
371
- # Update state with latest data
372
- process_uploaded_data(state, sales_file, supplier_file, text_data)
373
-
374
- # Initialize results
375
- current_results = []
376
- current_plots = []
377
- status_messages = []
378
-
379
- # Run selected analyses
380
- for analysis in analysis_choices:
381
- if analysis == "Demand Forecasting":
382
- text, fig, status = perform_demand_forecasting(state)
383
- state.analysis_results['Demand Forecasting'] = {'text': text, 'figure': fig}
384
- current_results.append(text)
385
- current_plots.append(fig)
386
- status_messages.append(status)
387
-
388
- elif analysis == "Risk Assessment":
389
- text, fig, status = perform_risk_assessment(state)
390
- state.analysis_results['Risk Assessment'] = {'text': text, 'figure': fig}
391
- current_results.append(text)
392
- current_plots.append(fig)
393
- status_messages.append(status)
394
-
395
- # Combine results
396
- combined_text = "\n\n".join(current_results) if current_results else "No analyses performed"
397
- latest_plot = current_plots[-1] if current_plots else None
398
- status = " | ".join(status_messages) if status_messages else "No analyses run"
399
-
400
- return combined_text, latest_plot, status
401
-
402
  analyze_button.click(
403
- fn=run_analyses,
404
  inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
405
  outputs=[analysis_output, plot_output, raw_output]
406
  )
407
 
408
- # 3. Freight Cost Prediction
409
- def predict_and_store_freight(state, *args):
410
- prediction = predict_freight_cost(*args)
411
- if isinstance(prediction, (int, float)):
412
- state.freight_predictions.append(prediction)
413
- return prediction
414
-
415
  shipment_mode.change(
416
- update_freight_inputs_visibility,
417
  inputs=[shipment_mode],
418
- outputs=[
419
- air_charter_weight, ocean_weight, truck_weight,
420
- air_charter_value, ocean_value, truck_value
421
- ]
422
  )
423
 
424
  predict_button.click(
@@ -431,17 +641,15 @@ def create_interface():
431
  outputs=[freight_result]
432
  )
433
 
434
- # 4. Chat
435
  chat_button.click(
436
  fn=lambda message: chat_with_navigator(state, message),
437
  inputs=[msg],
438
  outputs=[chatbot]
439
  ).then(
440
- fn=lambda: "", # Clear input after sending
441
  outputs=[msg]
442
  )
443
 
444
- # 5. Report Generation
445
  report_button.click(
446
  fn=lambda options: generate_pdf_report(state, options),
447
  inputs=[analysis_options],
 
11
  import tempfile
12
  import os
13
  from datetime import datetime
14
+ from dotenv import load_dotenv
15
 
16
+ # Load environment variables
17
+ load_dotenv()
18
+
19
+ # Configure Gemini API
20
+ GEMINI_API_KEY = os.getenv("gemini_api")
21
  genai.configure(api_key=GEMINI_API_KEY)
22
+ generation_config = {
23
+ "temperature": 1,
24
+ "top_p": 0.95,
25
+ "top_k": 64,
26
+ "max_output_tokens": 8192,
27
+ "response_mime_type": "text/plain",
28
+ }
29
+
30
+ model = genai.GenerativeModel(
31
+ model_name="gemini-2.0-pro-exp-02-05",
32
+ generation_config=generation_config,
33
+ )
34
+
35
+ chat_model = genai.GenerativeModel('"gemini-2.0-pro-exp-02-05"')
36
+
37
+ # Custom CSS styling
38
+ CUSTOM_CSS = """
39
+ .gradio-container {
40
+ max-width: 1200px !important;
41
+ margin: auto !important;
42
+ padding: 20px !important;
43
+ background-color: #f8f9fa !important;
44
+ }
45
+
46
+ .main-header {
47
+ background: linear-gradient(90deg, #2C3E50, #3498DB);
48
+ color: white !important;
49
+ padding: 20px !important;
50
+ border-radius: 10px !important;
51
+ margin-bottom: 20px !important;
52
+ text-align: center !important;
53
+ }
54
+
55
+ .tab-content {
56
+ background: white !important;
57
+ padding: 20px !important;
58
+ border-radius: 10px !important;
59
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
60
+ }
61
+
62
+ .action-button {
63
+ background: #3498DB !important;
64
+ color: white !important;
65
+ border: none !important;
66
+ padding: 10px 20px !important;
67
+ border-radius: 5px !important;
68
+ cursor: pointer !important;
69
+ transition: all 0.3s ease !important;
70
+ }
71
+
72
+ .action-button:hover {
73
+ background: #2980B9 !important;
74
+ transform: translateY(-2px) !important;
75
+ }
76
 
77
+ .status-box {
78
+ background: #E8F4F8 !important;
79
+ border-left: 4px solid #3498DB !important;
80
+ padding: 15px !important;
81
+ margin: 10px 0 !important;
82
+ border-radius: 0 5px 5px 0 !important;
83
+ }
84
+
85
+ .chart-container {
86
+ background: white !important;
87
+ padding: 20px !important;
88
+ border-radius: 10px !important;
89
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
90
+ }
91
+
92
+ .chat-container {
93
+ height: 400px !important;
94
+ overflow-y: auto !important;
95
+ border: 1px solid #dee2e6 !important;
96
+ border-radius: 10px !important;
97
+ padding: 15px !important;
98
+ }
99
+
100
+ .file-upload {
101
+ border: 2px dashed #dee2e6 !important;
102
+ border-radius: 10px !important;
103
+ padding: 20px !important;
104
+ text-align: center !important;
105
+ }
106
+
107
+ .result-box {
108
+ background: #f8f9fa !important;
109
+ border: 1px solid #dee2e6 !important;
110
+ border-radius: 10px !important;
111
+ padding: 20px !important;
112
+ margin-top: 15px !important;
113
+ }
114
+ """
115
 
116
  class SupplyChainState:
117
  def __init__(self):
 
122
  self.analysis_results = {}
123
  self.freight_predictions = []
124
 
125
+ # Load the XGBoost model
126
+ self.model_path = "optimized_xgboost_model.pkl"
127
+ try:
128
+ self.freight_model = joblib.load(self.model_path)
129
+ except:
130
+ print(f"Warning: Could not load freight prediction model from {self.model_path}")
131
+ self.freight_model = None
132
+
133
+ def predict_freight_cost(state, weight, line_item_value, cost_per_kg,
134
+ shipment_mode, air_charter_weight, ocean_weight, truck_weight,
135
+ air_charter_value, ocean_value, truck_value):
136
+ """Predict freight cost using the loaded model"""
137
+ if state.freight_model is None:
138
  return "Error: Freight prediction model not loaded"
139
 
140
  features = {
 
151
  input_data = pd.DataFrame([features])
152
 
153
  try:
154
+ prediction = state.freight_model.predict(input_data)
155
+ return round(float(prediction[0]), 2)
156
  except Exception as e:
157
  return f"Error making prediction: {str(e)}"
158
 
159
  def process_uploaded_data(state, sales_file, supplier_file, text_data):
160
+ """Process uploaded files and store in state"""
161
  try:
162
  if sales_file is not None:
163
  state.sales_df = pd.read_csv(sales_file.name)
 
166
  state.supplier_df = pd.read_excel(supplier_file.name)
167
 
168
  state.text_data = text_data
169
+ return "βœ… Data processed successfully"
170
  except Exception as e:
171
+ return f'❌ Error processing data: {str(e)}'
172
 
173
  def perform_demand_forecasting(state):
174
  """Perform demand forecasting using Gemini"""
 
189
 
190
  response = model.generate_content(prompt)
191
  analysis_text = response.text
192
+
193
+ # Create an enhanced visualization
194
  fig = px.line(state.sales_df, title='Historical Sales Data and Forecast')
195
+ fig.update_layout(
196
+ template='plotly_white',
197
+ title_x=0.5,
198
+ title_font_size=20,
199
+ showlegend=True,
200
+ hovermode='x'
201
+ )
202
 
203
+ return analysis_text, fig, "βœ… Analysis completed successfully"
204
  except Exception as e:
205
+ return f"❌ Error in demand forecasting: {str(e)}", None, "Analysis failed"
206
 
207
  def perform_risk_assessment(state):
208
  """Perform risk assessment using Gemini"""
 
226
 
227
  response = model.generate_content(prompt)
228
  analysis_text = response.text
229
+
230
+ # Create an enhanced risk visualization
231
  fig = px.scatter(state.supplier_df, title='Supplier Risk Assessment')
232
+ fig.update_layout(
233
+ template='plotly_white',
234
+ title_x=0.5,
235
+ title_font_size=20,
236
+ showlegend=True,
237
+ hovermode='closest'
238
+ )
239
 
240
+ return analysis_text, fig, "βœ… Risk assessment completed"
241
  except Exception as e:
242
+ return f"❌ Error in risk assessment: {str(e)}", None, "Assessment failed"
243
 
244
  def chat_with_navigator(state, message):
245
  """Handle chat interactions with the SupplyChainAI Navigator"""
 
253
  if state.text_data:
254
  context += "- Additional context from text data\n"
255
  if state.freight_predictions:
256
+ context += f"- Recent freight predictions: {state.freight_predictions[-5:]}\n"
257
 
258
  # Add analysis results
259
  if state.analysis_results:
 
293
  styles = getSampleStyleSheet()
294
  story = []
295
 
296
+ # Enhanced title style
297
  title_style = ParagraphStyle(
298
  'CustomTitle',
299
  parent=styles['Heading1'],
300
  fontSize=24,
301
+ spaceAfter=30,
302
+ textColor=colors.HexColor('#2C3E50')
303
  )
304
+
305
+ # Add company logo if available
306
+ # story.append(Image("logo.png", width=100, height=50))
307
+
308
  story.append(Paragraph("SupplyChainAI Navigator Report", title_style))
309
  story.append(Spacer(1, 12))
310
 
311
+ # Add executive summary
312
+ story.append(Paragraph("Executive Summary", styles['Heading2']))
313
+ summary_text = "This report provides a comprehensive analysis of supply chain data..."
314
+ story.append(Paragraph(summary_text, styles['Normal']))
315
+ story.append(Spacer(1, 20))
316
 
317
  # Analysis results
318
  for analysis_type, results in state.analysis_results.items():
 
333
  if state.freight_predictions:
334
  story.append(Paragraph("Recent Freight Cost Predictions", styles['Heading2']))
335
  story.append(Spacer(1, 12))
336
+
337
+ # Create a table for predictions
338
+ pred_data = [["Prediction #", "Cost (USD)"]]
339
+ for i, pred in enumerate(state.freight_predictions[-5:], 1):
340
+ pred_data.append([f"Prediction {i}", f"${pred:,.2f}"])
341
+
342
+ table = Table(pred_data)
343
+ table.setStyle(TableStyle([
344
+ ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#3498DB')),
345
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
346
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
347
+ ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
348
+ ('FONTSIZE', (0, 0), (-1, 0), 14),
349
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
350
+ ('BACKGROUND', (0, 1), (-1, -1), colors.whitesmoke),
351
+ ('TEXTCOLOR', (0, 1), (-1, -1), colors.black),
352
+ ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
353
+ ('FONTSIZE', (0, 1), (-1, -1), 12),
354
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
355
+ ]))
356
+ story.append(table)
357
  story.append(Spacer(1, 20))
358
 
359
  # Chat history
 
364
  story.append(Paragraph(f"{msg_type.title()}: {msg}", styles['Normal']))
365
  story.append(Spacer(1, 6))
366
 
367
+ # Build PDF
368
  doc.build(story)
369
  return pdf_path
370
  except Exception as e:
371
+ print(f"Error generating PDF: {str(e)}")
372
  return None
373
 
374
  def create_interface():
375
+ """Create Gradio interface with enhanced UI"""
376
  state = SupplyChainState()
377
 
378
+ with gr.Blocks(css=CUSTOM_CSS, title="SupplyChainAI Navigator") as demo:
379
+ # Header
380
+ with gr.Row(elem_classes="main-header"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  gr.Markdown("""
382
+ # 🚒 SupplyChainAI Navigator
383
+ ### Intelligent Supply Chain Analysis & Optimization
384
+ An AI-powered platform for comprehensive supply chain analytics
385
  """)
386
+
387
+ # Main Content Tabs
388
+ with gr.Tabs() as tabs:
389
+ # Data Upload Tab
390
+ with gr.Tab("πŸ“Š Data Upload", elem_classes="tab-content"):
391
+ with gr.Row():
392
+ gr.Markdown("""
393
+ ### Upload Your Supply Chain Data
394
+ Start by uploading your data files and providing additional context.
395
+ """)
396
+
397
+ with gr.Row():
398
+ with gr.Column(scale=1):
399
+ sales_data_upload = gr.File(
400
+ file_types=[".csv"],
401
+ label="πŸ“ˆ Sales Data (CSV)",
402
+ elem_classes="file-upload"
403
+ )
404
+ with gr.Column(scale=1):
405
+ supplier_data_upload = gr.File(
406
+ file_types=[".xlsx", ".xls"],
407
+ label="🏭 Supplier Data (Excel)",
408
+ elem_classes="file-upload"
409
+ )
410
+
411
+ text_input_area = gr.Textbox(
412
+ label="πŸ“ Additional Context",
413
+ placeholder="Add market updates, news, or other relevant information...",
414
+ lines=5
415
  )
416
+
417
+ with gr.Row():
418
+ upload_status = gr.Textbox(
419
+ label="Status",
420
+ elem_classes="status-box"
421
+ )
422
+ upload_button = gr.Button(
423
+ "πŸ”„ Process Data",
424
+ variant="primary",
425
+ elem_classes="action-button"
426
+ )
427
 
428
+ # Analysis Selection Tab
429
+ with gr.Tab("πŸ” Analysis", elem_classes="tab-content"):
430
+ with gr.Row():
431
+ gr.Markdown("### Select Analysis Types")
432
+
433
+ analysis_options = gr.CheckboxGroup(
434
+ choices=[
435
+ "πŸ“ˆ Demand Forecasting",
436
+ "⚠️ Risk Assessment",
437
+ "πŸ“¦ Inventory Optimization",
438
+ "🀝 Supplier Performance",
439
+ "🌿 Sustainability Analysis"
440
+ ],
441
+ label="Choose analyses to perform"
442
  )
443
+
444
+ analyze_button = gr.Button(
445
+ "πŸš€ Run Analysis",
446
+ variant="primary",
447
+ elem_classes="action-button"
448
  )
449
 
450
+ # Results Tab
451
+ with gr.Tab("πŸ“Š Results", elem_classes="tab-content"):
452
+ with gr.Row():
453
+ with gr.Column(scale=2):
454
+ analysis_output = gr.Textbox(
455
+ label="Analysis Results",
456
+ elem_classes="result-box"
457
+ )
458
+ with gr.Column(scale=3):
459
+ plot_output = gr.Plot(
460
+ label="Visualization",
461
+ elem_classes="chart-container"
462
+ )
463
+
464
+ raw_output = gr.Textbox(
465
+ label="Processing Status",
466
+ elem_classes="status-box"
467
  )
468
 
469
+ # Freight Cost Prediction Tab
470
+ with gr.Tab("πŸ’° Cost Prediction", elem_classes="tab-content"):
471
+ with gr.Row():
472
+ gr.Markdown("""
473
+ ### 🚒 Freight Cost Prediction
474
+ Estimate shipping costs based on your parameters
475
+ """)
476
+
477
+ with gr.Row():
478
+ shipment_mode = gr.Dropdown(
479
+ choices=["✈️ Air", "🚒 Ocean", "πŸš› Truck"],
480
+ label="Transport Mode",
481
+ value="✈️ Air"
482
+ )
483
+
484
+ with gr.Row():
485
+ with gr.Column():
486
+ weight = gr.Slider(
487
+ label="πŸ“¦ Weight (kg)",
488
+ minimum=1,
489
+ maximum=10000,
490
+ step=1,
491
+ value=1000
492
+ )
493
+ with gr.Column():
494
+ line_item_value = gr.Slider(
495
+ label="πŸ’΅ Item Value (USD)",
496
+ minimum=1,
497
+ maximum=1000000,
498
+ step=1,
499
+ value=10000
500
+ )
501
+ with gr.Column():
502
+ cost_per_kg = gr.Slider(
503
+ label="πŸ’° Cost per kg (USD)",
504
+ minimum=0,
505
+ maximum=500,
506
+ step=0.1,
507
+ value=50
508
+ )
509
+
510
+ # Mode-specific values
511
+ with gr.Row(visible=False) as air_inputs:
512
+ air_charter_weight = gr.Slider(
513
+ label="Air Charter Weight",
514
+ minimum=0,
515
+ maximum=10000,
516
+ step=1,
517
+ value=0
518
+ )
519
+ air_charter_value = gr.Slider(
520
+ label="Air Charter Value",
521
+ minimum=0,
522
+ maximum=1000000,
523
+ step=1,
524
+ value=0
525
+ )
526
+
527
+ with gr.Row(visible=False) as ocean_inputs:
528
+ ocean_weight = gr.Slider(
529
+ label="Ocean Weight",
530
+ minimum=0,
531
+ maximum=10000,
532
+ step=1,
533
+ value=0
534
+ )
535
+ ocean_value = gr.Slider(
536
+ label="Ocean Value",
537
+ minimum=0,
538
+ maximum=1000000,
539
+ step=1,
540
+ value=0
541
+ )
542
+
543
+ with gr.Row(visible=False) as truck_inputs:
544
+ truck_weight = gr.Slider(
545
+ label="Truck Weight",
546
+ minimum=0,
547
+ maximum=10000,
548
+ step=1,
549
+ value=0
550
+ )
551
+ truck_value = gr.Slider(
552
+ label="Truck Value",
553
+ minimum=0,
554
+ maximum=1000000,
555
+ step=1,
556
+ value=0
557
+ )
558
+
559
+ with gr.Row():
560
+ predict_button = gr.Button(
561
+ "πŸ” Calculate Cost",
562
+ variant="primary",
563
+ elem_classes="action-button"
564
+ )
565
+ freight_result = gr.Number(
566
+ label="Predicted Cost (USD)",
567
+ elem_classes="result-box"
568
+ )
569
 
570
+ # Chat Tab
571
+ with gr.Tab("πŸ’¬ Chat", elem_classes="tab-content"):
572
+ chatbot = gr.Chatbot(
573
+ label="Chat History",
574
+ elem_classes="chat-container",
575
+ height=400
576
+ )
577
+ with gr.Row():
578
+ msg = gr.Textbox(
579
+ label="Message",
580
+ placeholder="Ask about your supply chain data...",
581
+ scale=4
582
+ )
583
+ chat_button = gr.Button(
584
+ "πŸ“€ Send",
585
+ variant="primary",
586
+ scale=1,
587
+ elem_classes="action-button"
588
+ )
589
 
590
+ # Report Tab
591
+ with gr.Tab("πŸ“‘ Report", elem_classes="tab-content"):
592
+ gr.Markdown("""
593
+ ### Generate Comprehensive Report
594
+ Create a detailed PDF report including all analyses and insights.
595
+ """)
596
+
597
+ with gr.Row():
598
+ report_button = gr.Button(
599
+ "πŸ“„ Generate Report",
600
+ variant="primary",
601
+ elem_classes="action-button"
602
+ )
603
+ report_download = gr.File(
604
+ label="Download Report"
605
+ )
606
+
607
+ # Event Handlers
608
+ def update_mode_inputs(mode):
609
  return {
610
+ air_inputs: gr.update(visible=mode=="✈️ Air"),
611
+ ocean_inputs: gr.update(visible=mode=="🚒 Ocean"),
612
+ truck_inputs: gr.update(visible=mode=="πŸš› Truck")
 
 
 
613
  }
614
+
615
+ # Connect all components
 
616
  upload_button.click(
617
  fn=lambda *args: process_uploaded_data(state, *args),
618
  inputs=[sales_data_upload, supplier_data_upload, text_input_area],
619
  outputs=[upload_status]
620
  )
621
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  analyze_button.click(
623
+ fn=lambda choices, sales, supplier, text: run_analyses(state, choices, sales, supplier, text),
624
  inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
625
  outputs=[analysis_output, plot_output, raw_output]
626
  )
627
 
 
 
 
 
 
 
 
628
  shipment_mode.change(
629
+ fn=update_mode_inputs,
630
  inputs=[shipment_mode],
631
+ outputs=[air_inputs, ocean_inputs, truck_inputs]
 
 
 
632
  )
633
 
634
  predict_button.click(
 
641
  outputs=[freight_result]
642
  )
643
 
 
644
  chat_button.click(
645
  fn=lambda message: chat_with_navigator(state, message),
646
  inputs=[msg],
647
  outputs=[chatbot]
648
  ).then(
649
+ fn=lambda: "",
650
  outputs=[msg]
651
  )
652
 
 
653
  report_button.click(
654
  fn=lambda options: generate_pdf_report(state, options),
655
  inputs=[analysis_options],