mitdow commited on
Commit
267efe4
·
verified ·
1 Parent(s): be5e460

Initial DeepSite commit

Browse files
Files changed (4) hide show
  1. README.md +9 -6
  2. chat.html +450 -0
  3. index.html +274 -19
  4. utils.js +78 -0
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Deepsite Project G7pus
3
- emoji: 🦀
4
- colorFrom: purple
5
- colorTo: blue
6
  sdk: static
7
- pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: DeepSite Project
3
+ colorFrom: blue
4
+ colorTo: purple
 
5
  sdk: static
6
+ emoji: 💎
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # DeepSite Project
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
chat.html ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Chat | AI Companion</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/lucide@latest"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ body { font-family: 'Inter', sans-serif; }
12
+ .glass-panel {
13
+ background: rgba(30, 30, 40, 0.7);
14
+ backdrop-filter: blur(12px);
15
+ border: 1px solid rgba(255, 255, 255, 0.1);
16
+ }
17
+ .message-bubble {
18
+ max-width: 80%;
19
+ word-wrap: break-word;
20
+ }
21
+ .action-text {
22
+ color: #f472b6;
23
+ font-style: italic;
24
+ font-weight: 500;
25
+ }
26
+ .scrollbar-hide::-webkit-scrollbar {
27
+ display: none;
28
+ }
29
+ .scrollbar-hide {
30
+ -ms-overflow-style: none;
31
+ scrollbar-width: none;
32
+ }
33
+ .typing-indicator span {
34
+ animation: typing 1.4s infinite;
35
+ display: inline-block;
36
+ margin: 0 1px;
37
+ }
38
+ .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
39
+ .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
40
+ @keyframes typing {
41
+ 0%, 100% { opacity: 0.2; transform: translateY(0); }
42
+ 50% { opacity: 1; transform: translateY(-2px); }
43
+ }
44
+ .sidebar-item {
45
+ transition: all 0.2s;
46
+ }
47
+ .sidebar-item:hover {
48
+ background: rgba(168, 85, 247, 0.1);
49
+ border-left: 3px solid #a855f7;
50
+ }
51
+ .active-chat {
52
+ background: rgba(168, 85, 247, 0.15);
53
+ border-left: 3px solid #a855f7;
54
+ }
55
+ </style>
56
+ </head>
57
+ <body class="bg-gray-950 text-gray-100 h-screen overflow-hidden flex">
58
+ <!-- Mobile Sidebar Toggle -->
59
+ <button id="sidebarToggle" class="lg:hidden fixed top-4 left-4 z-50 p-2 bg-gray-800 rounded-lg shadow-lg">
60
+ <i data-lucide="menu" class="w-6 h-6"></i>
61
+ </button>
62
+
63
+ <!-- Sidebar -->
64
+ <aside id="sidebar" class="fixed lg:static inset-y-0 left-0 z-40 w-80 bg-gray-900 border-r border-gray-800 transform -translate-x-full lg:translate-x-0 transition-transform duration-300 flex flex-col">
65
+ <!-- Sidebar Header -->
66
+ <div class="p-4 border-b border-gray-800">
67
+ <div class="flex items-center justify-between mb-4">
68
+ <h1 class="text-xl font-bold gradient-text flex items-center gap-2">
69
+ <i data-lucide="heart" class="w-5 h-5 text-pink-500"></i>
70
+ AI Companion
71
+ </h1>
72
+ <button id="closeSidebar" class="lg:hidden text-gray-400 hover:text-white">
73
+ <i data-lucide="x" class="w-6 h-6"></i>
74
+ </button>
75
+ </div>
76
+ <button onclick="window.location.href='index.html'" class="w-full bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-500 hover:to-pink-500 text-white py-2 rounded-lg font-medium transition-all flex items-center justify-center gap-2">
77
+ <i data-lucide="plus" class="w-4 h-4"></i>
78
+ New Character
79
+ </button>
80
+ </div>
81
+
82
+ <!-- Recent Chats -->
83
+ <div class="flex-1 overflow-y-auto py-4">
84
+ <h3 class="px-4 text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Recent Chats</h3>
85
+ <div id="recentChatsList" class="space-y-1">
86
+ <!-- Populated by JS -->
87
+ </div>
88
+ </div>
89
+
90
+ <!-- Settings & User -->
91
+ <div class="border-t border-gray-800 p-4 space-y-2">
92
+ <button id="settingsBtn" class="sidebar-item w-full flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-white">
93
+ <i data-lucide="settings" class="w-5 h-5"></i>
94
+ <span>Settings</span>
95
+ </button>
96
+ <button id="clearHistory" class="sidebar-item w-full flex items-center gap-3 px-4 py-3 rounded-lg text-gray-300 hover:text-red-400">
97
+ <i data-lucide="trash-2" class="w-5 h-5"></i>
98
+ <span>Clear History</span>
99
+ </button>
100
+ </div>
101
+ </aside>
102
+
103
+ <!-- Main Chat Area -->
104
+ <main class="flex-1 flex flex-col h-full relative">
105
+ <!-- Chat Header -->
106
+ <header class="glass-panel border-b border-gray-800 p-4 flex items-center justify-between sticky top-0 z-30">
107
+ <div class="flex items-center gap-3 ml-12 lg:ml-0">
108
+ <div class="relative">
109
+ <img id="headerAvatar" src="" alt="Character" class="w-10 h-10 rounded-full object-cover border-2 border-pink-500/30">
110
+ <div class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-gray-900"></div>
111
+ </div>
112
+ <div>
113
+ <h2 id="headerName" class="font-semibold text-white">Loading...</h2>
114
+ <p class="text-xs text-gray-400">Online • Scenario Active</p>
115
+ </div>
116
+ </div>
117
+ <div class="flex items-center gap-2">
118
+ <button id="scenarioBtn" class="p-2 hover:bg-gray-800 rounded-lg transition-colors text-gray-400 hover:text-pink-400" title="View Scenario">
119
+ <i data-lucide="book-open" class="w-5 h-5"></i>
120
+ </button>
121
+ <button id="imageGenBtn" class="p-2 hover:bg-gray-800 rounded-lg transition-colors text-gray-400 hover:text-purple-400" title="Generate Image">
122
+ <i data-lucide="image" class="w-5 h-5"></i>
123
+ </button>
124
+ </div>
125
+ </header>
126
+
127
+ <!-- Messages Container -->
128
+ <div id="messagesContainer" class="flex-1 overflow-y-auto p-4 space-y-4 scrollbar-hide bg-gradient-to-b from-gray-950 to-gray-900">
129
+ <!-- Scene Setup Message -->
130
+ <div id="sceneMessage" class="hidden">
131
+ <div class="flex justify-center mb-6">
132
+ <div class="glass-panel rounded-2xl p-4 max-w-2xl border-l-4 border-pink-500">
133
+ <div class="flex items-center gap-2 mb-2 text-pink-400 text-sm font-semibold">
134
+ <i data-lucide="sparkles" class="w-4 h-4"></i>
135
+ Scene Setting
136
+ </div>
137
+ <p id="sceneText" class="text-gray-300 text-sm leading-relaxed"></p>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ <!-- Messages will be inserted here -->
142
+ </div>
143
+
144
+ <!-- Typing Indicator -->
145
+ <div id="typingIndicator" class="hidden px-4 py-2">
146
+ <div class="flex items-center gap-2 text-gray-500 text-sm">
147
+ <span id="typingName">Character</span>
148
+ <div class="typing-indicator">
149
+ <span class="w-1.5 h-1.5 bg-pink-500 rounded-full"></span>
150
+ <span class="w-1.5 h-1.5 bg-pink-500 rounded-full"></span>
151
+ <span class="w-1.5 h-1.5 bg-pink-500 rounded-full"></span>
152
+ </div>
153
+ </div>
154
+ </div>
155
+
156
+ <!-- Input Area -->
157
+ <div class="glass-panel border-t border-gray-800 p-4">
158
+ <form id="chatForm" class="flex gap-3 max-w-4xl mx-auto">
159
+ <div class="flex-1 relative">
160
+ <input type="text" id="messageInput" placeholder="Type your message... (use * for actions)"
161
+ class="w-full bg-gray-800/50 border border-gray-700 rounded-xl px-4 py-3 pr-12 text-white placeholder-gray-500 focus:outline-none focus:border-pink-500/50 transition-colors">
162
+ <button type="button" id="quickAction" class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-pink-400 transition-colors" title="Quick Action">
163
+ <i data-lucide="zap" class="w-5 h-5"></i>
164
+ </button>
165
+ </div>
166
+ <button type="submit" class="bg-gradient-to-r from-pink-600 to-purple-600 hover:from-pink-500 hover:to-purple-500 text-white px-6 py-3 rounded-xl font-medium transition-all transform hover:scale-105 flex items-center gap-2">
167
+ <i data-lucide="send" class="w-5 h-5"></i>
168
+ </button>
169
+ </form>
170
+ <p class="text-center text-xs text-gray-600 mt-2">Press Enter to send • Use *text* for actions</p>
171
+ </div>
172
+ </main>
173
+
174
+ <!-- Settings Modal -->
175
+ <div id="settingsModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden items-center justify-center p-4">
176
+ <div class="glass-panel rounded-2xl p-6 max-w-md w-full border border-gray-700">
177
+ <div class="flex justify-between items-center mb-6">
178
+ <h3 class="text-xl font-semibold">Settings</h3>
179
+ <button id="closeSettings" class="text-gray-400 hover:text-white">
180
+ <i data-lucide="x" class="w-5 h-5"></i>
181
+ </button>
182
+ </div>
183
+
184
+ <div class="space-y-4">
185
+ <div>
186
+ <label class="block text-sm font-medium text-gray-300 mb-2">API Configuration (Sinkin.ai)</label>
187
+ <input type="text" id="apiKey" placeholder="Enter your API key..."
188
+ class="w-full bg-gray-800 border border-gray-700 rounded-lg px-3 py-2 text-sm text-white focus:border-purple-500 focus:outline-none">
189
+ <p class="text-xs text-gray-500 mt-1">Required for image generation</p>
190
+ </div>
191
+
192
+ <div>
193
+ <label class="block text-sm font-medium text-gray-300 mb-2">Response Style</label>
194
+ <select id="responseStyle" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-3 py-2 text-sm text-white focus:border-purple-500 focus:outline-none">
195
+ <option value="balanced">Balanced</option>
196
+ <option value="creative">Creative/Descriptive</option>
197
+ <option value="direct">Direct</option>
198
+ </select>
199
+ </div>
200
+
201
+ <div class="flex items-center justify-between">
202
+ <span class="text-sm text-gray-300">NSFW Content</span>
203
+ <button id="toggleNSFW" class="w-12 h-6 bg-pink-600 rounded-full relative transition-colors">
204
+ <span class="absolute right-1 top-1 w-4 h-4 bg-white rounded-full transition-transform"></span>
205
+ </button>
206
+ </div>
207
+ </div>
208
+
209
+ <button id="saveSettings" class="w-full mt-6 bg-purple-600 hover:bg-purple-500 text-white py-3 rounded-lg font-medium transition-colors">
210
+ Save Settings
211
+ </button>
212
+ </div>
213
+ </div>
214
+
215
+ <!-- Scenario Modal -->
216
+ <div id="scenarioModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden items-center justify-center p-4">
217
+ <div class="glass-panel rounded-2xl p-6 max-w-lg w-full border border-gray-700">
218
+ <div class="flex justify-between items-center mb-4">
219
+ <h3 class="text-xl font-semibold gradient-text">Current Scenario</h3>
220
+ <button id="closeScenario" class="text-gray-400 hover:text-white">
221
+ <i data-lucide="x" class="w-5 h-5"></i>
222
+ </button>
223
+ </div>
224
+ <div class="bg-gray-800/30 rounded-xl p-4 mb-4">
225
+ <h4 id="scenarioTitle" class="font-semibold text-white mb-2"></h4>
226
+ <p id="scenarioDesc" class="text-gray-300 text-sm leading-relaxed"></p>
227
+ </div>
228
+ <div class="flex gap-2 text-sm text-gray-400">
229
+ <i data-lucide="info" class="w-4 h-4"></i>
230
+ <span>This scene sets the context for your conversation</span>
231
+ </div>
232
+ </div>
233
+ </div>
234
+
235
+ <script>
236
+ // Initialize icons
237
+ lucide.createIcons();
238
+
239
+ // State
240
+ let currentCharacter = null;
241
+ let messages = [];
242
+ let isTyping = false;
243
+
244
+ // Load character
245
+ function loadCharacter() {
246
+ const saved = localStorage.getItem('currentCharacter');
247
+ if (saved) {
248
+ currentCharacter = JSON.parse(saved);
249
+ document.getElementById('headerName').textContent = currentCharacter.name;
250
+ document.getElementById('typingName').textContent = currentCharacter.name;
251
+ document.getElementById('headerAvatar').src = currentCharacter.image || 'http://static.photos/minimal/640x360/1';
252
+ document.getElementById('scenarioTitle').textContent = `Scene: ${currentCharacter.name}`;
253
+ document.getElementById('scenarioDesc').textContent = currentCharacter.scene;
254
+
255
+ // Show scene setting if first message exists
256
+ if (currentCharacter.scene) {
257
+ document.getElementById('sceneMessage').classList.remove('hidden');
258
+ document.getElementById('sceneText').textContent = currentCharacter.scene;
259
+ }
260
+
261
+ // Add first message if exists
262
+ if (currentCharacter.firstMessage) {
263
+ addMessage('character', currentCharacter.firstMessage);
264
+ }
265
+ } else {
266
+ // Redirect to creator if no character
267
+ window.location.href = 'index.html';
268
+ }
269
+ }
270
+
271
+ // Parse message for actions (*text*)
272
+ function parseMessage(text) {
273
+ // Replace *text* with styled span
274
+ return text.replace(/\*(.*?)\*/g, '<span class="action-text">$1</span>');
275
+ }
276
+
277
+ // Add message to chat
278
+ function addMessage(sender, text, imageUrl = null) {
279
+ const container = document.getElementById('messagesContainer');
280
+ const isUser = sender === 'user';
281
+
282
+ const wrapper = document.createElement('div');
283
+ wrapper.className = `flex ${isUser ? 'justify-end' : 'justify-start'} mb-4`;
284
+
285
+ let content = '';
286
+ if (imageUrl) {
287
+ content = `<img src="${imageUrl}" class="rounded-lg max-w-sm shadow-lg border border-gray-700" alt="Generated">`;
288
+ } else {
289
+ const parsedText = parseMessage(text);
290
+ content = `<div class="message-bubble glass-panel ${isUser ? 'bg-pink-600/20 border-pink-500/30' : 'bg-gray-800/50'} rounded-2xl px-4 py-3 text-gray-100">${parsedText}</div>`;
291
+ }
292
+
293
+ wrapper.innerHTML = content;
294
+ container.appendChild(wrapper);
295
+ container.scrollTop = container.scrollHeight;
296
+
297
+ // Save to history
298
+ messages.push({ sender, text, imageUrl, timestamp: new Date() });
299
+ localStorage.setItem(`chat_${currentCharacter.id}`, JSON.stringify(messages));
300
+ }
301
+
302
+ // Simulate AI Response
303
+ function simulateResponse(userMessage) {
304
+ isTyping = true;
305
+ document.getElementById('typingIndicator').classList.remove('hidden');
306
+
307
+ setTimeout(() => {
308
+ isTyping = false;
309
+ document.getElementById('typingIndicator').classList.add('hidden');
310
+
311
+ // Simple response logic (replace with actual API integration)
312
+ const responses = [
313
+ "*leans in closer* That's quite interesting... tell me more about what you're thinking.",
314
+ "*smiles softly* I like where this is going. What else do you have in mind?",
315
+ "*traces finger along your arm* Mmm, you're being very intriguing today.",
316
+ "*bites lip* Really? I hadn't considered that... but I think I like it.",
317
+ "*moves closer, voice dropping to a whisper* Go on, I'm listening..."
318
+ ];
319
+
320
+ const response = responses[Math.floor(Math.random() * responses.length)];
321
+ addMessage('character', response);
322
+ }, 1500 + Math.random() * 1000);
323
+ }
324
+
325
+ // Handle send message
326
+ document.getElementById('chatForm').addEventListener('submit', (e) => {
327
+ e.preventDefault();
328
+ const input = document.getElementById('messageInput');
329
+ const text = input.value.trim();
330
+
331
+ if (text && !isTyping) {
332
+ addMessage('user', text);
333
+ input.value = '';
334
+ simulateResponse(text);
335
+ }
336
+ });
337
+
338
+ // Quick action button
339
+ document.getElementById('quickAction').addEventListener('click', () => {
340
+ const input = document.getElementById('messageInput');
341
+ input.value = '*' + input.value + '*';
342
+ input.focus();
343
+ });
344
+
345
+ // Sidebar toggle
346
+ const sidebar = document.getElementById('sidebar');
347
+ document.getElementById('sidebarToggle').addEventListener('click', () => {
348
+ sidebar.classList.remove('-translate-x-full');
349
+ });
350
+ document.getElementById('closeSidebar').addEventListener('click', () => {
351
+ sidebar.classList.add('-translate-x-full');
352
+ });
353
+
354
+ // Load recent chats
355
+ function loadRecentChats() {
356
+ const recent = JSON.parse(localStorage.getItem('recentCharacters') || '[]');
357
+ const list = document.getElementById('recentChatsList');
358
+ list.innerHTML = '';
359
+
360
+ recent.forEach(char => {
361
+ const item = document.createElement('button');
362
+ item.className = 'sidebar-item w-full flex items-center gap-3 px-4 py-3 text-left';
363
+ if (currentCharacter && char.id === currentCharacter.id) {
364
+ item.classList.add('active-chat');
365
+ }
366
+ item.innerHTML = `
367
+ <img src="${char.image || 'http://static.photos/minimal/640x360/1'}" class="w-10 h-10 rounded-full object-cover border border-gray-700">
368
+ <div class="flex-1 min-w-0">
369
+ <h4 class="text-sm font-medium text-white truncate">${char.name}</h4>
370
+ <p class="text-xs text-gray-500 truncate">${char.scene || 'No scenario'}</p>
371
+ </div>
372
+ `;
373
+ item.addEventListener('click', () => {
374
+ localStorage.setItem('currentCharacter', JSON.stringify(char));
375
+ location.reload();
376
+ });
377
+ list.appendChild(item);
378
+ });
379
+ }
380
+
381
+ // Settings Modal
382
+ const settingsModal = document.getElementById('settingsModal');
383
+ document.getElementById('settingsBtn').addEventListener('click', () => {
384
+ settingsModal.classList.remove('hidden');
385
+ settingsModal.classList.add('flex');
386
+ });
387
+ document.getElementById('closeSettings').addEventListener('click', () => {
388
+ settingsModal.classList.add('hidden');
389
+ settingsModal.classList.remove('flex');
390
+ });
391
+ document.getElementById('saveSettings').addEventListener('click', () => {
392
+ settingsModal.classList.add('hidden');
393
+ settingsModal.classList.remove('flex');
394
+ });
395
+
396
+ // Scenario Modal
397
+ const scenarioModal = document.getElementById('scenarioModal');
398
+ document.getElementById('scenarioBtn').addEventListener('click', () => {
399
+ scenarioModal.classList.remove('hidden');
400
+ scenarioModal.classList.add('flex');
401
+ });
402
+ document.getElementById('closeScenario').addEventListener('click', () => {
403
+ scenarioModal.classList.add('hidden');
404
+ scenarioModal.classList.remove('flex');
405
+ });
406
+
407
+ // Image Generation in chat
408
+ document.getElementById('imageGenBtn').addEventListener('click', () => {
409
+ const prompt = prompt("Enter image prompt for Sinkin.ai (CyberRealistic):");
410
+ if (prompt) {
411
+ // Open Sinkin.ai with prompt
412
+ const encoded = encodeURIComponent(`CyberRealistic, ${prompt}, high quality, detailed`);
413
+ window.open(`https://sinkin.ai/m/d55J1xB?prompt=${encoded}`, '_blank');
414
+
415
+ // Simulate adding to chat after delay
416
+ setTimeout(() => {
417
+ addMessage('user', `Generated image: "${prompt}"`, 'http://static.photos/minimal/640x360/69');
418
+ }, 1000);
419
+ }
420
+ });
421
+
422
+ // Clear history
423
+ document.getElementById('clearHistory').addEventListener('click', () => {
424
+ if (confirm('Clear current chat history?')) {
425
+ messages = [];
426
+ localStorage.removeItem(`chat_${currentCharacter.id}`);
427
+ document.getElementById('messagesContainer').innerHTML = '';
428
+ document.getElementById('sceneMessage').classList.remove('hidden');
429
+ }
430
+ });
431
+
432
+ // Initialize
433
+ loadCharacter();
434
+ loadRecentChats();
435
+
436
+ // Load previous messages if exist
437
+ const savedMessages = localStorage.getItem(`chat_${currentCharacter.id}`);
438
+ if (savedMessages) {
439
+ messages = JSON.parse(savedMessages);
440
+ messages.forEach(msg => {
441
+ if (msg.imageUrl) {
442
+ addMessage(msg.sender, null, msg.imageUrl);
443
+ } else {
444
+ addMessage(msg.sender, msg.text);
445
+ }
446
+ });
447
+ }
448
+ </script>
449
+ </body>
450
+ </html>
index.html CHANGED
@@ -1,19 +1,274 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Character Creator | AI Companion</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/lucide@latest"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ body { font-family: 'Inter', sans-serif; }
12
+ .glass-panel {
13
+ background: rgba(30, 30, 40, 0.7);
14
+ backdrop-filter: blur(12px);
15
+ border: 1px solid rgba(255, 255, 255, 0.1);
16
+ }
17
+ .gradient-text {
18
+ background: linear-gradient(135deg, #f472b6 0%, #a855f7 100%);
19
+ -webkit-background-clip: text;
20
+ -webkit-text-fill-color: transparent;
21
+ }
22
+ .input-field {
23
+ background: rgba(255, 255, 255, 0.05);
24
+ border: 1px solid rgba(255, 255, 255, 0.1);
25
+ transition: all 0.3s ease;
26
+ }
27
+ .input-field:focus {
28
+ border-color: #a855f7;
29
+ box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.1);
30
+ }
31
+ .preview-container {
32
+ background: linear-gradient(135deg, #1e1e28 0%, #2d2d3a 100%);
33
+ }
34
+ .action-pulse {
35
+ animation: pulse-glow 2s infinite;
36
+ }
37
+ @keyframes pulse-glow {
38
+ 0%, 100% { box-shadow: 0 0 5px rgba(244, 114, 182, 0.5); }
39
+ 50% { box-shadow: 0 0 20px rgba(244, 114, 182, 0.8); }
40
+ }
41
+ </style>
42
+ </head>
43
+ <body class="bg-gray-950 text-gray-100 min-h-screen overflow-x-hidden">
44
+ <!-- Background Effects -->
45
+ <div class="fixed inset-0 overflow-hidden pointer-events-none">
46
+ <div class="absolute top-0 left-1/4 w-96 h-96 bg-purple-600/20 rounded-full blur-3xl"></div>
47
+ <div class="absolute bottom-0 right-1/4 w-96 h-96 bg-pink-600/20 rounded-full blur-3xl"></div>
48
+ </div>
49
+
50
+ <div class="relative z-10 container mx-auto px-4 py-8 max-w-6xl">
51
+ <!-- Header -->
52
+ <header class="text-center mb-12">
53
+ <h1 class="text-5xl font-bold mb-4 gradient-text">Create Your Companion</h1>
54
+ <p class="text-gray-400 text-lg">Design your perfect AI partner and scenario</p>
55
+ </header>
56
+
57
+ <div class="grid lg:grid-cols-2 gap-8">
58
+ <!-- Character Builder Form -->
59
+ <div class="glass-panel rounded-2xl p-8">
60
+ <form id="characterForm" class="space-y-6">
61
+ <div>
62
+ <label class="block text-sm font-medium text-gray-300 mb-2">Character Name</label>
63
+ <input type="text" id="charName" required placeholder="e.g., Violet, Mistress Aurora..."
64
+ class="input-field w-full px-4 py-3 rounded-xl text-white placeholder-gray-500 focus:outline-none">
65
+ </div>
66
+
67
+ <div>
68
+ <label class="block text-sm font-medium text-gray-300 mb-2">Appearance Description</label>
69
+ <textarea id="charAppearance" rows="3" placeholder="Long silver hair, piercing blue eyes, wearing a black lace dress..."
70
+ class="input-field w-full px-4 py-3 rounded-xl text-white placeholder-gray-500 focus:outline-none resize-none"></textarea>
71
+ </div>
72
+
73
+ <div>
74
+ <label class="block text-sm font-medium text-gray-300 mb-2">Personality & Traits</label>
75
+ <textarea id="charPersonality" rows="3" placeholder="Dominant yet caring, playful tease, deeply affectionate..."
76
+ class="input-field w-full px-4 py-3 rounded-xl text-white placeholder-gray-500 focus:outline-none resize-none"></textarea>
77
+ </div>
78
+
79
+ <div>
80
+ <label class="block text-sm font-medium text-gray-300 mb-2">Scene/Scenario <span class="text-pink-400">*</span></label>
81
+ <textarea id="charScene" rows="4" required placeholder="You meet at a dimly lit bar. She notices you from across the room and approaches with a mysterious smile..."
82
+ class="input-field w-full px-4 py-3 rounded-xl text-white placeholder-gray-500 focus:outline-none resize-none"></textarea>
83
+ <p class="text-xs text-gray-500 mt-1">Set the mood, location, and initial context</p>
84
+ </div>
85
+
86
+ <div>
87
+ <label class="block text-sm font-medium text-gray-300 mb-2">First Message (Optional)</label>
88
+ <textarea id="firstMessage" rows="2" placeholder="*leans in close* Well, aren't you a interesting one..."
89
+ class="input-field w-full px-4 py-3 rounded-xl text-white placeholder-gray-500 focus:outline-none resize-none"></textarea>
90
+ </div>
91
+
92
+ <!-- Image Generation Section -->
93
+ <div class="border-t border-gray-700 pt-6">
94
+ <label class="block text-sm font-medium text-gray-300 mb-3">Character Portrait</label>
95
+ <div class="flex gap-4 mb-4">
96
+ <button type="button" id="generateImageBtn"
97
+ class="flex-1 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-500 hover:to-pink-500 text-white py-3 rounded-xl font-medium transition-all flex items-center justify-center gap-2">
98
+ <i data-lucide="sparkles" class="w-4 h-4"></i>
99
+ Generate with Sinkin.ai
100
+ </button>
101
+ </div>
102
+ <p class="text-xs text-gray-500">Uses CyberRealistic model via Sinkin.ai</p>
103
+ </div>
104
+
105
+ <button type="submit"
106
+ class="w-full bg-gradient-to-r from-pink-600 to-purple-600 hover:from-pink-500 hover:to-purple-500 text-white py-4 rounded-xl font-semibold text-lg transition-all transform hover:scale-[1.02] shadow-lg shadow-purple-500/25 flex items-center justify-center gap-2">
107
+ <i data-lucide="message-circle" class="w-5 h-5"></i>
108
+ Start Chatting
109
+ </button>
110
+ </form>
111
+ </div>
112
+
113
+ <!-- Live Preview -->
114
+ <div class="lg:sticky lg:top-8 h-fit">
115
+ <div class="glass-panel rounded-2xl p-6">
116
+ <h3 class="text-xl font-semibold mb-4 flex items-center gap-2">
117
+ <i data-lucide="eye" class="w-5 h-5 text-pink-400"></i>
118
+ Live Preview
119
+ </h3>
120
+ <div class="preview-container rounded-xl overflow-hidden aspect-[3/4] relative mb-4">
121
+ <img id="previewImage" src="http://static.photos/minimal/640x360/1" alt="Character Preview"
122
+ class="w-full h-full object-cover opacity-80">
123
+ <div class="absolute inset-0 bg-gradient-to-t from-gray-900 via-transparent to-transparent"></div>
124
+ <div class="absolute bottom-0 left-0 right-0 p-6">
125
+ <h2 id="previewName" class="text-2xl font-bold text-white mb-1">Your Character</h2>
126
+ <p id="previewScene" class="text-sm text-gray-300 line-clamp-2">Scene description will appear here...</p>
127
+ </div>
128
+ </div>
129
+ <div class="space-y-3">
130
+ <div class="flex items-center gap-3 text-sm text-gray-400">
131
+ <i data-lucide="user" class="w-4 h-4"></i>
132
+ <span id="previewPersonality" class="line-clamp-1">Personality traits...</span>
133
+ </div>
134
+ <div class="flex items-center gap-3 text-sm text-gray-400">
135
+ <i data-lucide="image" class="w-4 h-4"></i>
136
+ <span id="previewAppearance" class="line-clamp-1">Appearance details...</span>
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <!-- Tips Card -->
142
+ <div class="mt-6 glass-panel rounded-2xl p-6 border-l-4 border-pink-500">
143
+ <h4 class="font-semibold text-pink-400 mb-2 flex items-center gap-2">
144
+ <i data-lucide="lightbulb" class="w-4 h-4"></i>
145
+ Pro Tips
146
+ </h4>
147
+ <ul class="text-sm text-gray-400 space-y-2">
148
+ <li>• Use *asterisks* for actions in chat (e.g., *smiles seductively*)</li>
149
+ <li>• Detailed scenes create more immersive experiences</li>
150
+ <li>• Generate images to bring your character to life</li>
151
+ </ul>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Image Generation Modal -->
158
+ <div id="imageModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden items-center justify-center p-4">
159
+ <div class="glass-panel rounded-2xl p-6 max-w-md w-full">
160
+ <div class="flex justify-between items-center mb-4">
161
+ <h3 class="text-xl font-semibold">Generate Portrait</h3>
162
+ <button id="closeModal" class="text-gray-400 hover:text-white">
163
+ <i data-lucide="x" class="w-5 h-5"></i>
164
+ </button>
165
+ </div>
166
+ <p class="text-sm text-gray-400 mb-4">This will open Sinkin.ai with your character description.</p>
167
+ <div class="bg-gray-800/50 rounded-lg p-3 mb-4 text-sm text-gray-300" id="promptPreview"></div>
168
+ <div class="flex gap-3">
169
+ <button id="confirmGenerate" class="flex-1 bg-purple-600 hover:bg-purple-500 text-white py-3 rounded-lg font-medium transition-colors">
170
+ Open Sinkin.ai
171
+ </button>
172
+ <button id="cancelGenerate" class="flex-1 bg-gray-700 hover:bg-gray-600 text-white py-3 rounded-lg font-medium transition-colors">
173
+ Cancel
174
+ </button>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ <script>
180
+ // Initialize Lucide icons
181
+ lucide.createIcons();
182
+
183
+ // Live Preview Updates
184
+ const inputs = {
185
+ name: document.getElementById('charName'),
186
+ appearance: document.getElementById('charAppearance'),
187
+ personality: document.getElementById('charPersonality'),
188
+ scene: document.getElementById('charScene')
189
+ };
190
+
191
+ const preview = {
192
+ name: document.getElementById('previewName'),
193
+ appearance: document.getElementById('previewAppearance'),
194
+ personality: document.getElementById('previewPersonality'),
195
+ scene: document.getElementById('previewScene')
196
+ };
197
+
198
+ Object.keys(inputs).forEach(key => {
199
+ inputs[key].addEventListener('input', (e) => {
200
+ if (key === 'name') {
201
+ preview[key].textContent = e.target.value || 'Your Character';
202
+ } else {
203
+ preview[key].textContent = e.target.value || key.charAt(0).toUpperCase() + key.slice(1) + '...';
204
+ }
205
+ });
206
+ });
207
+
208
+ // Image Generation
209
+ const modal = document.getElementById('imageModal');
210
+ const generateBtn = document.getElementById('generateImageBtn');
211
+ const closeModal = document.getElementById('closeModal');
212
+ const cancelGenerate = document.getElementById('cancelGenerate');
213
+ const confirmGenerate = document.getElementById('confirmGenerate');
214
+ const promptPreview = document.getElementById('promptPreview');
215
+
216
+ generateBtn.addEventListener('click', () => {
217
+ const appearance = inputs.appearance.value || 'beautiful portrait';
218
+ const name = inputs.name.value || 'character';
219
+ const prompt = `CyberRealistic portrait of ${name}, ${appearance}, high quality, detailed, 8k, professional photography`;
220
+ promptPreview.textContent = prompt;
221
+ modal.classList.remove('hidden');
222
+ modal.classList.add('flex');
223
+ });
224
+
225
+ [closeModal, cancelGenerate].forEach(btn => {
226
+ btn.addEventListener('click', () => {
227
+ modal.classList.add('hidden');
228
+ modal.classList.remove('flex');
229
+ });
230
+ });
231
+
232
+ confirmGenerate.addEventListener('click', () => {
233
+ const appearance = inputs.appearance.value || 'beautiful portrait';
234
+ const name = inputs.name.value || 'character';
235
+ const prompt = encodeURIComponent(`CyberRealistic portrait of ${name}, ${appearance}, high quality, detailed, 8k`);
236
+ window.open(`https://sinkin.ai/m/d55J1xB?prompt=${prompt}`, '_blank');
237
+ modal.classList.add('hidden');
238
+ modal.classList.remove('flex');
239
+ });
240
+
241
+ // Form Submission
242
+ document.getElementById('characterForm').addEventListener('submit', (e) => {
243
+ e.preventDefault();
244
+ const characterData = {
245
+ id: Date.now().toString(),
246
+ name: inputs.name.value,
247
+ appearance: inputs.appearance.value,
248
+ personality: inputs.personality.value,
249
+ scene: inputs.scene.value,
250
+ firstMessage: document.getElementById('firstMessage').value,
251
+ createdAt: new Date().toISOString(),
252
+ image: document.getElementById('previewImage').src
253
+ };
254
+
255
+ // Save to localStorage
256
+ localStorage.setItem('currentCharacter', JSON.stringify(characterData));
257
+
258
+ // Add to recent characters
259
+ const recent = JSON.parse(localStorage.getItem('recentCharacters') || '[]');
260
+ recent.unshift(characterData);
261
+ localStorage.setItem('recentCharacters', JSON.stringify(recent.slice(0, 10)));
262
+
263
+ // Redirect to chat
264
+ window.location.href = 'chat.html';
265
+ });
266
+
267
+ // Update preview image randomly on load for variety
268
+ const seeds = [42, 69, 133, 256, 777];
269
+ const randomSeed = seeds[Math.floor(Math.random() * seeds.length)];
270
+ document.getElementById('previewImage').src = `http://static.photos/minimal/640x360/${randomSeed}`;
271
+ </script>
272
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
273
+ </body>
274
+ </html>
utils.js ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Text parsing utilities for NSFW chatbot
2
+ class MessageParser {
3
+ // Parse action text between asterisks
4
+ static parseActions(text) {
5
+ const actionRegex = /\*(.*?)\*/g;
6
+ return text.replace(actionRegex, '<span class="action-text">$1</span>');
7
+ }
8
+
9
+ // Detect NSFW content warnings
10
+ static containsExplicit(text) {
11
+ const explicitTerms = ['nsfw', 'explicit', 'xxx', 'adult']; // Simplified for demo
12
+ return explicitTerms.some(term => text.toLowerCase().includes(term));
13
+ }
14
+
15
+ // Format timestamp
16
+ static formatTime(date) {
17
+ return new Date(date).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
18
+ }
19
+
20
+ // Generate image prompt for Sinkin.ai
21
+ static generateImagePrompt(character, additionalPrompt = '') {
22
+ const basePrompt = `CyberRealistic, ${character.appearance || 'portrait'}, ${character.scene || ''}, ${additionalPrompt}, high quality, detailed, 8k, professional photography`;
23
+ return encodeURIComponent(basePrompt);
24
+ }
25
+ }
26
+
27
+ // Character storage management
28
+ class CharacterManager {
29
+ static save(character) {
30
+ const key = `char_${character.id}`;
31
+ localStorage.setItem(key, JSON.stringify(character));
32
+ this.addToRecent(character);
33
+ }
34
+
35
+ static load(id) {
36
+ return JSON.parse(localStorage.getItem(`char_${id}`) || 'null');
37
+ }
38
+
39
+ static addToRecent(character) {
40
+ let recent = JSON.parse(localStorage.getItem('recentCharacters') || '[]');
41
+ recent = recent.filter(c => c.id !== character.id);
42
+ recent.unshift(character);
43
+ localStorage.setItem('recentCharacters', JSON.stringify(recent.slice(0, 10)));
44
+ }
45
+
46
+ static getRecent() {
47
+ return JSON.parse(localStorage.getItem('recentCharacters') || '[]');
48
+ }
49
+
50
+ static delete(id) {
51
+ localStorage.removeItem(`char_${id}`);
52
+ let recent = this.getRecent();
53
+ recent = recent.filter(c => c.id !== id);
54
+ localStorage.setItem('recentCharacters', JSON.stringify(recent));
55
+ }
56
+ }
57
+
58
+ // Sinkin.ai integration helper
59
+ class SinkinAI {
60
+ static BASE_URL = 'https://sinkin.ai/m/d55J1xB';
61
+
62
+ static generateLink(prompt, options = {}) {
63
+ const params = new URLSearchParams({
64
+ prompt: `CyberRealistic, ${prompt}, detailed, high quality`,
65
+ ...options
66
+ });
67
+ return `${this.BASE_URL}?${params.toString()}`;
68
+ }
69
+
70
+ static openGenerator(prompt) {
71
+ window.open(this.generateLink(prompt), '_blank');
72
+ }
73
+ }
74
+
75
+ // Export for use in other scripts
76
+ if (typeof module !== 'undefined' && module.exports) {
77
+ module.exports = { MessageParser, CharacterManager, SinkinAI };
78
+ }