hi / index.html
AvanteGuardienOfTheGalaxies's picture
Update index.html
c912484 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HF Chat - Novita Provider</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 800px;
height: 80vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #ff6b6b, #ffd93d);
color: white;
padding: 20px;
text-align: center;
position: relative;
}
.header h1 {
font-size: 1.8em;
font-weight: 600;
margin-bottom: 10px;
}
.api-setup {
padding: 20px;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.api-input-group {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.api-input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e9ecef;
border-radius: 12px;
font-size: 14px;
transition: all 0.3s ease;
}
.api-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.connect-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 12px 24px;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
}
.connect-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.connect-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.model-select {
padding: 12px 16px;
border: 2px solid #e9ecef;
border-radius: 12px;
font-size: 14px;
background: white;
}
.status {
padding: 10px;
border-radius: 8px;
margin-top: 10px;
font-size: 14px;
font-weight: 500;
}
.status.connected {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.chat-area {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 80%;
padding: 15px 20px;
border-radius: 18px;
animation: fadeIn 0.3s ease;
word-wrap: break-word;
}
.message.user {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
align-self: flex-end;
border-bottom-right-radius: 6px;
}
.message.assistant {
background: #f1f3f4;
color: #333;
align-self: flex-start;
border-bottom-left-radius: 6px;
border: 1px solid #e0e0e0;
}
.message.loading {
background: #f1f3f4;
color: #666;
align-self: flex-start;
animation: pulse 1.5s ease-in-out infinite;
}
.input-area {
padding: 20px;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
}
.input-group {
display: flex;
gap: 12px;
align-items: flex-end;
}
.message-input {
flex: 1;
padding: 15px 20px;
border: 2px solid #e9ecef;
border-radius: 25px;
font-size: 16px;
resize: none;
min-height: 50px;
max-height: 120px;
transition: all 0.3s ease;
}
.message-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.send-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
font-size: 18px;
}
.send-btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.send-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { opacity: 0.7; }
50% { opacity: 1; }
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤗 HF Chat with Novita</h1>
<p>Connect to Hugging Face models via Novita provider</p>
</div>
<div class="api-setup">
<div class="api-input-group">
<input type="password" class="api-input" id="apiKey" placeholder="Enter your Hugging Face API key">
<select class="model-select" id="modelSelect">
<option value="microsoft/DialoGPT-medium">DialoGPT-medium</option>
<option value="microsoft/DialoGPT-large">DialoGPT-large</option>
<option value="facebook/blenderbot-400M-distill">BlenderBot-400M</option>
<option value="EleutherAI/gpt-neo-1.3B">GPT-Neo-1.3B</option>
<option value="EleutherAI/gpt-neo-2.7B">GPT-Neo-2.7B</option>
</select>
<button class="connect-btn" id="connectBtn">Connect</button>
</div>
<div class="status hidden" id="statusDiv"></div>
</div>
<div class="chat-area hidden" id="chatArea">
<div class="messages" id="messages"></div>
<div class="input-area">
<div class="input-group">
<textarea class="message-input" id="messageInput" placeholder="Type your message..." rows="1"></textarea>
<button class="send-btn" id="sendBtn"></button>
</div>
</div>
</div>
</div>
<script>
let apiKey = '';
let selectedModel = '';
let isConnected = false;
const elements = {
apiKey: document.getElementById('apiKey'),
modelSelect: document.getElementById('modelSelect'),
connectBtn: document.getElementById('connectBtn'),
statusDiv: document.getElementById('statusDiv'),
chatArea: document.getElementById('chatArea'),
messages: document.getElementById('messages'),
messageInput: document.getElementById('messageInput'),
sendBtn: document.getElementById('sendBtn')
};
// Auto-resize textarea
elements.messageInput.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = this.scrollHeight + 'px';
});
// Connect button handler
elements.connectBtn.addEventListener('click', async () => {
apiKey = elements.apiKey.value.trim();
selectedModel = elements.modelSelect.value;
if (!apiKey) {
showStatus('Please enter your API key', 'error');
return;
}
elements.connectBtn.disabled = true;
elements.connectBtn.textContent = 'Connecting...';
try {
// Test the connection with a simple request to HF Inference API
const response = await fetch(`https://api-inference.huggingface.co/models/${selectedModel}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'x-use-cache': 'false'
},
body: JSON.stringify({
inputs: "Hello",
parameters: {
max_length: 10,
return_full_text: false
}
})
});
if (response.ok) {
isConnected = true;
showStatus('Connected successfully! Using Novita provider via HF Inference API', 'connected');
elements.chatArea.classList.remove('hidden');
elements.messageInput.focus();
} else {
const errorText = await response.text();
throw new Error(`Connection failed: ${response.status} - ${errorText}`);
}
} catch (error) {
showStatus(`Connection failed: ${error.message}`, 'error');
}
elements.connectBtn.disabled = false;
elements.connectBtn.textContent = 'Connect';
});
// Send message handler
elements.sendBtn.addEventListener('click', sendMessage);
elements.messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
function showStatus(message, type) {
elements.statusDiv.textContent = message;
elements.statusDiv.className = `status ${type}`;
elements.statusDiv.classList.remove('hidden');
}
function addMessage(content, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}`;
messageDiv.textContent = content;
elements.messages.appendChild(messageDiv);
elements.messages.scrollTop = elements.messages.scrollHeight;
return messageDiv;
}
function addLoadingMessage() {
const messageDiv = document.createElement('div');
messageDiv.className = 'message loading';
messageDiv.textContent = 'Thinking...';
elements.messages.appendChild(messageDiv);
elements.messages.scrollTop = elements.messages.scrollHeight;
return messageDiv;
}
async function sendMessage() {
if (!isConnected) {
showStatus('Please connect first', 'error');
return;
}
const message = elements.messageInput.value.trim();
if (!message) return;
// Add user message
addMessage(message, 'user');
elements.messageInput.value = '';
elements.messageInput.style.height = 'auto';
// Disable send button
elements.sendBtn.disabled = true;
// Add loading message
const loadingMsg = addLoadingMessage();
try {
const response = await fetch(`https://api-inference.huggingface.co/models/${selectedModel}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'x-use-cache': 'false'
},
body: JSON.stringify({
inputs: message,
parameters: {
max_length: 200,
temperature: 0.7,
return_full_text: false,
do_sample: true
}
})
});
// Remove loading message
loadingMsg.remove();
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API Error: ${response.status} - ${errorText}`);
}
const data = await response.json();
// Handle the response based on HF Inference API structure
let assistantMessage = '';
if (Array.isArray(data) && data[0] && data[0].generated_text) {
assistantMessage = data[0].generated_text.trim();
} else if (data.generated_text) {
assistantMessage = data.generated_text.trim();
} else if (typeof data === 'string') {
assistantMessage = data.trim();
} else {
assistantMessage = 'Sorry, I received an unexpected response format.';
console.log('Unexpected response:', data);
}
// Clean up the response if it includes the input
if (assistantMessage.startsWith(message)) {
assistantMessage = assistantMessage.substring(message.length).trim();
}
if (!assistantMessage) {
assistantMessage = 'I received an empty response. Please try again.';
}
addMessage(assistantMessage, 'assistant');
} catch (error) {
loadingMsg.remove();
addMessage(`Error: ${error.message}`, 'assistant');
console.error('Chat error:', error);
}
elements.sendBtn.disabled = false;
}
// Initialize
elements.messageInput.focus();
</script>
</body>
</html>