Spaces:
Sleeping
Sleeping
| <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> |