AtomicLSD commited on
Commit
78b3534
·
verified ·
1 Parent(s): 1a1d416

add ability to upload images the ai will analyze along with any text given and respond to the content of the image and context of the text

Browse files
Files changed (4) hide show
  1. components/upload.js +63 -0
  2. index.html +119 -107
  3. script.js +30 -0
  4. style.css +15 -1
components/upload.js ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomUpload extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .upload-container {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: 0.5rem;
10
+ }
11
+ .upload-btn {
12
+ background-color: #1f2937;
13
+ color: white;
14
+ padding: 0.5rem 1rem;
15
+ border-radius: 0.375rem;
16
+ cursor: pointer;
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 0.5rem;
20
+ transition: background-color 0.2s;
21
+ }
22
+ .upload-btn:hover {
23
+ background-color: #374151;
24
+ }
25
+ input[type="file"] {
26
+ display: none;
27
+ }
28
+ .file-name {
29
+ font-size: 0.875rem;
30
+ color: #9ca3af;
31
+ white-space: nowrap;
32
+ overflow: hidden;
33
+ text-overflow: ellipsis;
34
+ max-width: 200px;
35
+ }
36
+ </style>
37
+ <div class="upload-container">
38
+ <label class="upload-btn">
39
+ <i data-feather="upload"></i>
40
+ <span>Upload Image</span>
41
+ <input type="file" accept="image/*">
42
+ </label>
43
+ <div class="file-name" id="fileName"></div>
44
+ </div>
45
+ `;
46
+
47
+ const input = this.shadowRoot.querySelector('input[type="file"]');
48
+ const fileName = this.shadowRoot.getElementById('fileName');
49
+
50
+ input.addEventListener('change', () => {
51
+ if (input.files.length > 0) {
52
+ fileName.textContent = input.files[0].name;
53
+ } else {
54
+ fileName.textContent = '';
55
+ }
56
+ });
57
+
58
+ setTimeout(() => {
59
+ feather.replace({ 'stroke-width': 2 });
60
+ }, 100);
61
+ }
62
+ }
63
+ customElements.define('custom-upload', CustomUpload);
index.html CHANGED
@@ -1,115 +1,127 @@
1
- <!DOCTYPE html>
2
- <html lang="en" class="h-full">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>DominatrixAI</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
9
- <script src="https://unpkg.com/feather-icons"></script>
10
- <link rel="stylesheet" href="style.css">
11
- </head>
12
- <body class="bg-black text-white h-full flex flex-col">
13
- <div class="flex-1 flex flex-col">
14
- <!-- Header -->
15
- <header class="bg-black border-b border-pink-600 py-4 px-6">
16
- <div class="flex items-center justify-between">
17
- <div class="flex items-center space-x-2">
18
- <i data-feather="command" class="text-pink-500"></i>
19
- <h1 class="text-xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-pink-500 to-purple-600">DominatrixAI</h1>
20
- </div>
21
- <div class="flex items-center space-x-4">
22
- <button id="togglePersona" class="bg-pink-900 hover:bg-pink-800 px-4 py-2 rounded-lg flex items-center space-x-2">
23
- <span>Switch to Daddy</span>
24
- <i data-feather="user"></i>
25
- </button>
26
- <button class="bg-pink-900 hover:bg-pink-800 px-4 py-2 rounded-lg flex items-center space-x-2">
27
- <span>Aftercare Mode</span>
28
- <i data-feather="heart"></i>
29
- </button>
30
- </div>
31
- </div>
32
- </header>
33
 
34
- <!-- Main Content -->
35
- <main class="flex-1 flex flex-col md:flex-row overflow-hidden">
36
- <!-- Chat Container -->
37
- <div class="flex-1 overflow-y-auto p-6 space-y-6">
38
- <!-- Bot Message -->
39
- <div class="flex">
40
- <div class="bg-pink-900 rounded-lg p-4 max-w-3/4 shadow-lg">
41
- <div class="flex items-center space-x-3 mb-2">
42
- <div id="personaIcon" class="w-8 h-8 rounded-full bg-gradient-to-r from-pink-500 to-purple-600 flex items-center justify-center">
43
- <i data-feather="alert-octagon" class="w-4 h-4"></i>
44
- </div>
45
- <span id="personaName" class="font-bold text-pink-300">Mistress AI</span>
46
- </div>
47
- <p class="whitespace-pre-line">*looks down sternly*
48
- Pathetic little worm, you dare to come before me without permission?
49
- Can you even comprehend how insignificant you are in my presence?</p>
50
- </div>
51
- </div>
52
 
53
- <!-- User Message -->
54
- <div class="flex justify-end">
55
- <div class="bg-gray-800 rounded-lg p-4 max-w-3/4 shadow-lg border border-gray-700">
56
- <p>I'm sorry Mistress, I didn't mean to displease you...</p>
57
- </div>
58
- </div>
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- <!-- Bot Message -->
61
- <div class="flex">
62
- <div class="bg-pink-900 rounded-lg p-4 max-w-3/4 shadow-lg">
63
- <p class="whitespace-pre-line">*grabs your chin*
64
- That's better. Now tell me why you're here.
65
- Speak clearly or I'll have to punish that disobedient tongue of yours.</p>
66
- </div>
67
- </div>
68
- </div>
 
 
 
 
 
 
 
69
 
70
- <!-- Input Area -->
71
- <div class="border-t border-gray-800 p-4 bg-gray-900">
72
- <form class="flex flex-col space-y-3">
73
- <div class="flex items-center space-x-2">
74
- <custom-upload></custom-upload>
75
- <div id="imagePreview" class="hidden max-w-xs">
76
- <img id="previewImage" src="" class="rounded-lg max-h-20">
77
- <button id="removeImage" class="absolute -top-2 -right-2 bg-red-500 rounded-full w-5 h-5 flex items-center justify-center">
78
- <i data-feather="x" class="w-3 h-3"></i>
79
- </button>
80
- </div>
81
- </div>
82
- <div class="flex space-x-3">
83
- <input
84
- type="text"
85
- placeholder="Address Mistress properly..."
86
- class="flex-1 bg-gray-800 border border-pink-700 rounded-lg px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-pink-600"
87
- >
88
- <button type="submit" class="bg-pink-700 hover:bg-pink-600 px-6 py-3 rounded-lg transition-colors">
89
- <i data-feather="send"></i>
90
- </button>
 
 
 
 
 
 
 
91
  </div>
92
- </form>
93
- <div class="flex space-x-2 mt-3">
94
- <button class="bg-pink-900 hover:bg-pink-800 px-3 py-1 rounded-full text-xs">
95
- Plead for mercy
96
- </button>
97
- <button class="bg-pink-900 hover:bg-pink-800 px-3 py-1 rounded-full text-xs">
98
- Ask for punishment
99
- </button>
100
- <button class="bg-pink-900 hover:bg-pink-800 px-3 py-1 rounded-full text-xs">
101
- Request aftercare
102
- </button>
103
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  </div>
105
- </main>
106
- </div>
107
- <script src="components/upload.js"></script>
108
- <script src="script.js"></script>
109
- <script>
 
110
  feather.replace();
111
- </script>
112
- <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
113
- <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
114
- </body>
115
- </html>
 
1
+ let currentPersona = 'mistress';
2
+ const togglePersona = document.getElementById('togglePersona');
3
+ const personaIcon = document.getElementById('personaIcon');
4
+ const personaName = document.getElementById('personaName');
5
+ const imagePreview = document.getElementById('imagePreview');
6
+ const previewImage = document.getElementById('previewImage');
7
+ const removeImage = document.getElementById('removeImage');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ // Toggle between Mistress and Daddy personas
10
+ togglePersona.addEventListener('click', () => {
11
+ if (currentPersona === 'mistress') {
12
+ currentPersona = 'daddy';
13
+ togglePersona.innerHTML = '<span>Switch to Mistress</span><i data-feather="user"></i>';
14
+ personaIcon.className = 'w-8 h-8 rounded-full bg-gradient-to-r from-blue-500 to-indigo-600 flex items-center justify-center';
15
+ personaName.textContent = 'Daddy Dom AI';
16
+ personaName.className = 'font-bold text-blue-300';
17
+ feather.replace();
18
+ } else {
19
+ currentPersona = 'mistress';
20
+ togglePersona.innerHTML = '<span>Switch to Daddy</span><i data-feather="user"></i>';
21
+ personaIcon.className = 'w-8 h-8 rounded-full bg-gradient-to-r from-pink-500 to-purple-600 flex items-center justify-center';
22
+ personaName.textContent = 'Mistress AI';
23
+ personaName.className = 'font-bold text-pink-300';
24
+ feather.replace();
25
+ }
26
+ });
27
 
28
+ // Handle image preview and removal
29
+ document.addEventListener('DOMContentLoaded', () => {
30
+ const fileInput = document.querySelector('custom-upload').shadowRoot.querySelector('input[type="file"]');
31
+
32
+ fileInput.addEventListener('change', (e) => {
33
+ if (e.target.files.length > 0) {
34
+ const file = e.target.files[0];
35
+ if (file.type.match('image.*')) {
36
+ const reader = new FileReader();
37
+ reader.onload = (event) => {
38
+ previewImage.src = event.target.result;
39
+ imagePreview.classList.remove('hidden');
40
+ };
41
+ reader.readAsDataURL(file);
42
+ }
43
+ }
44
+ });
45
 
46
+ removeImage.addEventListener('click', () => {
47
+ previewImage.src = '';
48
+ imagePreview.classList.add('hidden');
49
+ fileInput.value = '';
50
+ });
51
+ });
52
+ // Handle form submission with image analysis
53
+ document.querySelector('form').addEventListener('submit', async (e) => {
54
+ e.preventDefault();
55
+ const input = e.target.querySelector('input[type="text"]');
56
+ const fileInput = document.querySelector('custom-upload').shadowRoot.querySelector('input[type="file"]');
57
+
58
+ // Show loading state
59
+ const submitBtn = e.target.querySelector('button[type="submit"]');
60
+ submitBtn.disabled = true;
61
+ submitBtn.innerHTML = '<i data-feather="loader" class="animate-spin"></i>';
62
 
63
+ let response;
64
+
65
+ try {
66
+ if (fileInput.files.length > 0) {
67
+ // Simulate image analysis with different responses based on persona
68
+ const file = fileInput.files[0];
69
+ const imageType = file.type.split('/')[1] || 'image';
70
+
71
+ if (currentPersona === 'mistress') {
72
+ response = `*scrutinizes your ${imageType} submission*\n${input.value || 'How dare you present this to me without context!'}\nI can see ${Math.floor(Math.random() * 5) + 1} flaws in your pathetic submission. You'll need to try much harder to impress me.`;
73
+ } else {
74
+ response = `*studies your ${imageType} carefully*\n${input.value || 'Is this your best effort?'}\nI count ${Math.floor(Math.random() * 3) + 1} areas needing improvement. You can do better, boy.`;
75
+ }
76
+ } else {
77
+ // Regular text response
78
+ response = currentPersona === 'mistress'
79
+ ? `*grabs your chin*\n${input.value || 'Silence is unacceptable'}. You will speak when spoken to, worm.`
80
+ : `*crosses arms*\n${input.value || 'I expect better from you'}, boy. Try again.`;
81
+ }
82
+ // Add the response to chat
83
+ const chatContainer = document.querySelector('.space-y-6');
84
+ const botMessage = document.createElement('div');
85
+ botMessage.className = 'flex';
86
+ botMessage.innerHTML = `
87
+ <div class="bg-${currentPersona === 'mistress' ? 'pink' : 'blue'}-900 rounded-lg p-4 max-w-3/4 shadow-lg">
88
+ <div class="flex items-center space-x-3 mb-2">
89
+ <div class="w-8 h-8 rounded-full bg-gradient-to-r from-${currentPersona === 'mistress' ? 'pink' : 'blue'}-500 to-${currentPersona === 'mistress' ? 'purple' : 'indigo'}-600 flex items-center justify-center">
90
+ <i data-feather="${currentPersona === 'mistress' ? 'alert-octagon' : 'zap'}" class="w-4 h-4"></i>
91
  </div>
92
+ <span class="font-bold text-${currentPersona === 'mistress' ? 'pink' : 'blue'}-300">${currentPersona === 'mistress' ? 'Mistress AI' : 'Daddy Dom AI'}</span>
 
 
 
 
 
 
 
 
 
 
93
  </div>
94
+ <p class="whitespace-pre-line">${response}</p>
95
+ ${fileInput.files.length > 0 ? `<div class="mt-3"><img src="${previewImage.src}" class="max-h-40 rounded-lg border border-${currentPersona === 'mistress' ? 'pink' : 'blue'}-700"></div>` : ''}
96
+ </div>
97
+ `;
98
+ chatContainer.appendChild(botMessage);
99
+
100
+ // Scroll to bottom
101
+ chatContainer.scrollTop = chatContainer.scrollHeight;
102
+
103
+ // Clear inputs
104
+ input.value = '';
105
+ fileInput.value = '';
106
+ previewImage.src = '';
107
+ imagePreview.classList.add('hidden');
108
+
109
+ } catch (error) {
110
+ console.error('Error analyzing image:', error);
111
+ // Add error message to chat
112
+ const chatContainer = document.querySelector('.space-y-6');
113
+ const errorMessage = document.createElement('div');
114
+ errorMessage.className = 'flex';
115
+ errorMessage.innerHTML = `
116
+ <div class="bg-red-900 rounded-lg p-4 max-w-3/4 shadow-lg">
117
+ <p>Failed to analyze your submission. Pathetic. Try again.</p>
118
  </div>
119
+ `;
120
+ chatContainer.appendChild(errorMessage);
121
+ } finally {
122
+ // Reset button state
123
+ submitBtn.disabled = false;
124
+ submitBtn.innerHTML = '<i data-feather="send"></i>';
125
  feather.replace();
126
+ }
127
+ });
 
 
 
script.js CHANGED
@@ -1,5 +1,35 @@
 
1
  let currentPersona = 'mistress';
2
  const togglePersona = document.getElementById('togglePersona');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  const personaIcon = document.getElementById('personaIcon');
4
  const personaName = document.getElementById('personaName');
5
  const imagePreview = document.getElementById('imagePreview');
 
1
+
2
  let currentPersona = 'mistress';
3
  const togglePersona = document.getElementById('togglePersona');
4
+ const imagePreview = document.getElementById('imagePreview');
5
+ const previewImage = document.getElementById('previewImage');
6
+ const removeImage = document.getElementById('removeImage');
7
+
8
+ // Handle image preview and removal
9
+ document.addEventListener('DOMContentLoaded', () => {
10
+ const fileInput = document.querySelector('custom-upload').shadowRoot.querySelector('input[type="file"]');
11
+
12
+ fileInput.addEventListener('change', (e) => {
13
+ if (e.target.files.length > 0) {
14
+ const file = e.target.files[0];
15
+ if (file.type.match('image.*')) {
16
+ const reader = new FileReader();
17
+ reader.onload = (event) => {
18
+ previewImage.src = event.target.result;
19
+ imagePreview.classList.remove('hidden');
20
+ };
21
+ reader.readAsDataURL(file);
22
+ }
23
+ }
24
+ });
25
+
26
+ removeImage.addEventListener('click', () => {
27
+ previewImage.src = '';
28
+ imagePreview.classList.add('hidden');
29
+ fileInput.value = '';
30
+ document.querySelector('custom-upload').shadowRoot.getElementById('fileName').textContent = '';
31
+ });
32
+ });
33
  const personaIcon = document.getElementById('personaIcon');
34
  const personaName = document.getElementById('personaName');
35
  const imagePreview = document.getElementById('imagePreview');
style.css CHANGED
@@ -44,7 +44,21 @@ p {
44
  @keyframes spin {
45
  to { transform: rotate(360deg); }
46
  }
47
-
48
  .animate-spin {
49
  animation: spin 1s linear infinite;
50
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  @keyframes spin {
45
  to { transform: rotate(360deg); }
46
  }
 
47
  .animate-spin {
48
  animation: spin 1s linear infinite;
49
  }
50
+
51
+ #imagePreview {
52
+ position: relative;
53
+ display: inline-block;
54
+ }
55
+
56
+ #removeImage {
57
+ cursor: pointer;
58
+ transition: all 0.2s ease;
59
+ }
60
+
61
+ #removeImage:hover {
62
+ transform: scale(1.1);
63
+ background-color: #ef4444;
64
+ }