Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>BMS AI Assistant - Standalone Demo</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #D01010; | |
| --primary-dark: #A00C0C; | |
| --bg-color: #F3F4F6; | |
| --chat-bg: #FFFFFF; | |
| --user-msg-bg: #D01010; | |
| --user-msg-text: #FFFFFF; | |
| --bot-msg-bg: #F3F4F6; | |
| --bot-msg-text: #1F2937; | |
| --border-color: #E5E7EB; | |
| --text-color: #1F2937; | |
| --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
| --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background-color: var(--bg-color); | |
| margin: 0; | |
| display: flex; | |
| justify-content: center; | |
| height: 100vh; | |
| color: var(--text-color); | |
| } | |
| .chat-container { | |
| width: 100%; | |
| max-width: 900px; | |
| background-color: var(--chat-bg); | |
| box-shadow: var(--shadow-md); | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| .header { | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 20px; | |
| text-align: center; | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| box-shadow: var(--shadow-sm); | |
| z-index: 10; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 10px; | |
| } | |
| .header svg { | |
| width: 24px; | |
| height: 24px; | |
| fill: currentColor; | |
| } | |
| .demo-badge { | |
| background: #FFA500; | |
| padding: 5px 15px; | |
| border-radius: 20px; | |
| font-size: 0.8em; | |
| margin-left: 10px; | |
| } | |
| .chat-window { | |
| flex: 1; | |
| padding: 20px; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| scroll-behavior: smooth; | |
| } | |
| .message { | |
| max-width: 80%; | |
| padding: 14px 18px; | |
| border-radius: 16px; | |
| line-height: 1.5; | |
| position: relative; | |
| animation: fadeIn 0.3s ease-out; | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| font-size: 0.95rem; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .message.user { | |
| align-self: flex-end; | |
| background-color: var(--user-msg-bg); | |
| color: var(--user-msg-text); | |
| border-bottom-right-radius: 4px; | |
| flex-direction: row-reverse; | |
| } | |
| .message.bot { | |
| align-self: flex-start; | |
| background-color: var(--bot-msg-bg); | |
| color: var(--bot-msg-text); | |
| border-bottom-left-radius: 4px; | |
| border: 1px solid var(--border-color); | |
| } | |
| .icon-container { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| flex-shrink: 0; | |
| background-color: white; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .message.user .icon-container { | |
| color: var(--primary-color); | |
| } | |
| .message.bot .icon-container { | |
| background-color: var(--primary-color); | |
| color: white; | |
| } | |
| .icon-container svg { | |
| width: 20px; | |
| height: 20px; | |
| fill: currentColor; | |
| } | |
| .message-content { | |
| flex: 1; | |
| word-wrap: break-word; | |
| } | |
| .input-area { | |
| padding: 20px; | |
| border-top: 1px solid var(--border-color); | |
| display: flex; | |
| gap: 12px; | |
| background-color: #fff; | |
| align-items: center; | |
| } | |
| input[type="text"] { | |
| flex: 1; | |
| padding: 14px 20px; | |
| border: 1px solid var(--border-color); | |
| border-radius: 30px; | |
| outline: none; | |
| font-size: 1rem; | |
| transition: all 0.2s; | |
| font-family: inherit; | |
| background-color: #F9FAFB; | |
| } | |
| input[type="text"]:focus { | |
| border-color: var(--primary-color); | |
| background-color: #fff; | |
| box-shadow: 0 0 0 3px rgba(208, 16, 16, 0.1); | |
| } | |
| button { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 14px 28px; | |
| border-radius: 30px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: background-color 0.2s, transform 0.1s; | |
| font-family: inherit; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| button:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| button:active { | |
| transform: scale(0.98); | |
| } | |
| .chart-container { | |
| margin-top: 12px; | |
| background: #fff; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| overflow: hidden; | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 0.9rem; | |
| } | |
| th, | |
| td { | |
| padding: 10px 14px; | |
| text-align: left; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| th { | |
| background-color: #F9FAFB; | |
| font-weight: 600; | |
| color: var(--text-color); | |
| } | |
| tr:last-child td { | |
| border-bottom: none; | |
| } | |
| .download-btn { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 10px 20px; | |
| text-decoration: none; | |
| border-radius: 25px; | |
| font-weight: 600; | |
| margin-top: 12px; | |
| transition: background-color 0.2s; | |
| font-size: 0.9rem; | |
| cursor: pointer; | |
| } | |
| .download-btn:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="chat-container"> | |
| <div class="header"> | |
| <svg viewBox="0 0 24 24"> | |
| <path | |
| d="M12 2L2 7l10 5 10-5-10-5zm0 9l2.5-1.25L12 8.5l-2.5 1.25L12 11zm0 2.5l-5-2.5-5 2.5L12 22l10-8.5-5-2.5-5 2.5z" /> | |
| </svg> | |
| BMS AI Assistant | |
| <span class="demo-badge">DEMO MODE</span> | |
| </div> | |
| <div class="chat-window" id="chat-window"> | |
| <div class="message bot"> | |
| <div class="icon-container"> | |
| <svg viewBox="0 0 24 24"> | |
| <path | |
| d="M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7V5.73C9.4 5.39 9 4.74 9 4a2 2 0 0 1 2-2M7.5 13A2.5 2.5 0 0 0 5 15.5A2.5 2.5 0 0 0 7.5 18A2.5 2.5 0 0 0 10 15.5A2.5 2.5 0 0 0 7.5 13m9 0a2.5 2.5 0 0 0-2.5 2.5a2.5 2.5 0 0 0 2.5 2.5a2.5 2.5 0 0 0 2.5-2.5a2.5 2.5 0 0 0-2.5-2.5M12 8a6 6 0 0 0-6 6h12a6 6 0 0 0-6-6z" /> | |
| </svg> | |
| </div> | |
| <div class="message-content"> | |
| <strong>Hello! I am your BMS AI Assistant.</strong><br><br> | |
| I can help you with:<br> | |
| β’ Demand Forecasting (e.g., "Forecast for BMS0015")<br> | |
| β’ Inventory Checks (e.g., "Stock for BMS0015")<br> | |
| β’ Supplier Information<br> | |
| β’ Order Requisitions<br> | |
| β’ General Inquiries<br><br> | |
| How can I assist you today? | |
| </div> | |
| </div> | |
| </div> | |
| <div class="input-area"> | |
| <input type="text" id="user-input" placeholder="Type your query..." autocomplete="off"> | |
| <button onclick="sendMessage()"> | |
| Send | |
| <svg viewBox="0 0 24 24" style="width: 16px; height: 16px;"> | |
| <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <script> | |
| const chatWindow = document.getElementById('chat-window'); | |
| const userInput = document.getElementById('user-input'); | |
| // Mock data | |
| const mockData = { | |
| forecast_bms0015: [ | |
| { date: '2025-12-01', qty: 152 }, | |
| { date: '2025-12-02', qty: 148 }, | |
| { date: '2025-12-03', qty: 155 }, | |
| { date: '2025-12-04', qty: 151 }, | |
| { date: '2025-12-05', qty: 149 }, | |
| { date: '2025-12-06', qty: 153 }, | |
| { date: '2025-12-07', qty: 150 } | |
| ], | |
| forecast_bms0020: [ | |
| { date: '2025-12-01', qty: 89 }, | |
| { date: '2025-12-02', qty: 92 }, | |
| { date: '2025-12-03', qty: 87 }, | |
| { date: '2025-12-04', qty: 90 }, | |
| { date: '2025-12-05', qty: 88 }, | |
| { date: '2025-12-06', qty: 91 }, | |
| { date: '2025-12-07', qty: 89 } | |
| ] | |
| }; | |
| userInput.addEventListener('keypress', function (e) { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| function sendMessage() { | |
| const text = userInput.value.trim(); | |
| if (!text) return; | |
| addMessage(text, 'user'); | |
| userInput.value = ''; | |
| // Simulate processing delay | |
| setTimeout(() => { | |
| const response = processQuery(text.toLowerCase()); | |
| addMessage(response.answer, 'bot', true, response.forecast); | |
| }, 500); | |
| } | |
| function processQuery(query) { | |
| // Greeting | |
| if (query.match(/^(hi|hello|hey|greetings)$/)) { | |
| return { | |
| answer: "Hello! I am the BMS AI Assistant. How can I help you today?" | |
| }; | |
| } | |
| // Forecast | |
| if (query.includes('forecast') || query.includes('predict')) { | |
| if (query.includes('bms0015')) { | |
| return { | |
| answer: "π <strong>Demand Forecast for BMS0015</strong> (Next 30 days)<br><br>Based on historical data analysis using ARIMA model:", | |
| forecast: mockData.forecast_bms0015 | |
| }; | |
| } else if (query.includes('bms0020')) { | |
| return { | |
| answer: "π <strong>Demand Forecast for BMS0020</strong> (Next 30 days)<br><br>Based on historical data analysis using ARIMA model:", | |
| forecast: mockData.forecast_bms0020 | |
| }; | |
| } else { | |
| return { answer: "Please specify an item code (e.g., BMS0015 or BMS0020)." }; | |
| } | |
| } | |
| // Item details | |
| if (query.includes('details') || query.includes('about') || query.includes('info')) { | |
| if (query.includes('bms0015')) { | |
| return { answer: "<strong>Item Details:</strong><br>β’ Code: BMS0015<br>β’ Description: Fuel Water Separator<br>β’ UOM: Each<br>β’ List Price: $45.99" }; | |
| } else if (query.includes('bms0020')) { | |
| return { answer: "<strong>Item Details:</strong><br>β’ Code: BMS0020<br>β’ Description: Lube Oil Filter<br>β’ UOM: Each<br>β’ List Price: $32.50" }; | |
| } | |
| } | |
| // Inventory | |
| if (query.includes('inventory') || query.includes('stock') || query.includes('available')) { | |
| if (query.includes('bms0015')) { | |
| return { answer: "π¦ <strong>Inventory Status for BMS0015:</strong><br>β’ On Hand: 450 units<br>β’ Location: NA Warehouse<br>β’ Last Updated: 2025-11-29" }; | |
| } else if (query.includes('bms0020')) { | |
| return { answer: "π¦ <strong>Inventory Status for BMS0020:</strong><br>β’ On Hand: 320 units<br>β’ Location: NA Warehouse<br>β’ Last Updated: 2025-11-29" }; | |
| } | |
| } | |
| // Supplier | |
| if (query.includes('supplier') || query.includes('vendor') || query.includes('who supplies')) { | |
| return { answer: "π <strong>Supplier Information:</strong><br>β’ Supplier: Acme Filters Inc.<br>β’ Lead Time: 14 days<br>β’ Contact: [email protected]" }; | |
| } | |
| // Order/Requisition | |
| if (query.includes('order') || query.includes('buy') || query.includes('purchase') || query.includes('requisition')) { | |
| const reqId = 'REQ' + Math.floor(Math.random() * 9000 + 1000); | |
| return { answer: `β <strong>Requisition Created Successfully!</strong><br>β’ Requisition ID: ${reqId}<br>β’ Item: BMS0015<br>β’ Quantity: 50<br>β’ Status: Pending` }; | |
| } | |
| // System status | |
| if (query.includes('status') || query.includes('alerts') || query.includes('dashboard')) { | |
| return { answer: "β οΈ <strong>System Alerts:</strong><br>β’ BMS0015: Low stock warning (below reorder point)<br>β’ AB9999: Supplier lead time increased<br><br>β All other systems normal." }; | |
| } | |
| if (query.includes('pdf') || query.includes('download') || query.includes('report')) { | |
| return { answer: 'π <strong>Report Generation</strong><br><br><a href="#" class="download-btn" onclick="alert(\'In production, this would download a PDF report.\'); return false;">π₯ Download Forecast Report</a>' }; | |
| } | |
| // General about BMS | |
| if (query.includes('bms') || query.includes('what do') || query.includes('company')) { | |
| return { answer: "BMS Inc. is a global power leader that designs, manufactures, distributes, and services a broad portfolio of power solutions. Our products range from diesel, natural gas, electric and hybrid powertrains to components including filtration, aftertreatment, and turbochargers." }; | |
| } | |
| // Default | |
| return { answer: "I can help you with demand forecasting, inventory checks, supplier information, and order requisitions. Try asking about item BMS0015 or BMS0020!" }; | |
| } | |
| function addMessage(text, sender, isHtml = false, forecast = null) { | |
| const div = document.createElement('div'); | |
| div.className = `message ${sender}`; | |
| const iconDiv = document.createElement('div'); | |
| iconDiv.className = 'icon-container'; | |
| if (sender === 'user') { | |
| iconDiv.innerHTML = `<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>`; | |
| } else { | |
| iconDiv.innerHTML = `<svg viewBox="0 0 24 24"><path d="M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7V5.73C9.4 5.39 9 4.74 9 4a2 2 0 0 1 2-2M7.5 13A2.5 2.5 0 0 0 5 15.5A2.5 2.5 0 0 0 7.5 18A2.5 2.5 0 0 0 10 15.5A2.5 2.5 0 0 0 7.5 13m9 0a2.5 2.5 0 0 0-2.5 2.5a2.5 2.5 0 0 0 2.5 2.5a2.5 2.5 0 0 0 2.5-2.5a2.5 2.5 0 0 0-2.5-2.5M12 8a6 6 0 0 0-6 6h12a6 6 0 0 0-6-6z"/></svg>`; | |
| } | |
| const contentDiv = document.createElement('div'); | |
| contentDiv.className = 'message-content'; | |
| if (isHtml) { | |
| contentDiv.innerHTML = text; | |
| if (forecast) { | |
| contentDiv.innerHTML += renderForecastTable(forecast); | |
| } | |
| } else { | |
| contentDiv.textContent = text; | |
| } | |
| div.appendChild(iconDiv); | |
| div.appendChild(contentDiv); | |
| chatWindow.appendChild(div); | |
| chatWindow.scrollTop = chatWindow.scrollHeight; | |
| } | |
| function renderForecastTable(forecastData) { | |
| let html = '<div class="chart-container"><table><thead><tr><th>Date</th><th>Quantity</th></tr></thead><tbody>'; | |
| forecastData.forEach(row => { | |
| html += `<tr><td>${row.date}</td><td>${row.qty}</td></tr>`; | |
| }); | |
| html += '</tbody></table></div>'; | |
| return html; | |
| } | |
| </script> | |
| </body> | |
| </html> |