nubia / index.html
HapppyHooochie's picture
Add 2 files
b817857 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NeonBloom AI - STEM Student Assistant</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;700&display=swap');
:root {
--neon-pink: #ff6ec7;
--dark-bg: #0f0f1a;
--darker-bg: #0a0a12;
--light-text: #e0e0e0;
}
body {
font-family: 'Montserrat', sans-serif;
background-color: var(--dark-bg);
color: var(--light-text);
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path fill="rgba(255,110,199,0.05)" d="M30,10 Q50,0 70,10 Q90,20 90,40 Q100,50 90,60 Q90,80 70,90 Q50,100 30,90 Q10,80 10,60 Q0,50 10,40 Q10,20 30,10 Z"/></svg>');
background-size: 200px;
background-repeat: repeat;
}
.neon-text {
text-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink);
}
.neon-border {
border: 1px solid var(--neon-pink);
box-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink) inset;
}
.neon-glow {
box-shadow: 0 0 10px var(--neon-pink);
}
.cherry-blossom {
position: absolute;
width: 15px;
height: 15px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path fill="rgba(255,110,199,0.3)" d="M50,0 Q60,40 100,50 Q60,60 50,100 Q40,60 0,50 Q40,40 50,0 Z"/></svg>');
background-size: contain;
opacity: 0.6;
pointer-events: none;
z-index: -1;
}
.document-viewer {
background-color: rgba(15, 15, 26, 0.8);
backdrop-filter: blur(5px);
}
.model-card:hover {
transform: translateY(-5px);
transition: all 0.3s ease;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--darker-bg);
}
::-webkit-scrollbar-thumb {
background: var(--neon-pink);
border-radius: 4px;
}
/* Animation for cherry blossoms */
@keyframes fall {
0% {
transform: translateY(-10vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 0.6;
}
90% {
opacity: 0.6;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
.typing-indicator {
display: flex;
justify-content: center;
align-items: center;
}
.typing-dot {
width: 8px;
height: 8px;
margin: 0 2px;
background-color: var(--neon-pink);
border-radius: 50%;
opacity: 0.6;
animation: typing-animation 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(1) {
animation-delay: 0s;
}
.typing-dot:nth-child(2) {
animation-delay: 0.2s;
}
.typing-dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes typing-animation {
0%, 60%, 100% {
transform: translateY(0);
opacity: 0.6;
}
30% {
transform: translateY(-5px);
opacity: 1;
}
}
</style>
</head>
<body class="min-h-screen">
<!-- Cherry Blossom Animation -->
<div id="blossoms-container" class="fixed inset-0 overflow-hidden pointer-events-none"></div>
<!-- Main App Container -->
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="flex justify-between items-center mb-10">
<div class="flex items-center">
<div class="w-12 h-12 rounded-full neon-glow bg-gradient-to-br from-pink-600 to-purple-800 flex items-center justify-center mr-4">
<i class="fas fa-robot text-2xl text-white"></i>
</div>
<h1 class="text-3xl font-bold neon-text">NeonBloom AI</h1>
</div>
<div class="flex items-center space-x-4">
<button id="theme-toggle" class="w-12 h-6 rounded-full bg-gray-800 flex items-center transition duration-300 focus:outline-none shadow">
<div id="theme-toggle-dot" class="w-6 h-6 rounded-full bg-pink-500 shadow-lg transform translate-x-6"></div>
</button>
<div class="relative group">
<button class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center neon-glow hover:bg-gray-700 transition">
<i class="fas fa-user-graduate text-xl"></i>
</button>
<div class="absolute right-0 mt-2 w-48 bg-gray-900 rounded-md shadow-lg py-1 z-50 hidden group-hover:block neon-border">
<a href="#" class="block px-4 py-2 hover:bg-gray-800">Profile</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-800">Settings</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-800">Logout</a>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- Sidebar -->
<aside class="lg:col-span-1 bg-gray-900 rounded-xl p-6 neon-border">
<h2 class="text-xl font-semibold mb-6 neon-text">Navigation</h2>
<nav>
<ul class="space-y-3">
<li>
<a href="#" class="flex items-center p-3 rounded-lg hover:bg-gray-800 transition">
<i class="fas fa-home mr-3 text-pink-500"></i>
<span>Dashboard</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-3 rounded-lg bg-gray-800 transition">
<i class="fas fa-brain mr-3 text-pink-500"></i>
<span>AI Models</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-3 rounded-lg hover:bg-gray-800 transition">
<i class="fas fa-book mr-3 text-pink-500"></i>
<span>Study Materials</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-3 rounded-lg hover:bg-gray-800 transition">
<i class="fas fa-chalkboard mr-3 text-pink-500"></i>
<span>Blackboard</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-3 rounded-lg hover:bg-gray-800 transition">
<i class="fas fa-video mr-3 text-pink-500"></i>
<span>Video Lectures</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-3 rounded-lg hover:bg-gray-800 transition">
<i class="fas fa-flask mr-3 text-pink-500"></i>
<span>STEM Tools</span>
</a>
</li>
</ul>
</nav>
<div class="mt-8 pt-6 border-t border-gray-800">
<h3 class="text-lg font-semibold mb-4 neon-text">Quick Access</h3>
<div class="space-y-2">
<button id="upload-btn" class="w-full flex items-center justify-between p-3 rounded-lg bg-gray-800 hover:bg-gray-700 transition">
<span>Upload Document</span>
<i class="fas fa-upload text-pink-500"></i>
</button>
<button id="new-chat-btn" class="w-full flex items-center justify-between p-3 rounded-lg bg-gray-800 hover:bg-gray-700 transition">
<span>New Chat</span>
<i class="fas fa-comment-alt text-pink-500"></i>
</button>
<button class="w-full flex items-center justify-between p-3 rounded-lg bg-gray-800 hover:bg-gray-700 transition">
<span>Equation Solver</span>
<i class="fas fa-square-root-alt text-pink-500"></i>
</button>
</div>
</div>
<!-- Hidden file input -->
<input type="file" id="file-input" class="hidden" accept=".pdf,.jpg,.jpeg,.png,.txt,.docx">
</aside>
<!-- Main Panel -->
<div class="lg:col-span-3 space-y-8">
<!-- Model Selection -->
<section class="bg-gray-900 rounded-xl p-6 neon-border">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold neon-text">AI Model Selection</h2>
<div class="relative">
<input type="text" placeholder="Search models..." class="bg-gray-800 rounded-full py-2 px-4 pl-10 w-64 focus:outline-none focus:ring-2 focus:ring-pink-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-500"></i>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Model Cards -->
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="meta-llama/Meta-Llama-3-70B-Instruct">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-pink-900 flex items-center justify-center mr-3">
<i class="fas fa-robot text-pink-400"></i>
</div>
<h3 class="font-semibold">Llama 3 70B</h3>
</div>
<p class="text-gray-400 text-sm mb-3">Latest open model from Meta with 70B parameters, excellent for STEM reasoning.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-pink-900 bg-opacity-50 text-pink-300 px-2 py-1 rounded">Document Analysis</span>
<span class="text-gray-500">Free</span>
</div>
</div>
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="mistralai/Mistral-7B-Instruct-v0.1">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-purple-900 flex items-center justify-center mr-3">
<i class="fas fa-lock-open text-purple-400"></i>
</div>
<h3 class="font-semibold">Mistral 7B</h3>
</div>
<p class="text-gray-400 text-sm mb-3">High-quality uncensored model with 7B parameters, great for creative tasks.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-purple-900 bg-opacity-50 text-purple-300 px-2 py-1 rounded">Uncensored</span>
<span class="text-gray-500">Free</span>
</div>
</div>
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="stabilityai/stable-diffusion-xl-base-1.0">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center mr-3">
<i class="fas fa-film text-blue-400"></i>
</div>
<h3 class="font-semibold">Text-to-Image</h3>
</div>
<p class="text-gray-400 text-sm mb-3">Generate images from text descriptions with high quality results.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-blue-900 bg-opacity-50 text-blue-300 px-2 py-1 rounded">Image Generation</span>
<span class="text-gray-500">Free</span>
</div>
</div>
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="deepseek-ai/deepseek-llm-67b-chat">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-green-900 flex items-center justify-center mr-3">
<i class="fas fa-file-pdf text-green-400"></i>
</div>
<h3 class="font-semibold">DocMaster</h3>
</div>
<p class="text-gray-400 text-sm mb-3">Specialized in PDF, DOCX analysis with high accuracy for academic papers.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-green-900 bg-opacity-50 text-green-300 px-2 py-1 rounded">Document Expert</span>
<span class="text-gray-500">Free</span>
</div>
</div>
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="google/gemma-7b-it">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-yellow-900 flex items-center justify-center mr-3">
<i class="fas fa-atom text-yellow-400"></i>
</div>
<h3 class="font-semibold">STEM Specialist</h3>
</div>
<p class="text-gray-400 text-sm mb-3">Focused on science, technology, engineering, and mathematics.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-yellow-900 bg-opacity-50 text-yellow-300 px-2 py-1 rounded">STEM Focused</span>
<span class="text-gray-500">Free</span>
</div>
</div>
<div class="model-card bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-lg transition" data-model="NousResearch/Nous-Hermes-2-Mistral-7B-DPO">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-red-900 flex items-center justify-center mr-3">
<i class="fas fa-lock-open text-red-400"></i>
</div>
<h3 class="font-semibold">Uncensored Hermes</h3>
</div>
<p class="text-gray-400 text-sm mb-3">No restrictions version for unfiltered discussions and creative tasks.</p>
<div class="flex justify-between items-center text-xs">
<span class="bg-red-900 bg-opacity-50 text-red-300 px-2 py-1 rounded">Uncensored</span>
<span class="text-gray-500">Free</span>
</div>
</div>
</div>
<div class="mt-6 flex justify-between items-center">
<span class="text-sm text-gray-500">Showing 6 of 42 available models</span>
<button class="bg-pink-900 bg-opacity-50 hover:bg-opacity-70 text-pink-300 px-4 py-2 rounded-lg transition">
View All Models
</button>
</div>
</section>
<!-- Chat Interface -->
<section class="bg-gray-900 rounded-xl p-6 neon-border">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold neon-text">Chat with AI</h2>
<div class="flex space-x-3">
<button class="bg-gray-800 hover:bg-gray-700 p-2 rounded-lg transition">
<i class="fas fa-cog text-pink-500"></i>
</button>
<button id="clear-chat-btn" class="bg-gray-800 hover:bg-gray-700 p-2 rounded-lg transition">
<i class="fas fa-history text-pink-500"></i>
</button>
</div>
</div>
<div id="document-viewer" class="document-viewer rounded-lg mb-4 p-4 h-48 overflow-y-auto hidden">
<div class="flex items-center mb-3">
<i class="fas fa-file-pdf text-pink-500 mr-2"></i>
<span id="document-name" class="font-medium"></span>
<span class="ml-auto text-sm text-gray-500" id="document-time"></span>
</div>
<p id="document-preview" class="text-sm text-gray-300"></p>
</div>
<div id="chat-messages" class="chat-messages h-64 overflow-y-auto mb-4 space-y-4">
<div class="flex justify-center">
<div class="bg-gray-800 rounded-lg px-4 py-2 text-sm text-gray-400">
Select a model and start chatting or upload a document
</div>
</div>
</div>
<div class="flex items-center">
<button id="attach-btn" class="bg-gray-800 hover:bg-gray-700 p-3 rounded-lg mr-3 transition">
<i class="fas fa-paperclip text-pink-500"></i>
</button>
<div class="flex-1 relative">
<input id="chat-input" type="text" placeholder="Ask your question..." class="w-full bg-gray-800 rounded-full py-3 px-5 pr-12 focus:outline-none focus:ring-2 focus:ring-pink-500">
<button id="send-btn" class="absolute right-3 top-1/2 transform -translate-y-1/2 bg-pink-900 hover:bg-pink-800 w-8 h-8 rounded-full flex items-center justify-center transition">
<i class="fas fa-paper-plane text-sm"></i>
</button>
</div>
</div>
</section>
<!-- STEM Tools -->
<section class="bg-gray-900 rounded-xl p-6 neon-border">
<h2 class="text-2xl font-bold mb-6 neon-text">STEM Student Tools</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-pink-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-calculator text-xl text-pink-400"></i>
</div>
<span class="text-center">Equation Solver</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-purple-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-chart-line text-xl text-purple-400"></i>
</div>
<span class="text-center">Graph Plotter</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-blue-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-vial text-xl text-blue-400"></i>
</div>
<span class="text-center">Chem Lab</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-green-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-dna text-xl text-green-400"></i>
</div>
<span class="text-center">Bio Visualizer</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-yellow-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-code text-xl text-yellow-400"></i>
</div>
<span class="text-center">Code Runner</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-red-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-atom text-xl text-red-400"></i>
</div>
<span class="text-center">Physics Sim</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-indigo-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-square-root-alt text-xl text-indigo-400"></i>
</div>
<span class="text-center">Math Helper</span>
</div>
<div class="bg-gray-800 rounded-lg p-4 flex flex-col items-center cursor-pointer hover:bg-gray-700 transition">
<div class="w-12 h-12 rounded-full bg-teal-900 bg-opacity-50 flex items-center justify-center mb-3">
<i class="fas fa-brain text-xl text-teal-400"></i>
</div>
<span class="text-center">Neuroscience</span>
</div>
</div>
</section>
</div>
</main>
</div>
<!-- Footer -->
<footer class="bg-gray-900 mt-12 py-6 border-t border-gray-800">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="flex items-center mb-4 md:mb-0">
<div class="w-8 h-8 rounded-full neon-glow bg-gradient-to-br from-pink-600 to-purple-800 flex items-center justify-center mr-3">
<i class="fas fa-robot text-sm text-white"></i>
</div>
<span class="font-medium">NeonBloom AI</span>
</div>
<div class="flex space-x-6">
<a href="#" class="hover:text-pink-400 transition">Terms</a>
<a href="#" class="hover:text-pink-400 transition">Privacy</a>
<a href="#" class="hover:text-pink-400 transition">Docs</a>
<a href="#" class="hover:text-pink-400 transition">Status</a>
</div>
<div class="flex space-x-4 mt-4 md:mt-0">
<a href="#" class="w-8 h-8 rounded-full bg-gray-800 flex items-center justify-center hover:bg-gray-700 transition">
<i class="fab fa-github"></i>
</a>
<a href="#" class="w-8 h-8 rounded-full bg-gray-800 flex items-center justify-center hover:bg-gray-700 transition">
<i class="fab fa-discord"></i>
</a>
<a href="#" class="w-8 h-8 rounded-full bg-gray-800 flex items-center justify-center hover:bg-gray-700 transition">
<i class="fab fa-twitter"></i>
</a>
</div>
</div>
<div class="mt-6 text-center text-sm text-gray-500">
<p>© 2023 NeonBloom AI. All models provided by HuggingFace. Free for academic use.</p>
</div>
</div>
</footer>
<script>
// App state
const state = {
currentModel: null,
chatHistory: [],
currentDocument: null,
apiKey: "hf_YourAPIKeyHere" // Replace with your Hugging Face API key
};
// DOM elements
const elements = {
chatMessages: document.getElementById('chat-messages'),
chatInput: document.getElementById('chat-input'),
sendBtn: document.getElementById('send-btn'),
attachBtn: document.getElementById('attach-btn'),
fileInput: document.getElementById('file-input'),
documentViewer: document.getElementById('document-viewer'),
documentName: document.getElementById('document-name'),
documentPreview: document.getElementById('document-preview'),
documentTime: document.getElementById('document-time'),
uploadBtn: document.getElementById('upload-btn'),
newChatBtn: document.getElementById('new-chat-btn'),
clearChatBtn: document.getElementById('clear-chat-btn'),
modelCards: document.querySelectorAll('.model-card')
};
// Initialize the app
function init() {
// Cherry blossom animation
createBlossomAnimation();
// Event listeners
setupEventListeners();
// Load any saved state from localStorage
loadState();
}
// Create cherry blossom animation
function createBlossomAnimation() {
function createBlossom() {
const blossom = document.createElement('div');
blossom.className = 'cherry-blossom';
// Random position and size
const size = Math.random() * 10 + 5;
blossom.style.width = `${size}px`;
blossom.style.height = `${size}px`;
blossom.style.left = `${Math.random() * 100}vw`;
// Random animation duration and delay
const duration = Math.random() * 10 + 5;
const delay = Math.random() * 5;
blossom.style.animation = `fall ${duration}s linear ${delay}s infinite`;
document.getElementById('blossoms-container').appendChild(blossom);
// Remove after animation completes to prevent DOM clutter
setTimeout(() => {
blossom.remove();
}, (duration + delay) * 1000);
}
// Create multiple blossoms
for (let i = 0; i < 15; i++) {
setTimeout(createBlossom, i * 1000);
}
}
// Set up event listeners
function setupEventListeners() {
// Theme toggle
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);
// Model selection
elements.modelCards.forEach(card => {
card.addEventListener('click', () => selectModel(card));
});
// Chat input
elements.chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && elements.chatInput.value.trim() !== '') {
sendMessage();
}
});
elements.sendBtn.addEventListener('click', sendMessage);
// Document handling
elements.attachBtn.addEventListener('click', () => elements.fileInput.click());
elements.uploadBtn.addEventListener('click', () => elements.fileInput.click());
elements.fileInput.addEventListener('change', handleFileUpload);
// Chat management
elements.newChatBtn.addEventListener('click', startNewChat);
elements.clearChatBtn.addEventListener('click', clearChat);
}
// Toggle between dark and light theme
function toggleTheme() {
const dot = document.getElementById('theme-toggle-dot');
const isDark = dot.classList.contains('translate-x-6');
if (isDark) {
// Switch to light mode
dot.classList.remove('translate-x-6');
dot.classList.add('translate-x-0');
document.body.classList.remove('bg-gray-900');
document.body.classList.add('bg-gray-100');
document.body.classList.remove('text-gray-100');
document.body.classList.add('text-gray-900');
} else {
// Switch to dark mode
dot.classList.remove('translate-x-0');
dot.classList.add('translate-x-6');
document.body.classList.remove('bg-gray-100');
document.body.classList.add('bg-gray-900');
document.body.classList.remove('text-gray-900');
document.body.classList.add('text-gray-100');
}
}
// Select a model
function selectModel(card) {
// Remove selection from all cards
elements.modelCards.forEach(c => {
c.classList.remove('neon-border');
});
// Add selection to clicked card
card.classList.add('neon-border');
// Update current model
state.currentModel = card.dataset.model;
// Add message about model selection
addMessage({
type: 'system',
content: `Switched to ${card.querySelector('h3').textContent} model`
});
// Save state
saveState();
}
// Send a message to the AI
async function sendMessage() {
const message = elements.chatInput.value.trim();
if (!message) return;
if (!state.currentModel) {
addMessage({
type: 'system',
content: 'Please select a model first'
});
return;
}
// Add user message to chat
addMessage({
type: 'user',
content: message
});
// Clear input
elements.chatInput.value = '';
// Show typing indicator
const typingId = showTypingIndicator();
try {
// Prepare the prompt
let prompt = message;
if (state.currentDocument) {
prompt = `Document context: ${state.currentDocument.content.substring(0, 1000)}...\n\nQuestion: ${message}`;
}
// Call the Hugging Face API
const response = await queryHuggingFace(state.currentModel, prompt);
// Remove typing indicator
removeTypingIndicator(typingId);
// Add AI response to chat
addMessage({
type: 'ai',
content: response,
model: state.currentModel
});
// Save state
saveState();
} catch (error) {
console.error('Error calling Hugging Face API:', error);
removeTypingIndicator(typingId);
addMessage({
type: 'system',
content: 'Error getting response from the AI. Please try again.'
});
}
}
// Query Hugging Face API
async function queryHuggingFace(model, prompt) {
// Different endpoints for different model types
let endpoint;
let payload;
if (model.includes('stable-diffusion')) {
// Image generation model
endpoint = `https://api-inference.huggingface.co/models/${model}`;
payload = { inputs: prompt };
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${state.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const imageBlob = await response.blob();
const imageUrl = URL.createObjectURL(imageBlob);
return `![Generated Image](${imageUrl})`;
} else {
// Text generation model
endpoint = `https://api-inference.huggingface.co/models/${model}`;
payload = {
inputs: prompt,
parameters: {
max_new_tokens: 500,
temperature: 0.7,
top_p: 0.9
}
};
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${state.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (Array.isArray(result) && result[0].generated_text) {
return result[0].generated_text;
} else if (result.error) {
throw new Error(result.error);
} else {
return "I couldn't generate a response. Please try again.";
}
}
}
// Handle file upload
async function handleFileUpload(event) {
const file = event.target.files[0];
if (!file) return;
// Reset file input
elements.fileInput.value = '';
// Show loading state
addMessage({
type: 'system',
content: `Processing ${file.name}...`
});
try {
let content;
if (file.type === 'application/pdf') {
// PDF processing
content = await extractTextFromPDF(file);
} else if (file.type.startsWith('image/')) {
// Image processing
content = await extractTextFromImage(file);
} else if (file.type === 'text/plain' || file.name.endsWith('.txt')) {
// Text file processing
content = await file.text();
} else if (file.name.endsWith('.docx')) {
// DOCX processing
content = await extractTextFromDOCX(file);
} else {
throw new Error('Unsupported file type');
}
// Update document state
state.currentDocument = {
name: file.name,
content: content,
uploadedAt: new Date().toLocaleString()
};
// Show document preview
showDocumentPreview();
// Add success message
addMessage({
type: 'system',
content: `Document "${file.name}" uploaded successfully. You can now ask questions about it.`
});
// Save state
saveState();
} catch (error) {
console.error('Error processing file:', error);
addMessage({
type: 'system',
content: `Error processing ${file.name}: ${error.message}`
});
}
}
// Extract text from PDF (simplified - in a real app you'd use a library like pdf.js)
async function extractTextFromPDF(file) {
return new Promise((resolve) => {
// Simulate PDF processing
setTimeout(() => {
resolve(`PDF content extracted from ${file.name}. This would contain the actual text from the PDF in a real implementation.`);
}, 1500);
});
}
// Extract text from image (simplified - in a real app you'd use OCR)
async function extractTextFromImage(file) {
return new Promise((resolve) => {
// Simulate OCR processing
setTimeout(() => {
resolve(`Text extracted from image ${file.name}. This would contain the OCR results in a real implementation.`);
}, 1500);
});
}
// Extract text from DOCX (simplified - in a real app you'd use a library like mammoth)
async function extractTextFromDOCX(file) {
return new Promise((resolve) => {
// Simulate DOCX processing
setTimeout(() => {
resolve(`DOCX content extracted from ${file.name}. This would contain the actual text from the document in a real implementation.`);
}, 1500);
});
}
// Show document preview
function showDocumentPreview() {
if (!state.currentDocument) {
elements.documentViewer.classList.add('hidden');
return;
}
elements.documentName.textContent = state.currentDocument.name;
elements.documentPreview.textContent = state.currentDocument.content.substring(0, 500) + '...';
elements.documentTime.textContent = state.currentDocument.uploadedAt;
elements.documentViewer.classList.remove('hidden');
}
// Add a message to the chat
function addMessage({ type, content, model }) {
let messageElement;
switch (type) {
case 'user':
messageElement = createUserMessage(content);
break;
case 'ai':
messageElement = createAIMessage(content, model);
break;
case 'system':
messageElement = createSystemMessage(content);
break;
default:
return;
}
elements.chatMessages.appendChild(messageElement);
elements.chatMessages.scrollTop = elements.chatMessages.scrollHeight;
// Add to chat history
state.chatHistory.push({ type, content, model, timestamp: new Date() });
}
// Create user message element
function createUserMessage(content) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex';
messageDiv.innerHTML = `
<div class="w-8 h-8 rounded-full bg-pink-900 flex items-center justify-center mr-3">
<i class="fas fa-user text-sm"></i>
</div>
<div class="bg-gray-800 rounded-lg p-3 max-w-3/4">
<p>${content}</p>
</div>
`;
return messageDiv;
}
// Create AI message element
function createAIMessage(content, model) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex justify-end';
// Handle image responses
if (content.startsWith('![Generated Image](')) {
const imageUrl = content.match(/\(([^)]+)\)/)[1];
messageDiv.innerHTML = `
<div class="bg-pink-900 bg-opacity-30 rounded-lg p-3 max-w-3/4">
<img src="${imageUrl}" alt="Generated image" class="max-w-full rounded-lg">
<div class="mt-2 text-xs text-pink-300 flex items-center">
<i class="fas fa-robot mr-1"></i>
<span>${model}</span>
</div>
</div>
<div class="w-8 h-8 rounded-full bg-gray-700 flex items-center justify-center ml-3">
<i class="fas fa-robot text-sm"></i>
</div>
`;
} else {
messageDiv.innerHTML = `
<div class="bg-pink-900 bg-opacity-30 rounded-lg p-3 max-w-3/4">
<p>${content}</p>
<div class="mt-2 text-xs text-pink-300 flex items-center">
<i class="fas fa-robot mr-1"></i>
<span>${model}</span>
</div>
</div>
<div class="w-8 h-8 rounded-full bg-gray-700 flex items-center justify-center ml-3">
<i class="fas fa-robot text-sm"></i>
</div>
`;
}
return messageDiv;
}
// Create system message element
function createSystemMessage(content) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex justify-center';
messageDiv.innerHTML = `
<div class="bg-gray-800 rounded-lg px-4 py-2 text-sm text-gray-400">
${content}
</div>
`;
return messageDiv;
}
// Show typing indicator
function showTypingIndicator() {
const typingId = 'typing-' + Date.now();
const typingDiv = document.createElement('div');
typingDiv.className = 'flex justify-end';
typingDiv.id = typingId;
typingDiv.innerHTML = `
<div class="bg-pink-900 bg-opacity-30 rounded-lg p-3 max-w-3/4">
<div class="typing-indicator flex space-x-1">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>
</div>
<div class="w-8 h-8 rounded-full bg-gray-700 flex items-center justify-center ml-3">
<i class="fas fa-robot text-sm"></i>
</div>
`;
elements.chatMessages.appendChild(typingDiv);
elements.chatMessages.scrollTop = elements.chatMessages.scrollHeight;
return typingId;
}
// Remove typing indicator
function removeTypingIndicator(id) {
const indicator = document.getElementById(id);
if (indicator) {
indicator.remove();
}
}
// Start a new chat
function startNewChat() {
state.chatHistory = [];
elements.chatMessages.innerHTML = `
<div class="flex justify-center">
<div class="bg-gray-800 rounded-lg px-4 py-2 text-sm text-gray-400">
Select a model and start chatting or upload a document
</div>
</div>
`;
if (state.currentDocument) {
showDocumentPreview();
}
saveState();
}
// Clear chat but keep current model and document
function clearChat() {
state.chatHistory = [];
elements.chatMessages.innerHTML = `
<div class="flex justify-center">
<div class="bg-gray-800 rounded-lg px-4 py-2 text-sm text-gray-400">
Chat cleared. Ready for new messages.
</div>
</div>
`;
if (state.currentDocument) {
showDocumentPreview();
}
saveState();
}
// Save app state to localStorage
function saveState() {
localStorage.setItem('neonbloomState', JSON.stringify({
currentModel: state.currentModel,
chatHistory: state.chatHistory,
currentDocument: state.currentDocument
}));
}
// Load app state from localStorage
function loadState() {
const savedState = localStorage.getItem('neonbloomState');
if (savedState) {
const parsedState = JSON.parse(savedState);
// Restore state
state.currentModel = parsedState.currentModel;
state.chatHistory = parsedState.chatHistory || [];
state.currentDocument = parsedState.currentDocument;
// Restore UI
if (state.currentModel) {
const modelCard = document.querySelector(`.model-card[data-model="${state.currentModel}"]`);
if (modelCard) {
modelCard.classList.add('neon-border');
}
}
if (state.currentDocument) {
showDocumentPreview();
}
// Restore chat history
if (state.chatHistory.length > 0) {
elements.chatMessages.innerHTML = '';
state.chatHistory.forEach(msg => addMessage(msg));
}
}
}
// Initialize the app when DOM is loaded
document.addEventListener('DOMContentLoaded', init);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=HapppyHooochie/nubia" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>