Download index.html from Hodely/AmsideAi: direct link, hf CLI and curl.
- Browser
- Download file 19 kB
-
https://huggingface.co/spaces/Hodely/AmsideAi/resolve/main/index.html
- Command line
-
hf download hf://spaces/Hodely/AmsideAi/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Hodely/AmsideAi/resolve/main/index.html
19 kB
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Amside AI - Interfaz con IA Real</title> | |
| <style> | |
| :root { | |
| --primary-color: #22272b; /* Dark Background */ | |
| --secondary-color: #37404a; /* Darker Grey */ | |
| --accent-color: #00bcd4; /* Cyan */ | |
| --text-color-primary: #eee; | |
| --text-color-secondary: #ccc; | |
| --error-color: #f44336; /* Red accent */ | |
| --border-radius: 8px; | |
| --box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); | |
| --transition: all 0.3s ease-in-out; | |
| --sidebar-width: 300px; | |
| } | |
| body { | |
| font-family: 'Roboto Mono', monospace; | |
| background-color: var(--primary-color); | |
| color: var(--text-color-primary); | |
| margin: 0; | |
| display: flex; | |
| min-height: 100vh; | |
| padding: 0; | |
| } | |
| .sidebar { | |
| background-color: var(--secondary-color); | |
| width: var(--sidebar-width); | |
| border-right: 1px solid #444d57; | |
| padding: 25px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| flex-shrink: 0; | |
| } | |
| .sidebar-header { | |
| color: var(--text-color-primary); | |
| margin-bottom: 30px; | |
| text-align: left; | |
| width: 100%; | |
| } | |
| .sidebar-header h2 { | |
| margin: 0; | |
| font-size: 1.8em; | |
| font-weight: 400; | |
| } | |
| .new-chat-button { | |
| background-color: var(--accent-color); | |
| color: var(--text-color-primary); | |
| border: none; | |
| padding: 12px 18px; | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| font-size: 1em; | |
| margin-bottom: 20px; | |
| transition: background-color var(--transition); | |
| width: 100%; | |
| text-align: left; | |
| display: flex; | |
| align-items: center; | |
| justify-content: flex-start; | |
| } | |
| .new-chat-button svg { | |
| margin-right: 10px; | |
| } | |
| .chat-list-title { | |
| font-size: 0.9em; | |
| color: var(--text-color-secondary); | |
| margin-bottom: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.8px; | |
| } | |
| .chat-list { | |
| list-style: none; | |
| padding: 0; | |
| margin: 0; | |
| width: 100%; | |
| } | |
| .chat-list li { | |
| padding: 10px 15px; | |
| border-radius: var(--border-radius); | |
| margin-bottom: 6px; | |
| cursor: pointer; | |
| background-color: #2c343c; | |
| color: var(--text-color-secondary); | |
| transition: background-color var(--transition), color var(--transition); | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .chat-list li:hover { | |
| background-color: var(--accent-color); | |
| color: var(--text-color-primary); | |
| } | |
| .chat-container { | |
| background-color: var(--primary-color); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--box-shadow); | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| flex-grow: 1; | |
| margin: 20px; | |
| border: 1px solid #333a40; | |
| } | |
| .chat-header { | |
| background-color: var(--secondary-color); | |
| color: var(--text-color-primary); | |
| padding: 15px 20px; | |
| text-align: left; | |
| border-bottom: 1px solid #444d57; | |
| border-top-left-radius: var(--border-radius); | |
| border-top-right-radius: var(--border-radius); | |
| display: flex; | |
| align-items: center; | |
| } | |
| .chat-header button { | |
| background: none; | |
| border: none; | |
| color: var(--text-color-primary); | |
| font-size: 1em; | |
| cursor: pointer; | |
| margin-right: 20px; | |
| padding: 8px 12px; | |
| border-radius: var(--border-radius); | |
| transition: background-color var(--transition); | |
| } | |
| .chat-header button:hover { | |
| background-color: #444d57; | |
| } | |
| .chat-header h2 { | |
| margin: 0; | |
| font-size: 1.4em; | |
| font-weight: 400; | |
| } | |
| .chat-body { | |
| padding: 20px; | |
| overflow-y: auto; | |
| flex-grow: 1; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| } | |
| .message { | |
| background-color: #2c343c; | |
| color: var(--text-color-secondary); | |
| border-radius: var(--border-radius); | |
| padding: 10px 14px; | |
| word-break: break-word; | |
| align-self: flex-start; | |
| max-width: 80%; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| font-size: 0.95em; | |
| } | |
| .error-message { | |
| background-color: #422b2b; | |
| color: var(--error-color); | |
| border-radius: var(--border-radius); | |
| padding: 10px 14px; | |
| word-break: break-word; | |
| align-self: flex-start; | |
| max-width: 80%; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| font-size: 0.95em; | |
| border: 1px solid #5a3232; | |
| } | |
| .user-message-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-end; | |
| max-width: 80%; | |
| align-self: flex-end; | |
| } | |
| .user-message { | |
| background-color: var(--accent-color); | |
| color: var(--text-color-primary); | |
| border-radius: var(--border-radius); | |
| padding: 10px 14px; | |
| word-break: break-word; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| font-size: 0.95em; | |
| margin-bottom: 5px; | |
| } | |
| .loading-indicator { | |
| display: flex; | |
| align-self: flex-end; | |
| margin-top: 5px; | |
| align-items: center; | |
| font-size: 0.8em; | |
| color: var(--text-color-secondary); | |
| } | |
| .loading-spinner { | |
| border: 2px solid rgba(255, 255, 255, 0.1); | |
| border-top: 2px solid var(--accent-color); | |
| border-radius: 50%; | |
| width: 14px; | |
| height: 14px; | |
| animation: spin 1s linear infinite; | |
| margin-left: 6px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .input-area { | |
| padding: 15px; | |
| border-top: 1px solid #444d57; | |
| display: flex; | |
| align-items: center; | |
| background-color: var(--secondary-color); | |
| border-bottom-left-radius: var(--border-radius); | |
| border-bottom-right-radius: var(--border-radius); | |
| } | |
| .input-field { | |
| flex-grow: 1; | |
| padding: 10px 12px; | |
| border: 1px solid #555e68; | |
| border-radius: var(--border-radius); | |
| margin-right: 10px; | |
| font-size: 0.95em; | |
| color: var(--text-color-primary); | |
| background-color: #2c343c; | |
| } | |
| .input-field:focus { | |
| outline: none; | |
| border-color: var(--accent-color); | |
| box-shadow: 0 1px 3px rgba(var(--accent-color-rgb), 0.2); | |
| } | |
| .send-button { | |
| background-color: var(--accent-color); | |
| color: var(--text-color-primary); | |
| border: none; | |
| padding: 10px 15px; | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| font-size: 0.95em; | |
| transition: background-color var(--transition); | |
| } | |
| .send-button:hover { | |
| background-color: #00838f; /* Cyan darken-1 */ | |
| } | |
| </style> | |
| <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet"> | |
| </head> | |
| <body> | |
| <div class="sidebar"> | |
| <div class="sidebar-header"> | |
| <h2>Amside AI</h2> | |
| </div> | |
| <button class="new-chat-button" id="new-chat-button"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square-fill" viewBox="0 0 16 16"> | |
| <path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z"/> | |
| </svg> | |
| Nueva Conversación | |
| </button> | |
| <h3 class="chat-list-title">Historial</h3> | |
| <ul class="chat-list" id="chat-list"> | |
| </ul> | |
| </div> | |
| <div class="chat-container"> | |
| <div class="chat-header"> | |
| <button id="new-conversation-header-button"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square-fill" viewBox="0 0 16 16"> | |
| <path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z"/> | |
| </svg> | |
| Nuevo | |
| </button> | |
| <h2>Chat</h2> | |
| </div> | |
| <div class="chat-body" id="chat-messages"> | |
| </div> | |
| <div class="input-area"> | |
| <input type="text" class="input-field" placeholder="Escribe tu mensaje..."> | |
| <button class="send-button" id="send-button">Enviar</button> | |
| </div> | |
| </div> | |
| <script> | |
| const chatMessages = document.getElementById('chat-messages'); | |
| const inputField = document.querySelector('.input-field'); | |
| const sendButton = document.getElementById('send-button'); | |
| const chatList = document.getElementById('chat-list'); | |
| const newChatButtonSidebar = document.getElementById('new-chat-button'); | |
| const newChatButtonHeader = document.getElementById('new-conversation-header-button'); | |
| let chatHistory = []; | |
| let currentChat = []; | |
| // --- URL de tu servidor backend --- | |
| // Asegúrate de que esta URL coincida con la dirección y el puerto donde se ejecuta tu app.py | |
| const BACKEND_URL = 'http://127.0.0.1:5000/chat'; | |
| // Función para añadir un solo mensaje al chat | |
| function addMessageToChat(msg) { | |
| const messageContainer = document.createElement('div'); | |
| if (msg.sender === 'user') { | |
| messageContainer.classList.add('user-message-container'); | |
| const userMessageDiv = document.createElement('div'); | |
| userMessageDiv.classList.add('user-message'); | |
| userMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(userMessageDiv); | |
| } else if (msg.sender === 'ai') { | |
| const aiMessageDiv = document.createElement('div'); | |
| aiMessageDiv.classList.add('message'); | |
| aiMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(aiMessageDiv); | |
| } else if (msg.sender === 'error') { | |
| const errorMessageDiv = document.createElement('div'); | |
| errorMessageDiv.classList.add('error-message'); | |
| errorMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(errorMessageDiv); | |
| } | |
| chatMessages.appendChild(messageContainer); | |
| scrollToBottom(); | |
| } | |
| // Esta función se usa para cargar un historial completo (ej. al seleccionar un chat de la lista) | |
| function displayChat(messages) { | |
| chatMessages.innerHTML = ''; // Vaciar todo antes de cargar el historial | |
| messages.forEach(msg => { | |
| const messageContainer = document.createElement('div'); | |
| if (msg.sender === 'user') { | |
| messageContainer.classList.add('user-message-container'); | |
| const userMessageDiv = document.createElement('div'); | |
| userMessageDiv.classList.add('user-message'); | |
| userMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(userMessageDiv); | |
| } else if (msg.sender === 'ai') { | |
| const aiMessageDiv = document.createElement('div'); | |
| aiMessageDiv.classList.add('message'); | |
| aiMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(aiMessageDiv); | |
| } else if (msg.sender === 'error') { | |
| const errorMessageDiv = document.createElement('div'); | |
| errorMessageDiv.classList.add('error-message'); | |
| errorMessageDiv.textContent = msg.text; | |
| messageContainer.appendChild(errorMessageDiv); | |
| } | |
| chatMessages.appendChild(messageContainer); | |
| }); | |
| scrollToBottom(); | |
| } | |
| function updateChatList() { | |
| chatList.innerHTML = ''; | |
| chatHistory.forEach((chat, index) => { | |
| const listItem = document.createElement('li'); | |
| listItem.textContent = chat.name.substring(0, 22) + (chat.name.length > 22 ? '...' : ''); | |
| listItem.addEventListener('click', () => { | |
| currentChat = chat.messages; | |
| displayChat(currentChat); | |
| }); | |
| chatList.appendChild(listItem); | |
| }); | |
| } | |
| function saveChat(firstUserMessage) { | |
| if (currentChat.length > 0 && firstUserMessage) { | |
| const chatName = firstUserMessage.substring(0, 25); | |
| if (!chatHistory.some(chat => chat.messages === currentChat) && currentChat.length > 1) { | |
| chatHistory.unshift({ name: chatName, messages: [...currentChat] }); | |
| updateChatList(); | |
| } | |
| } | |
| } | |
| function startNewChat() { | |
| if (currentChat.length > 1 && currentChat[0].sender === 'ai' && currentChat[1].sender === 'user') { | |
| saveChat(currentChat[1].text); | |
| } | |
| currentChat = [{ sender: 'ai', text: 'Bienvenido a Amside AI. Estoy aquí para ayudarte. ¿Qué te gustaría saber?' }]; | |
| displayChat(currentChat); | |
| } | |
| sendButton.addEventListener('click', async () => { | |
| const messageText = inputField.value.trim(); | |
| if (messageText === '') { | |
| return; | |
| } | |
| const isFirstUserMessageInChat = currentChat.length === 1 && currentChat[0].sender === 'ai'; | |
| const userMessage = { sender: 'user', text: messageText }; | |
| currentChat.push(userMessage); | |
| const userMessageContainer = document.createElement('div'); | |
| userMessageContainer.classList.add('user-message-container'); | |
| const userMessageDiv = document.createElement('div'); | |
| userMessageDiv.classList.add('user-message'); | |
| userMessageDiv.textContent = userMessage.text; | |
| userMessageContainer.appendChild(userMessageDiv); | |
| const loadingIndicator = document.createElement('div'); | |
| loadingIndicator.classList.add('loading-indicator'); | |
| loadingIndicator.innerHTML = '<div class="loading-spinner"></div> Procesando...'; | |
| userMessageContainer.appendChild(loadingIndicator); | |
| chatMessages.appendChild(userMessageContainer); | |
| scrollToBottom(); | |
| inputField.value = ''; | |
| try { | |
| // Preparamos los mensajes en el formato que espera el backend de Python | |
| // (que a su vez los prepara para Hugging Face) | |
| const messagesForBackend = currentChat.map(msg => ({ | |
| role: msg.sender === 'user' ? 'user' : 'assistant', | |
| content: msg.text | |
| })); | |
| const response = await fetch(BACKEND_URL, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ messages: messagesForBackend }), | |
| }); | |
| if (!response.ok) { | |
| const errorData = await response.json(); | |
| throw new Error(errorData.error || `HTTP error! status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| const aiResponseText = data.response; // La respuesta de la IA viene en 'response' | |
| const aiResponse = { sender: 'ai', text: aiResponseText }; | |
| currentChat.push(aiResponse); | |
| if (loadingIndicator && userMessageContainer.contains(loadingIndicator)) { | |
| loadingIndicator.remove(); | |
| } | |
| addMessageToChat(aiResponse); | |
| if (isFirstUserMessageInChat) { | |
| saveChat(messageText); | |
| } | |
| } catch (error) { | |
| console.error("Error al obtener respuesta de la IA (backend):", error); | |
| if (loadingIndicator && userMessageContainer.contains(loadingIndicator)) { | |
| loadingIndicator.remove(); | |
| } | |
| const errorMessage = { sender: 'error', text: `Lo siento, hubo un error al conectar con la IA. Asegúrate de que el servidor está corriendo. Detalle: ${error.message}` }; | |
| currentChat.push(errorMessage); | |
| addMessageToChat(errorMessage); | |
| } | |
| }); | |
| inputField.addEventListener('keypress', (event) => { | |
| if (event.key === 'Enter') { | |
| sendButton.click(); | |
| } | |
| }); | |
| newChatButtonSidebar.addEventListener('click', startNewChat); | |
| newChatButtonHeader.addEventListener('click', startNewChat); | |
| function scrollToBottom() { | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| // Inicializar al cargar la página | |
| startNewChat(); | |
| updateChatList(); | |
| </script> | |
| </body> | |
| </html> |