Download components/chat-component.js from secutorpro/comsync-pro-team-connect-hub: direct link, hf CLI and curl.
- Browser
- Download file 9 kB
-
https://huggingface.co/spaces/secutorpro/comsync-pro-team-connect-hub/resolve/main/components/chat-component.js
- Command line
-
hf download hf://spaces/secutorpro/comsync-pro-team-connect-hub/components/chat-component.js
-
curl -L -o chat-component.js https://huggingface.co/spaces/secutorpro/comsync-pro-team-connect-hub/resolve/main/components/chat-component.js
9 kB
| class ChatComponent extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.client = null; | |
| this.messages = [ | |
| { | |
| role: "assistant", | |
| content: "Hello! I'm your AI assistant. How can I help you today?" | |
| } | |
| ]; | |
| } | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.render(); | |
| this.initializeOpenAI(); | |
| this.setupEventListeners(); | |
| } | |
| render() { | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .chat-container { | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| background: rgba(31, 41, 55, 0.8); | |
| backdrop-filter: blur(10px); | |
| border-radius: 0.75rem; | |
| border: 1px solid rgba(75, 85, 99, 0.5); | |
| overflow: hidden; | |
| } | |
| .messages-container { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 1rem; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1rem; | |
| } | |
| .message { | |
| max-width: 80%; | |
| padding: 1rem; | |
| border-radius: 12px; | |
| animation: slideIn 0.3s ease-out; | |
| } | |
| .message-user { | |
| align-self: flex-end; | |
| background: linear-gradient(135deg, #3b82f6, #8b5cf6); | |
| } | |
| .message-ai { | |
| align-self: flex-start; | |
| background: rgba(55, 65, 81, 0.8); | |
| } | |
| .message-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| font-weight: 600; | |
| } | |
| .input-container { | |
| padding: 1rem; | |
| border-top: 1px solid rgba(75, 85, 99, 0.5); | |
| background: rgba(31, 41, 55, 0.9); | |
| } | |
| .input-form { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .message-input { | |
| flex: 1; | |
| background: rgba(55, 65, 81, 0.5); | |
| border: 1px solid #4b5563; | |
| border-radius: 0.5rem; | |
| padding: 0.75rem 1rem; | |
| color: #f3f4f6; | |
| font-family: inherit; | |
| } | |
| .message-input:focus { | |
| outline: none; | |
| border-color: #3b82f6; | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); | |
| } | |
| .send-button { | |
| background: #3b82f6; | |
| color: white; | |
| border: none; | |
| border-radius: 0.5rem; | |
| padding: 0 1.5rem; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .send-button:hover { | |
| background: #2563eb; | |
| } | |
| .typing-indicator { | |
| display: flex; | |
| align-self: flex-start; | |
| background: rgba(55, 65, 81, 0.8); | |
| padding: 1rem; | |
| border-radius: 12px 12px 12px 0; | |
| gap: 0.25rem; | |
| } | |
| .typing-dot { | |
| width: 0.5rem; | |
| height: 0.5rem; | |
| background: #9ca3af; | |
| border-radius: 50%; | |
| animation: typing 1.4s infinite ease-in-out; | |
| } | |
| .typing-dot:nth-child(1) { animation-delay: 0s; } | |
| .typing-dot:nth-child(2) { animation-delay: 0.2s; } | |
| .typing-dot:nth-child(3) { animation-delay: 0.4s; } | |
| @keyframes slideIn { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes typing { | |
| 0%, 60%, 100% { transform: translateY(0); } | |
| 30% { transform: translateY(-5px); } | |
| } | |
| </style> | |
| <div class="chat-container"> | |
| <div class="messages-container" id="messagesContainer"> | |
| <!-- Messages will be inserted here --> | |
| </div> | |
| <div class="input-container"> | |
| <form class="input-form" id="chatForm"> | |
| <input type="text" class="message-input" id="messageInput" placeholder="Type your message..." autocomplete="off"> | |
| <button type="submit" class="send-button" id="sendButton"> | |
| <i data-feather="send"></i> | |
| </button> | |
| </form> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| initializeOpenAI() { | |
| // Note: In a real implementation, the API key should be handled securely on the server-side | |
| // This is just for demonstration purposes | |
| try { | |
| // Load Feather icons | |
| const script = document.createElement('script'); | |
| script.src = "https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"; | |
| script.onload = () => { | |
| if (this.shadowRoot) { | |
| window.feather.replace(); | |
| } | |
| }; | |
| this.shadowRoot.appendChild(script); | |
| } catch (error) { | |
| console.error('Error initializing OpenAI:', error); | |
| } | |
| } | |
| setupEventListeners() { | |
| const form = this.shadowRoot.getElementById('chatForm'); | |
| const input = this.shadowRoot.getElementById('messageInput'); | |
| form.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const message = input.value.trim(); | |
| if (message) { | |
| this.sendMessage(message); | |
| input.value = ''; | |
| } | |
| }); | |
| // Load initial messages | |
| this.loadMessages(); | |
| } | |
| loadMessages() { | |
| const container = this.shadowRoot.getElementById('messagesContainer'); | |
| container.innerHTML = ''; | |
| this.messages.forEach(msg => { | |
| this.displayMessage(msg); | |
| }); | |
| container.scrollTop = container.scrollHeight; | |
| } | |
| displayMessage(message) { | |
| const container = this.shadowRoot.getElementById('messagesContainer'); | |
| if (!container) return; | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message message-${message.role || 'user'}`; | |
| let icon = 'user'; | |
| let name = 'You'; | |
| if (message.role === 'assistant') { | |
| icon = 'cpu'; | |
| name = 'AI Assistant'; | |
| } | |
| const safeContent = (message.content && String(message.content)) || ''; | |
| messageDiv.innerHTML = ` | |
| <div class="message-header"> | |
| <i data-feather="${icon}" style="width: 16px; height: 16px;"></i> | |
| <span>${name}</span> | |
| </div> | |
| <div>${safeContent}</div> | |
| `; | |
| container.appendChild(messageDiv); | |
| if (typeof window.feather !== 'undefined' && window.feather.replace) { | |
| window.feather.replace(); | |
| } | |
| container.scrollTop = container.scrollHeight; | |
| } | |
| showTypingIndicator() { | |
| const container = this.shadowRoot.getElementById('messagesContainer'); | |
| const typingDiv = document.createElement('div'); | |
| typingDiv.className = 'typing-indicator'; | |
| typingDiv.id = 'typingIndicator'; | |
| typingDiv.innerHTML = ` | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| `; | |
| container.appendChild(typingDiv); | |
| container.scrollTop = container.scrollHeight; | |
| } | |
| hideTypingIndicator() { | |
| const indicator = this.shadowRoot.getElementById('typingIndicator'); | |
| if (indicator) { | |
| indicator.remove(); | |
| } | |
| } | |
| async sendMessage(content) { | |
| // Add user message to UI | |
| const userMessage = { role: 'user', content }; | |
| this.messages.push(userMessage); | |
| this.displayMessage(userMessage); | |
| // Show typing indicator | |
| this.showTypingIndicator(); | |
| try { | |
| // In a real implementation, this would call the actual API | |
| // For now, we'll simulate a response | |
| const response = await this.getAIResponse(content); | |
| // Add AI response to UI | |
| const aiMessage = { role: 'assistant', content: response }; | |
| this.messages.push(aiMessage); | |
| this.hideTypingIndicator(); | |
| this.displayMessage(aiMessage); | |
| } catch (error) { | |
| console.error('Error getting AI response:', error); | |
| this.hideTypingIndicator(); | |
| const errorMessage = { | |
| role: 'assistant', | |
| content: 'Sorry, I encountered an error. Please try again.' | |
| }; | |
| this.messages.push(errorMessage); | |
| this.displayMessage(errorMessage); | |
| } | |
| } | |
| async getAIResponse(prompt) { | |
| // Simulate API delay | |
| await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 2000)); | |
| // Simple response logic for demonstration | |
| const responses = [ | |
| "I understand your question about \"" + prompt + "\". Based on my analysis, this is an important topic that requires careful consideration.", | |
| "Thanks for asking about \"" + prompt + "\". I've processed your request and here's what I found...", | |
| "Regarding \"" + prompt + "\", I can provide some insights. This is a complex matter with several factors to consider.", | |
| "I've analyzed your query about \"" + prompt + "\". Here's what I recommend based on current best practices.", | |
| "That's an interesting question about \"" + prompt + "\". Let me break this down for you..." | |
| ]; | |
| return responses[Math.floor(Math.random() * responses.length)] + | |
| " This is a simulated response. In a real implementation, this would connect to the Gemma v4 API."; | |
| } | |
| } | |
| customElements.define('chat-component', ChatComponent); |