prernajeet14 commited on
Commit
2a9c74b
Β·
verified Β·
1 Parent(s): c006a7e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +872 -27
app.py CHANGED
@@ -1,27 +1,872 @@
1
- gradio>=4.0.0
2
- pandas>=1.5.0
3
- numpy>=1.24.0
4
- pyautogen>=0.2.0
5
- openai>=1.0.0
6
- tavily-python>=0.3.0
7
- plotly>=5.17.0
8
- matplotlib>=3.7.0
9
- seaborn>=0.12.0
10
- openpyxl>=3.1.0
11
- xlrd>=2.0.0
12
- PyPDF2>=3.0.0
13
- python-docx>=0.8.11
14
- python-pptx>=0.6.21
15
- requests>=2.31.0
16
- beautifulsoup4>=4.12.0
17
- lxml>=4.9.0
18
- python-dateutil>=2.8.0
19
- pytz>=2023.3
20
- scikit-learn>=1.3.0
21
- scipy>=1.11.0
22
- networkx>=3.1
23
- asyncio-throttle>=1.0.2
24
- aiohttp>=3.8.0
25
- pydantic>=2.0.0
26
- diskcache>=5.6.0
27
- joblib>=1.3.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import pandas as pd
4
+ import gradio as gr
5
+ from typing import Annotated, Dict, List, Any
6
+ from tavily import TavilyClient
7
+ from autogen import AssistantAgent, UserProxyAgent, register_function, Cache
8
+ from autogen.agentchat import GroupChat, GroupChatManager
9
+ import plotly.graph_objects as go
10
+ import plotly.express as px
11
+ from datetime import datetime
12
+ import asyncio
13
+ import threading
14
+ import time
15
+ import io
16
+ import docx
17
+ from pptx import Presentation
18
+ import PyPDF2
19
+
20
+ # Disable Docker globally
21
+ os.environ["AUTOGEN_USE_DOCKER"] = "0"
22
+
23
+ class SupplyChainOptimizer:
24
+ def __init__(self):
25
+ # Initialize API keys from environment variables
26
+ self.openai_api_key = os.environ.get("OPENAI_API_KEY") or os.environ.get("OPENAI_KEY")
27
+ self.tavily_api_key = os.environ.get("TAVILY_API_KEY") or os.environ.get("TAVILY_KEY")
28
+
29
+ # For development/testing, allow demo mode
30
+ self.demo_mode = False
31
+ if not self.openai_api_key or not self.tavily_api_key:
32
+ print("API keys not found. Running in demo mode.")
33
+ self.demo_mode = True
34
+ self.openai_api_key = "demo-key"
35
+ self.tavily_api_key = "demo-key"
36
+
37
+ # Initialize Tavily client (only if not in demo mode)
38
+ if not self.demo_mode:
39
+ try:
40
+ self.tavily = TavilyClient(api_key=self.tavily_api_key)
41
+ except Exception as e:
42
+ print(f"Error initializing Tavily: {e}")
43
+ self.demo_mode = True
44
+
45
+ # Initialize agents
46
+ self._setup_agents()
47
+
48
+ # Store results
49
+ self.latest_analysis = ""
50
+ self.latest_optimization = ""
51
+ self.search_results = ""
52
+
53
+ def _setup_agents(self):
54
+ """Setup AutoGen agents"""
55
+ self.user_proxy = UserProxyAgent(
56
+ name="UserProxy",
57
+ system_message="You are the user interacting with the agents.",
58
+ human_input_mode="NEVER",
59
+ code_execution_config={"work_dir": "code", "use_docker": False},
60
+ )
61
+
62
+ # Only setup LLM agents if not in demo mode
63
+ if not self.demo_mode:
64
+ self.reasoning_agent = AssistantAgent(
65
+ name="ReasoningAgent",
66
+ llm_config={"config_list": [{"model": "gpt-3.5-turbo", "api_key": self.openai_api_key}]},
67
+ system_message="""You are an expert supply chain analyst. Analyze forecast data using real-time search results.
68
+ Evaluate if forecasts are reasonable based on current market conditions, events, and trends.
69
+ Provide detailed reasoning and recommendations. Format your response clearly with proper structure and avoid using asterisks for emphasis."""
70
+ )
71
+
72
+ self.optimization_agent = AssistantAgent(
73
+ name="OptimizationAgent",
74
+ llm_config={"config_list": [{"model": "gpt-3.5-turbo", "api_key": self.openai_api_key}]},
75
+ system_message="""You are a supply chain optimization expert. Create detailed redistribution plans.
76
+ Consider costs, travel time, inventory levels, and demand forecasts.
77
+ Provide step-by-step optimization plans with clear recommendations and cost analysis. Use professional formatting without asterisks."""
78
+ )
79
+
80
+ # Register search tool
81
+ register_function(
82
+ self.tavily_search_tool,
83
+ caller=self.reasoning_agent,
84
+ executor=self.user_proxy,
85
+ name="tavily_search_tool",
86
+ description="Conducts real-time market research using Tavily."
87
+ )
88
+ else:
89
+ self.reasoning_agent = None
90
+ self.optimization_agent = None
91
+
92
+ def tavily_search_tool(self, query: Annotated[str, "Market Research Query"]) -> Annotated[str, "Search results"]:
93
+ """Search tool using Tavily API"""
94
+ if self.demo_mode:
95
+ return f"Demo Mode: Search query '{query}' - Market conditions show stable tourism activity with moderate demand fluctuations in the specified regions."
96
+
97
+ try:
98
+ results = self.tavily.get_search_context(query=query, search_depth="advanced")
99
+ self.search_results = results
100
+ return results
101
+ except Exception as e:
102
+ return f"Search error: {str(e)}"
103
+
104
+ def parse_file_content(self, file_path, file_type):
105
+ """Parse various file formats and extract data"""
106
+ try:
107
+ if file_type == "excel":
108
+ # Try to read Excel file
109
+ df = pd.read_excel(file_path, sheet_name=None)
110
+ return self._process_excel_data(df)
111
+ elif file_type == "csv":
112
+ df = pd.read_csv(file_path)
113
+ return self._process_csv_data(df)
114
+ elif file_type == "pdf":
115
+ return self._process_pdf_data(file_path)
116
+ elif file_type == "word":
117
+ return self._process_word_data(file_path)
118
+ elif file_type == "ppt":
119
+ return self._process_ppt_data(file_path)
120
+ else:
121
+ return "Unsupported file format"
122
+ except Exception as e:
123
+ return f"Error processing file: {str(e)}"
124
+
125
+ def _process_excel_data(self, excel_data):
126
+ """Process Excel data and extract forecast, inventory, and route information"""
127
+ processed_data = {
128
+ 'forecast': [],
129
+ 'inventory': [],
130
+ 'routes': []
131
+ }
132
+
133
+ for sheet_name, df in excel_data.items():
134
+ if 'forecast' in sheet_name.lower():
135
+ processed_data['forecast'] = df.to_dict('records')
136
+ elif 'inventory' in sheet_name.lower():
137
+ processed_data['inventory'] = df.to_dict('records')
138
+ elif 'route' in sheet_name.lower():
139
+ processed_data['routes'] = df.to_dict('records')
140
+
141
+ return processed_data
142
+
143
+ def _process_csv_data(self, df):
144
+ """Process CSV data"""
145
+ return {'data': df.to_dict('records')}
146
+
147
+ def _process_pdf_data(self, file_path):
148
+ """Extract text from PDF"""
149
+ try:
150
+ with open(file_path, 'rb') as file:
151
+ pdf_reader = PyPDF2.PdfReader(file)
152
+ text = ""
153
+ for page in pdf_reader.pages:
154
+ text += page.extract_text()
155
+ return {'text': text}
156
+ except Exception as e:
157
+ return f"Error reading PDF: {str(e)}"
158
+
159
+ def _process_word_data(self, file_path):
160
+ """Extract text from Word document"""
161
+ try:
162
+ doc = docx.Document(file_path)
163
+ text = ""
164
+ for paragraph in doc.paragraphs:
165
+ text += paragraph.text + "\n"
166
+ return {'text': text}
167
+ except Exception as e:
168
+ return f"Error reading Word document: {str(e)}"
169
+
170
+ def _process_ppt_data(self, file_path):
171
+ """Extract text from PowerPoint"""
172
+ try:
173
+ prs = Presentation(file_path)
174
+ text = ""
175
+ for slide in prs.slides:
176
+ for shape in slide.shapes:
177
+ if hasattr(shape, "text"):
178
+ text += shape.text + "\n"
179
+ return {'text': text}
180
+ except Exception as e:
181
+ return f"Error reading PowerPoint: {str(e)}"
182
+
183
+ def create_forecast_visualization(self, forecast_data):
184
+ """Create interactive forecast visualization with vibrant colors"""
185
+ df = pd.DataFrame(forecast_data)
186
+
187
+ fig = go.Figure()
188
+
189
+ # Vibrant color palette
190
+ colors = ['#FF6B35', '#F7931E', '#FFD23F', '#06FFA5', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD', '#FA8072']
191
+
192
+ for i, (city, group) in enumerate(df.groupby('City')):
193
+ fig.add_trace(go.Bar(
194
+ name=city,
195
+ x=group['Product'],
196
+ y=group['Forecasted_Demand'],
197
+ marker_color=colors[i % len(colors)],
198
+ text=group['Forecasted_Demand'],
199
+ textposition='auto',
200
+ textfont=dict(size=14, color='white', family='Arial Black'),
201
+ ))
202
+
203
+ fig.update_layout(
204
+ title={
205
+ 'text': "Demand Forecast by City & Product",
206
+ 'x': 0.5,
207
+ 'xanchor': 'center',
208
+ 'font': {'size': 20, 'color': '#B8860B', 'family': 'Arial Black'}
209
+ },
210
+ xaxis_title="Products",
211
+ yaxis_title="Forecasted Demand",
212
+ xaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
213
+ yaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
214
+ barmode='group',
215
+ plot_bgcolor='rgba(255,248,220,0.9)',
216
+ paper_bgcolor='rgba(255,248,220,0.9)',
217
+ font=dict(color='#8B4513', size=12, family='Arial'),
218
+ height=500,
219
+ legend=dict(font=dict(size=12, color='#8B4513', family='Arial'))
220
+ )
221
+
222
+ return fig
223
+
224
+ def create_inventory_chart(self, inventory_data, forecast_data):
225
+ """Create inventory vs demand comparison with vibrant styling"""
226
+ inv_df = pd.DataFrame(inventory_data)
227
+ fore_df = pd.DataFrame(forecast_data)
228
+
229
+ # Merge data
230
+ merged = pd.merge(inv_df, fore_df, on=['City', 'Product'], how='outer')
231
+ merged = merged.fillna(0)
232
+
233
+ fig = go.Figure()
234
+
235
+ fig.add_trace(go.Bar(
236
+ name='Current Stock',
237
+ x=[f"{row['City']} - {row['Product']}" for _, row in merged.iterrows()],
238
+ y=merged['Stock_Level'],
239
+ marker_color='#FF4757',
240
+ opacity=0.9,
241
+ text=merged['Stock_Level'],
242
+ textposition='auto',
243
+ textfont=dict(size=12, color='white', family='Arial Black')
244
+ ))
245
+
246
+ fig.add_trace(go.Bar(
247
+ name='Forecasted Demand',
248
+ x=[f"{row['City']} - {row['Product']}" for _, row in merged.iterrows()],
249
+ y=merged['Forecasted_Demand'],
250
+ marker_color='#FFA502',
251
+ opacity=0.9,
252
+ text=merged['Forecasted_Demand'],
253
+ textposition='auto',
254
+ textfont=dict(size=12, color='white', family='Arial Black')
255
+ ))
256
+
257
+ fig.update_layout(
258
+ title={
259
+ 'text': "Inventory vs Demand Analysis",
260
+ 'x': 0.5,
261
+ 'xanchor': 'center',
262
+ 'font': {'size': 20, 'color': '#B8860B', 'family': 'Arial Black'}
263
+ },
264
+ xaxis_title="City & Product",
265
+ yaxis_title="Units",
266
+ xaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
267
+ yaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
268
+ barmode='group',
269
+ plot_bgcolor='rgba(255,248,220,0.9)',
270
+ paper_bgcolor='rgba(255,248,220,0.9)',
271
+ font=dict(color='#8B4513', size=12, family='Arial'),
272
+ height=500,
273
+ legend=dict(font=dict(size=12, color='#8B4513', family='Arial'))
274
+ )
275
+
276
+ return fig
277
+
278
+ def create_route_network(self, route_data):
279
+ """Create route network visualization with vibrant colors"""
280
+ df = pd.DataFrame(route_data)
281
+
282
+ fig = go.Figure()
283
+
284
+ fig.add_trace(go.Scatter(
285
+ x=df['Distance_km'],
286
+ y=df['Cost_per_km'],
287
+ mode='markers+text',
288
+ marker=dict(
289
+ size=[cost*2 for cost in df['Cost_per_km']],
290
+ color=df['Average_Travel_Time_hrs'],
291
+ colorscale=[[0, '#FFD700'], [0.5, '#FF6347'], [1, '#DC143C']],
292
+ showscale=True,
293
+ colorbar=dict(title="Travel Time (hrs)", titlefont=dict(size=14, color='#8B4513', family='Arial Black'))
294
+ ),
295
+ text=[f"{row['Source']} β†’ {row['Destination']}" for _, row in df.iterrows()],
296
+ textposition="top center",
297
+ textfont=dict(size=12, color='#8B0000', family='Arial Black'),
298
+ name="Routes"
299
+ ))
300
+
301
+ fig.update_layout(
302
+ title={
303
+ 'text': "Route Analysis: Distance vs Cost",
304
+ 'x': 0.5,
305
+ 'xanchor': 'center',
306
+ 'font': {'size': 20, 'color': '#B8860B', 'family': 'Arial Black'}
307
+ },
308
+ xaxis_title="Distance (km)",
309
+ yaxis_title="Cost per km (β‚Ή)",
310
+ xaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
311
+ yaxis=dict(titlefont=dict(size=16, color='#8B4513', family='Arial Black')),
312
+ plot_bgcolor='rgba(255,248,220,0.9)',
313
+ paper_bgcolor='rgba(255,248,220,0.9)',
314
+ font=dict(color='#8B4513', size=12, family='Arial'),
315
+ height=500
316
+ )
317
+
318
+ return fig
319
+
320
+ def optimize_supply_chain(self, forecast_data, inventory_data, route_data, search_query, progress=gr.Progress()):
321
+ """Main optimization function"""
322
+ progress(0.1, desc="Conducting market research...")
323
+
324
+ # Conduct search
325
+ search_results = self.tavily_search_tool(search_query)
326
+
327
+ progress(0.3, desc="Analyzing forecast data...")
328
+
329
+ if self.demo_mode:
330
+ time.sleep(2)
331
+ progress(0.6, desc="Optimizing redistribution plan...")
332
+
333
+ self.latest_analysis = """
334
+ DEMO MODE - Market Analysis & Forecast Reasoning
335
+
336
+ Market Conditions Assessment:
337
+ - Current tourism trends show moderate activity in hill stations
338
+ - Seasonal demand patterns indicate December is peak season for tourist destinations
339
+ - Economic indicators suggest stable consumer spending on FMCG products
340
+
341
+ Forecast Accuracy Evaluation:
342
+ - Goa: Forecasted demand of 1,500 units appears reasonable given tourist influx
343
+ - Coorg: 700 units forecast aligns with typical seasonal patterns
344
+ - Mahabaleshwar: 1,000 units seems appropriate for weekend destination
345
+ - Lonavala: 850 units matches proximity to major cities
346
+ - Ooty: 400 units may be conservative given popularity
347
+
348
+ Risk Factors:
349
+ - Weather conditions could impact transportation
350
+ - Festival seasons may create demand spikes
351
+ - Competition from local suppliers
352
+
353
+ Recommendations:
354
+ - Monitor real-time booking data
355
+ - Prepare for demand fluctuations
356
+ - Consider safety stock adjustments
357
+
358
+ Note: Set your API keys to get real-time market intelligence
359
+ """
360
+
361
+ time.sleep(2)
362
+ progress(0.8, desc="Generating insights...")
363
+
364
+ self.latest_optimization = """
365
+ DEMO MODE - Optimized Redistribution Plan
366
+
367
+ Priority Actions:
368
+
369
+ 1. Immediate Redistribution (Week 1)
370
+ - Move 300 Biscuit units from Lonavala to Coorg (Cost: β‚Ή6,480)
371
+ - Route: Lonavala β†’ Goa β†’ Coorg (Total: 1,000 km)
372
+ - Expected delivery: 17 hours
373
+
374
+ 2. Strategic Rebalancing (Week 2)
375
+ - Reduce Goa soap inventory by 500 units
376
+ - Distribute to Mahabaleshwar and Ooty based on demand
377
+ - Utilize cost-effective Goa β†’ Ooty route (β‚Ή16,500)
378
+
379
+ 3. Cost Optimization Strategies
380
+ - Consolidate shipments to reduce per-km costs
381
+ - Use off-peak travel times for better rates
382
+ - Implement just-in-time delivery schedules
383
+
384
+ 4. Expected Outcomes
385
+ - Total redistribution cost: β‚Ή45,000
386
+ - Inventory optimization: 15% reduction in carrying costs
387
+ - Service level improvement: 98% demand fulfillment
388
+ - Risk mitigation: 20% safety stock maintained
389
+
390
+ 5. Timeline & Priorities
391
+ - High Priority: Coorg biscuits shortage (2 days)
392
+ - Medium Priority: Ooty soap rebalancing (1 week)
393
+ - Low Priority: General inventory optimization (2 weeks)
394
+
395
+ Cost-Benefit Analysis:
396
+ - Investment: β‚Ή45,000 in transportation
397
+ - Savings: β‚Ή65,000 in carrying costs + lost sales prevention
398
+ - Net Benefit: β‚Ή20,000 + improved customer satisfaction
399
+
400
+ Note: Set your API keys for AI-powered optimization with real market data
401
+ """
402
+
403
+ else:
404
+ # Real AI agent processing (similar structure but without asterisks in system messages)
405
+ reasoning_prompt = f"""
406
+ Analyze the forecast data against the real-time search results and evaluate if the forecast is reasonable.
407
+
408
+ Forecast Data: {json.dumps(forecast_data, indent=2)}
409
+ Search Results: {search_results}
410
+
411
+ Please provide detailed reasoning on:
412
+ 1. Market conditions affecting demand
413
+ 2. External factors from search results
414
+ 3. Forecast accuracy assessment
415
+ 4. Risk factors to consider
416
+
417
+ Please format your response professionally without using asterisks for emphasis.
418
+ """
419
+
420
+ try:
421
+ with Cache.disk(cache_seed=42) as cache:
422
+ reasoning_result = self.user_proxy.initiate_chat(
423
+ self.reasoning_agent,
424
+ message=reasoning_prompt,
425
+ cache=cache,
426
+ max_turns=1
427
+ )
428
+
429
+ if reasoning_result and reasoning_result.chat_history:
430
+ self.latest_analysis = reasoning_result.chat_history[-1]['content']
431
+ else:
432
+ self.latest_analysis = "Analysis completed but no detailed response received."
433
+
434
+ except Exception as e:
435
+ self.latest_analysis = f"Analysis error: {str(e)}"
436
+
437
+ progress(0.6, desc="Optimizing redistribution plan...")
438
+
439
+ # Optimization phase
440
+ optimization_prompt = f"""
441
+ Create an optimized redistribution plan using the analyzed data.
442
+
443
+ Forecast Data: {json.dumps(forecast_data, indent=2)}
444
+ Inventory Data: {json.dumps(inventory_data, indent=2)}
445
+ Route Data: {json.dumps(route_data, indent=2)}
446
+
447
+ Analysis Context: {self.latest_analysis}
448
+
449
+ Please provide:
450
+ 1. Redistribution recommendations
451
+ 2. Cost optimization strategies
452
+ 3. Risk mitigation plans
453
+ 4. Timeline and priorities
454
+ 5. Expected cost savings
455
+
456
+ Please format your response professionally without using asterisks for emphasis.
457
+ """
458
+
459
+ try:
460
+ with Cache.disk(cache_seed=43) as cache:
461
+ optimization_result = self.user_proxy.initiate_chat(
462
+ self.optimization_agent,
463
+ message=optimization_prompt,
464
+ cache=cache,
465
+ max_turns=1
466
+ )
467
+
468
+ if optimization_result and optimization_result.chat_history:
469
+ self.latest_optimization = optimization_result.chat_history[-1]['content']
470
+ else:
471
+ self.latest_optimization = "Optimization completed but no detailed response received."
472
+
473
+ except Exception as e:
474
+ self.latest_optimization = f"Optimization error: {str(e)}"
475
+
476
+ progress(1.0, desc="Optimization complete!")
477
+
478
+ return self.latest_analysis, self.latest_optimization, search_results
479
+
480
+ # Initialize the optimizer
481
+ try:
482
+ optimizer = SupplyChainOptimizer()
483
+ startup_message = "Supply Chain Optimizer initialized successfully!"
484
+ if optimizer.demo_mode:
485
+ startup_message = "Running in DEMO mode. Set API keys for full functionality."
486
+ except Exception as e:
487
+ print(f"Error initializing optimizer: {e}")
488
+ class DemoOptimizer:
489
+ def __init__(self):
490
+ self.demo_mode = True
491
+
492
+ def create_forecast_visualization(self, data):
493
+ return go.Figure().add_annotation(text="Set API keys to enable charts")
494
+
495
+ def create_inventory_chart(self, inv, fore):
496
+ return go.Figure().add_annotation(text="Set API keys to enable charts")
497
+
498
+ def create_route_network(self, routes):
499
+ return go.Figure().add_annotation(text="Set API keys to enable charts")
500
+
501
+ def optimize_supply_chain(self, f, i, r, q, progress=None):
502
+ return "Demo mode", "Demo mode", "Demo mode"
503
+
504
+ def parse_file_content(self, path, file_type):
505
+ return "Demo mode"
506
+
507
+ optimizer = DemoOptimizer()
508
+ startup_message = "Running in minimal demo mode due to initialization error."
509
+
510
+ # Default data
511
+ DEFAULT_FORECAST = [
512
+ {"City": "Goa", "Product": "Soap", "Forecasted_Demand": 1500, "Month": "December"},
513
+ {"City": "Coorg", "Product": "Biscuits", "Forecasted_Demand": 700, "Month": "December"},
514
+ {"City": "Mahabaleshwar", "Product": "Soap", "Forecasted_Demand": 1000, "Month": "December"},
515
+ {"City": "Lonavala", "Product": "Biscuits", "Forecasted_Demand": 850, "Month": "December"},
516
+ {"City": "Ooty", "Product": "Soap", "Forecasted_Demand": 400, "Month": "December"}
517
+ ]
518
+
519
+ DEFAULT_INVENTORY = [
520
+ {"City": "Goa", "Product": "Soap", "Stock_Level": 2000},
521
+ {"City": "Coorg", "Product": "Biscuits", "Stock_Level": 400},
522
+ {"City": "Mahabaleshwar", "Product": "Soap", "Stock_Level": 1100},
523
+ {"City": "Lonavala", "Product": "Biscuits", "Stock_Level": 800},
524
+ {"City": "Ooty", "Product": "Soap", "Stock_Level": 500}
525
+ ]
526
+
527
+ DEFAULT_ROUTES = [
528
+ {"Source": "Goa", "Destination": "Coorg", "Distance_km": 550, "Cost_per_km": 20, "Average_Travel_Time_hrs": 10},
529
+ {"Source": "Goa", "Destination": "Ooty", "Distance_km": 750, "Cost_per_km": 22, "Average_Travel_Time_hrs": 15},
530
+ {"Source": "Coorg", "Destination": "Goa", "Distance_km": 550, "Cost_per_km": 20, "Average_Travel_Time_hrs": 10},
531
+ {"Source": "Coorg", "Destination": "Mahabaleshwar", "Distance_km": 400, "Cost_per_km": 18, "Average_Travel_Time_hrs": 8},
532
+ {"Source": "Lonavala", "Destination": "Goa", "Distance_km": 450, "Cost_per_km": 19, "Average_Travel_Time_hrs": 7},
533
+ {"Source": "Ooty", "Destination": "Coorg", "Distance_km": 800, "Cost_per_km": 21, "Average_Travel_Time_hrs": 16}
534
+ ]
535
+
536
+ def process_files_and_optimize(forecast_file, inventory_file, routes_file, text_input, search_query):
537
+ """Process uploaded files and text input for optimization"""
538
+ try:
539
+ forecast_data = DEFAULT_FORECAST
540
+ inventory_data = DEFAULT_INVENTORY
541
+ route_data = DEFAULT_ROUTES
542
+
543
+ # Process uploaded files
544
+ file_contents = []
545
+
546
+ if forecast_file:
547
+ file_ext = forecast_file.name.split('.')[-1].lower()
548
+ if file_ext in ['xlsx', 'xls']:
549
+ content = optimizer.parse_file_content(forecast_file.name, 'excel')
550
+ if 'forecast' in content:
551
+ forecast_data = content['forecast']
552
+ file_contents.append(f"Forecast file processed: {forecast_file.name}")
553
+ elif file_ext == 'csv':
554
+ df = pd.read_csv(forecast_file.name)
555
+ forecast_data = df.to_dict('records')
556
+ file_contents.append(f"Forecast CSV processed: {forecast_file.name}")
557
+
558
+ if inventory_file:
559
+ file_ext = inventory_file.name.split('.')[-1].lower()
560
+ if file_ext in ['xlsx', 'xls']:
561
+ content = optimizer.parse_file_content(inventory_file.name, 'excel')
562
+ if 'inventory' in content:
563
+ inventory_data = content['inventory']
564
+ file_contents.append(f"Inventory file processed: {inventory_file.name}")
565
+ elif file_ext == 'csv':
566
+ df = pd.read_csv(inventory_file.name)
567
+ inventory_data = df.to_dict('records')
568
+ file_contents.append(f"Inventory CSV processed: {inventory_file.name}")
569
+
570
+ if routes_file:
571
+ file_ext = routes_file.name.split('.')[-1].lower()
572
+ if file_ext in ['xlsx', 'xls']:
573
+ content = optimizer.parse_file_content(routes_file.name, 'excel')
574
+ if 'routes' in content:
575
+ route_data = content['routes']
576
+ file_contents.append(f"Routes file processed: {routes_file.name}")
577
+ elif file_ext == 'csv':
578
+ df = pd.read_csv(routes_file.name)
579
+ route_data = df.to_dict('records')
580
+ file_contents.append(f"Routes CSV processed: {routes_file.name}")
581
+
582
+ # Process text input if provided
583
+ if text_input and text_input.strip():
584
+ file_contents.append(f"Text input processed: {len(text_input)} characters")
585
+
586
+ # Create visualizations
587
+ forecast_chart = optimizer.create_forecast_visualization(forecast_data)
588
+ inventory_chart = optimizer.create_inventory_chart(inventory_data, forecast_data)
589
+ route_chart = optimizer.create_route_network(route_data)
590
+
591
+ # Run optimization
592
+ analysis, optimization, search_results = optimizer.optimize_supply_chain(
593
+ forecast_data, inventory_data, route_data, search_query
594
+ )
595
+
596
+ # Processing summary
597
+ processing_summary = "Files processed:\n" + "\n".join(file_contents) if file_contents else "Using default data"
598
+
599
+ return (
600
+ forecast_chart,
601
+ inventory_chart,
602
+ route_chart,
603
+ analysis,
604
+ optimization,
605
+ search_results[:2000] + "..." if len(search_results) > 2000 else search_results,
606
+ processing_summary
607
+ )
608
+
609
+ except Exception as e:
610
+ error_msg = f"Processing error: {str(e)}"
611
+ return None, None, None, error_msg, error_msg, error_msg, error_msg
612
+
613
+ # Create Gradio interface with updated warm color scheme
614
+ custom_css = """
615
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
616
+
617
+ .gradio-container {
618
+ font-family: 'Inter', sans-serif;
619
+ background: linear-gradient(135deg, #FFF8DC 0%, #FFEBCD 100%);
620
+ min-height: 100vh;
621
+ }
622
+
623
+ .main-header {
624
+ text-align: center;
625
+ background: linear-gradient(135deg, #DC143C 0%, #FF6347 50%, #FFD700 100%);
626
+ color: white;
627
+ padding: 2.5rem;
628
+ border-radius: 15px;
629
+ margin-bottom: 2rem;
630
+ box-shadow: 0 8px 25px rgba(220, 20, 60, 0.3);
631
+ border: 2px solid #B8860B;
632
+ }
633
+
634
+ .main-header h1 {
635
+ font-size: 2.5rem;
636
+ font-weight: 700;
637
+ margin-bottom: 1rem;
638
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
639
+ }
640
+
641
+ .main-header p {
642
+ font-size: 1.1rem;
643
+ font-weight: 500;
644
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
645
+ }
646
+
647
+ .section-header {
648
+ background: linear-gradient(90deg, #FF4757 0%, #FFA502 100%);
649
+ color: white;
650
+ padding: 1.2rem;
651
+ border-radius: 10px;
652
+ margin: 1rem 0;
653
+ text-align: center;
654
+ font-weight: 600;
655
+ font-size: 1.1rem;
656
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
657
+ border: 2px solid #B8860B;
658
+ box-shadow: 0 4px 15px rgba(255, 71, 87, 0.2);
659
+ }
660
+
661
+ .results-container {
662
+ background: linear-gradient(135deg, #FFFACD 0%, #F5DEB3 100%);
663
+ padding: 2rem;
664
+ border-radius: 12px;
665
+ margin: 1rem 0;
666
+ box-shadow: 0 4px 20px rgba(184, 134, 11, 0.15);
667
+ border: 2px solid #DAA520;
668
+ }
669
+
670
+ .footer {
671
+ text-align: center;
672
+ color: #8B4513;
673
+ padding: 2rem;
674
+ border-top: 2px solid #DAA520;
675
+ margin-top: 2rem;
676
+ background: linear-gradient(135deg, #FFF8DC 0%, #FFEBCD 100%);
677
+ border-radius: 10px;
678
+ font-weight: 500;
679
+ }
680
+
681
+ .upload-area {
682
+ border: 3px dashed #DAA520;
683
+ border-radius: 10px;
684
+ padding: 1.5rem;
685
+ margin: 0.5rem 0;
686
+ background: linear-gradient(135deg, #FFFACD 0%, #F0E68C 100%);
687
+ transition: all 0.3s ease;
688
+ }
689
+
690
+ .upload-area:hover {
691
+ border-color: #B8860B;
692
+ background: linear-gradient(135deg, #F0E68C 0%, #DAA520 100%);
693
+ transform: translateY(-2px);
694
+ }
695
+
696
+ /* Button styling */
697
+ .gradio-button {
698
+ background: linear-gradient(135deg, #FF4757 0%, #FFA502 100%) !important;
699
+ color: white !important;
700
+ font-weight: 600 !important;
701
+ border: 2px solid #B8860B !important;
702
+ border-radius: 8px !important;
703
+ padding: 12px 24px !important;
704
+ font-size: 1rem !important;
705
+ transition: all 0.3s ease !important;
706
+ box-shadow: 0 4px 15px rgba(255, 71, 87, 0.2) !important;
707
+ }
708
+
709
+ .gradio-button:hover {
710
+ background: linear-gradient(135deg, #FFA502 0%, #FF4757 100%) !important;
711
+ transform: translateY(-2px) !important;
712
+ box-shadow: 0 6px 20px rgba(255, 71, 87, 0.3) !important;
713
+ }
714
+
715
+ /* Input styling */
716
+ .gradio-textbox, .gradio-dropdown {
717
+ border: 2px solid #DAA520 !important;
718
+ border-radius: 8px !important;
719
+ background: linear-gradient(135deg, #FFFACD 0%, #F5DEB3 100%) !important;
720
+ }
721
+
722
+ .gradio-textbox:focus, .gradio-dropdown:focus {
723
+ border-color: #B8860B !important;
724
+ box-shadow: 0 0 10px rgba(184, 134, 11, 0.3) !important;
725
+ }
726
+ """
727
+
728
+ # Create the Gradio interface
729
+ with gr.Blocks(css=custom_css, title="AI-Powered Supply Chain Optimizer") as interface:
730
+ # Header
731
+ gr.HTML("""
732
+ <div class="main-header">
733
+ <h1>🚚 AI-Powered Supply Chain Optimizer</h1>
734
+ <p>Optimize your supply chain with real-time market intelligence and advanced analytics</p>
735
+ </div>
736
+ """)
737
+
738
+ # Status message
739
+ gr.HTML(f"""
740
+ <div style="text-align: center; padding: 1rem; background: #E6FFE6; border-radius: 8px; margin-bottom: 1rem; border: 2px solid #90EE90;">
741
+ <strong>System Status:</strong> {startup_message}
742
+ </div>
743
+ """)
744
+
745
+ with gr.Tabs():
746
+ # Tab 1: File Upload and Input
747
+ with gr.TabItem("πŸ“ Data Input", elem_id="input-tab"):
748
+ gr.HTML('<div class="section-header">Upload Your Data Files</div>')
749
+
750
+ with gr.Row():
751
+ with gr.Column():
752
+ forecast_file = gr.File(
753
+ label="πŸ“Š Forecast Data (Excel/CSV)",
754
+ file_types=[".xlsx", ".xls", ".csv"],
755
+ elem_classes=["upload-area"]
756
+ )
757
+ inventory_file = gr.File(
758
+ label="πŸ“¦ Inventory Data (Excel/CSV)",
759
+ file_types=[".xlsx", ".xls", ".csv"],
760
+ elem_classes=["upload-area"]
761
+ )
762
+ with gr.Column():
763
+ routes_file = gr.File(
764
+ label="πŸ—ΊοΈ Routes Data (Excel/CSV)",
765
+ file_types=[".xlsx", ".xls", ".csv"],
766
+ elem_classes=["upload-area"]
767
+ )
768
+ text_input = gr.Textbox(
769
+ label="πŸ“ Additional Context (Optional)",
770
+ placeholder="Enter any additional business context, constraints, or special requirements...",
771
+ lines=4,
772
+ elem_classes=["upload-area"]
773
+ )
774
+
775
+ search_query = gr.Textbox(
776
+ label="πŸ” Market Research Query",
777
+ placeholder="Enter search terms for real-time market analysis (e.g., 'tourism trends December 2024 hill stations')",
778
+ value="tourism trends December 2024 hill stations demand forecast",
779
+ lines=2
780
+ )
781
+
782
+ optimize_btn = gr.Button(
783
+ "πŸš€ Optimize Supply Chain",
784
+ variant="primary",
785
+ size="lg",
786
+ elem_classes=["gradio-button"]
787
+ )
788
+
789
+ processing_status = gr.Textbox(
790
+ label="πŸ“‹ Processing Status",
791
+ interactive=False,
792
+ lines=3
793
+ )
794
+
795
+ # Tab 2: Visualizations
796
+ with gr.TabItem("πŸ“ˆ Analytics Dashboard", elem_id="viz-tab"):
797
+ gr.HTML('<div class="section-header">Interactive Data Visualizations</div>')
798
+
799
+ with gr.Row():
800
+ forecast_plot = gr.Plot(label="πŸ“Š Demand Forecast Analysis")
801
+ inventory_plot = gr.Plot(label="πŸ“¦ Inventory vs Demand")
802
+
803
+ route_plot = gr.Plot(label="πŸ—ΊοΈ Route Network Analysis")
804
+
805
+ # Tab 3: AI Analysis Results
806
+ with gr.TabItem("πŸ€– AI Analysis", elem_id="analysis-tab"):
807
+ gr.HTML('<div class="section-header">AI-Powered Market Analysis & Recommendations</div>')
808
+
809
+ with gr.Row():
810
+ with gr.Column():
811
+ gr.HTML('<h3 style="color: #B8860B; text-align: center;">πŸ” Market Intelligence & Forecast Analysis</h3>')
812
+ analysis_output = gr.Textbox(
813
+ label="",
814
+ lines=15,
815
+ interactive=False,
816
+ elem_classes=["results-container"]
817
+ )
818
+
819
+ with gr.Column():
820
+ gr.HTML('<h3 style="color: #B8860B; text-align: center;">⚑ Optimization Recommendations</h3>')
821
+ optimization_output = gr.Textbox(
822
+ label="",
823
+ lines=15,
824
+ interactive=False,
825
+ elem_classes=["results-container"]
826
+ )
827
+
828
+ # Tab 4: Search Results
829
+ with gr.TabItem("🌐 Market Research", elem_id="search-tab"):
830
+ gr.HTML('<div class="section-header">Real-Time Market Intelligence</div>')
831
+
832
+ search_output = gr.Textbox(
833
+ label="πŸ” Market Research Results",
834
+ lines=20,
835
+ interactive=False,
836
+ elem_classes=["results-container"]
837
+ )
838
+
839
+ # Footer
840
+ gr.HTML("""
841
+ <div class="footer">
842
+ <p><strong>AI-Powered Supply Chain Optimizer</strong> | Advanced Analytics & Real-Time Intelligence</p>
843
+ <p>πŸ”§ Built with AutoGen, Tavily API, and Gradio | πŸš€ Powered by OpenAI GPT</p>
844
+ </div>
845
+ """)
846
+
847
+ # Connect the optimization function
848
+ optimize_btn.click(
849
+ fn=process_files_and_optimize,
850
+ inputs=[forecast_file, inventory_file, routes_file, text_input, search_query],
851
+ outputs=[
852
+ forecast_plot,
853
+ inventory_plot,
854
+ route_plot,
855
+ analysis_output,
856
+ optimization_output,
857
+ search_output,
858
+ processing_status
859
+ ],
860
+ show_progress=True
861
+ )
862
+
863
+ # Launch the interface
864
+ if __name__ == "__main__":
865
+ interface.launch(
866
+ server_name="0.0.0.0",
867
+ server_port=7860,
868
+ share=True,
869
+ show_error=True,
870
+ debug=True,
871
+ inbrowser=True
872
+ )