anycoder-be345eff / index.html
Pehchan's picture
Upload folder using huggingface_hub
9ced45c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Digital Library</title>
<style>
:root {
--primary: #2c3e50;
--accent: #3498db;
--bg: #f4f7f6;
--card-bg: #ffffff;
--text: #333;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--bg);
color: var(--text);
margin: 0;
padding: 0;
line-height: 1.6;
}
header {
background-color: var(--primary);
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
header h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 300;
}
header a {
color: white;
text-decoration: none;
font-size: 0.8rem;
opacity: 0.8;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 5px 10px;
border-radius: 4px;
transition: opacity 0.3s;
}
header a:hover {
opacity: 1;
background: rgba(255, 255, 255, 0.1);
}
nav {
background: white;
padding: 0 2rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
margin-bottom: 2rem;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
nav button {
background: none;
border: none;
padding: 1rem 1.5rem;
font-size: 1rem;
color: var(--text);
cursor: pointer;
border-bottom: 3px solid transparent;
transition: all 0.3s;
}
nav button.active {
color: var(--accent);
border-bottom: 3px solid var(--accent);
font-weight: bold;
}
main {
max-width: 1000px;
margin: 0 auto;
padding: 0 2rem;
}
.section {
display: none;
animation: fadeIn 0.5s;
}
.section.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.card {
background: var(--card-bg);
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
display: flex;
flex-direction: column;
}
.card:hover {
transform: translateY(-5px);
}
.card h3 {
color: var(--primary);
margin-top: 0;
}
.card .meta {
font-size: 0.85rem;
color: #777;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
}
.tag {
background: #eee;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.75rem;
margin-right: 5px;
display: inline-block;
}
input[type="text"],
textarea {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 1rem;
margin-bottom: 10px;
box-sizing: box;
font-family: inherit;
}
textarea {
height: 150px;
resize: vertical;
}
button.action-btn {
background-color: var(--accent);
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s;
}
button.action-btn:hover {
background-color: #2980b9;
}
button.action-btn:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.status-bar {
background: #e8f4fc;
padding: 10px;
border-radius: 6px;
margin-bottom: 20px;
font-size: 0.9rem;
color: var(--primary);
display: flex;
align-items: center;
gap: 10px;
}
.spinner {
width: 20px;
height: 20px;
border: 3px solid rgba(0, 0, 0, 0.1);
border-top: 3px solid var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.result-box {
background: #f8f9fa;
border-left: 4px solid var(--accent);
padding: 15px;
margin-top: 15px;
white-space: pre-wrap;
}
.highlight-match {
background-color: #fff3cd;
padding: 2px 4px;
border-radius: 2px;
}
.progress-bar {
width: 100%;
height: 4px;
background: #ddd;
border-radius: 2px;
overflow: hidden;
margin-top: 5px;
}
.progress-fill {
height: 100%;
background: var(--accent);
transition: width 0.3s;
}
.error-message {
background: #ffebee;
border-left: 4px solid #f44336;
padding: 15px;
margin-top: 15px;
color: #c62828;
}
</style>
</head>
<body>
<header>
<h1>📚 AI Digital Library</h1>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a>
</header>
<nav>
<button onclick="switchTab('library')" class="active" id="tab-library">Library View</button>
<button onclick="switchTab('search')" id="tab-search">Semantic Search</button>
<button onclick="switchTab('summarize')" id="tab-summarize">Book Summarizer</button>
<button onclick="switchTab('classify')" id="tab-classify">Auto-Tagging</button>
</nav>
<main>
<!-- Status Bar for Model Loading -->
<div id="status-container" class="status-bar" style="display:none;">
<div class="spinner"></div>
<span id="status-text">Initializing AI Models...</span>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill" style="width: 0%"></div>
</div>
</div>
<!-- Tab 1: Library View -->
<div id="library" class="section active">
<h2>Current Collection</h2>
<p>Your local digital library containing classic texts and summaries.</p>
<div class="card-grid" id="library-grid">
<!-- Cards injected by JS -->
</div>
</div>
<!-- Tab 2: Semantic Search -->
<div id="search" class="section">
<h2>Semantic Search</h2>
<p>Find books based on meaning, not just keywords. Try searching for "war" to find books about conflict, or "love"
to find romance.</p>
<input type="text" id="search-input" placeholder="Describe what you are looking for...">
<button class="action-btn" onclick="performSearch()" id="search-btn">Search Library</button>
<div id="search-results" class="card-grid" style="margin-top: 20px;"></div>
</div>
<!-- Tab 3: Summarizer -->
<div id="summarize" class="section">
<h2>Text Summarizer</h2>
<p>Paste a long chapter or article description to get an instant AI summary.</p>
<textarea id="summarize-input" placeholder="Paste text here (e.g., a book synopsis)..."></textarea>
<button class="action-btn" onclick="performSummarization()" id="summarize-btn">Generate Summary</button>
<div id="summarize-output" class="result-box"></div>
</div>
<!-- Tab 4: Classification -->
<div id="classify" class="section">
<h2>Automatic Tagging</h2>
<p>Enter a book description and let AI suggest the best categories for your library.</p>
<textarea id="classify-input" placeholder="Enter book description..."></textarea>
<button class="action-btn" onclick="performClassification()" id="classify-btn">Generate Tags</button>
<div id="classify-output" class="result-box"></div>
</div>
</main>
<script type="module">
import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0';
// Configuration
env.useLocalModels = false; // Use remote models from Hugging Face
env.allowRemoteModels = true;
// State Management
let embedder = null;
let summarizer = null;
let classifier = null;
let isModelsLoaded = false;
// Mock Library Data
const libraryData = [
{
id: 1,
title: "The Great Gatsby",
author: "F. Scott Fitzgerald",
year: 1925,
text: "The story primarily concerns the young and mysterious millionaire Jay Gatsby and his quixotic passion and
obsession for the beautiful former debutante Daisy Buchanan.",
tags: ["Fiction", "Classic", "Romance"]
},
{
id: 2,
title: "1984",
author: "George Orwell",
year: 1949,
text: "Set in an imagined future where Great Britain has fallen to a totalitarian regime, the story follows Winston
Smith, a low-ranking member of 'the Party', who is frustrated by the omnipresent eyes of the party, and its ominous
ruler Big Brother.",
tags: ["Sci-Fi", "Political", "Dystopian"]
},
{
id: 3,
title: "To Kill a Mockingbird",
author: "Harper Lee",
year: 1960,
text: "The story takes place during the Great Depression in the fictional town of Maycomb, Alabama. It focuses on
six-year-old Jean Louise Finch (known as Scout), who lives with her older brother Jeremy (known as Jem) and their father
Atticus, a middle-aged lawyer.",
tags: ["Historical", "Legal", "Drama"]
},
{
id: 4,
title: "Dune",
author: "Frank Herbert",
year: 1965,
text: "Set on the desert planet Arrakis, the story follows young Paul Atreides as his family accepts stewardship of the
planet Arrakis. While the planet is an inhospitable and sparsely populated desert wasteland, it is the only source of
melange, or 'the spice', a drug which extends life and enhances mental abilities.",
tags: ["Sci-Fi", "Adventure", "Space"]
},
{
id: 5,
title: "Pride and Prejudice",
author: "Jane Austen",
year: 1813,
text: "The story follows the emotional development of Elizabeth Bennet, who learns the error of her ways and hard
prejudices, through the plot of the novel.",
tags: ["Romance", "Classic", "Social"]
}
];
// Initialize Application
async function init() {
showStatus("Loading Embedding Model (for Search)...", 0);
try {
// Load Embedding Model (MiniLM for fast semantic search)
embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6', {
dtype: 'q8', // Quantized for speed
progress_callback: (data) => {
if (data.status === 'progress') {
showStatus(`Loading Embedding: ${data.file} (${Math.round(data.progress * 100)}%)`, data.progress * 100);
}
}
});
showStatus("Loading Summarization Model...", 30);
// Load Summarization Model (DistilBART for speed)
summarizer = await pipeline('summarization', 'Xenova/distilbart-cnn-12-6', {
dtype: 'q8',
progress_callback: (data) => {
if (data.status === 'progress') {
showStatus(`Loading Summarizer: ${data.file} (${Math.round(data.progress * 100)}%)`, 30 + data.progress * 40);
}
}
});
showStatus("Loading Classification Model...", 70);
// Load Zero-Shot Classification (BART for topic detection)
classifier = await pipeline('zero-shot-classification', 'Xenova/bart-base', {
dtype: 'q8',
progress_callback: (data) => {
if (data.status === 'progress') {
showStatus(`Loading Classifier: ${data.file} (${Math.round(data.progress * 100)}%)`, 70 + data.progress * 30);
}
}
});
isModelsLoaded = true;
hideStatus();
renderLibrary();
console.log("All models loaded successfully.");
// Enable all buttons
document.querySelectorAll('.action-btn').forEach(btn => {
btn.disabled = false;
});
} catch (err) {
console.error(err);
showError("Error loading models: " + err.message);
}
}
// UI Helpers
function showStatus(text, progress = 0) {
const container = document.getElementById('status-container');
const textEl = document.getElementById('status-text');
const progressFill = document.getElementById('progress-fill');
container.style.display = 'flex';
textEl.innerText = text;
progressFill.style.width = `${progress}%`;
}
function hideStatus() {
document.getElementById('status-container').style.display = 'none';
}
function showError(message) {
const container = document.getElementById('status-container');
container.style.display = 'flex';
container.style.background = '#ffebee';
container.style.color = '#c62828';
const textEl = document.getElementById('status-text');
textEl.innerText = message;
document.getElementById('progress-fill').style.width = '0%';
}
function switchTab(tabId) {
// Update Nav
document.querySelectorAll('nav button').forEach(b => b.classList.remove('active'));
document.getElementById(`tab-${tabId}`).classList.add('active');
// Update Section
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
}
// Feature 1: Render Library
function renderLibrary() {
const grid = document.getElementById('library-grid');
grid.innerHTML = '';
libraryData.forEach(book => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h3>${book.title}</h3>
<div class="meta">
<span>${book.author}</span>
<span>${book.year}</span>
</div>
<p style="font-size: 0.9rem; color: #555; height: 60px; overflow: hidden;">${book.text}</p>
<div style="margin-top: 10px;">
${book.tags.map(t => `<span class="tag">${t}</span>`).join('')}
</div>
`;
grid.appendChild(card);
});
}
// Feature 2: Semantic Search
async function performSearch() {
if (!isModelsLoaded || !embedder) {
showSearchError("Models not loaded yet. Please wait.");
return;
}
const query = document.getElementById('search-input').value.trim();
if (!query) {
showSearchError("Please enter a search query.");
return;
}
const searchBtn = document.getElementById('search-btn');
searchBtn.disabled = true;
const resultsDiv = document.getElementById('search-results');
resultsDiv.innerHTML = '<div class="spinner"></div> Searching...';
try {
// 1. Embed the query
const queryOutput = await embedder(query, { pooling: 'mean', normalize: true });
const queryVector = queryOutput.data; // Float32Array
// 2. Embed all library texts and calculate cosine similarity
const scoredBooks = libraryData.map(book => {
const bookOutput = await embedder(book.text, { pooling: 'mean', normalize: true });
const bookVector = bookOutput.data;
// Cosine Similarity Calculation
let dotProduct = 0;
let normQuery = 0;
let normBook = 0;
for (let i = 0; i < queryVector.length; i++) {
dotProduct += queryVector[i] * bookVector[i];
normQuery += queryVector[i] * queryVector[i];
normBook += bookVector[i] * bookVector[i];
}
const similarity = dotProduct / (Math.sqrt(normQuery) * Math.sqrt(normBook));
return { ...book, similarity };
});
// 3. Sort by similarity
scoredBooks.sort((a, b) => b.similarity - a.similarity);
// 4. Render Top 3
resultsDiv.innerHTML = '';
const topResults = scoredBooks.slice(0, 3);
if (topResults.length === 0) {
resultsDiv.innerHTML = '<p>No results found.</p>';
} else {
topResults.forEach(result => {
const card = document.createElement('div');
card.className = 'card';
card.style.borderLeft = "4px solid #3498db";
card.innerHTML = `
<h3>${result.title} <span style="float:right; font-size:0.8rem">Match: ${Math.round(result.similarity * 100)}%</span></h3>
<div class="meta">${result.author}</div>
<p>${result.text}</p>
`;
resultsDiv.appendChild(card);
});
}
} catch (e) {
console.error(e);
showSearchError('Error performing search: ' + e.message);
} finally {
searchBtn.disabled = false;
}
}
function showSearchError(message) {
const resultsDiv = document.getElementById('search-results');
resultsDiv.innerHTML = `<div class="error-message">${message}</div>`;
}
// Feature 3: Summarization
async function performSummarization() {
if (!isModelsLoaded || !summarizer) {
showSummarizeError("Models not loaded yet. Please wait.");
return;
}
const text = document.getElementById('summarize-input').value.trim();
if (!text) {
showSummarizeError("Please enter text to summarize.");
return;
}
const summarizeBtn = document.getElementById('summarize-btn');
summarizeBtn.disabled = true;
const outputDiv = document.getElementById('summarize-output');
outputDiv.innerHTML = '<div class="spinner"></div> Summarizing...';
try {
const result = await summarizer(text, {
top_k: 1,
max_length: 100
});
outputDiv.innerHTML = `<strong>Summary:</strong><br>${result[0].summary_text}`;
} catch (e) {
console.error(e);
showSummarizeError('Error summarizing text: ' + e.message);
} finally {
summarizeBtn.disabled = false;
}
}
function showSummarizeError(message) {
const outputDiv = document.getElementById('summarize-output');
outputDiv.innerHTML = `<div class="error-message">${message}</div>`;
}
// Feature 4: Classification (Zero-Shot)
async function performClassification() {
if (!isModelsLoaded || !classifier) {
showClassifyError("Models not loaded yet. Please wait.");
return;
}
const text = document.getElementById('classify-input').value.trim();
if (!text) {
showClassifyError("Please enter text to classify.");
return;
}
const classifyBtn = document.getElementById('classify-btn');
classifyBtn.disabled = true;
const outputDiv = document.getElementById('classify-output');
outputDiv.innerHTML = '<div class="spinner"></div> Analyzing topics...';
try {
// Define candidate labels for a library
const candidateLabels = ["Science", "History", "Fiction", "Romance", "Technology", "Biography", "Fantasy"];
const result = await classifier(text, candidateLabels);
// Format output
let html = '<strong>Recommended Tags:</strong><br>';
result.labels.forEach((label, index) => {
const score = Math.round(result.scores[index] * 100);
html += `<span class="tag" style="background:${score > 50 ? '#3498db' : '#eee'}">${label} (${score}%)</span>`;
});
outputDiv.innerHTML = html;
} catch (e) {
console.error(e);
showClassifyError('Error classifying text: ' + e.message);
} finally {
classifyBtn.disabled = false;
}
}
function showClassifyError(message) {
const outputDiv = document.getElementById('classify-output');
outputDiv.innerHTML = `<div class="error-message">${message}</div>`;
}
// Start initialization
init();
</script>
</body>
</html>