aj-mini-api / index.html
tomo14151
Deploy AJ Mini API to Hugging Face Spaces - Created by AJ STUDIOZ
9d79680
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJ - AI Assistant by AJ STUDIOZ</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-width: 800px;
width: 100%;
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
opacity: 0.9;
font-size: 1.1em;
}
.url-setup {
background: #fff3cd;
padding: 20px;
border-bottom: 2px solid #ffc107;
}
.url-setup-label {
font-size: 12px;
font-weight: bold;
color: #856404;
margin-bottom: 10px;
display: block;
}
.url-input-group {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.url-setup input {
flex: 1;
min-width: 250px;
padding: 10px 15px;
border: 1px solid #ffc107;
border-radius: 5px;
font-size: 13px;
font-family: 'Courier New', monospace;
}
.url-setup button {
padding: 10px 20px;
background: #ffc107;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
white-space: nowrap;
}
.url-setup button:hover {
background: #e0a800;
}
.url-status {
font-size: 12px;
padding: 8px 12px;
text-align: center;
background: #fff;
border-radius: 5px;
border: 1px solid #ddd;
min-width: 180px;
}
.url-status.connected {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.url-status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.chat-container {
padding: 30px;
height: 400px;
overflow-y: auto;
background: #f8f9fa;
}
.message {
margin-bottom: 20px;
display: flex;
align-items: flex-start;
}
.message.user {
justify-content: flex-end;
}
.message-content {
max-width: 70%;
padding: 15px 20px;
border-radius: 15px;
word-wrap: break-word;
}
.message.user .message-content {
background: #667eea;
color: white;
border-bottom-right-radius: 5px;
}
.message.ai .message-content {
background: white;
color: #333;
border-bottom-left-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.input-container {
padding: 20px;
background: white;
border-top: 2px solid #e9ecef;
display: flex;
gap: 10px;
}
#messageInput {
flex: 1;
padding: 15px;
border: 2px solid #e9ecef;
border-radius: 25px;
font-size: 16px;
outline: none;
}
#messageInput:focus {
border-color: #667eea;
}
#sendBtn {
padding: 15px 30px;
background: #667eea;
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
transition: 0.3s;
min-width: 100px;
}
#sendBtn:hover:not(:disabled) {
background: #764ba2;
transform: scale(1.05);
}
#sendBtn:disabled {
background: #ccc;
cursor: not-allowed;
}
.error-message {
color: #d32f2f;
padding: 15px;
background: #ffebee;
border-radius: 5px;
margin-bottom: 15px;
}
.loader {
display: inline-block;
width: 8px;
height: 8px;
background: #667eea;
border-radius: 50%;
margin-left: 5px;
animation: bounce 0.6s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 AJ</h1>
<p>Perfect AI Model - Powered by aj-mini</p>
<p style="font-size: 0.9em; margin-top: 10px;">By AJ STUDIOZ</p>
</div>
<div class="url-setup">
<label class="url-setup-label">📡 ngrok API URL Configuration</label>
<div class="url-input-group">
<input
type="text"
id="ngrokUrl"
placeholder="https://xxxxx-xxxxx-xxxxx.ngrok.io"
title="Enter your ngrok public URL from http://localhost:4040"
>
<button onclick="saveNgrokUrl()">Save URL</button>
<div class="url-status" id="urlStatus">Not connected</div>
</div>
<div style="font-size: 11px; color: #856404; margin-top: 10px;">
💡 Get your ngrok URL from: <code style="background: white; padding: 2px 5px; border-radius: 3px;">http://localhost:4040</code>
</div>
</div>
<div id="errorContainer"></div>
<div class="chat-container" id="chatContainer">
<div style="text-align: center; color: #999; padding: 20px;">
👋 Start by entering your ngrok URL above, then send a message!
</div>
</div>
<div class="input-container">
<input
type="text"
id="messageInput"
placeholder="Ask AJ something..."
autocomplete="off"
>
<button id="sendBtn" onclick="sendMessage()">Send</button>
</div>
</div>
<script>
let API_BASE_URL = localStorage.getItem('ngrokUrl') || '';
function saveNgrokUrl() {
const url = document.getElementById('ngrokUrl').value.trim();
const statusEl = document.getElementById('urlStatus');
if (!url) {
statusEl.textContent = '❌ URL required';
statusEl.className = 'url-status error';
return;
}
if (!url.startsWith('http')) {
statusEl.textContent = '❌ Invalid URL (must start with http/https)';
statusEl.className = 'url-status error';
return;
}
statusEl.textContent = '⏳ Testing...';
statusEl.className = 'url-status';
fetch(url + '/', { method: 'GET', mode: 'cors' })
.then(resp => {
if (resp.ok) {
API_BASE_URL = url;
localStorage.setItem('ngrokUrl', url);
statusEl.textContent = '✅ Connected!';
statusEl.className = 'url-status connected';
clearError();
document.getElementById('chatContainer').innerHTML = '<div style="text-align: center; color: #999; padding: 20px;">💬 Connected! Send a message to AJ...</div>';
} else {
throw new Error('Server responded with error');
}
})
.catch(err => {
statusEl.textContent = '❌ Connection failed';
statusEl.className = 'url-status error';
showError('Failed to connect to API. Check URL and try again.');
});
}
function showError(msg) {
const container = document.getElementById('errorContainer');
container.innerHTML = '<div class="error-message">⚠️ ' + msg + '</div>';
}
function clearError() {
document.getElementById('errorContainer').innerHTML = '';
}
function addMessage(text, isUser = false) {
const chatContainer = document.getElementById('chatContainer');
if (chatContainer.innerHTML.includes('Start by entering')) {
chatContainer.innerHTML = '';
}
const messageEl = document.createElement('div');
messageEl.className = 'message ' + (isUser ? 'user' : 'ai');
const contentEl = document.createElement('div');
contentEl.className = 'message-content';
contentEl.textContent = text;
messageEl.appendChild(contentEl);
chatContainer.appendChild(messageEl);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function sendMessage() {
if (!API_BASE_URL) {
showError('Please enter and save your ngrok URL first!');
return;
}
const input = document.getElementById('messageInput');
const message = input.value.trim();
if (!message) return;
addMessage(message, true);
input.value = '';
const sendBtn = document.getElementById('sendBtn');
sendBtn.disabled = true;
sendBtn.textContent = 'Sending' + '<span class="loader"></span>';
fetch(API_BASE_URL + '/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: message }),
mode: 'cors'
})
.then(resp => {
if (!resp.ok) throw new Error('API error: ' + resp.status);
return resp.json();
})
.then(data => {
if (data.response) {
addMessage(data.response, false);
clearError();
} else if (data.error) {
showError('API Error: ' + data.error);
addMessage('Error: ' + data.error, false);
}
})
.catch(err => {
showError('Failed to get response: ' + err.message);
addMessage('Error: ' + err.message, false);
})
.finally(() => {
sendBtn.disabled = false;
sendBtn.textContent = 'Send';
document.getElementById('messageInput').focus();
});
}
document.getElementById('messageInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
document.getElementById('ngrokUrl').addEventListener('keypress', (e) => {
if (e.key === 'Enter') saveNgrokUrl();
});
if (API_BASE_URL) {
document.getElementById('ngrokUrl').value = API_BASE_URL;
saveNgrokUrl();
}
window.addEventListener('load', () => {
document.getElementById('messageInput').focus();
});
</script>
</body>
</html>