Ai25 / HTML
Pq234's picture
Create HTML
8b5ce31 verified
Raw
History Blame Contribute Delete
17.4 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>πŸ€– AI-Hub Live Connector - v4.0</title>
<style>
/* --- CSS: THEME & STYLING --- */
:root {
--bg-dark: #0a0f14;
--bg-card: #11181f;
--bg-input: #141a20;
--neon-green: #00ffaa;
--neon-blue: #00d4ff;
--neon-red: #ff3366;
--text-main: #e0e6ed;
--text-muted: #7a8b9e;
--border-color: #2a3540;
}
* { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', 'Courier New', sans-serif; }
body {
background-color: var(--bg-dark);
color: var(--text-main);
padding: 20px;
display: flex;
justify-content: center;
min-height: 100vh;
background-image: radial-gradient(circle at 50% 0%, #11181f 0%, #0a0f14 100%);
}
.app-container {
max-width: 1200px;
width: 100%;
background: rgba(20, 26, 32, 0.8);
border: 1px solid rgba(0, 255, 170, 0.1);
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0,0,0,0.8);
backdrop-filter: blur(5px);
}
/* Header */
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-color); padding-bottom: 15px; margin-bottom: 25px; flex-wrap: wrap;}
h1 { color: var(--neon-green); text-shadow: 0 0 20px rgba(0, 255, 170, 0.2); font-size: 1.8rem; }
.status-dot { display: inline-block; width: 10px; height: 10px; background: var(--neon-green); border-radius: 50%; animation: pulse 2s infinite; }
@keyframes pulse { 0% { opacity: 0.5; } 50% { opacity: 1; } 100% { opacity: 0.5; } }
/* Search Bar */
.search-section { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 12px; padding: 20px; margin-bottom: 25px; }
.search-row { display: flex; gap: 12px; flex-wrap: wrap; }
.search-wrapper { flex: 1; position: relative; min-width: 200px; }
.search-wrapper input {
width: 100%; padding: 14px 20px; background: var(--bg-input);
border: 1px solid var(--border-color); border-radius: 50px; color: white;
font-size: 1rem; outline: none; transition: 0.3s;
}
.search-wrapper input:focus { border-color: var(--neon-blue); box-shadow: 0 0 15px rgba(0, 212, 255, 0.1); }
.search-wrapper input::placeholder { color: #555; }
.search-row select {
background: var(--bg-input); border: 1px solid var(--border-color);
color: white; padding: 0 15px; border-radius: 50px; outline: none; cursor: pointer;
}
.search-row button {
background: transparent; border: 1px solid var(--neon-green); color: var(--neon-green);
padding: 12px 28px; border-radius: 50px; cursor: pointer; font-weight: 600;
transition: 0.3s; text-transform: uppercase; letter-spacing: 1px;
}
.search-row button:hover { background: rgba(0, 255, 170, 0.1); box-shadow: 0 0 20px rgba(0, 255, 170, 0.2); }
.search-row button:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }
/* Stats & Status */
.status-bar { display: flex; justify-content: space-between; align-items: center; margin-top: 15px; font-size: 0.9rem; color: var(--text-muted); flex-wrap: wrap; gap: 10px; }
.status-msg { padding: 8px 15px; border-radius: 20px; }
.status-msg.error { background: rgba(255, 51, 102, 0.1); border: 1px solid var(--neon-red); color: var(--neon-red); }
.status-msg.success { background: rgba(0, 255, 170, 0.1); border: 1px solid var(--neon-green); color: var(--neon-green); }
/* Results Grid */
.results-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; margin-top: 20px; }
.result-card {
background: var(--bg-card); border: 1px solid var(--border-color);
border-radius: 12px; padding: 20px; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative; overflow: hidden;
}
.result-card:hover { border-color: var(--neon-blue); transform: translateY(-5px) scale(1.02); box-shadow: 0 10px 20px rgba(0,0,0,0.5); }
.card-badge { position: absolute; top: 10px; right: 10px; font-size: 0.7rem; background: #2a3540; padding: 4px 10px; border-radius: 12px; color: var(--text-muted); }
.model-name { color: var(--neon-green); font-weight: bold; font-size: 1.2rem; margin-bottom: 10px; word-break: break-all; }
.model-detail { display: flex; justify-content: space-between; color: var(--text-muted); font-size: 0.9rem; margin-bottom: 8px; border-bottom: 1px dotted #222; padding-bottom: 5px; }
.action-btn {
display: inline-flex; align-items: center; gap: 5px; margin-top: 15px;
color: var(--neon-blue); text-decoration: none; border: 1px solid var(--neon-blue);
padding: 6px 15px; border-radius: 20px; font-size: 0.85rem; transition: 0.2s; width: fit-content;
}
.action-btn:hover { background: rgba(0, 212, 255, 0.1); box-shadow: 0 0 15px rgba(0,212,255,0.1); }
/* Skeleton Loading */
.skeleton { background: linear-gradient(90deg, var(--bg-card) 25%, #1f2a33 50%, var(--bg-card) 75%); background-size: 200% 100%; animation: load 1.5s infinite; border-radius: 6px; height: 20px; margin-bottom: 10px; width: 100%; }
@keyframes load { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
/* History Dropdown */
.history-dropdown { background: var(--bg-input); border: 1px solid var(--border-color); border-radius: 8px; padding: 10px; margin-top: 15px; display: none; max-height: 200px; overflow-y: auto; }
.history-dropdown.active { display: block; }
.history-item { padding: 8px; cursor: pointer; border-bottom: 1px solid #222; transition: 0.2s; }
.history-item:hover { background: #2a3540; color: var(--neon-green); }
/* Footer */
.social-footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--border-color); text-align: center; }
.social-links { display: flex; justify-content: center; gap: 15px; flex-wrap: wrap; margin-top: 10px; }
.social-btn { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--border-color); padding: 8px 20px; border-radius: 30px; text-decoration: none; color: var(--text-muted); transition: 0.2s; font-size: 0.9rem; }
.social-btn:hover { border-color: var(--neon-blue); color: white; transform: translateY(-2px); }
.creator-credit { margin-top: 20px; font-size: 0.9rem; color: #555; }
.creator-credit strong { color: var(--neon-blue); }
/* Responsive */
@media (max-width: 600px) {
.app-container { padding: 15px; }
.search-row button { width: 100%; justify-content: center; }
.search-wrapper input { padding: 12px; }
h1 { font-size: 1.4rem; }
}
</style>
</head>
<body>
<div class="app-container">
<div class="header">
<h1>πŸ€– AI-Hub <span style="color:var(--text-muted); font-weight:300;">Live Connector</span></h1>
<div style="display:flex; align-items:center; gap:8px; font-size:0.9rem; color:var(--text-muted);">
<span class="status-dot"></span> API Connected
</div>
</div>
<div class="search-section">
<div class="search-row">
<div class="search-wrapper">
<input type="text" id="searchInput" placeholder="Search models, datasets, spaces... (e.g., 'Llama', 'Diffusers')" onkeypress="if(event.key==='Enter') handleSearch()">
</div>
<select id="searchType">
<option value="models">Models</option>
<option value="datasets">Datasets</option>
<option value="spaces">Spaces</option>
</select>
<button onclick="handleSearch()" id="searchBtn">πŸ” Search Hub</button>
</div>
<div class="status-bar">
<div id="statusMessage" class="status-msg success">Ready. Enter a query to explore the Hub.</div>
<div style="display:flex; gap:10px; align-items:center;">
<span id="resultCount">0 Results</span>
<button onclick="toggleHistory()" style="background:transparent; border:1px solid var(--border-color); color:var(--text-muted); padding:4px 12px; border-radius:15px; cursor:pointer; font-size:0.8rem;">History πŸ“œ</button>
</div>
</div>
<div class="history-dropdown" id="historyDropdown">
<div style="color:var(--text-muted); font-size:0.8rem; margin-bottom:5px;">Recent Searches</div>
<div id="historyList"></div>
</div>
</div>
<div id="resultsContainer">
<div style="text-align:center; color:var(--text-muted); padding:50px 0;">
<div style="font-size:3rem; margin-bottom:10px;">πŸš€</div>
Awaiting your first search.<br> <span style="font-size:0.9rem;">Searching accesses the live Hugging Face API.</span>
</div>
</div>
<div class="social-footer">
<div class="social-links">
<a href="https://www.facebook.com/" target="_blank" class="social-btn">πŸ“˜ Facebook</a>
<a href="https://github.com/pathum25" target="_blank" class="social-btn">πŸ™ GitHub</a>
<a href="https://huggingface.co/Pq234" target="_blank" class="social-btn">πŸ€— Hugging Face</a>
<a href="https://wa.me/94767605853" target="_blank" class="social-btn">πŸ’¬ WhatsApp</a>
</div>
<div class="creator-credit">Built by <strong>A.P.PATHUm LAKMAL</strong> Β© 2026</div>
</div>
</div>
<script>
/**
* =========================================
* THE JAVASCRIPT ENGINE (REAL APP LOGIC)
* =========================================
*/
// --- CONFIGURATION ---
// IMPORTANT: If you want higher rate limits, add your token here: hf_xxxxxxxxx
const HF_TOKEN = "";
const BASE_URL = "https://huggingface.co/api";
// --- STATE MANAGEMENT ---
const state = {
isLoading: false,
history: JSON.parse(localStorage.getItem('hf_search_history') || '[]'),
currentType: 'models',
currentQuery: ''
};
// --- DOM REFERENCES ---
const dom = {
input: document.getElementById('searchInput'),
type: document.getElementById('searchType'),
btn: document.getElementById('searchBtn'),
status: document.getElementById('statusMessage'),
count: document.getElementById('resultCount'),
container: document.getElementById('resultsContainer'),
historyDropdown: document.getElementById('historyDropdown'),
historyList: document.getElementById('historyList')
};
// --- CORE LOGIC: SEARCH ---
async function handleSearch() {
const query = dom.input.value.trim();
const type = dom.type.value;
if (!query) {
setStatus("Please enter a search term.", "error");
return;
}
// Toggle UI state
state.isLoading = true;
dom.btn.disabled = true;
dom.btn.textContent = "⏳ Scanning Hub...";
dom.container.innerHTML = renderSkeletons(6);
setStatus(`Connecting to Hugging Face Cloud to search "${query}"...`, "success");
try {
// Construct URL based on type
let apiUrl = `${BASE_URL}/${type}?search=${encodeURIComponent(query)}&limit=12&sort=downloads`;
const headers = {};
if (HF_TOKEN) headers['Authorization'] = `Bearer ${HF_TOKEN}`;
const response = await fetch(apiUrl, { headers });
if (!response.ok) throw new Error(`API Error ${response.status}`);
const data = await response.json();
const items = Array.isArray(data) ? data : data.models || data.datasets || data.spaces || [];
// Save to history
saveToHistory(query, type);
// Render
if (items.length === 0) {
setStatus(`No results found for "${query}".`, "error");
dom.container.innerHTML = `<div style="text-align:center; color:var(--text-muted); padding:40px 0;">No ${type} found matching your criteria.</div>`;
} else {
setStatus(`βœ… Found ${items.length} ${type} for "${query}".`, "success");
dom.container.innerHTML = renderCards(items, type);
}
dom.count.textContent = `${items.length} Results`;
} catch (err) {
console.error(err);
setStatus(`Error: ${err.message}. Check console.`, "error");
dom.container.innerHTML = `<div style="text-align:center; color:var(--neon-red); padding:40px 0;">Failed to connect to Hub. ${err.message}</div>`;
} finally {
state.isLoading = false;
dom.btn.disabled = false;
dom.btn.textContent = "πŸ” Search Hub";
}
}
// --- RENDER FUNCTIONS ---
function renderCards(items, type) {
return `<div class="results-grid">
${items.map(item => {
// Normalize data
const id = item.modelId || item._id || item.id || "Unknown";
const downloads = item.downloads ? formatNumber(item.downloads) : "New";
const likes = item.likes ? `❀️ ${item.likes}` : "";
const tags = (item.tags || []).slice(0, 3).join(', ');
return `
<div class="result-card">
<span class="card-badge">${type.slice(0,-1).toUpperCase()}</span>
<div class="model-name">${id}</div>
<div class="model-detail"><span>Downloads</span> <span>${downloads}</span></div>
<div class="model-detail"><span>Likes</span> <span>${likes || 'None'}</span></div>
<div style="color:var(--text-muted); font-size:0.8rem; margin-top:5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${tags}</div>
<a href="https://huggingface.co/${id}" target="_blank" class="action-btn">πŸ“– Read Docs &rarr;</a>
</div>
`;
}).join('')}
</div>`;
}
function renderSkeletons(count) {
let html = `<div class="results-grid">`;
for(let i=0; i<count; i++) {
html += `
<div class="result-card">
<div class="skeleton" style="height:25px; width:80%;"></div>
<div class="skeleton" style="height:15px; width:50%;"></div>
<div class="skeleton" style="height:15px; width:40%;"></div>
<div class="skeleton" style="height:15px; width:60%;"></div>
<div class="skeleton" style="height:35px; width:120px; margin-top:15px;"></div>
</div>
`;
}
html += `</div>`;
return html;
}
// --- HISTORY FUNCTIONS ---
function saveToHistory(query, type) {
const entry = { query, type, time: new Date().toLocaleTimeString() };
state.history = state.history.filter(h => h.query !== query); // Remove duplicates
state.history.unshift(entry);
if(state.history.length > 5) state.history.pop(); // Limit to 5
localStorage.setItem('hf_search_history', JSON.stringify(state.history));
renderHistory();
}
function renderHistory() {
dom.historyList.innerHTML = state.history.map(h => `
<div class="history-item" onclick="loadHistory('${h.query}', '${h.type}')">
<span style="color:var(--neon-green);">${h.query}</span> <span style="color:#555; font-size:0.8rem;">(${h.type})</span>
<span style="float:right; font-size:0.7rem; color:#444;">${h.time}</span>
</div>
`).join('');
}
function loadHistory(query, type) {
dom.input.value = query;
dom.type.value = type;
dom.historyDropdown.classList.remove('active');
handleSearch();
}
function toggleHistory() {
dom.historyDropdown.classList.toggle('active');
renderHistory();
}
// --- UTILITIES ---
function setStatus(msg, type = 'success') {
dom.status.className = `status-msg ${type}`;
dom.status.textContent = msg;
}
function formatNumber(num) {
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
if (num >= 1000) return (num / 1000).toFixed(1) + 'k';
return num.toString();
}
// --- INITIALIZATION ---
// Load saved history on startup
renderHistory();
console.log("πŸ€– A.P.PATHUm LAKMAL's AI-Hub Live Connector initialized.");
console.log("πŸ’‘ Tip: Add your HF Token in the JS to prevent API blocking.");
</script>
</body>
</html>