Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>CatGPT</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<script> | |
tailwind.config = { | |
darkMode: 'class', | |
theme: { | |
extend: { | |
colors: { | |
dark: { | |
50: '#f9fafb', | |
100: '#f3f4f6', | |
200: '#e5e7eb', | |
300: '#d1d5db', | |
400: '#9ca3af', | |
500: '#6b7280', | |
600: '#4b5563', | |
700: '#374151', | |
800: '#1f2937', | |
900: '#111827', | |
primary: '#10a37f', | |
chat: '#343541', | |
input: '#40414f', | |
} | |
} | |
} | |
} | |
} | |
</script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
body { | |
font-family: 'Inter', sans-serif; | |
background-color: #343541; | |
color: #d1d5db; | |
height: 100vh; | |
overflow: hidden; | |
} | |
.catgpt-logo { | |
font-size: 1.25rem; | |
font-weight: 800; | |
letter-spacing: -0.03em; | |
} | |
.messages-container { | |
scrollbar-width: thin; | |
scrollbar-color: #4b5563 #343541; | |
} | |
.messages-container::-webkit-scrollbar { | |
width: 6px; | |
} | |
.messages-container::-webkit-scrollbar-track { | |
background: #343541; | |
} | |
.messages-container::-webkit-scrollbar-thumb { | |
background-color: #4b5563; | |
border-radius: 3px; | |
} | |
.input-textarea { | |
resize: none; | |
max-height: 200px; | |
} | |
.chat-message { | |
transition: background-color 0.2s ease; | |
} | |
.user-message { | |
background-color: #40414f; | |
} | |
.assistant-message { | |
background-color: #343541; | |
} | |
.model-selector { | |
background: #10a37f; | |
} | |
.regenerate-button { | |
border: 1px solid #4b5563; | |
} | |
.code-block { | |
background-color: rgba(16, 163, 127, 0.1); | |
border-radius: 0.375rem; | |
font-family: monospace; | |
padding: 0.25rem 0.5rem; | |
} | |
.animate-pulse { | |
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; | |
} | |
@keyframes pulse { | |
0%, 100% { | |
opacity: 1; | |
} | |
50% { | |
opacity: 0.5; | |
} | |
} | |
.typing-indicator span { | |
display: inline-block; | |
width: 8px; | |
height: 8px; | |
border-radius: 50%; | |
background-color: #9ca3af; | |
margin: 0 2px; | |
animation: bounce 1.4s infinite ease-in-out both; | |
} | |
.typing-indicator span:nth-child(1) { | |
animation-delay: -0.32s; | |
} | |
.typing-indicator span:nth-child(2) { | |
animation-delay: -0.16s; | |
} | |
@keyframes bounce { | |
0%, 80%, 100% { | |
transform: scale(0); | |
} | |
40% { | |
transform: scale(1.0); | |
} | |
} | |
</style> | |
</head> | |
<body class="flex flex-col h-screen bg-dark-700"> | |
<!-- Sidebar for desktop --> | |
<div class="hidden md:flex md:w-64 lg:w-72 bg-dark-800 flex-col fixed h-full border-r border-dark-600"> | |
<div class="flex items-center p-4 border-b border-dark-600"> | |
<button class="p-2 rounded-md hover:bg-dark-700 mr-2"> | |
<i class="fas fa-bars text-dark-200"></i> | |
</button> | |
<div class="catgpt-logo">🐱 CatGPT</div> | |
</div> | |
<button class="flex items-center justify-between p-3 mx-2 my-2 rounded-md border border-dark-600 hover:bg-dark-700 text-dark-200"> | |
<span class="flex items-center"> | |
<i class="fas fa-plus mr-2 text-dark-400"></i> | |
<span>New Chat</span> | |
</span> | |
<i class="fas fa-pencil-alt text-xs text-dark-500"></i> | |
</button> | |
<div class="flex-1 overflow-y-auto messages-container py-2"> | |
<div class="px-2"> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left text-dark-200"> | |
<i class="fas fa-comment text-dark-400"></i> | |
<span class="truncate">Meow about quantum physics</span> | |
</button> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left text-dark-200"> | |
<i class="fas fa-comment text-dark-400"></i> | |
<span class="truncate">Purr me a JavaScript function</span> | |
</button> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left text-dark-200"> | |
<i class="fas fa-comment text-dark-400"></i> | |
<span class="truncate">Meow me some CSS tips</span> | |
</button> | |
</div> | |
<div class="p-4 text-dark-500 text-sm mt-4"> | |
Previous conversations | |
</div> | |
<div class="px-2"> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left text-dark-200"> | |
<i class="fas fa-comment text-dark-400"></i> | |
<span class="truncate">Meow-tivation for coding</span> | |
</button> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left text-dark-200"> | |
<i class="fas fa-comment text-dark-400"></i> | |
<span class="truncate">Best nap positions</span> | |
</button> | |
</div> | |
</div> | |
<div class="p-4 border-t border-dark-600"> | |
<div class="flex items-center p-3 rounded-md hover:bg-dark-700 cursor-pointer text-dark-200"> | |
<div class="w-8 h-8 rounded-full bg-dark-600 flex items-center justify-center mr-2"> | |
<i class="fas fa-user text-dark-400"></i> | |
</div> | |
<span class="truncate">catlover@example.com</span> | |
</div> | |
<button class="flex items-center space-x-3 p-3 rounded-md hover:bg-dark-700 w-full text-left mt-2 text-dark-200"> | |
<i class="fas fa-cog text-dark-400"></i> | |
<span>Settings</span> | |
</button> | |
</div> | |
</div> | |
<!-- Main content area --> | |
<div class="flex-1 flex flex-col md:ml-64 lg:ml-72 bg-dark-700"> | |
<!-- Mobile header --> | |
<header class="flex justify-between items-center p-4 border-b border-dark-600 bg-dark-800 md:hidden"> | |
<button class="p-2 rounded-md hover:bg-dark-700"> | |
<i class="fas fa-bars text-dark-200"></i> | |
</button> | |
<div class="catgpt-logo">🐱 CatGPT</div> | |
<button class="p-2 rounded-md hover:bg-dark-700"> | |
<i class="fas fa-user text-dark-200"></i> | |
</button> | |
</header> | |
<!-- Model info bar --> | |
<div class="flex items-center justify-between p-2 bg-dark-800 border-b border-dark-600 text-xs text-dark-400"> | |
<span class="px-2">Model: Meow-4</span> | |
<div class="flex space-x-2"> | |
<button class="px-2 py-1 rounded hover:bg-dark-700">Temporary chat</button> | |
<button class="px-2 py-1 rounded hover:bg-dark-700"><i class="fas fa-compass"></i></button> | |
</div> | |
</div> | |
<!-- Messages container --> | |
<div class="flex-1 overflow-y-auto messages-container" id="messagesContainer"> | |
<!-- Welcome message --> | |
<div class="flex flex-col items-center justify-center text-center py-16 px-4"> | |
<div class="mb-6"> | |
<div class="catgpt-logo text-4xl mb-2">🐱 CatGPT</div> | |
<div class="text-dark-400">The purrfect AI model for all your meow needs</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-8 w-full max-w-5xl"> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Meow about quantum physics</h3> | |
<p class="text-sm text-dark-400">but keep it simple for humans</p> | |
</button> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Create a purr-gram</h3> | |
<p class="text-sm text-dark-400">to calculate nap intervals</p> | |
</button> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Explain bird watching</h3> | |
<p class="text-sm text-dark-400">from a cat's perspective</p> | |
</button> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Design a scratching post</h3> | |
<p class="text-sm text-dark-400">that also tracks your naps</p> | |
</button> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Write a purr-ome</h3> | |
<p class="text-sm text-dark-400">about tuna fishing</p> | |
</button> | |
<button class="example-prompt p-4 rounded-lg bg-dark-800 border border-dark-600 hover:border-dark-primary cursor-pointer hover:text-dark-primary text-left"> | |
<h3 class="font-bold mb-2">Recommend books</h3> | |
<p class="text-sm text-dark-400">about feline philosophy</p> | |
</button> | |
</div> | |
</div> | |
<!-- Example conversation (hidden by default) --> | |
<div id="sampleMessages" class="hidden"> | |
<div class="chat-message user-message border-b border-dark-600 p-4"> | |
<div class="max-w-3xl mx-auto flex items-start gap-4"> | |
<div class="w-8 h-8 rounded-full bg-dark-600 flex items-center justify-center flex-shrink-0"> | |
<i class="fas fa-user text-dark-400"></i> | |
</div> | |
<div class="flex-1"> | |
<p>How do I center a div in CSS?</p> | |
</div> | |
<div class="flex items-center space-x-2 opacity-0 group-hover:opacity-100"> | |
<button class="action-button p-1 text-dark-400 hover:text-dark-200"> | |
<i class="fas fa-pencil-alt text-sm"></i> | |
</button> | |
<button class="action-button p-1 text-dark-400 hover:text-dark-200"> | |
<i class="fas fa-copy text-sm"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="chat-message assistant-message border-b border-dark-600 p-4"> | |
<div class="max-w-3xl mx-auto flex items-start gap-4"> | |
<div class="w-8 h-8 rounded-full bg-dark-primary flex items-center justify-center flex-shrink-0"> | |
<i class="fas fa-paw text-white"></i> | |
</div> | |
<div class="flex-1"> | |
<p>Meow meow meow meow meow:</p> | |
<div class="code-block mt-2"> | |
.container {<br> | |
display: flex;<br> | |
justify-content: center;<br> | |
align-items: center;<br> | |
}<br> | |
</div> | |
<div class="flex items-center mt-3 space-x-2"> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-thumbs-up mr-1"></i> | |
</button> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-thumbs-down mr-1"></i> | |
</button> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-copy mr-1"></i> Copy | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Input area --> | |
<div class="p-4 bg-dark-800 border-t border-dark-600"> | |
<!-- Regenerate response button --> | |
<div id="regenerateButton" class="max-w-3xl mx-auto mb-4 bg-dark-800 rounded-lg p-3 hidden"> | |
<div class="flex justify-center"> | |
<button class="regenerate-button flex items-center space-x-2 px-4 py-2 rounded-md hover:bg-dark-700 text-sm text-dark-200"> | |
<i class="fas fa-redo"></i> | |
<span>Regenerate response</span> | |
</button> | |
</div> | |
</div> | |
<!-- Main input box --> | |
<div class="max-w-3xl mx-auto relative"> | |
<div class="relative"> | |
<textarea | |
id="messageInput" | |
class="input-textarea w-full p-4 pr-16 rounded-lg bg-dark-700 border border-dark-600 focus:outline-none focus:border-dark-500 text-dark-200 shadow-sm" | |
placeholder="Message CatGPT..." | |
rows="1" | |
></textarea> | |
<div class="absolute right-3 bottom-3 flex space-x-2"> | |
<button id="sendButton" class="p-2 rounded-md text-dark-400 hover:bg-dark-700"> | |
<i class="fas fa-paw text-dark-400 hover:text-dark-primary"></i> | |
</button> | |
</div> | |
</div> | |
<div class="text-xs text-dark-500 mt-2 text-center"> | |
CatGPT can make mistakes. Consider checking important information (with your human). | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
const messageInput = document.getElementById('messageInput'); | |
const sendButton = document.getElementById('sendButton'); | |
const messagesContainer = document.getElementById('messagesContainer'); | |
const regenerateButton = document.getElementById('regenerateButton'); | |
const examplePrompts = document.querySelectorAll('.example-prompt'); | |
const sampleMessages = document.getElementById('sampleMessages'); | |
// Cat-like responses | |
const meows = [ | |
"Meow", "Mew", "Purr", "Mrow", "Mewo", "Mrrp", "Mrao", "Paw", "Nya", "Meowww", | |
"Meow meow", "Purr purr", "Meow purr", "Mrow?", "Mew meow", "Prrrr", "Mrraow", | |
"Meow *licks paw*", "Meow *tail flick*", "Purrrr *headbutt*", "*pounces* Meow!", | |
"Meow *stretches*", "Prrrr *kneads*", "Mew *blinks slowly*" | |
]; | |
// Generate random meow response | |
function generateMeowResponse() { | |
const sentenceLength = Math.floor(Math.random() * 5) + 3; | |
let response = ""; | |
for (let i = 0; i < sentenceLength; i++) { | |
const meow = meows[Math.floor(Math.random() * meows.length)]; | |
response += i === 0 ? meow : " " + meow.toLowerCase(); | |
// Add random cat behavior | |
if (Math.random() > 0.8) { | |
const behaviors = ["*purrs*", "*flicks tail*", "*blinks slowly*", "*kneads*", "*licks paw*", "*rolls over*"]; | |
response += " " + behaviors[Math.floor(Math.random() * behaviors.length)]; | |
} | |
} | |
return response + (Math.random() > 0.7 ? "?" : "."); | |
} | |
// Auto-resize textarea | |
messageInput.addEventListener('input', function() { | |
this.style.height = 'auto'; | |
this.style.height = (this.scrollHeight) + 'px'; | |
}); | |
// Focus the input on load | |
messageInput.focus(); | |
// Add message to the chat | |
function addMessage(content, isUser) { | |
// Hide welcome message when first message is sent | |
if (document.querySelector('.flex.flex-col.items-center.justify-center')) { | |
document.querySelector('.flex.flex-col.items-center.justify-center').style.display = 'none'; | |
regenerateButton.classList.remove('hidden'); | |
} | |
// If this is the first user message, hide sample messages | |
if (isUser && sampleMessages) { | |
sampleMessages.style.display = 'none'; | |
} | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = `chat-message ${isUser ? 'user-message' : 'assistant-message'} border-b border-dark-600 p-4`; | |
if (isUser) { | |
messageDiv.innerHTML = ` | |
<div class="max-w-3xl mx-auto flex items-start gap-4"> | |
<div class="w-8 h-8 rounded-full bg-dark-600 flex items-center justify-center flex-shrink-0"> | |
<i class="fas fa-user text-dark-400"></i> | |
</div> | |
<div class="flex-1"> | |
<p>${content}</p> | |
</div> | |
</div> | |
`; | |
} else { | |
messageDiv.innerHTML = ` | |
<div class="max-w-3xl mx-auto flex items-start gap-4"> | |
<div class="w-8 h-8 rounded-full bg-dark-primary flex items-center justify-center flex-shrink-0"> | |
<i class="fas fa-paw text-white"></i> | |
</div> | |
<div class="flex-1"> | |
<p>${content}</p> | |
<div class="flex items-center mt-3 space-x-2"> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-thumbs-up mr-1"></i> | |
</button> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-thumbs-down mr-1"></i> | |
</button> | |
<button class="action-button px-3 py-1 text-xs rounded-md bg-dark-600 text-dark-200 hover:bg-dark-500"> | |
<i class="fas fa-copy mr-1"></i> Copy | |
</button> | |
</div> | |
</div> | |
</div> | |
`; | |
} | |
messagesContainer.appendChild(messageDiv); | |
messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
} | |
// Simulate typing indicator | |
function showTypingIndicator() { | |
const typingDiv = document.createElement('div'); | |
typingDiv.className = 'chat-message assistant-message border-b border-dark-600 p-4'; | |
typingDiv.innerHTML = ` | |
<div class="max-w-3xl mx-auto flex items-start gap-4"> | |
<div class="w-8 h-8 rounded-full bg-dark-primary flex items-center justify-center flex-shrink-0"> | |
<i class="fas fa-paw text-white"></i> | |
</div> | |
<div class="flex-1"> | |
<div class="typing-indicator"> | |
<span></span> | |
<span></span> | |
<span></span> | |
</div> | |
</div> | |
</div> | |
`; | |
messagesContainer.appendChild(typingDiv); | |
messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
return typingDiv; | |
} | |
// Generate AI response (simulated) | |
function generateResponse(userMessage) { | |
// Show typing indicator | |
const typingIndicator = showTypingIndicator(); | |
// Calculate delay based on message length (more meows = longer time) | |
const delay = 1000 + Math.min(userMessage.length * 20, 3000); | |
// Simulate API delay | |
setTimeout(() => { | |
// Remove typing indicator | |
messagesContainer.removeChild(typingIndicator); | |
// Generate meow responses based on the user message | |
let response = generateMeowResponse(); | |
// 30% chance to add a second sentence | |
if (Math.random() > 0.7) { | |
response += " " + generateMeowResponse(); | |
} | |
// If the user asked about code, add a code block with cat-themed variable names | |
if (userMessage.toLowerCase().includes("code") || | |
userMessage.toLowerCase().includes("function") || | |
userMessage.toLowerCase().includes("program")) { | |
const codeExamples = [ | |
`function feedMe(tuna) {\n if (tuna === 'fresh') {\n return 'Purrrrrr!';\n } else {\n return 'Mrow! (disapproval)';\n }\n}`, | |
`class Cat {\n constructor(name) {\n this.name = name;\n this.napCount = 0;\n }\n\n nap() {\n this.napCount++;\n return 'zzz';\n }\n}`, | |
`const favoriteToys = ['feather', 'laser', 'box', 'yarn'];\n\nfavoriteToys.forEach(toy => {\n console.log('Pounce on ' + toy);\n});`, | |
`# Purr-ython code example\n\ndef purr(count):\n for i in range(count):\n print("Purr")\n return "Contented cat"` | |
]; | |
const randomCode = codeExamples[Math.floor(Math.random() * codeExamples.length)]; | |
response += `\n\n<div class="code-block mt-2">${randomCode}</div>`; | |
} | |
addMessage(response, false); | |
}, delay); | |
} | |
// Handle send message | |
function handleSend() { | |
const message = messageInput.value.trim(); | |
if (message) { | |
addMessage(message, true); | |
messageInput.value = ''; | |
messageInput.style.height = 'auto'; | |
generateResponse(message); | |
} | |
} | |
// Send message on button click | |
sendButton.addEventListener('click', handleSend); | |
// Send message on Enter key (but allow Shift+Enter for new lines) | |
messageInput.addEventListener('keydown', function(e) { | |
if (e.key === 'Enter' && !e.shiftKey) { | |
e.preventDefault(); | |
handleSend(); | |
} | |
}); | |
// Handle example prompts | |
examplePrompts.forEach(prompt => { | |
prompt.addEventListener('click', function() { | |
const question = this.querySelector('h3').textContent; | |
const context = this.querySelector('p').textContent; | |
const fullQuestion = question + ' ' + context; | |
messageInput.value = fullQuestion; | |
messageInput.dispatchEvent(new Event('input')); | |
messageInput.focus(); | |
}); | |
}); | |
// Handle regenerate button | |
regenerateButton.querySelector('button').addEventListener('click', function() { | |
const userMessages = document.querySelectorAll('.user-message'); | |
if (userMessages.length > 0) { | |
const lastUserMessage = userMessages[userMessages.length - 1].querySelector('p').textContent; | |
const assistantMessages = document.querySelectorAll('.assistant-message'); | |
if (assistantMessages.length > 0) { | |
messagesContainer.removeChild(assistantMessages[assistantMessages.length - 1]); | |
} | |
generateResponse(lastUserMessage); | |
} | |
}); | |
// Add copy functionality to all copy buttons | |
document.addEventListener('click', function(e) { | |
if (e.target.closest('.action-button') && e.target.closest('.action-button').textContent.includes('Copy')) { | |
const message = e.target.closest('.assistant-message').querySelector('p')?.textContent || | |
e.target.closest('.assistant-message').textContent.trim(); | |
navigator.clipboard.writeText(message); | |
// Show temporary feedback | |
const button = e.target.closest('.action-button'); | |
const originalText = button.innerHTML; | |
button.innerHTML = '<i class="fas fa-check mr-1"></i> Copied'; | |
button.classList.add('text-green-500'); | |
setTimeout(() => { | |
button.innerHTML = originalText; | |
button.classList.remove('text-green-500'); | |
}, 1500); | |
} | |
}); | |
}); | |
</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=DaxtonBrandon/catgpt" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
</html> |