Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,527 +1,29 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
{"month": "Feb", "sales": 32000, "orders": 280, "customers": 52},
|
| 31 |
-
{"month": "Mar", "sales": 35000, "orders": 310, "customers": 48},
|
| 32 |
-
{"month": "Apr", "sales": 38000, "orders": 340, "customers": 61},
|
| 33 |
-
{"month": "May", "sales": 42000, "orders": 380, "customers": 55},
|
| 34 |
-
{"month": "Jun", "sales": 45000, "orders": 420, "customers": 67},
|
| 35 |
-
]
|
| 36 |
-
|
| 37 |
-
def show_dashboard():
|
| 38 |
-
"""Simple dashboard display"""
|
| 39 |
-
total_products = len(inventory_data)
|
| 40 |
-
in_stock = sum(1 for p in inventory_data if p["stock"] > p["min_stock"])
|
| 41 |
-
low_stock = sum(1 for p in inventory_data if p["stock"] <= p["min_stock"] and p["stock"] > 0)
|
| 42 |
-
out_of_stock = sum(1 for p in inventory_data if p["stock"] == 0)
|
| 43 |
-
|
| 44 |
-
return f"""
|
| 45 |
-
📦 SETA INVENTORY DASHBOARD
|
| 46 |
-
|
| 47 |
-
📊 KEY METRICS:
|
| 48 |
-
• Total Products: {total_products}
|
| 49 |
-
• In Stock: {in_stock}
|
| 50 |
-
• Low Stock: {low_stock}
|
| 51 |
-
• Out of Stock: {out_of_stock}
|
| 52 |
-
|
| 53 |
-
📈 RECENT ACTIVITY:
|
| 54 |
-
• Stock updated: Wireless Headphones
|
| 55 |
-
• Low stock alert: Office Chair
|
| 56 |
-
• New order received
|
| 57 |
-
• Customer registered
|
| 58 |
-
|
| 59 |
-
🚨 ALERTS:
|
| 60 |
-
• Office Chair: Only 8 units left (Min: 15)
|
| 61 |
-
• Laptop Stand: Out of stock (Min: 5)
|
| 62 |
-
"""
|
| 63 |
-
|
| 64 |
-
def show_inventory():
|
| 65 |
-
"""Display inventory table"""
|
| 66 |
-
data = []
|
| 67 |
-
for item in inventory_data:
|
| 68 |
-
status = "In Stock" if item["stock"] > item["min_stock"] else "Low Stock" if item["stock"] > 0 else "Out of Stock"
|
| 69 |
-
data.append([
|
| 70 |
-
item["id"],
|
| 71 |
-
item["name"],
|
| 72 |
-
item["category"],
|
| 73 |
-
item["stock"],
|
| 74 |
-
item["min_stock"],
|
| 75 |
-
f"${item['price']:.2f}",
|
| 76 |
-
status
|
| 77 |
-
])
|
| 78 |
-
|
| 79 |
-
df = pd.DataFrame(data, columns=["ID", "Name", "Category", "Stock", "Min Stock", "Price", "Status"])
|
| 80 |
-
return df
|
| 81 |
-
|
| 82 |
-
def search_products(search_term):
|
| 83 |
-
"""Search products"""
|
| 84 |
-
if not search_term:
|
| 85 |
-
return show_inventory()
|
| 86 |
-
|
| 87 |
-
filtered = [p for p in inventory_data if search_term.lower() in p["name"].lower() or search_term.lower() in p["id"].lower()]
|
| 88 |
-
|
| 89 |
-
data = []
|
| 90 |
-
for item in filtered:
|
| 91 |
-
status = "In Stock" if item["stock"] > item["min_stock"] else "Low Stock" if item["stock"] > 0 else "Out of Stock"
|
| 92 |
-
data.append([
|
| 93 |
-
item["id"],
|
| 94 |
-
item["name"],
|
| 95 |
-
item["category"],
|
| 96 |
-
item["stock"],
|
| 97 |
-
item["min_stock"],
|
| 98 |
-
f"${item['price']:.2f}",
|
| 99 |
-
status
|
| 100 |
-
])
|
| 101 |
-
|
| 102 |
-
df = pd.DataFrame(data, columns=["ID", "Name", "Category", "Stock", "Min Stock", "Price", "Status"])
|
| 103 |
-
return df
|
| 104 |
-
|
| 105 |
-
def scan_product(product_input):
|
| 106 |
-
"""Scan product by ID or name"""
|
| 107 |
-
if not product_input:
|
| 108 |
-
return "Please enter a product ID or name"
|
| 109 |
-
|
| 110 |
-
for product in inventory_data:
|
| 111 |
-
if product_input.upper() in product["id"] or product_input.lower() in product["name"].lower():
|
| 112 |
-
status = "In Stock" if product["stock"] > product["min_stock"] else "Low Stock" if product["stock"] > 0 else "Out of Stock"
|
| 113 |
-
return f"""
|
| 114 |
-
SCAN RESULT:
|
| 115 |
-
Product: {product["name"]}
|
| 116 |
-
ID: {product["id"]}
|
| 117 |
-
Category: {product["category"]}
|
| 118 |
-
Current Stock: {product["stock"]} units
|
| 119 |
-
Minimum Stock: {product["min_stock"]} units
|
| 120 |
-
Price: ${product["price"]:.2f}
|
| 121 |
-
Status: {status}
|
| 122 |
-
"""
|
| 123 |
-
|
| 124 |
-
return f"No product found for: {product_input}"
|
| 125 |
-
|
| 126 |
-
def add_product(product_id, name, category, stock, min_stock, price):
|
| 127 |
-
"""Add new product"""
|
| 128 |
-
if not all([product_id, name, category]):
|
| 129 |
-
return "Please fill in Product ID, Name, and Category"
|
| 130 |
-
|
| 131 |
-
if any(item["id"] == product_id for item in inventory_data):
|
| 132 |
-
return f"Product ID {product_id} already exists!"
|
| 133 |
-
|
| 134 |
-
new_product = {
|
| 135 |
-
"id": product_id,
|
| 136 |
-
"name": name,
|
| 137 |
-
"category": category,
|
| 138 |
-
"stock": int(stock or 0),
|
| 139 |
-
"min_stock": int(min_stock or 0),
|
| 140 |
-
"price": float(price or 0)
|
| 141 |
-
}
|
| 142 |
-
|
| 143 |
-
inventory_data.append(new_product)
|
| 144 |
-
return f"Successfully added {name} to inventory!"
|
| 145 |
-
|
| 146 |
-
def update_stock_level(product_id, new_stock):
|
| 147 |
-
"""Update product stock"""
|
| 148 |
-
if not product_id or new_stock is None:
|
| 149 |
-
return "Please select a product and enter stock amount"
|
| 150 |
-
|
| 151 |
-
for item in inventory_data:
|
| 152 |
-
if item["id"] == product_id:
|
| 153 |
-
old_stock = item["stock"]
|
| 154 |
-
item["stock"] = int(new_stock)
|
| 155 |
-
return f"Updated {item['name']}: {old_stock} → {new_stock} units"
|
| 156 |
-
|
| 157 |
-
return "Product not found"
|
| 158 |
-
|
| 159 |
-
def create_sales_chart():
|
| 160 |
-
"""Create sales trend chart"""
|
| 161 |
-
df = pd.DataFrame(sales_data)
|
| 162 |
-
fig = px.line(df, x='month', y=['sales', 'orders'],
|
| 163 |
-
title='📈 Sales & Orders Trend (6 Months)',
|
| 164 |
-
labels={'value': 'Amount', 'variable': 'Metric'})
|
| 165 |
-
fig.update_layout(height=400)
|
| 166 |
-
return fig
|
| 167 |
-
|
| 168 |
-
def create_inventory_chart():
|
| 169 |
-
"""Create inventory distribution chart"""
|
| 170 |
-
categories = {}
|
| 171 |
-
for item in inventory_data:
|
| 172 |
-
cat = item['category']
|
| 173 |
-
categories[cat] = categories.get(cat, 0) + item['stock']
|
| 174 |
-
|
| 175 |
-
df = pd.DataFrame(list(categories.items()), columns=['Category', 'Stock'])
|
| 176 |
-
fig = px.pie(df, values='Stock', names='Category',
|
| 177 |
-
title='📦 Inventory Distribution by Category')
|
| 178 |
-
fig.update_layout(height=400)
|
| 179 |
-
return fig
|
| 180 |
-
|
| 181 |
-
def create_customer_chart():
|
| 182 |
-
"""Create customer status chart"""
|
| 183 |
-
status_counts = {}
|
| 184 |
-
for customer in customers_data:
|
| 185 |
-
status = customer['status']
|
| 186 |
-
status_counts[status] = status_counts.get(status, 0) + 1
|
| 187 |
-
|
| 188 |
-
df = pd.DataFrame(list(status_counts.items()), columns=['Status', 'Count'])
|
| 189 |
-
fig = px.bar(df, x='Status', y='Count',
|
| 190 |
-
title='👥 Customer Status Distribution')
|
| 191 |
-
fig.update_layout(height=400)
|
| 192 |
-
return fig
|
| 193 |
-
|
| 194 |
-
def process_ocr_image(image):
|
| 195 |
-
"""Process image with simulated OCR"""
|
| 196 |
-
if image is None:
|
| 197 |
-
return "📷 Please upload an image to process with OCR."
|
| 198 |
-
|
| 199 |
-
# Simulate OCR processing
|
| 200 |
-
product_types = ["Fusion", "Agroking", "Jaguar", "Generic"]
|
| 201 |
-
selected_type = random.choice(product_types)
|
| 202 |
-
|
| 203 |
-
if selected_type == "Fusion":
|
| 204 |
-
result = f"""
|
| 205 |
-
🔍 **OCR PROCESSING COMPLETE**
|
| 206 |
-
|
| 207 |
-
**Product Detected:** Fusion Pro Tablet
|
| 208 |
-
**Product ID:** FUS-2024-{random.randint(100, 999)}
|
| 209 |
-
**Manufacturer:** Fusion Tech
|
| 210 |
-
**Price:** $349.99
|
| 211 |
-
**Quantity:** 1 unit
|
| 212 |
-
**Serial Number:** FT{random.randint(10000, 99999)}
|
| 213 |
-
|
| 214 |
-
**Extracted Attributes:**
|
| 215 |
-
• Screen Size: 10.5 inches
|
| 216 |
-
• Storage: 128GB
|
| 217 |
-
• Color: Space Gray
|
| 218 |
-
• Warranty: 12 months
|
| 219 |
-
• Model Year: 2024
|
| 220 |
-
|
| 221 |
-
**OCR Confidence:** {random.randint(88, 97)}%
|
| 222 |
-
**Processing Time:** 2.3 seconds
|
| 223 |
-
**Status:** ✅ Ready for inventory update
|
| 224 |
-
"""
|
| 225 |
-
elif selected_type == "Agroking":
|
| 226 |
-
result = f"""
|
| 227 |
-
🔍 **OCR PROCESSING COMPLETE**
|
| 228 |
-
|
| 229 |
-
**Product Detected:** Agroking Premium Fertilizer
|
| 230 |
-
**Product ID:** AGK-2024-{random.randint(100, 999)}
|
| 231 |
-
**Manufacturer:** Agroking
|
| 232 |
-
**Price:** $45.99
|
| 233 |
-
**Quantity:** 5 bags
|
| 234 |
-
**Batch Number:** BN{random.randint(10000, 99999)}
|
| 235 |
-
|
| 236 |
-
**Extracted Attributes:**
|
| 237 |
-
• Weight: 25kg per bag
|
| 238 |
-
• Type: NPK Fertilizer
|
| 239 |
-
• Composition: 20-10-10
|
| 240 |
-
• Expiry Date: 2025-06-30
|
| 241 |
-
• Organic Certified: Yes
|
| 242 |
-
|
| 243 |
-
**OCR Confidence:** {random.randint(85, 94)}%
|
| 244 |
-
**Processing Time:** 1.8 seconds
|
| 245 |
-
**Status:** ✅ Ready for inventory update
|
| 246 |
-
"""
|
| 247 |
-
elif selected_type == "Jaguar":
|
| 248 |
-
result = f"""
|
| 249 |
-
🔍 **OCR PROCESSING COMPLETE**
|
| 250 |
-
|
| 251 |
-
**Product Detected:** Jaguar Power Drill
|
| 252 |
-
**Product ID:** JAG-2024-{random.randint(100, 999)}
|
| 253 |
-
**Manufacturer:** Jaguar Inc
|
| 254 |
-
**Price:** $129.99
|
| 255 |
-
**Quantity:** 1 unit
|
| 256 |
-
**Serial Number:** JI{random.randint(10000, 99999)}
|
| 257 |
-
|
| 258 |
-
**Extracted Attributes:**
|
| 259 |
-
• Power: 850W
|
| 260 |
-
• Voltage: 220V
|
| 261 |
-
• Warranty: 24 months
|
| 262 |
-
• Accessories: 10 drill bits included
|
| 263 |
-
• Chuck Size: 13mm
|
| 264 |
-
|
| 265 |
-
**OCR Confidence:** {random.randint(90, 98)}%
|
| 266 |
-
**Processing Time:** 2.1 seconds
|
| 267 |
-
**Status:** ✅ Ready for inventory update
|
| 268 |
-
"""
|
| 269 |
-
else:
|
| 270 |
-
result = f"""
|
| 271 |
-
🔍 **OCR PROCESSING COMPLETE**
|
| 272 |
-
|
| 273 |
-
**Product Detected:** Generic Product
|
| 274 |
-
**Product ID:** GEN-{random.randint(1000, 9999)}
|
| 275 |
-
**Manufacturer:** Unknown
|
| 276 |
-
**Price:** ${random.randint(10, 500)}.99
|
| 277 |
-
**Quantity:** {random.randint(1, 10)} units
|
| 278 |
-
|
| 279 |
-
**Extracted Attributes:**
|
| 280 |
-
• Category: Miscellaneous
|
| 281 |
-
• Condition: New
|
| 282 |
-
• Barcode: {random.randint(100000000000, 999999999999)}
|
| 283 |
-
|
| 284 |
-
**OCR Confidence:** {random.randint(70, 85)}%
|
| 285 |
-
**Processing Time:** 3.2 seconds
|
| 286 |
-
**Status:** ⚠️ Manual verification recommended
|
| 287 |
-
"""
|
| 288 |
-
|
| 289 |
-
return result
|
| 290 |
-
|
| 291 |
-
def simulate_salesforce_sync():
|
| 292 |
-
"""Simulate Salesforce synchronization"""
|
| 293 |
-
# Simulate processing time
|
| 294 |
-
success_rate = random.random()
|
| 295 |
-
|
| 296 |
-
if success_rate > 0.1: # 90% success rate
|
| 297 |
-
sf_id = f"SF-{random.randint(100000, 999999)}"
|
| 298 |
-
sync_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 299 |
-
|
| 300 |
-
result = f"""
|
| 301 |
-
☁️ **SALESFORCE SYNC SUCCESSFUL**
|
| 302 |
-
|
| 303 |
-
**Sync Details:**
|
| 304 |
-
• **Salesforce ID:** {sf_id}
|
| 305 |
-
• **Sync Time:** {sync_time}
|
| 306 |
-
• **Objects Updated:** Product2, PricebookEntry, Inventory__c
|
| 307 |
-
• **Fields Mapped:** 12
|
| 308 |
-
• **Records Created:** 1
|
| 309 |
-
• **Records Updated:** 3
|
| 310 |
-
|
| 311 |
-
**Sync Summary:**
|
| 312 |
-
✅ Product information synced
|
| 313 |
-
✅ Pricing data updated
|
| 314 |
-
✅ Inventory levels synchronized
|
| 315 |
-
✅ Supplier information mapped
|
| 316 |
-
✅ Location data updated
|
| 317 |
-
|
| 318 |
-
**Next Steps:**
|
| 319 |
-
• Product is now available in Salesforce
|
| 320 |
-
• Inventory alerts configured
|
| 321 |
-
• Price book entries created
|
| 322 |
-
• Workflow rules activated
|
| 323 |
-
|
| 324 |
-
**Sync Status:** Complete
|
| 325 |
-
**Data Integrity:** 100% verified
|
| 326 |
-
"""
|
| 327 |
-
else:
|
| 328 |
-
error_types = ["Authentication Error", "Field Mapping Error", "Network Timeout", "Duplicate Record"]
|
| 329 |
-
error = random.choice(error_types)
|
| 330 |
-
attempt_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 331 |
-
|
| 332 |
-
result = f"""
|
| 333 |
-
❌ **SALESFORCE SYNC FAILED**
|
| 334 |
-
|
| 335 |
-
**Error Details:**
|
| 336 |
-
• **Error Type:** {error}
|
| 337 |
-
• **Attempt Time:** {attempt_time}
|
| 338 |
-
• **Error Code:** SF-ERR-{random.randint(1000, 9999)}
|
| 339 |
-
|
| 340 |
-
**Possible Causes:**
|
| 341 |
-
• Network connectivity issues
|
| 342 |
-
• Invalid field mappings
|
| 343 |
-
• Authentication token expired
|
| 344 |
-
• Duplicate record constraints
|
| 345 |
-
|
| 346 |
-
**Recommended Actions:**
|
| 347 |
-
• Check network connection
|
| 348 |
-
• Verify Salesforce credentials
|
| 349 |
-
• Review field mapping configuration
|
| 350 |
-
• Contact system administrator
|
| 351 |
-
|
| 352 |
-
**Retry Options:**
|
| 353 |
-
• Automatic retry in 5 minutes
|
| 354 |
-
• Manual retry available
|
| 355 |
-
• Batch sync alternative
|
| 356 |
-
"""
|
| 357 |
-
|
| 358 |
-
return result
|
| 359 |
-
|
| 360 |
-
def search_customers(search_term):
|
| 361 |
-
"""Search customers"""
|
| 362 |
-
if not search_term:
|
| 363 |
-
return get_customers_table()
|
| 364 |
-
|
| 365 |
-
filtered_customers = [
|
| 366 |
-
customer for customer in customers_data
|
| 367 |
-
if search_term.lower() in customer["name"].lower()
|
| 368 |
-
or search_term.lower() in customer["email"].lower()
|
| 369 |
-
or search_term.lower() in customer["company"].lower()
|
| 370 |
-
or search_term.lower() in customer["id"].lower()
|
| 371 |
-
]
|
| 372 |
-
|
| 373 |
-
df_data = []
|
| 374 |
-
for customer in filtered_customers:
|
| 375 |
-
avg_order = customer["total_spent"] / customer["total_orders"] if customer["total_orders"] > 0 else 0
|
| 376 |
-
df_data.append([
|
| 377 |
-
customer["id"],
|
| 378 |
-
customer["name"],
|
| 379 |
-
customer["email"],
|
| 380 |
-
customer["phone"],
|
| 381 |
-
customer["company"],
|
| 382 |
-
customer["total_orders"],
|
| 383 |
-
f"${customer['total_spent']:,.2f}",
|
| 384 |
-
f"${avg_order:.2f}",
|
| 385 |
-
customer["status"]
|
| 386 |
-
])
|
| 387 |
-
|
| 388 |
-
df = pd.DataFrame(df_data, columns=[
|
| 389 |
-
"Customer ID", "Name", "Email", "Phone", "Company",
|
| 390 |
-
"Total Orders", "Total Spent", "Avg Order Value", "Status"
|
| 391 |
-
])
|
| 392 |
-
return df
|
| 393 |
-
|
| 394 |
-
def get_customers_table():
|
| 395 |
-
"""Get customers as DataFrame"""
|
| 396 |
-
df_data = []
|
| 397 |
-
for customer in customers_data:
|
| 398 |
-
avg_order = customer["total_spent"] / customer["total_orders"] if customer["total_orders"] > 0 else 0
|
| 399 |
-
df_data.append([
|
| 400 |
-
customer["id"],
|
| 401 |
-
customer["name"],
|
| 402 |
-
customer["email"],
|
| 403 |
-
customer["phone"],
|
| 404 |
-
customer["company"],
|
| 405 |
-
customer["total_orders"],
|
| 406 |
-
f"${customer['total_spent']:,.2f}",
|
| 407 |
-
f"${avg_order:.2f}",
|
| 408 |
-
customer["status"]
|
| 409 |
-
])
|
| 410 |
-
|
| 411 |
-
df = pd.DataFrame(df_data, columns=[
|
| 412 |
-
"Customer ID", "Name", "Email", "Phone", "Company",
|
| 413 |
-
"Total Orders", "Total Spent", "Avg Order Value", "Status"
|
| 414 |
-
])
|
| 415 |
-
return df
|
| 416 |
-
|
| 417 |
-
def refresh_charts():
|
| 418 |
-
"""Refresh all charts"""
|
| 419 |
-
return create_sales_chart(), create_inventory_chart(), create_customer_chart()
|
| 420 |
-
|
| 421 |
-
# Create simple interfaces
|
| 422 |
-
with gr.Blocks(title="SETA Inventory System") as demo:
|
| 423 |
-
gr.Markdown("# 📦 SETA Inventory Management System")
|
| 424 |
-
|
| 425 |
-
with gr.Tabs():
|
| 426 |
-
with gr.Tab("📊 Dashboard"):
|
| 427 |
-
gr.Markdown("## Dashboard Overview")
|
| 428 |
-
dashboard_btn = gr.Button("Refresh Dashboard")
|
| 429 |
-
dashboard_output = gr.Textbox(label="Dashboard", lines=15, value=show_dashboard())
|
| 430 |
-
dashboard_btn.click(show_dashboard, outputs=dashboard_output)
|
| 431 |
-
|
| 432 |
-
with gr.Tab("📦 Inventory"):
|
| 433 |
-
gr.Markdown("## Product Inventory")
|
| 434 |
-
search_input = gr.Textbox(label="Search Products", placeholder="Enter product name or ID")
|
| 435 |
-
inventory_output = gr.Dataframe(label="Products", value=show_inventory())
|
| 436 |
-
search_input.change(search_products, inputs=search_input, outputs=inventory_output)
|
| 437 |
-
|
| 438 |
-
with gr.Tab("🔍 Scanner"):
|
| 439 |
-
gr.Markdown("## Product Scanner")
|
| 440 |
-
scan_input = gr.Textbox(label="Scan Product", placeholder="Enter product ID or name")
|
| 441 |
-
scan_output = gr.Textbox(label="Scan Result", lines=10)
|
| 442 |
-
scan_btn = gr.Button("Scan")
|
| 443 |
-
scan_btn.click(scan_product, inputs=scan_input, outputs=scan_output)
|
| 444 |
-
|
| 445 |
-
with gr.Tab("➕ Add Product"):
|
| 446 |
-
gr.Markdown("## Add New Product")
|
| 447 |
-
with gr.Row():
|
| 448 |
-
new_id = gr.Textbox(label="Product ID")
|
| 449 |
-
new_name = gr.Textbox(label="Product Name")
|
| 450 |
-
with gr.Row():
|
| 451 |
-
new_category = gr.Dropdown(["Electronics", "Furniture", "Accessories", "Lighting"], label="Category")
|
| 452 |
-
new_stock = gr.Number(label="Stock", value=0)
|
| 453 |
-
with gr.Row():
|
| 454 |
-
new_min_stock = gr.Number(label="Min Stock", value=5)
|
| 455 |
-
new_price = gr.Number(label="Price", value=0.0)
|
| 456 |
-
|
| 457 |
-
add_btn = gr.Button("Add Product")
|
| 458 |
-
add_output = gr.Textbox(label="Result")
|
| 459 |
-
add_btn.click(
|
| 460 |
-
add_product,
|
| 461 |
-
inputs=[new_id, new_name, new_category, new_stock, new_min_stock, new_price],
|
| 462 |
-
outputs=add_output
|
| 463 |
-
)
|
| 464 |
-
|
| 465 |
-
with gr.Tab("📝 Update Stock"):
|
| 466 |
-
gr.Markdown("## Update Stock Levels")
|
| 467 |
-
product_dropdown = gr.Dropdown(
|
| 468 |
-
choices=[f"{item['id']} - {item['name']}" for item in inventory_data],
|
| 469 |
-
label="Select Product"
|
| 470 |
-
)
|
| 471 |
-
stock_input = gr.Number(label="New Stock Amount")
|
| 472 |
-
update_btn = gr.Button("Update Stock")
|
| 473 |
-
update_output = gr.Textbox(label="Update Result")
|
| 474 |
-
|
| 475 |
-
def update_wrapper(product_selection, new_stock):
|
| 476 |
-
if product_selection:
|
| 477 |
-
product_id = product_selection.split(" - ")[0]
|
| 478 |
-
return update_stock_level(product_id, new_stock)
|
| 479 |
-
return "Please select a product"
|
| 480 |
-
|
| 481 |
-
update_btn.click(
|
| 482 |
-
update_wrapper,
|
| 483 |
-
inputs=[product_dropdown, stock_input],
|
| 484 |
-
outputs=update_output
|
| 485 |
-
)
|
| 486 |
-
|
| 487 |
-
with gr.Tab("📈 Analytics"):
|
| 488 |
-
gr.Markdown("## Business Analytics")
|
| 489 |
-
refresh_btn = gr.Button("Refresh Charts")
|
| 490 |
-
|
| 491 |
-
with gr.Row():
|
| 492 |
-
sales_chart = gr.Plot(label="Sales Trend")
|
| 493 |
-
inventory_chart = gr.Plot(label="Inventory Distribution")
|
| 494 |
-
|
| 495 |
-
customer_chart = gr.Plot(label="Customer Status")
|
| 496 |
-
|
| 497 |
-
# Set initial chart values
|
| 498 |
-
refresh_btn.click(
|
| 499 |
-
refresh_charts,
|
| 500 |
-
outputs=[sales_chart, inventory_chart, customer_chart]
|
| 501 |
-
)
|
| 502 |
-
|
| 503 |
-
with gr.Tab("👥 Customers"):
|
| 504 |
-
gr.Markdown("## Customer Directory")
|
| 505 |
-
customer_search_input = gr.Textbox(label="Search Customers", placeholder="Enter customer name, email, company, or ID")
|
| 506 |
-
customer_output = gr.Dataframe(label="Customers", value=get_customers_table())
|
| 507 |
-
customer_search_input.change(search_customers, inputs=customer_search_input, outputs=customer_output)
|
| 508 |
-
|
| 509 |
-
with gr.Tab("📷 OCR Scanner"):
|
| 510 |
-
gr.Markdown("## OCR Scanner")
|
| 511 |
-
ocr_image_input = gr.Image(label="Upload Product Image")
|
| 512 |
-
ocr_output = gr.Textbox(label="OCR Results", lines=20)
|
| 513 |
-
ocr_image_input.change(process_ocr_image, inputs=ocr_image_input, outputs=ocr_output)
|
| 514 |
-
|
| 515 |
-
with gr.Tab("☁️ Salesforce Sync"):
|
| 516 |
-
gr.Markdown("## Salesforce Sync")
|
| 517 |
-
salesforce_sync_btn = gr.Button("Sync with Salesforce")
|
| 518 |
-
salesforce_sync_output = gr.Textbox(label="Salesforce Sync Results", lines=20)
|
| 519 |
-
salesforce_sync_btn.click(simulate_salesforce_sync, outputs=salesforce_sync_output)
|
| 520 |
-
|
| 521 |
-
if __name__ == "__main__":
|
| 522 |
-
print("🚀 Starting SETA Inventory System...")
|
| 523 |
-
demo.launch(
|
| 524 |
-
share=True,
|
| 525 |
-
server_name="0.0.0.0",
|
| 526 |
-
server_port=7860
|
| 527 |
-
)
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from fastapi.staticfiles import StaticFiles
|
| 3 |
+
from simple_salesforce import Salesforce
|
| 4 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 5 |
+
|
| 6 |
+
app = FastAPI()
|
| 7 |
+
|
| 8 |
+
# CORS for frontend communication
|
| 9 |
+
app.add_middleware(
|
| 10 |
+
CORSMiddleware,
|
| 11 |
+
allow_origins=["*"],
|
| 12 |
+
allow_methods=["*"],
|
| 13 |
+
allow_headers=["*"],
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
# Serve static files (Next.js build)
|
| 17 |
+
app.mount("/", StaticFiles(directory="static", html=True), name="static")
|
| 18 |
+
|
| 19 |
+
# Salesforce setup (replace with real creds)
|
| 20 |
+
sf = Salesforce(
|
| 21 |
+
username='your@email.com',
|
| 22 |
+
password='yourpassword',
|
| 23 |
+
security_token='yoursecuritytoken'
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
@app.get("/api/inventory")
|
| 27 |
+
def get_inventory():
|
| 28 |
+
result = sf.query("SELECT Id, Name, Quantity__c FROM Inventory__c")
|
| 29 |
+
return result['records']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|