Chat-Humour-LLM-v1 / index.html
DarkNeuron-AI's picture
Update index.html
07c8330 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>DNAI Humour - Advanced</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600&display=swap');
* { font-family: 'Inter', sans-serif; -webkit-tap-highlight-color: transparent; }
h1, h2, h3, button { font-family: 'Space Grotesk', sans-serif; }
/* Animations */
@keyframes blob {
0% { transform: translate(0px, 0px) scale(1); }
33% { transform: translate(30px, -50px) scale(1.1); }
66% { transform: translate(-20px, 20px) scale(0.9); }
100% { transform: translate(0px, 0px) scale(1); }
}
@keyframes twinkle {
0%, 100% { opacity: 0.2; transform: scale(1); }
50% { opacity: 1; transform: scale(1.5); }
}
.animate-blob { animation: blob 7s infinite; }
.animation-delay-2000 { animation-delay: 2s; }
.animation-delay-4000 { animation-delay: 4s; }
/* Custom Scrollbar */
.custom-scrollbar::-webkit-scrollbar { width: 4px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(156, 163, 175, 0.5); border-radius: 4px; }
/* Range Slider Styling */
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: #8b5cf6;
cursor: pointer;
margin-top: -6px;
box-shadow: 0 0 10px rgba(139, 92, 246, 0.5);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
}
.glass-panel {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.glass-panel-light {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(16px);
border: 1px solid rgba(0, 0, 0, 0.05);
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useRef } = React;
// --- Icons ---
const Icon = ({ path, className = "w-5 h-5" }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>{path}</svg>
);
const Icons = {
Brain: (p) => <Icon {...p} path={<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2ZM14.5 2a2.5 2.5 0 0 0-2.5 2.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>} />,
Send: (p) => <Icon {...p} path={<><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></>} />,
Settings: (p) => <Icon {...p} path={<><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></>} />,
X: (p) => <Icon {...p} path={<><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></>} />,
Sun: (p) => <Icon {...p} path={<><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></>} />,
Moon: (p) => <Icon {...p} path={<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>} />,
Refresh: (p) => <Icon {...p} path={<path d="M23 4v6h-6M1 20v-6h6"></path>} />,
User: (p) => <Icon {...p} path={<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>} />
};
// --- Components ---
const SettingsPanel = ({ isOpen, onClose, settings, setSettings, darkMode }) => {
const panelClass = darkMode ? 'bg-slate-900 border-l border-slate-700' : 'bg-white border-l border-gray-200';
const textClass = darkMode ? 'text-gray-200' : 'text-gray-800';
const inputBg = darkMode ? 'bg-slate-800 border-slate-700' : 'bg-gray-100 border-gray-200';
return (
<div className={`fixed inset-y-0 right-0 w-full sm:w-80 transform transition-transform duration-300 ease-in-out z-50 ${isOpen ? 'translate-x-0' : 'translate-x-full'} ${panelClass} shadow-2xl`}>
<div className="p-6 h-full flex flex-col">
<div className="flex justify-between items-center mb-8">
<h2 className={`text-xl font-bold ${textClass}`}>Configuration</h2>
<button onClick={onClose} className={`p-2 rounded-full hover:bg-opacity-10 hover:bg-gray-500 transition-colors ${textClass}`}>
<Icons.X className="w-6 h-6" />
</button>
</div>
<div className="space-y-6 flex-1 overflow-y-auto custom-scrollbar pr-2">
{/* System Prompt */}
<div>
<label className={`block text-sm font-medium mb-2 ${textClass}`}>System Persona</label>
<textarea
value={settings.systemPrompt}
onChange={(e) => setSettings({...settings, systemPrompt: e.target.value})}
className={`w-full p-3 rounded-xl text-sm h-32 resize-none focus:outline-none focus:ring-2 focus:ring-purple-500 ${inputBg} ${textClass}`}
placeholder="Define how the AI should behave..."
/>
</div>
{/* Temperature */}
<div>
<div className="flex justify-between mb-2">
<label className={`text-sm font-medium ${textClass}`}>Creativity (Temp)</label>
<span className="text-xs font-mono text-purple-500">{settings.temperature}</span>
</div>
<input
type="range" min="0.1" max="1.5" step="0.1"
value={settings.temperature}
onChange={(e) => setSettings({...settings, temperature: parseFloat(e.target.value)})}
/>
</div>
{/* Top P */}
<div>
<div className="flex justify-between mb-2">
<label className={`text-sm font-medium ${textClass}`}>Focus (Top P)</label>
<span className="text-xs font-mono text-purple-500">{settings.topP}</span>
</div>
<input
type="range" min="0.1" max="1.0" step="0.05"
value={settings.topP}
onChange={(e) => setSettings({...settings, topP: parseFloat(e.target.value)})}
/>
</div>
{/* Max Tokens */}
<div>
<div className="flex justify-between mb-2">
<label className={`text-sm font-medium ${textClass}`}>Response Length</label>
<span className="text-xs font-mono text-purple-500">{settings.maxTokens}</span>
</div>
<input
type="range" min="64" max="1024" step="64"
value={settings.maxTokens}
onChange={(e) => setSettings({...settings, maxTokens: parseInt(e.target.value)})}
/>
</div>
</div>
<div className="mt-6 pt-6 border-t border-gray-700/20">
<button
onClick={() => setSettings({
temperature: 0.7,
topP: 0.9,
maxTokens: 256,
systemPrompt: "You are DNAI, a helpful and humorous AI assistant."
})}
className="w-full py-3 rounded-xl text-sm font-medium bg-purple-500/10 text-purple-500 hover:bg-purple-500/20 transition-all"
>
Reset to Defaults
</button>
</div>
</div>
</div>
);
};
const MainApp = () => {
const [darkMode, setDarkMode] = useState(true);
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [settings, setSettings] = useState({
temperature: 0.7,
topP: 0.8,
maxTokens: 64,
systemPrompt: "You are DN-Humour, a helpful and humorous AI assistant, created by DarkNeuronAI. Always answer in a funny, sarcastic and humorous way. You like to joke and make fun of everything."
});
const [messages, setMessages] = useState([
{ role: 'assistant', content: "System Online! DarkNeuron Core Initialized. How Can I Help You Today?", timestamp: new Date() }
]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const messagesEndRef = useRef(null);
const scrollToBottom = () => messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
useEffect(scrollToBottom, [messages]);
const sendMessage = async () => {
if (!input.trim() || loading) return;
const userMessage = { role: 'user', content: input, timestamp: new Date() };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage],
temperature: settings.temperature,
top_p: settings.topP,
max_tokens: settings.maxTokens,
system_prompt: settings.systemPrompt
})
});
if (!response.ok) throw new Error('API Error');
const data = await response.json();
setMessages(prev => [...prev, { role: 'assistant', content: data.response, timestamp: new Date() }]);
} catch (error) {
setMessages(prev => [...prev, { role: 'assistant', content: "โš ๏ธ Error connecting to neural pathways. Please try again.", timestamp: new Date() }]);
} finally {
setLoading(false);
}
};
// Dynamic Classes
const bgClass = darkMode ? 'bg-slate-950' : 'bg-gray-50';
const glassClass = darkMode ? 'glass-panel' : 'glass-panel-light';
const textClass = darkMode ? 'text-white' : 'text-gray-800';
return (
<div className={`min-h-screen relative overflow-hidden transition-colors duration-500 ${bgClass}`}>
{/* Animated Background (CSS Only for Performance) */}
<div className="absolute inset-0 overflow-hidden pointer-events-none">
<div className={`absolute -top-20 -left-20 w-72 h-72 bg-purple-500 rounded-full mix-blend-multiply filter blur-xl opacity-20 animate-blob`}></div>
<div className={`absolute top-0 -right-4 w-72 h-72 bg-blue-500 rounded-full mix-blend-multiply filter blur-xl opacity-20 animate-blob animation-delay-2000`}></div>
<div className={`absolute -bottom-8 left-20 w-72 h-72 bg-pink-500 rounded-full mix-blend-multiply filter blur-xl opacity-20 animate-blob animation-delay-4000`}></div>
{darkMode && Array.from({length: 20}).map((_, i) => (
<div key={i} className="absolute bg-white rounded-full animate-[twinkle_4s_ease-in-out_infinite]"
style={{
top: `${Math.random() * 100}%`, left: `${Math.random() * 100}%`,
width: Math.random() * 3 + 'px', height: Math.random() * 3 + 'px',
animationDelay: `${Math.random() * 5}s`
}}
/>
))}
</div>
{/* Overlay for Settings */}
{isSettingsOpen && <div onClick={() => setIsSettingsOpen(false)} className="fixed inset-0 bg-black/50 backdrop-blur-sm z-40 transition-opacity" />}
{/* Settings Panel */}
<SettingsPanel
isOpen={isSettingsOpen}
onClose={() => setIsSettingsOpen(false)}
settings={settings}
setSettings={setSettings}
darkMode={darkMode}
/>
{/* Main Content */}
<div className="relative z-10 flex flex-col h-[100dvh] max-w-5xl mx-auto p-4 md:p-6">
{/* Header */}
<div className="flex justify-between items-center mb-4">
<div className="flex items-center gap-3">
<div className={`p-2.5 rounded-xl bg-gradient-to-br from-indigo-600 to-purple-600 shadow-lg shadow-purple-500/20`}>
<Icons.Brain className="w-6 h-6 text-white" />
</div>
<div>
<h1 className={`text-xl font-bold tracking-tight ${textClass}`}>DarkNeuronAI <span className="text-purple-500">v1.1</span></h1>
</div>
</div>
<div className={`flex items-center gap-2 p-1.5 rounded-2xl ${darkMode ? 'bg-slate-900/50' : 'bg-white/50'} border border-gray-200/10`}>
<button onClick={() => setDarkMode(!darkMode)} className={`p-2 rounded-xl transition-all ${darkMode ? 'hover:bg-slate-800 text-yellow-400' : 'hover:bg-gray-200 text-slate-700'}`}>
{darkMode ? <Icons.Sun className="w-5 h-5"/> : <Icons.Moon className="w-5 h-5"/>}
</button>
<div className="w-px h-6 bg-gray-500/20"></div>
<button onClick={() => setIsSettingsOpen(true)} className={`p-2 rounded-xl transition-all ${darkMode ? 'hover:bg-slate-800 text-gray-300' : 'hover:bg-gray-200 text-gray-600'}`}>
<Icons.Settings className="w-5 h-5"/>
</button>
</div>
</div>
{/* Chat Area */}
<div className={`flex-1 rounded-3xl mb-4 overflow-hidden flex flex-col shadow-2xl border ${glassClass} ${darkMode ? 'border-slate-700/50' : 'border-white/50'}`}>
<div className="flex-1 overflow-y-auto p-4 space-y-6 custom-scrollbar">
{messages.map((msg, idx) => (
<div key={idx} className={`flex gap-4 ${msg.role === 'user' ? 'flex-row-reverse' : ''}`}>
<div className={`w-8 h-8 rounded-lg flex-shrink-0 flex items-center justify-center text-xs font-bold shadow-lg
${msg.role === 'user'
? 'bg-gradient-to-br from-pink-500 to-rose-500 text-white'
: 'bg-gradient-to-br from-indigo-500 to-blue-600 text-white'}`}>
{msg.role === 'user' ? 'YOU' : 'AI'}
</div>
<div className={`max-w-[85%] md:max-w-[75%]`}>
<div className={`p-3.5 rounded-2xl shadow-sm text-sm md:text-base leading-relaxed
${msg.role === 'user'
? 'bg-gradient-to-r from-purple-600 to-indigo-600 text-white rounded-tr-sm'
: (darkMode ? 'bg-slate-800 text-slate-200' : 'bg-white text-gray-800') + ' rounded-tl-sm'}`}>
{msg.content}
</div>
<div className={`text-[10px] mt-1 opacity-50 ${textClass} ${msg.role === 'user' ? 'text-right' : 'text-left'}`}>
{msg.timestamp.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}
</div>
</div>
</div>
))}
{loading && (
<div className="flex gap-4">
<div className="w-8 h-8 rounded-lg bg-indigo-600 flex items-center justify-center"><Icons.Brain className="w-4 h-4 text-white animate-pulse"/></div>
<div className={`p-4 rounded-2xl ${darkMode ? 'bg-slate-800' : 'bg-white'}`}>
<div className="flex gap-1.5">
{[0, 1, 2].map(i => (
<div key={i} className="w-2 h-2 rounded-full bg-indigo-400 animate-bounce" style={{animationDelay: `${i * 0.15}s`}}/>
))}
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{/* Input Area */}
<div className={`p-3 md:p-4 border-t ${darkMode ? 'border-slate-700/50 bg-slate-900/30' : 'border-gray-200/50 bg-white/50'}`}>
<div className={`flex items-end gap-2 p-1.5 rounded-2xl border transition-all focus-within:ring-2 focus-within:ring-purple-500/50
${darkMode ? 'bg-slate-800 border-slate-700' : 'bg-white border-gray-200'}`}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && !e.shiftKey && (e.preventDefault(), sendMessage())}
placeholder="Type A Message..."
rows="1"
className={`flex-1 bg-transparent border-none focus:ring-0 p-3 max-h-32 resize-none custom-scrollbar ${textClass} placeholder-opacity-50`}
/>
<button
onClick={sendMessage}
disabled={!input.trim() || loading}
className={`p-3 rounded-xl flex-shrink-0 transition-all active:scale-95
${!input.trim() || loading
? 'bg-gray-500/20 text-gray-500 cursor-not-allowed'
: 'bg-gradient-to-r from-indigo-500 to-purple-500 text-white shadow-lg shadow-purple-500/25 hover:shadow-purple-500/40'}`}
>
<Icons.Send className="w-5 h-5" />
</button>
</div>
<div className="text-center mt-2">
<p className={`text-[10px] uppercase tracking-widest opacity-40 ${textClass}`}>Powered by DarkNeuronAI</p>
</div>
</div>
</div>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MainApp />);
</script>
</body>
</html>