kickvista / components /chatbot.js
luizdal18's picture
reaf all usert input and enhance add llm to all this as a bot helper a new way to interact with innterface
694023c verified
class ChatBot extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
:host {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
font-family: 'Inter', sans-serif;
}
.chat-container {
position: relative;
}
.chat-toggle {
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.chat-toggle:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
}
.chat-window {
position: absolute;
bottom: 70px;
right: 0;
width: 350px;
height: 450px;
background: white;
border-radius: 16px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
opacity: 0;
visibility: hidden;
transform: translateY(20px);
transition: all 0.3s ease;
}
.chat-window.open {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.chat-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 16px;
border-radius: 16px 16px 0 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.chat-title {
font-weight: 600;
font-size: 16px;
}
.close-chat {
background: none;
border: none;
color: white;
cursor: pointer;
font-size: 20px;
}
.chat-messages {
flex: 1;
padding: 16px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 12px;
}
.message {
max-width: 80%;
padding: 12px 16px;
border-radius: 18px;
font-size: 14px;
line-height: 1.4;
}
.user-message {
align-self: flex-end;
background: #667eea;
color: white;
border-bottom-right-radius: 4px;
}
.bot-message {
align-self: flex-start;
background: #f1f5f9;
color: #1e293b;
border-bottom-left-radius: 4px;
}
.chat-input {
display: flex;
padding: 16px;
border-top: 1px solid #e2e8f0;
gap: 8px;
}
.message-input {
flex: 1;
padding: 12px 16px;
border: 1px solid #cbd5e1;
border-radius: 24px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
.message-input:focus {
border-color: #667eea;
}
.send-button {
width: 40px;
height: 40px;
border-radius: 50%;
background: #667eea;
color: white;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}
.send-button:hover {
background: #5a6fd8;
}
.typing-indicator {
align-self: flex-start;
background: #f1f5f9;
padding: 12px 16px;
border-radius: 18px;
display: none;
}
.typing-dots {
display: flex;
gap: 4px;
}
.dot {
width: 8px;
height: 8px;
background: #94a3b8;
border-radius: 50%;
animation: bounce 1.5s infinite;
}
.dot:nth-child(2) {
animation-delay: 0.2s;
}
.dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
</style>
<div class="chat-container">
<button class="chat-toggle" id="chatToggle">
<i data-feather="message-circle"></i>
</button>
<div class="chat-window" id="chatWindow">
<div class="chat-header">
<div class="chat-title">SoccerViz Assistant</div>
<button class="close-chat" id="closeChat">×</button>
</div>
<div class="chat-messages" id="chatMessages">
<div class="message bot-message">
Hello! I'm your SoccerViz assistant. How can I help you with football analytics today?
</div>
</div>
<div class="typing-indicator" id="typingIndicator">
<div class="typing-dots">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>
<div class="chat-input">
<input type="text" class="message-input" id="messageInput" placeholder="Ask about players, teams, or stats...">
<button class="send-button" id="sendButton">
<i data-feather="send"></i>
</button>
</div>
</div>
</div>
`;
this.init();
}
init() {
// Load Feather icons
if (typeof feather !== 'undefined') {
setTimeout(() => {
feather.replace();
}, 100);
}
// Get elements
this.chatToggle = this.shadowRoot.getElementById('chatToggle');
this.chatWindow = this.shadowRoot.getElementById('chatWindow');
this.closeChat = this.shadowRoot.getElementById('closeChat');
this.chatMessages = this.shadowRoot.getElementById('chatMessages');
this.messageInput = this.shadowRoot.getElementById('messageInput');
this.sendButton = this.shadowRoot.getElementById('sendButton');
this.typingIndicator = this.shadowRoot.getElementById('typingIndicator');
// Event listeners
this.chatToggle.addEventListener('click', () => this.toggleChat());
this.closeChat.addEventListener('click', () => this.closeChatWindow());
this.sendButton.addEventListener('click', () => this.sendMessage());
this.messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.sendMessage();
}
});
}
toggleChat() {
this.chatWindow.classList.toggle('open');
}
closeChatWindow() {
this.chatWindow.classList.remove('open');
}
async sendMessage() {
const message = this.messageInput.value.trim();
if (!message) return;
// Add user message
this.addMessage(message, 'user');
this.messageInput.value = '';
// Show typing indicator
this.typingIndicator.style.display = 'block';
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
try {
// Simulate API call to LLM
const response = await this.getLLMResponse(message);
this.typingIndicator.style.display = 'none';
this.addMessage(response, 'bot');
} catch (error) {
this.typingIndicator.style.display = 'none';
this.addMessage("Sorry, I encountered an error. Please try again.", 'bot');
}
}
async getLLMResponse(message) {
// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000));
// Simple response logic - in a real app, this would call an actual LLM API
const responses = {
"hello": "Hi there! I'm here to help you with football analytics. What would you like to know?",
"help": "I can help you with player stats, team comparisons, match insights, and more. Try asking questions like 'Who is the top scorer?' or 'Compare Messi and Ronaldo'.",
"player": "I can show you detailed stats for any player. Which player would you like to know more about?",
"team": "I have data on teams from major leagues. Which team are you interested in?",
"stat": "I can provide various statistics including goals, assists, passing accuracy, defensive actions, and more.",
"default": "I understand you're asking about football analytics. Could you be more specific? I can help with player stats, team performance, or match insights."
};
const lowerMessage = message.toLowerCase();
if (lowerMessage.includes("hello") || lowerMessage.includes("hi")) return responses.hello;
if (lowerMessage.includes("help")) return responses.help;
if (lowerMessage.includes("player")) return responses.player;
if (lowerMessage.includes("team")) return responses.team;
if (lowerMessage.includes("stat")) return responses.stat;
return responses.default;
}
addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}-message`;
messageDiv.textContent = text;
this.chatMessages.appendChild(messageDiv);
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
}
}
customElements.define('chat-bot', ChatBot);