Spaces:
No application file
No application file
| <html lang="vi"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Chatbot Mini PLT</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background: #f4f6f9; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| #chatbox { | |
| max-width: 700px; | |
| margin: 40px auto; | |
| background: white; | |
| border-radius: 16px; | |
| box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08); | |
| padding: 20px; | |
| display: flex; | |
| flex-direction: column; | |
| height: 80vh; | |
| } | |
| #header { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| border-bottom: 1px solid #eee; | |
| padding-bottom: 12px; | |
| margin-bottom: 16px; | |
| } | |
| #header img { | |
| width: 32px; | |
| } | |
| #header h2 { | |
| margin: 0; | |
| font-weight: 600; | |
| color: #1e2a44; | |
| } | |
| #messages { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 10px; | |
| background: #f9fafb; | |
| border-radius: 12px; | |
| scroll-behavior: smooth; | |
| } | |
| .msg { | |
| display: flex; | |
| align-items: flex-end; | |
| margin: 12px 0; | |
| } | |
| .msg .bubble { | |
| padding: 12px 16px; | |
| border-radius: 16px; | |
| max-width: 70%; | |
| word-wrap: break-word; | |
| font-size: 14px; | |
| line-height: 1.4; | |
| } | |
| .msg.user { | |
| justify-content: flex-end; | |
| } | |
| .msg.user .bubble { | |
| background: #1e3a8a; | |
| color: white; | |
| border-bottom-right-radius: 6px; | |
| } | |
| .msg.bot { | |
| justify-content: flex-start; | |
| } | |
| .msg.bot .bubble { | |
| background: #ffffff; | |
| color: #1e2a44; | |
| border: 1px solid #e2e8f0; | |
| border-bottom-left-radius: 6px; | |
| } | |
| #inputArea { | |
| margin-top: 15px; | |
| display: flex; | |
| gap: 10px; | |
| } | |
| #inputArea input[type="text"] { | |
| flex: 1; | |
| padding: 12px; | |
| border: 1px solid #ddd; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| } | |
| #inputArea button, | |
| #uploadLabel { | |
| padding: 10px 18px; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-size: 14px; | |
| transition: 0.2s; | |
| } | |
| #sendBtn { | |
| background: #2563eb; | |
| color: white; | |
| } | |
| #sendBtn:hover { | |
| background: #1d4ed8; | |
| } | |
| #uploadLabel { | |
| background: #64748b; | |
| color: white; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| #uploadLabel:hover { | |
| background: #475569; | |
| } | |
| #fileUpload { | |
| display: none; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="chatbox"> | |
| <div id="header"> | |
| <img src="https://cdn-icons-png.flaticon.com/512/4712/4712035.png" alt="bot"> | |
| <h2>Chatbot Mini</h2> | |
| </div> | |
| <div id="messages"></div> | |
| <div id="inputArea"> | |
| <input id="userInput" type="text" placeholder="Nhập câu hỏi..."> | |
| <button id="sendBtn">Gửi</button> | |
| <label for="fileUpload" id="uploadLabel">📂 Upload Excel</label> | |
| <input type="file" id="fileUpload"> | |
| </div> | |
| </div> | |
| <script> | |
| const API_URL = window.API_URL || "http://127.0.0.1:5000"; // Flask server | |
| const messagesDiv = document.getElementById("messages"); | |
| const userInput = document.getElementById("userInput"); | |
| function addMessage(text, sender) { | |
| const div = document.createElement("div"); | |
| div.className = "msg " + sender; | |
| const bubble = document.createElement("div"); | |
| bubble.className = "bubble"; | |
| bubble.textContent = text; | |
| div.appendChild(bubble); | |
| messagesDiv.appendChild(div); | |
| messagesDiv.scrollTop = messagesDiv.scrollHeight; | |
| } | |
| document.getElementById("sendBtn").onclick = async () => { | |
| const text = userInput.value.trim(); | |
| if (!text) return; | |
| addMessage(text, "user"); | |
| userInput.value = ""; | |
| try { | |
| const res = await fetch(API_URL + "/chat", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ message: text }) | |
| }); | |
| const data = await res.json(); | |
| addMessage(data.reply, "bot"); | |
| } catch { | |
| addMessage("❌ Lỗi kết nối server!", "bot"); | |
| } | |
| }; | |
| document.getElementById("fileUpload").addEventListener("change", async function () { | |
| const file = this.files[0]; | |
| if (!file) return; | |
| addMessage("⏳ Đang upload file " + file.name + "...", "bot"); | |
| const formData = new FormData(); | |
| formData.append("file", file); // 👈 phải khớp với app.py | |
| try { | |
| const res = await fetch(`${API_URL}/upload`, { | |
| method: "POST", | |
| body: formData | |
| }); | |
| const data = await res.json(); | |
| if (data.message) { | |
| addMessage(data.message, "bot"); | |
| } else { | |
| addMessage("❌ " + (data.error || "Lỗi upload!"), "bot"); | |
| } | |
| } catch (err) { | |
| addMessage("❌ Lỗi kết nối server!", "bot"); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |