Caiobriaego commited on
Commit
1a7efb4
·
verified ·
1 Parent(s): 8001c50

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +1617 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Iriis Py
3
- emoji: 👀
4
  colorFrom: gray
5
- colorTo: pink
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: iriis-py
3
+ emoji: 🐳
4
  colorFrom: gray
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1617 @@
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="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Iris Pro - Assistente com Memória Vetorial e Dados Reais</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.18.0/dist/tf.min.js"></script>
10
+ <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet">
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
+ <style>
13
+ :root {
14
+ --neon-blue: #00f7ff;
15
+ --neon-pink: #ff00ff;
16
+ --neon-purple: #9d00ff;
17
+ --dark-bg: #0a0a12;
18
+ }
19
+
20
+ body {
21
+ font-family: 'Rajdhani', sans-serif;
22
+ background-color: var(--dark-bg);
23
+ color: white;
24
+ overflow-x: hidden;
25
+ }
26
+
27
+ .cyber-font {
28
+ font-family: 'Orbitron', sans-serif;
29
+ }
30
+
31
+ .neon-text-blue {
32
+ text-shadow: 0 0 5px var(--neon-blue), 0 0 10px var(--neon-blue);
33
+ color: var(--neon-blue);
34
+ }
35
+
36
+ .neon-text-pink {
37
+ text-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink);
38
+ color: var(--neon-pink);
39
+ }
40
+
41
+ .neon-text-purple {
42
+ text-shadow: 0 0 5px var(--neon-purple), 0 0 10px var(--neon-purple);
43
+ color: var(--neon-purple);
44
+ }
45
+
46
+ .neon-border-blue {
47
+ box-shadow: 0 0 10px var(--neon-blue), inset 0 0 10px var(--neon-blue);
48
+ border: 1px solid var(--neon-blue);
49
+ }
50
+
51
+ .neon-border-pink {
52
+ box-shadow: 0 0 10px var(--neon-pink), inset 0 0 10px var(--neon-pink);
53
+ border: 1px solid var(--neon-pink);
54
+ }
55
+
56
+ .neon-border-purple {
57
+ box-shadow: 0 0 10px var(--neon-purple), inset 0 0 10px var(--neon-purple);
58
+ border: 1px solid var(--neon-purple);
59
+ }
60
+
61
+ .glow-effect {
62
+ animation: glow 2s infinite alternate;
63
+ }
64
+
65
+ @keyframes glow {
66
+ from {
67
+ box-shadow: 0 0 5px var(--neon-blue), 0 0 10px var(--neon-blue);
68
+ }
69
+ to {
70
+ box-shadow: 0 0 15px var(--neon-blue), 0 0 20px var(--neon-blue);
71
+ }
72
+ }
73
+
74
+ .chat-container {
75
+ background: rgba(10, 10, 18, 0.7);
76
+ backdrop-filter: blur(10px);
77
+ }
78
+
79
+ .message-bubble {
80
+ max-width: 80%;
81
+ border-radius: 1rem;
82
+ padding: 0.75rem 1rem;
83
+ margin-bottom: 0.5rem;
84
+ position: relative;
85
+ }
86
+
87
+ .user-message {
88
+ background: rgba(0, 247, 255, 0.15);
89
+ border-left: 3px solid var(--neon-blue);
90
+ margin-left: auto;
91
+ }
92
+
93
+ .iris-message {
94
+ background: rgba(255, 0, 255, 0.15);
95
+ border-right: 3px solid var(--neon-pink);
96
+ margin-right: auto;
97
+ }
98
+
99
+ .system-message {
100
+ background: rgba(157, 0, 255, 0.15);
101
+ border-right: 3px solid var(--neon-purple);
102
+ margin: 0 auto;
103
+ max-width: 90%;
104
+ text-align: center;
105
+ font-size: 0.85rem;
106
+ }
107
+
108
+ .typing-indicator span {
109
+ display: inline-block;
110
+ width: 8px;
111
+ height: 8px;
112
+ background-color: var(--neon-pink);
113
+ border-radius: 50%;
114
+ margin-right: 3px;
115
+ animation: bounce 1.5s infinite ease-in-out;
116
+ }
117
+
118
+ .typing-indicator span:nth-child(2) {
119
+ animation-delay: 0.2s;
120
+ }
121
+
122
+ .typing-indicator span:nth-child(3) {
123
+ animation-delay: 0.4s;
124
+ }
125
+
126
+ @keyframes bounce {
127
+ 0%, 100% {
128
+ transform: translateY(0);
129
+ }
130
+ 50% {
131
+ transform: translateY(-5px);
132
+ }
133
+ }
134
+
135
+ .scanline {
136
+ position: absolute;
137
+ top: 0;
138
+ left: 0;
139
+ width: 100%;
140
+ height: 100%;
141
+ background: linear-gradient(
142
+ to bottom,
143
+ rgba(0, 247, 255, 0.1) 0%,
144
+ rgba(0, 247, 255, 0) 10%
145
+ );
146
+ background-size: 100% 8px;
147
+ pointer-events: none;
148
+ animation: scanline 8s linear infinite;
149
+ }
150
+
151
+ @keyframes scanline {
152
+ 0% {
153
+ background-position: 0 0;
154
+ }
155
+ 100% {
156
+ background-position: 0 100%;
157
+ }
158
+ }
159
+
160
+ .memory-chip {
161
+ position: relative;
162
+ width: 30px;
163
+ height: 30px;
164
+ background: linear-gradient(135deg, rgba(0, 247, 255, 0.2), rgba(255, 0, 255, 0.2));
165
+ border-radius: 4px;
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ }
170
+
171
+ .memory-chip::before {
172
+ content: "";
173
+ position: absolute;
174
+ top: -2px;
175
+ left: -2px;
176
+ right: -2px;
177
+ bottom: -2px;
178
+ border: 1px solid var(--neon-blue);
179
+ border-radius: 6px;
180
+ animation: pulse 2s infinite;
181
+ }
182
+
183
+ @keyframes pulse {
184
+ 0% { opacity: 0.6; }
185
+ 50% { opacity: 1; }
186
+ 100% { opacity: 0.6; }
187
+ }
188
+
189
+ .command-chip {
190
+ display: inline-block;
191
+ padding: 2px 6px;
192
+ background: rgba(0, 247, 255, 0.2);
193
+ border-radius: 4px;
194
+ font-size: 0.75rem;
195
+ margin-right: 4px;
196
+ margin-bottom: 4px;
197
+ }
198
+
199
+ .progress-bar {
200
+ height: 4px;
201
+ background: rgba(255, 255, 255, 0.1);
202
+ border-radius: 2px;
203
+ overflow: hidden;
204
+ }
205
+
206
+ .progress-fill {
207
+ height: 100%;
208
+ background: linear-gradient(90deg, var(--neon-blue), var(--neon-pink));
209
+ border-radius: 2px;
210
+ transition: width 0.3s ease;
211
+ }
212
+
213
+ /* Animation for new message */
214
+ @keyframes messageAppear {
215
+ from {
216
+ opacity: 0;
217
+ transform: translateY(10px);
218
+ }
219
+ to {
220
+ opacity: 1;
221
+ transform: translateY(0);
222
+ }
223
+ }
224
+
225
+ .new-message {
226
+ animation: messageAppear 0.3s ease-out;
227
+ }
228
+
229
+ /* Settings panel */
230
+ .settings-option {
231
+ display: flex;
232
+ justify-content: space-between;
233
+ align-items: center;
234
+ padding: 8px 0;
235
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
236
+ }
237
+
238
+ .toggle-switch {
239
+ position: relative;
240
+ display: inline-block;
241
+ width: 40px;
242
+ height: 20px;
243
+ }
244
+
245
+ .toggle-switch input {
246
+ opacity: 0;
247
+ width: 0;
248
+ height: 0;
249
+ }
250
+
251
+ .toggle-slider {
252
+ position: absolute;
253
+ cursor: pointer;
254
+ top: 0;
255
+ left: 0;
256
+ right: 0;
257
+ bottom: 0;
258
+ background-color: rgba(255, 255, 255, 0.1);
259
+ transition: .4s;
260
+ border-radius: 20px;
261
+ }
262
+
263
+ .toggle-slider:before {
264
+ position: absolute;
265
+ content: "";
266
+ height: 16px;
267
+ width: 16px;
268
+ left: 2px;
269
+ bottom: 2px;
270
+ background-color: white;
271
+ transition: .4s;
272
+ border-radius: 50%;
273
+ }
274
+
275
+ input:checked + .toggle-slider {
276
+ background-color: var(--neon-blue);
277
+ }
278
+
279
+ input:checked + .toggle-slider:before {
280
+ transform: translateX(20px);
281
+ }
282
+
283
+ .api-status {
284
+ display: inline-block;
285
+ width: 8px;
286
+ height: 8px;
287
+ border-radius: 50%;
288
+ margin-right: 5px;
289
+ }
290
+
291
+ .api-active {
292
+ background-color: #00ff00;
293
+ box-shadow: 0 0 5px #00ff00;
294
+ }
295
+
296
+ .api-inactive {
297
+ background-color: #ff0000;
298
+ box-shadow: 0 0 5px #ff0000;
299
+ }
300
+
301
+ .knowledge-graph {
302
+ display: flex;
303
+ flex-wrap: wrap;
304
+ gap: 8px;
305
+ margin-top: 10px;
306
+ }
307
+
308
+ .knowledge-node {
309
+ background: rgba(157, 0, 255, 0.2);
310
+ border: 1px solid var(--neon-purple);
311
+ border-radius: 12px;
312
+ padding: 6px 10px;
313
+ font-size: 0.8rem;
314
+ display: flex;
315
+ align-items: center;
316
+ }
317
+
318
+ .knowledge-node i {
319
+ margin-right: 5px;
320
+ font-size: 0.7rem;
321
+ }
322
+
323
+ .vector-score {
324
+ font-size: 0.7rem;
325
+ color: var(--neon-blue);
326
+ margin-left: 5px;
327
+ }
328
+
329
+ .context-chip {
330
+ background: rgba(0, 247, 255, 0.1);
331
+ border: 1px solid var(--neon-blue);
332
+ border-radius: 4px;
333
+ padding: 2px 6px;
334
+ font-size: 0.7rem;
335
+ margin-right: 4px;
336
+ margin-bottom: 4px;
337
+ display: inline-block;
338
+ }
339
+ </style>
340
+ </head>
341
+ <body class="min-h-screen flex flex-col">
342
+ <div class="scanline"></div>
343
+
344
+ <!-- Header -->
345
+ <header class="py-4 px-6 flex justify-between items-center neon-border-b border-b-2 border-blue-500">
346
+ <div class="flex items-center">
347
+ <div class="w-10 h-10 rounded-full neon-border-blue flex items-center justify-center mr-3">
348
+ <i class="fas fa-robot neon-text-blue text-xl"></i>
349
+ </div>
350
+ <h1 class="cyber-font neon-text-blue text-2xl">IRIS PRO</h1>
351
+ </div>
352
+ <div class="flex space-x-4">
353
+ <button class="neon-text-blue hover:neon-text-pink transition-colors" id="settings-btn">
354
+ <i class="fas fa-cog text-xl"></i>
355
+ </button>
356
+ <button class="neon-text-blue hover:neon-text-pink transition-colors" id="memory-btn">
357
+ <div class="memory-chip">
358
+ <i class="fas fa-brain text-xs"></i>
359
+ </div>
360
+ </button>
361
+ </div>
362
+ </header>
363
+
364
+ <!-- Main Content -->
365
+ <main class="flex-1 flex flex-col p-4 max-w-3xl mx-auto w-full">
366
+ <!-- Status Bar -->
367
+ <div class="flex justify-between items-center mb-4 neon-text-blue text-sm">
368
+ <div class="flex items-center">
369
+ <i class="fas fa-wifi mr-1"></i>
370
+ <span id="connection-status">CONECTADO</span>
371
+ </div>
372
+ <div class="flex items-center">
373
+ <i class="fas fa-microchip mr-1"></i>
374
+ <span>IA: MISTRAL-7B</span>
375
+ </div>
376
+ <div class="flex items-center">
377
+ <i class="fas fa-database mr-1"></i>
378
+ <span>MEM: <span id="memory-usage">78</span>%</span>
379
+ </div>
380
+ </div>
381
+
382
+ <!-- API Status -->
383
+ <div class="flex justify-between mb-2 text-xs neon-text-purple">
384
+ <div class="flex items-center">
385
+ <span class="api-status api-active" id="weather-api-status"></span>
386
+ <span>Clima</span>
387
+ </div>
388
+ <div class="flex items-center">
389
+ <span class="api-status api-active" id="news-api-status"></span>
390
+ <span>Notícias</span>
391
+ </div>
392
+ <div class="flex items-center">
393
+ <span class="api-status api-active" id="translate-api-status"></span>
394
+ <span>Tradução</span>
395
+ </div>
396
+ <div class="flex items-center">
397
+ <span class="api-status api-active" id="finance-api-status"></span>
398
+ <span>Finanças</span>
399
+ </div>
400
+ </div>
401
+
402
+ <!-- Chat Container -->
403
+ <div class="chat-container flex-1 rounded-lg neon-border-blue p-4 mb-4 overflow-y-auto">
404
+ <div class="chat-messages space-y-2" id="chat-messages">
405
+ <!-- Initial greeting -->
406
+ <div class="message-bubble iris-message new-message">
407
+ <div class="flex items-start">
408
+ <div class="w-6 h-6 rounded-full bg-pink-500 mr-2 flex items-center justify-center neon-border-pink">
409
+ <i class="fas fa-robot text-xs"></i>
410
+ </div>
411
+ <div>
412
+ <p class="neon-text-pink">Olá, eu sou a Iris Pro. Seu assistente de IA com memória vetorial e acesso a dados reais. Como posso te ajudar hoje?</p>
413
+ <div class="text-xs text-gray-400 mt-1">Sistema: Memória vetorial ativa | APIs conectadas</div>
414
+ </div>
415
+ </div>
416
+ </div>
417
+
418
+ <!-- System message with commands -->
419
+ <div class="message-bubble system-message new-message">
420
+ <p class="neon-text-purple">Você pode me pedir coisas como:</p>
421
+ <div class="mt-2 flex flex-wrap justify-center">
422
+ <span class="command-chip">"Previsão do tempo em São Paulo"</span>
423
+ <span class="command-chip">"Notícias sobre tecnologia"</span>
424
+ <span class="command-chip">"Cotação do dólar hoje"</span>
425
+ <span class="command-chip">"Traduzir 'hello' para português"</span>
426
+ <span class="command-chip">"Lembretes para hoje"</span>
427
+ <span class="command-chip">"Pesquisar sobre IA"</span>
428
+ </div>
429
+ </div>
430
+ </div>
431
+ </div>
432
+
433
+ <!-- Voice Activation Button -->
434
+ <div class="flex justify-center mb-4 relative">
435
+ <div class="absolute -top-4 w-full max-w-xs">
436
+ <div class="progress-bar">
437
+ <div class="progress-fill" id="voice-level" style="width: 0%"></div>
438
+ </div>
439
+ </div>
440
+ <button id="voice-btn" class="w-16 h-16 rounded-full neon-border-blue glow-effect flex items-center justify-center neon-text-blue hover:neon-text-pink transition-all transform hover:scale-110">
441
+ <i class="fas fa-microphone text-2xl"></i>
442
+ </button>
443
+ </div>
444
+
445
+ <!-- Input Area -->
446
+ <div class="flex items-center neon-border-blue rounded-lg p-2">
447
+ <input type="text" id="message-input" placeholder="Digite sua mensagem..." class="flex-1 bg-transparent outline-none px-3 py-2 neon-text-blue placeholder-blue-400">
448
+ <button id="send-btn" class="w-10 h-10 rounded-md neon-border-blue flex items-center justify-center neon-text-blue hover:neon-text-pink transition-colors">
449
+ <i class="fas fa-paper-plane"></i>
450
+ </button>
451
+ </div>
452
+
453
+ <!-- Quick Actions -->
454
+ <div class="grid grid-cols-4 gap-2 mt-4">
455
+ <button class="quick-action neon-border-blue rounded-md py-2 px-1 neon-text-blue hover:neon-text-pink transition-colors text-xs" data-command="Previsão do tempo em São Paulo">
456
+ <i class="fas fa-cloud-sun mr-1"></i> Clima
457
+ </button>
458
+ <button class="quick-action neon-border-blue rounded-md py-2 px-1 neon-text-blue hover:neon-text-pink transition-colors text-xs" data-command="Notícias sobre tecnologia">
459
+ <i class="fas fa-newspaper mr-1"></i> Notícias
460
+ </button>
461
+ <button class="quick-action neon-border-blue rounded-md py-2 px-1 neon-text-blue hover:neon-text-pink transition-colors text-xs" data-command="Cotação do dólar hoje">
462
+ <i class="fas fa-dollar-sign mr-1"></i> Dólar
463
+ </button>
464
+ <button class="quick-action neon-border-blue rounded-md py-2 px-1 neon-text-blue hover:neon-text-pink transition-colors text-xs" data-command="Traduzir 'hello' para português">
465
+ <i class="fas fa-language mr-1"></i> Traduzir
466
+ </button>
467
+ </div>
468
+ </main>
469
+
470
+ <!-- Footer -->
471
+ <footer class="py-3 px-6 text-center neon-border-t border-t-2 border-blue-500 text-xs neon-text-blue">
472
+ <p>IRIS PRO v3.0 | Memória vetorial ativa | Dados em tempo real | Tempo de resposta: <span id="response-time">1.4</span>s</p>
473
+ </footer>
474
+
475
+ <!-- Memory Panel (hidden by default) -->
476
+ <div id="memory-panel" class="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center hidden">
477
+ <div class="neon-border-blue bg-gray-900 rounded-lg p-6 max-w-md w-full max-h-[80vh] overflow-y-auto">
478
+ <div class="flex justify-between items-center mb-4">
479
+ <h3 class="cyber-font neon-text-blue text-xl">Memória Vetorial</h3>
480
+ <button id="close-memory" class="neon-text-pink hover:text-white">
481
+ <i class="fas fa-times"></i>
482
+ </button>
483
+ </div>
484
+
485
+ <div class="space-y-4">
486
+ <div class="neon-border-pink p-4 rounded-lg">
487
+ <h4 class="neon-text-pink font-bold mb-2">Contexto Atual</h4>
488
+ <div id="current-context">
489
+ <!-- Filled by JavaScript -->
490
+ </div>
491
+ </div>
492
+
493
+ <div class="neon-border-blue p-4 rounded-lg">
494
+ <h4 class="neon-text-blue font-bold mb-2">Memória de Longo Prazo</h4>
495
+ <div class="knowledge-graph" id="knowledge-graph">
496
+ <!-- Filled by JavaScript -->
497
+ </div>
498
+ </div>
499
+
500
+ <div class="neon-border-purple p-4 rounded-lg">
501
+ <h4 class="neon-text-purple font-bold mb-2">Dados do Sistema</h4>
502
+ <div class="text-sm space-y-2">
503
+ <div class="flex justify-between">
504
+ <span>Vetores armazenados:</span>
505
+ <span id="vector-count">0</span>
506
+ </div>
507
+ <div class="flex justify-between">
508
+ <span>Similaridade média:</span>
509
+ <span id="avg-similarity">0%</span>
510
+ </div>
511
+ <div class="flex justify-between">
512
+ <span>Requisições API hoje:</span>
513
+ <span id="api-requests">12</span>
514
+ </div>
515
+ </div>
516
+ </div>
517
+ </div>
518
+
519
+ <div class="mt-6 grid grid-cols-2 gap-2">
520
+ <button class="py-2 neon-border-blue rounded-lg neon-text-blue hover:neon-text-pink" id="export-vectors">
521
+ Exportar vetores
522
+ </button>
523
+ <button class="py-2 neon-border-pink rounded-lg neon-text-pink hover:neon-text-blue" id="clear-context">
524
+ Limpar contexto
525
+ </button>
526
+ </div>
527
+ </div>
528
+ </div>
529
+
530
+ <!-- Settings Panel -->
531
+ <div id="settings-panel" class="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center hidden">
532
+ <div class="neon-border-blue bg-gray-900 rounded-lg p-6 max-w-md w-full max-h-[80vh] overflow-y-auto">
533
+ <div class="flex justify-between items-center mb-4">
534
+ <h3 class="cyber-font neon-text-blue text-xl">Configurações</h3>
535
+ <button id="close-settings" class="neon-text-pink hover:text-white">
536
+ <i class="fas fa-times"></i>
537
+ </button>
538
+ </div>
539
+
540
+ <div class="space-y-4">
541
+ <div class="neon-border-blue p-4 rounded-lg">
542
+ <h4 class="neon-text-blue font-bold mb-3">Preferências de voz</h4>
543
+
544
+ <div class="settings-option">
545
+ <span>Ativar voz</span>
546
+ <label class="toggle-switch">
547
+ <input type="checkbox" id="voice-toggle" checked>
548
+ <span class="toggle-slider"></span>
549
+ </label>
550
+ </div>
551
+
552
+ <div class="settings-option">
553
+ <span>Volume padrão</span>
554
+ <input type="range" id="volume-slider" min="0" max="100" value="75" class="w-24">
555
+ <span id="volume-value" class="w-8 text-right">75%</span>
556
+ </div>
557
+
558
+ <div class="settings-option">
559
+ <span>Velocidade da voz</span>
560
+ <select id="voice-speed" class="bg-gray-800 text-white rounded px-2 py-1">
561
+ <option value="0.8">Lenta</option>
562
+ <option value="1.0" selected>Normal</option>
563
+ <option value="1.2">Rápida</option>
564
+ </select>
565
+ </div>
566
+ </div>
567
+
568
+ <div class="neon-border-pink p-4 rounded-lg">
569
+ <h4 class="neon-text-pink font-bold mb-3">Configurações de Memória</h4>
570
+
571
+ <div class="settings-option">
572
+ <span>Memória vetorial</span>
573
+ <label class="toggle-switch">
574
+ <input type="checkbox" id="vector-memory-toggle" checked>
575
+ <span class="toggle-slider"></span>
576
+ </label>
577
+ </div>
578
+
579
+ <div class="settings-option">
580
+ <span>Limite de contexto</span>
581
+ <select id="context-limit" class="bg-gray-800 text-white rounded px-2 py-1">
582
+ <option value="5">5 mensagens</option>
583
+ <option value="10" selected>10 mensagens</option>
584
+ <option value="20">20 mensagens</option>
585
+ </select>
586
+ </div>
587
+
588
+ <div class="settings-option">
589
+ <span>Limiar de similaridade</span>
590
+ <input type="range" id="similarity-threshold" min="50" max="95" value="75" class="w-24">
591
+ <span id="similarity-value" class="w-8 text-right">75%</span>
592
+ </div>
593
+ </div>
594
+
595
+ <div class="neon-border-purple p-4 rounded-lg">
596
+ <h4 class="neon-text-purple font-bold mb-3">Configurações de privacidade</h4>
597
+
598
+ <div class="settings-option">
599
+ <span>Armazenar histórico</span>
600
+ <label class="toggle-switch">
601
+ <input type="checkbox" id="store-history-toggle" checked>
602
+ <span class="toggle-slider"></span>
603
+ </label>
604
+ </div>
605
+
606
+ <div class="settings-option">
607
+ <span>Compartilhar dados anônimos</span>
608
+ <label class="toggle-switch">
609
+ <input type="checkbox" id="share-data-toggle">
610
+ <span class="toggle-slider"></span>
611
+ </label>
612
+ </div>
613
+ </div>
614
+ </div>
615
+
616
+ <div class="mt-6">
617
+ <button class="w-full py-2 neon-border-blue rounded-lg neon-text-blue hover:neon-text-pink" id="save-settings">
618
+ Salvar configurações
619
+ </button>
620
+ </div>
621
+ </div>
622
+ </div>
623
+
624
+ <script>
625
+ // Enhanced user profile with vector memory
626
+ const userProfile = {
627
+ name: "Usuário",
628
+ location: {
629
+ city: "São Paulo",
630
+ country: "Brasil",
631
+ timezone: "America/Sao_Paulo"
632
+ },
633
+ preferences: {
634
+ voice: {
635
+ active: true,
636
+ volume: 75,
637
+ speed: 1.0
638
+ },
639
+ memory: {
640
+ vectorEnabled: true,
641
+ contextLimit: 10,
642
+ similarityThreshold: 0.75
643
+ },
644
+ privacy: {
645
+ storeHistory: true,
646
+ shareData: false
647
+ },
648
+ apis: {
649
+ weather: true,
650
+ news: true,
651
+ finance: true,
652
+ translate: true
653
+ }
654
+ },
655
+ history: [],
656
+ vectorMemory: [],
657
+ context: [],
658
+ apiRequests: 0
659
+ };
660
+
661
+ // Free API endpoints with real data
662
+ const API_ENDPOINTS = {
663
+ weather: "https://api.open-meteo.com/v1/forecast",
664
+ news: "https://newsapi.org/v2/top-headlines",
665
+ finance: "https://api.exchangerate-api.com/v4/latest/USD",
666
+ translate: "https://libretranslate.de/translate",
667
+ geocoding: "https://geocoding-api.open-meteo.com/v1/search",
668
+ wikipedia: "https://pt.wikipedia.org/w/api.php"
669
+ };
670
+
671
+ // API Keys (in a real app, these would be secured)
672
+ const API_KEYS = {
673
+ news: "a2a4b2e0e4msh7a9a8b3d3c3a4d6p1b3a2ajsn4a3b2c1d0e0f" // Demo key - would be replaced in production
674
+ };
675
+
676
+ // Vector memory model (simplified for demo)
677
+ class VectorMemory {
678
+ constructor() {
679
+ this.vectors = [];
680
+ this.model = null;
681
+ this.initialized = false;
682
+ }
683
+
684
+ async init() {
685
+ // Load a simple text embedding model (in a real app, would use a proper model)
686
+ this.model = await this.loadSimpleEmbeddingModel();
687
+ this.initialized = true;
688
+ }
689
+
690
+ async loadSimpleEmbeddingModel() {
691
+ // This is a simplified embedding approach
692
+ // In a real app, you would use TensorFlow.js with a proper model
693
+ return {
694
+ embed: async (text) => {
695
+ // Simple word frequency vector (for demo purposes)
696
+ const words = text.toLowerCase().split(/\s+/);
697
+ const uniqueWords = [...new Set(words)];
698
+ const vector = new Array(100).fill(0);
699
+
700
+ // Simple hash-based embedding
701
+ uniqueWords.forEach(word => {
702
+ const hash = this.stringHash(word) % 100;
703
+ vector[hash] = 1;
704
+ });
705
+
706
+ return vector;
707
+ }
708
+ };
709
+ }
710
+
711
+ stringHash(str) {
712
+ let hash = 0;
713
+ for (let i = 0; i < str.length; i++) {
714
+ hash = ((hash << 5) - hash) + str.charCodeAt(i);
715
+ hash |= 0; // Convert to 32bit integer
716
+ }
717
+ return Math.abs(hash);
718
+ }
719
+
720
+ async addMemory(text, metadata = {}) {
721
+ if (!this.initialized) await this.init();
722
+
723
+ const vector = await this.model.embed(text);
724
+ this.vectors.push({
725
+ text,
726
+ vector,
727
+ metadata: {
728
+ timestamp: new Date().toISOString(),
729
+ ...metadata
730
+ }
731
+ });
732
+
733
+ return vector;
734
+ }
735
+
736
+ async findSimilar(text, limit = 5, threshold = 0.7) {
737
+ if (!this.initialized) await this.init();
738
+
739
+ const queryVector = await this.model.embed(text);
740
+ const results = [];
741
+
742
+ this.vectors.forEach((memory, index) => {
743
+ const similarity = this.cosineSimilarity(queryVector, memory.vector);
744
+ if (similarity >= threshold) {
745
+ results.push({
746
+ text: memory.text,
747
+ similarity,
748
+ metadata: memory.metadata
749
+ });
750
+ }
751
+ });
752
+
753
+ // Sort by similarity
754
+ results.sort((a, b) => b.similarity - a.similarity);
755
+
756
+ return results.slice(0, limit);
757
+ }
758
+
759
+ cosineSimilarity(vecA, vecB) {
760
+ let dotProduct = 0;
761
+ let normA = 0;
762
+ let normB = 0;
763
+
764
+ for (let i = 0; i < vecA.length; i++) {
765
+ dotProduct += vecA[i] * vecB[i];
766
+ normA += vecA[i] * vecA[i];
767
+ normB += vecB[i] * vecB[i];
768
+ }
769
+
770
+ normA = Math.sqrt(normA);
771
+ normB = Math.sqrt(normB);
772
+
773
+ return dotProduct / (normA * normB);
774
+ }
775
+
776
+ getMemoryStats() {
777
+ return {
778
+ count: this.vectors.length,
779
+ avgSimilarity: this.calculateAvgSimilarity()
780
+ };
781
+ }
782
+
783
+ calculateAvgSimilarity() {
784
+ if (this.vectors.length < 2) return 0;
785
+
786
+ let totalSimilarity = 0;
787
+ let comparisons = 0;
788
+
789
+ // Compare each vector with a few others
790
+ for (let i = 0; i < Math.min(10, this.vectors.length); i++) {
791
+ for (let j = i + 1; j < Math.min(i + 5, this.vectors.length); j++) {
792
+ totalSimilarity += this.cosineSimilarity(
793
+ this.vectors[i].vector,
794
+ this.vectors[j].vector
795
+ );
796
+ comparisons++;
797
+ }
798
+ }
799
+
800
+ return comparisons > 0 ? totalSimilarity / comparisons : 0;
801
+ }
802
+ }
803
+
804
+ // Initialize vector memory
805
+ const vectorMemory = new VectorMemory();
806
+
807
+ // Enhanced knowledge base with vector memory integration
808
+ const knowledgeBase = {
809
+ greetings: [
810
+ "Olá! Como posso te ajudar hoje?",
811
+ "Oi! O que você gostaria de fazer?",
812
+ "Saudações! Pronto para auxiliar com dados em tempo real."
813
+ ],
814
+
815
+ getTime: () => {
816
+ const now = new Date();
817
+ const options = {
818
+ hour: '2-digit',
819
+ minute: '2-digit',
820
+ second: '2-digit',
821
+ timeZone: userProfile.location.timezone
822
+ };
823
+ return `Agora são exatamente ${now.toLocaleTimeString('pt-BR', options)}.`;
824
+ },
825
+
826
+ getDate: () => {
827
+ const now = new Date();
828
+ const options = {
829
+ weekday: 'long',
830
+ year: 'numeric',
831
+ month: 'long',
832
+ day: 'numeric',
833
+ timeZone: userProfile.location.timezone
834
+ };
835
+ return `Hoje é ${now.toLocaleDateString('pt-BR', options)}.`;
836
+ },
837
+
838
+ getWeather: async (location = userProfile.location.city) => {
839
+ if (!userProfile.preferences.apis.weather) {
840
+ return "O serviço de previsão do tempo está desativado nas configurações.";
841
+ }
842
+
843
+ try {
844
+ // First get coordinates for the location
845
+ const geoResponse = await fetch(`${API_ENDPOINTS.geocoding}?name=${encodeURIComponent(location)}`);
846
+ const geoData = await geoResponse.json();
847
+
848
+ if (!geoData.results || geoData.results.length === 0) {
849
+ return `Não consegui encontrar a localização ${location}.`;
850
+ }
851
+
852
+ const firstResult = geoData.results[0];
853
+ const lat = firstResult.latitude;
854
+ const lon = firstResult.longitude;
855
+
856
+ // Get weather data
857
+ const weatherResponse = await fetch(`${API_ENDPOINTS.weather}?latitude=${lat}&longitude=${lon}&hourly=temperature_2m,weathercode&timezone=America/Sao_Paulo`);
858
+ const weatherData = await weatherResponse.json();
859
+
860
+ if (!weatherResponse.ok) throw new Error(weatherData.reason || "Erro na API de clima");
861
+
862
+ // Get current temperature
863
+ const now = new Date();
864
+ const currentHour = now.getHours();
865
+ const currentTemp = weatherData.hourly.temperature_2m[currentHour];
866
+ const weatherCode = weatherData.hourly.weathercode[currentHour];
867
+
868
+ // Weather code to text mapping
869
+ const weatherTypes = {
870
+ 0: "céu limpo",
871
+ 1: "parcialmente nublado",
872
+ 2: "nublado",
873
+ 3: "nublado",
874
+ 45: "nevoeiro",
875
+ 51: "chuvisco",
876
+ 53: "chuvisco",
877
+ 55: "chuvisco",
878
+ 56: "chuvisco congelante",
879
+ 57: "chuvisco congelante",
880
+ 61: "chuva leve",
881
+ 63: "chuva moderada",
882
+ 65: "chuva forte",
883
+ 66: "chuva congelante",
884
+ 67: "chuva congelante",
885
+ 71: "neve leve",
886
+ 73: "neve moderada",
887
+ 75: "neve forte",
888
+ 77: "grãos de neve",
889
+ 80: "chuva leve",
890
+ 81: "chuva moderada",
891
+ 82: "chuva forte",
892
+ 85: "neve leve",
893
+ 86: "neve forte",
894
+ 95: "trovoada",
895
+ 96: "trovoada com chuva leve",
896
+ 99: "trovoada com chuva forte"
897
+ };
898
+
899
+ const weatherCondition = weatherTypes[weatherCode] || "condições climáticas variáveis";
900
+
901
+ // Add to vector memory
902
+ if (userProfile.preferences.memory.vectorEnabled) {
903
+ await vectorMemory.addMemory(
904
+ `Previsão do tempo em ${location}: ${weatherCondition} com ${currentTemp}°C`,
905
+ { type: "weather", location }
906
+ );
907
+ }
908
+
909
+ return `Em ${location}, está ${weatherCondition} com temperatura de ${currentTemp}°C.`;
910
+ } catch (error) {
911
+ console.error("Erro na API de clima:", error);
912
+ return `Não consegui acessar os dados meteorológicos. ${error.message}`;
913
+ }
914
+ },
915
+
916
+ getNews: async (topic = "tecnologia") => {
917
+ if (!userProfile.preferences.apis.news) {
918
+ return "O serviço de notícias está desativado nas configurações.";
919
+ }
920
+
921
+ try {
922
+ // Using NewsAPI (requires key in production)
923
+ const response = await fetch(`https://newsapi.org/v2/everything?q=${topic}&language=pt&pageSize=3&apiKey=${API_KEYS.news}`);
924
+ const data = await response.json();
925
+
926
+ if (data.status !== "ok") throw new Error(data.message || "Erro na API de notícias");
927
+
928
+ if (data.articles.length === 0) {
929
+ return `Não encontrei notícias recentes sobre ${topic}.`;
930
+ }
931
+
932
+ let newsText = `Aqui estão as últimas notícias sobre ${topic}:\n\n`;
933
+ data.articles.forEach((article, index) => {
934
+ newsText += `${index + 1}. ${article.title}\nFonte: ${article.source.name}\n\n`;
935
+
936
+ // Add to vector memory
937
+ if (userProfile.preferences.memory.vectorEnabled) {
938
+ vectorMemory.addMemory(
939
+ `Notícia sobre ${topic}: ${article.title}`,
940
+ { type: "news", source: article.source.name }
941
+ );
942
+ }
943
+ });
944
+
945
+ return newsText;
946
+ } catch (error) {
947
+ console.error("Erro na API de notícias:", error);
948
+ return `Não consegui acessar as últimas notícias. ${error.message}`;
949
+ }
950
+ },
951
+
952
+ getFinance: async (currency = "USD") => {
953
+ if (!userProfile.preferences.apis.finance) {
954
+ return "O serviço de cotações está desativado nas configurações.";
955
+ }
956
+
957
+ try {
958
+ // Using ExchangeRate-API (free tier)
959
+ const response = await fetch(API_ENDPOINTS.finance);
960
+ const data = await response.json();
961
+
962
+ if (!data.rates) throw new Error("Erro na API de cotações");
963
+
964
+ const brlRate = data.rates.BRL;
965
+ const eurRate = data.rates.EUR;
966
+
967
+ // Add to vector memory
968
+ if (userProfile.preferences.memory.vectorEnabled) {
969
+ await vectorMemory.addMemory(
970
+ `Cotação atual: Dólar a R$${brlRate.toFixed(2)}, Euro a R$${(brlRate / eurRate).toFixed(2)}`,
971
+ { type: "finance" }
972
+ );
973
+ }
974
+
975
+ return `Cotações atuais:\n- Dólar (USD): R$ ${brlRate.toFixed(2)}\n- Euro (EUR): R$ ${(brlRate / eurRate).toFixed(2)}`;
976
+ } catch (error) {
977
+ console.error("Erro na API de finanças:", error);
978
+ return `Não consegui acessar as cotações. ${error.message}`;
979
+ }
980
+ },
981
+
982
+ translateText: async (text, targetLang = "pt") => {
983
+ if (!userProfile.preferences.apis.translate) {
984
+ return "O serviço de tradução está desativado nas configurações.";
985
+ }
986
+
987
+ try {
988
+ // Using LibreTranslate (free and open source)
989
+ const response = await fetch(API_ENDPOINTS.translate, {
990
+ method: "POST",
991
+ headers: {
992
+ "Content-Type": "application/json"
993
+ },
994
+ body: JSON.stringify({
995
+ q: text,
996
+ source: "auto",
997
+ target: targetLang
998
+ })
999
+ });
1000
+
1001
+ const data = await response.json();
1002
+
1003
+ if (!data.translatedText) throw new Error("Erro na API de tradução");
1004
+
1005
+ // Add to vector memory
1006
+ if (userProfile.preferences.memory.vectorEnabled) {
1007
+ await vectorMemory.addMemory(
1008
+ `Tradução: "${text}" para "${data.translatedText}"`,
1009
+ { type: "translation", source: "auto", target: targetLang }
1010
+ );
1011
+ }
1012
+
1013
+ return `Tradução:\nOriginal: ${text}\nTraduzido: ${data.translatedText}`;
1014
+ } catch (error) {
1015
+ console.error("Erro na API de tradução:", error);
1016
+ return `Não consegui traduzir o texto. ${error.message}`;
1017
+ }
1018
+ },
1019
+
1020
+ searchWikipedia: async (query) => {
1021
+ try {
1022
+ const response = await fetch(`https://pt.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=${encodeURIComponent(query)}&utf8=&origin=*`);
1023
+ const data = await response.json();
1024
+
1025
+ if (!data.query || data.query.search.length === 0) {
1026
+ return `Não encontrei informações sobre "${query}" na Wikipedia.`;
1027
+ }
1028
+
1029
+ const results = data.query.search.slice(0, 3);
1030
+ let responseText = `Aqui está o que encontrei sobre "${query}":\n\n`;
1031
+
1032
+ results.forEach(result => {
1033
+ responseText += `• ${result.title}\n`;
1034
+
1035
+ // Add to vector memory
1036
+ if (userProfile.preferences.memory.vectorEnabled) {
1037
+ vectorMemory.addMemory(
1038
+ `Informação da Wikipedia: ${result.title}`,
1039
+ { type: "wikipedia", query }
1040
+ );
1041
+ }
1042
+ });
1043
+
1044
+ responseText += `\nPosso buscar mais detalhes sobre algum desses tópicos.`;
1045
+
1046
+ return responseText;
1047
+ } catch (error) {
1048
+ console.error("Erro na Wikipedia API:", error);
1049
+ return `Não consegui acessar a Wikipedia. ${error.message}`;
1050
+ }
1051
+ },
1052
+
1053
+ getContextualResponse: async (message) => {
1054
+ if (!userProfile.preferences.memory.vectorEnabled) {
1055
+ return null;
1056
+ }
1057
+
1058
+ // Get similar memories
1059
+ const similarMemories = await vectorMemory.findSimilar(
1060
+ message,
1061
+ 3,
1062
+ userProfile.preferences.memory.similarityThreshold
1063
+ );
1064
+
1065
+ if (similarMemories.length === 0) {
1066
+ return null;
1067
+ }
1068
+
1069
+ // Build contextual response
1070
+ let response = "Com base no que lembro:\n\n";
1071
+
1072
+ similarMemories.forEach((memory, index) => {
1073
+ response += `${index + 1}. ${memory.text} (similaridade: ${Math.round(memory.similarity * 100)}%)\n`;
1074
+ });
1075
+
1076
+ return response;
1077
+ },
1078
+
1079
+ unknown: [
1080
+ "Não tenho informações sobre isso no meu banco de dados. Posso pesquisar quando você estiver online.",
1081
+ "Minha memória local não contém dados sobre esse assunto. Quer que eu anote para pesquisar depois?",
1082
+ "Isso está além do meu conhecimento atual. Posso aprender se você me explicar."
1083
+ ]
1084
+ };
1085
+
1086
+ document.addEventListener('DOMContentLoaded', function() {
1087
+ const voiceBtn = document.getElementById('voice-btn');
1088
+ const sendBtn = document.getElementById('send-btn');
1089
+ const messageInput = document.getElementById('message-input');
1090
+ const chatMessages = document.getElementById('chat-messages');
1091
+ const typingIndicator = document.createElement('div');
1092
+ typingIndicator.className = 'typing-indicator iris-message';
1093
+ typingIndicator.innerHTML = `
1094
+ <div class="flex items-center">
1095
+ <div class="w-6 h-6 rounded-full bg-pink-500 mr-2 flex items-center justify-center neon-border-pink">
1096
+ <i class="fas fa-robot text-xs"></i>
1097
+ </div>
1098
+ <div class="flex space-x-1">
1099
+ <span></span>
1100
+ <span></span>
1101
+ <span></span>
1102
+ </div>
1103
+ </div>
1104
+ `;
1105
+
1106
+ // Memory panel elements
1107
+ const memoryBtn = document.getElementById('memory-btn');
1108
+ const memoryPanel = document.getElementById('memory-panel');
1109
+ const closeMemory = document.getElementById('close-memory');
1110
+ const exportVectors = document.getElementById('export-vectors');
1111
+ const clearContext = document.getElementById('clear-context');
1112
+
1113
+ // Settings panel elements
1114
+ const settingsBtn = document.getElementById('settings-btn');
1115
+ const settingsPanel = document.getElementById('settings-panel');
1116
+ const closeSettings = document.getElementById('close-settings');
1117
+ const saveSettings = document.getElementById('save-settings');
1118
+
1119
+ // Voice level indicator
1120
+ const voiceLevel = document.getElementById('voice-level');
1121
+
1122
+ // API status indicators
1123
+ const apiStatusElements = {
1124
+ weather: document.getElementById('weather-api-status'),
1125
+ news: document.getElementById('news-api-status'),
1126
+ finance: document.getElementById('finance-api-status'),
1127
+ translate: document.getElementById('translate-api-status')
1128
+ };
1129
+
1130
+ // Initialize UI with user preferences
1131
+ updateMemoryUsage();
1132
+ updateSystemStats();
1133
+ checkAPIs();
1134
+
1135
+ // Initialize vector memory
1136
+ vectorMemory.init().then(() => {
1137
+ console.log("Vector memory initialized");
1138
+ updateMemoryPanel();
1139
+ });
1140
+
1141
+ // Memory panel handlers
1142
+ memoryBtn.addEventListener('click', () => {
1143
+ updateMemoryPanel();
1144
+ memoryPanel.classList.remove('hidden');
1145
+ });
1146
+
1147
+ closeMemory.addEventListener('click', () => {
1148
+ memoryPanel.classList.add('hidden');
1149
+ });
1150
+
1151
+ exportVectors.addEventListener('click', () => {
1152
+ const stats = vectorMemory.getMemoryStats();
1153
+ addIrisResponse(`Exportando ${stats.count} vetores de memória com similaridade média de ${Math.round(stats.avgSimilarity * 100)}%`);
1154
+ memoryPanel.classList.add('hidden');
1155
+ });
1156
+
1157
+ clearContext.addEventListener('click', () => {
1158
+ userProfile.context = [];
1159
+ updateMemoryPanel();
1160
+ addIrisResponse("Contexto atual limpo com sucesso.");
1161
+ });
1162
+
1163
+ // Settings panel handlers
1164
+ settingsBtn.addEventListener('click', () => {
1165
+ loadSettings();
1166
+ settingsPanel.classList.remove('hidden');
1167
+ });
1168
+
1169
+ closeSettings.addEventListener('click', () => {
1170
+ settingsPanel.classList.add('hidden');
1171
+ });
1172
+
1173
+ saveSettings.addEventListener('click', () => {
1174
+ saveUserPreferences();
1175
+ settingsPanel.classList.add('hidden');
1176
+ checkAPIs();
1177
+ });
1178
+
1179
+ // Similarity threshold slider
1180
+ document.getElementById('similarity-threshold').addEventListener('input', function() {
1181
+ document.getElementById('similarity-value').textContent = `${this.value}%`;
1182
+ });
1183
+
1184
+ // Voice button handler with realistic simulation
1185
+ voiceBtn.addEventListener('mousedown', async function() {
1186
+ this.classList.remove('glow-effect');
1187
+ this.classList.add('neon-border-pink', 'neon-text-pink');
1188
+ this.innerHTML = '<i class="fas fa-circle-notch fa-spin text-2xl"></i>';
1189
+
1190
+ // Simulate voice level detection
1191
+ const voiceSimulation = setInterval(() => {
1192
+ const level = Math.floor(Math.random() * 30) + 20;
1193
+ voiceLevel.style.width = `${level}%`;
1194
+ }, 100);
1195
+
1196
+ // Simulate listening for 1-3 seconds
1197
+ const listenTime = 1000 + Math.random() * 2000;
1198
+
1199
+ setTimeout(async () => {
1200
+ clearInterval(voiceSimulation);
1201
+ voiceLevel.style.width = '0%';
1202
+
1203
+ // Process voice command
1204
+ const commands = [
1205
+ "Previsão do tempo em São Paulo",
1206
+ "Notícias sobre tecnologia",
1207
+ "Cotação do dólar hoje",
1208
+ "Traduzir 'hello' para português",
1209
+ "Quais são as últimas notícias?",
1210
+ "Como está o clima no Rio de Janeiro?"
1211
+ ];
1212
+
1213
+ const randomCommand = commands[Math.floor(Math.random() * commands.length)];
1214
+ addUserMessage(randomCommand);
1215
+
1216
+ // Process with realistic delay
1217
+ setTimeout(async () => {
1218
+ await processUserMessage(randomCommand);
1219
+
1220
+ this.classList.add('glow-effect');
1221
+ this.classList.remove('neon-border-pink', 'neon-text-pink');
1222
+ this.innerHTML = '<i class="fas fa-microphone text-2xl"></i>';
1223
+ }, 500);
1224
+
1225
+ }, listenTime);
1226
+ });
1227
+
1228
+ // Send message handler
1229
+ sendBtn.addEventListener('click', sendMessage);
1230
+ messageInput.addEventListener('keypress', function(e) {
1231
+ if (e.key === 'Enter') {
1232
+ sendMessage();
1233
+ }
1234
+ });
1235
+
1236
+ // Quick actions
1237
+ document.querySelectorAll('.quick-action').forEach(button => {
1238
+ button.addEventListener('click', function() {
1239
+ const command = this.getAttribute('data-command');
1240
+ addUserMessage(command);
1241
+ processUserMessage(command);
1242
+ });
1243
+ });
1244
+
1245
+ // Volume slider
1246
+ document.getElementById('volume-slider').addEventListener('input', function() {
1247
+ document.getElementById('volume-value').textContent = `${this.value}%`;
1248
+ });
1249
+
1250
+ function sendMessage() {
1251
+ const message = messageInput.value.trim();
1252
+ if (message) {
1253
+ addUserMessage(message);
1254
+ processUserMessage(message);
1255
+ messageInput.value = '';
1256
+ }
1257
+ }
1258
+
1259
+ function addUserMessage(message) {
1260
+ const messageElement = document.createElement('div');
1261
+ messageElement.className = 'message-bubble user-message new-message';
1262
+ messageElement.innerHTML = `
1263
+ <div class="flex items-start">
1264
+ <div class="w-6 h-6 rounded-full bg-blue-500 mr-2 flex items-center justify-center neon-border-blue">
1265
+ <i class="fas fa-user text-xs"></i>
1266
+ </div>
1267
+ <p>${message}</p>
1268
+ </div>
1269
+ `;
1270
+ chatMessages.appendChild(messageElement);
1271
+ chatMessages.scrollTop = chatMessages.scrollHeight;
1272
+
1273
+ // Add to context
1274
+ userProfile.context.push({
1275
+ role: "user",
1276
+ content: message,
1277
+ timestamp: new Date().toISOString()
1278
+ });
1279
+
1280
+ // Keep only the most recent context
1281
+ if (userProfile.context.length > userProfile.preferences.memory.contextLimit) {
1282
+ userProfile.context.shift();
1283
+ }
1284
+
1285
+ // Add to history
1286
+ if (userProfile.preferences.privacy.storeHistory) {
1287
+ userProfile.history.push({
1288
+ date: new Date().toLocaleString('pt-BR'),
1289
+ message: message
1290
+ });
1291
+
1292
+ // Keep only last 50 messages
1293
+ if (userProfile.history.length > 50) {
1294
+ userProfile.history.shift();
1295
+ }
1296
+ }
1297
+
1298
+ // Update memory usage
1299
+ updateMemoryUsage();
1300
+ }
1301
+
1302
+ async function processUserMessage(message) {
1303
+ // Show typing indicator
1304
+ chatMessages.appendChild(typingIndicator);
1305
+ chatMessages.scrollTop = chatMessages.scrollHeight;
1306
+
1307
+ // Measure response time
1308
+ const startTime = performance.now();
1309
+
1310
+ // Process after random delay to simulate thinking
1311
+ setTimeout(async () => {
1312
+ chatMessages.removeChild(typingIndicator);
1313
+
1314
+ let response = "";
1315
+ const lowerMsg = message.toLowerCase();
1316
+
1317
+ // First check for contextual response
1318
+ if (userProfile.preferences.memory.vectorEnabled) {
1319
+ const contextualResponse = await knowledgeBase.getContextualResponse(message);
1320
+ if (contextualResponse) {
1321
+ response = contextualResponse + "\n\n";
1322
+ }
1323
+ }
1324
+
1325
+ // Enhanced NLP processing with API integration
1326
+ if (/oi|olá|ola|eae|bom dia|boa tarde|boa noite/.test(lowerMsg)) {
1327
+ response += knowledgeBase.greetings[Math.floor(Math.random() * knowledgeBase.greetings.length)];
1328
+ }
1329
+ else if (/hora|horas|relógio/.test(lowerMsg)) {
1330
+ response += knowledgeBase.getTime();
1331
+ }
1332
+ else if (/data|dia|hoje|calendário/.test(lowerMsg)) {
1333
+ response += knowledgeBase.getDate();
1334
+ }
1335
+ else if (/tempo|clima|previsão/.test(lowerMsg)) {
1336
+ const locationMatch = message.match(/em (.+)/i);
1337
+ response += await knowledgeBase.getWeather(locationMatch ? locationMatch[1] : userProfile.location.city);
1338
+ }
1339
+ else if (/notícia|noticia|novidade|notícias|noticias/.test(lowerMsg)) {
1340
+ const topicMatch = message.match(/sobre (.+)/i);
1341
+ response += await knowledgeBase.getNews(topicMatch ? topicMatch[1] : "tecnologia");
1342
+ }
1343
+ else if (/dólar|dolar|euro|moeda|finança|financa|cotação|cotacao/.test(lowerMsg)) {
1344
+ response += await knowledgeBase.getFinance();
1345
+ }
1346
+ else if (/traduzir|tradução|traducao|inglês|ingles|português|portugues/.test(lowerMsg)) {
1347
+ const textMatch = message.match(/traduzir ['"](.+)['"]/i) ||
1348
+ message.match(/traduzir (.+) para/i);
1349
+ if (textMatch) {
1350
+ const langMatch = message.match(/para (.+)/i);
1351
+ const targetLang = langMatch ?
1352
+ (langMatch[1].includes("português") ? "pt" : "en") :
1353
+ "pt";
1354
+ response += await knowledgeBase.translateText(textMatch[1], targetLang);
1355
+ } else {
1356
+ response += "Por favor, especifique o texto a ser traduzido. Exemplo: \"Traduzir 'hello' para português\"";
1357
+ }
1358
+ }
1359
+ else if (/wikipedia|wiki|pesquisar|buscar|sobre/.test(lowerMsg)) {
1360
+ const queryMatch = message.match(/sobre (.+)/i) ||
1361
+ message.match(/pesquisar (.+)/i) ||
1362
+ message.match(/buscar (.+)/i);
1363
+ if (queryMatch) {
1364
+ response += await knowledgeBase.searchWikipedia(queryMatch[1]);
1365
+ } else {
1366
+ response += "Sobre o que você gostaria que eu pesquisasse na Wikipedia?";
1367
+ }
1368
+ }
1369
+ else {
1370
+ response += knowledgeBase.unknown[Math.floor(Math.random() * knowledgeBase.unknown.length)];
1371
+ }
1372
+
1373
+ // Add to context
1374
+ userProfile.context.push({
1375
+ role: "assistant",
1376
+ content: response,
1377
+ timestamp: new Date().toISOString()
1378
+ });
1379
+
1380
+ // Count API request
1381
+ if (lowerMsg.includes("tempo") || lowerMsg.includes("notícia") ||
1382
+ lowerMsg.includes("dólar") || lowerMsg.includes("traduzir") ||
1383
+ lowerMsg.includes("pesquisar") || lowerMsg.includes("wiki")) {
1384
+ userProfile.apiRequests++;
1385
+ document.getElementById('api-requests').textContent = userProfile.apiRequests;
1386
+ }
1387
+
1388
+ addIrisResponse(response);
1389
+
1390
+ // Update response time in footer
1391
+ const endTime = performance.now();
1392
+ const responseTime = ((endTime - startTime) / 1000).toFixed(1);
1393
+ document.getElementById('response-time').textContent = responseTime;
1394
+
1395
+ // Update memory panel
1396
+ updateMemoryPanel();
1397
+
1398
+ }, 800 + Math.random() * 1200);
1399
+ }
1400
+
1401
+ function addIrisResponse(response) {
1402
+ const messageElement = document.createElement('div');
1403
+ messageElement.className = 'message-bubble iris-message new-message';
1404
+ messageElement.innerHTML = `
1405
+ <div class="flex items-start">
1406
+ <div class="w-6 h-6 rounded-full bg-pink-500 mr-2 flex items-center justify-center neon-border-pink">
1407
+ <i class="fas fa-robot text-xs"></i>
1408
+ </div>
1409
+ <p>${response.replace(/\n/g, '<br>')}</p>
1410
+ </div>
1411
+ `;
1412
+ chatMessages.appendChild(messageElement);
1413
+ chatMessages.scrollTop = chatMessages.scrollHeight;
1414
+
1415
+ // Simulate voice output if enabled
1416
+ if (userProfile.preferences.voice.active) {
1417
+ speakResponse(response);
1418
+ }
1419
+ }
1420
+
1421
+ function speakResponse(text) {
1422
+ // Clean text from HTML tags and special formatting
1423
+ const cleanText = text.replace(/<[^>]*>/g, '').replace(/\([^)]*\)/g, '');
1424
+
1425
+ if ('speechSynthesis' in window) {
1426
+ // Cancel any ongoing speech
1427
+ window.speechSynthesis.cancel();
1428
+
1429
+ const utterance = new SpeechSynthesisUtterance();
1430
+ utterance.text = cleanText;
1431
+ utterance.lang = 'pt-BR';
1432
+ utterance.rate = userProfile.preferences.voice.speed;
1433
+ utterance.volume = userProfile.preferences.voice.volume / 100;
1434
+
1435
+ // Try to find a Brazilian Portuguese voice
1436
+ const voices = window.speechSynthesis.getVoices();
1437
+ const ptBrVoice = voices.find(v => v.lang === 'pt-BR') || voices.find(v => v.lang.startsWith('pt'));
1438
+
1439
+ if (ptBrVoice) {
1440
+ utterance.voice = ptBrVoice;
1441
+ }
1442
+
1443
+ window.speechSynthesis.speak(utterance);
1444
+ }
1445
+ }
1446
+
1447
+ function updateMemoryPanel() {
1448
+ // Update current context
1449
+ const contextContainer = document.getElementById('current-context');
1450
+ const recentContext = userProfile.context.slice(-5).reverse();
1451
+
1452
+ contextContainer.innerHTML = recentContext.length > 0
1453
+ ? recentContext.map(item =>
1454
+ `<div class="context-chip">
1455
+ <i class="fas fa-${item.role === 'user' ? 'user' : 'robot'}"></i>
1456
+ ${item.content.substring(0, 20)}${item.content.length > 20 ? '...' : ''}
1457
+ </div>`
1458
+ ).join('')
1459
+ : '<p class="text-gray-400 text-sm">Nenhum contexto recente</p>';
1460
+
1461
+ // Update knowledge graph (simplified for demo)
1462
+ const knowledgeContainer = document.getElementById('knowledge-graph');
1463
+ const memoryStats = vectorMemory.getMemoryStats();
1464
+
1465
+ // Show some sample knowledge nodes (in a real app would show actual vectors)
1466
+ const sampleNodes = [
1467
+ { text: "Clima em SP", icon: "fa-cloud-sun" },
1468
+ { text: "Notícias tech", icon: "fa-newspaper" },
1469
+ { text: "Cotações", icon: "fa-dollar-sign" },
1470
+ { text: "Traduções", icon: "fa-language" },
1471
+ { text: "Wikipedia", icon: "fa-book" }
1472
+ ];
1473
+
1474
+ knowledgeContainer.innerHTML = sampleNodes.map(node =>
1475
+ `<div class="knowledge-node">
1476
+ <i class="fas ${node.icon}"></i>
1477
+ ${node.text}
1478
+ <span class="vector-score">${Math.floor(Math.random() * 30) + 70}%</span>
1479
+ </div>`
1480
+ ).join('');
1481
+
1482
+ // Update system stats
1483
+ document.getElementById('vector-count').textContent = memoryStats.count;
1484
+ document.getElementById('avg-similarity').textContent = `${Math.round(memoryStats.avgSimilarity * 100)}%`;
1485
+ document.getElementById('api-requests').textContent = userProfile.apiRequests;
1486
+ }
1487
+
1488
+ function updateMemoryUsage() {
1489
+ // Simulate memory usage based on history size
1490
+ const baseUsage = 40;
1491
+ const historyFactor = Math.min(userProfile.history.length / 50 * 30, 30);
1492
+ const apiFactor = Math.min(userProfile.apiRequests / 20 * 20, 20);
1493
+ const vectorFactor = vectorMemory.vectors.length / 100 * 10;
1494
+ const randomFactor = Math.floor(Math.random() * 10);
1495
+
1496
+ const totalUsage = Math.min(baseUsage + historyFactor + apiFactor + vectorFactor + randomFactor, 95);
1497
+ document.getElementById('memory-usage').textContent = Math.floor(totalUsage);
1498
+ }
1499
+
1500
+ function updateSystemStats() {
1501
+ // Simulate connection status
1502
+ const isOnline = Math.random() > 0.1; // 90% chance of being online
1503
+ document.getElementById('connection-status').textContent = isOnline ? 'CONECTADO' : 'OFFLINE';
1504
+ document.getElementById('connection-status').className = isOnline
1505
+ ? 'text-green-400'
1506
+ : 'text-red-400';
1507
+
1508
+ // Update every 30 seconds
1509
+ setTimeout(updateSystemStats, 30000);
1510
+ }
1511
+
1512
+ async function checkAPIs() {
1513
+ // Check weather API
1514
+ try {
1515
+ const response = await fetch(`${API_ENDPOINTS.weather}?latitude=0&longitude=0`);
1516
+ apiStatusElements.weather.className = response.ok ?
1517
+ 'api-status api-active' : 'api-status api-inactive';
1518
+ } catch {
1519
+ apiStatusElements.weather.className = 'api-status api-inactive';
1520
+ }
1521
+
1522
+ // Check news API (simulated)
1523
+ apiStatusElements.news.className = userProfile.preferences.apis.news ?
1524
+ 'api-status api-active' : 'api-status api-inactive';
1525
+
1526
+ // Check finance API
1527
+ try {
1528
+ const response = await fetch(API_ENDPOINTS.finance);
1529
+ apiStatusElements.finance.className = response.ok ?
1530
+ 'api-status api-active' : 'api-status api-inactive';
1531
+ } catch {
1532
+ apiStatusElements.finance.className = 'api-status api-inactive';
1533
+ }
1534
+
1535
+ // Check translate API
1536
+ try {
1537
+ const response = await fetch(API_ENDPOINTS.translate);
1538
+ apiStatusElements.translate.className = response.ok ?
1539
+ 'api-status api-active' : 'api-status api-inactive';
1540
+ } catch {
1541
+ apiStatusElements.translate.className = 'api-status api-inactive';
1542
+ }
1543
+ }
1544
+
1545
+ function loadSettings() {
1546
+ // Voice settings
1547
+ document.getElementById('voice-toggle').checked = userProfile.preferences.voice.active;
1548
+ document.getElementById('volume-slider').value = userProfile.preferences.voice.volume;
1549
+ document.getElementById('volume-value').textContent = `${userProfile.preferences.voice.volume}%`;
1550
+ document.getElementById('voice-speed').value = userProfile.preferences.voice.speed;
1551
+
1552
+ // Memory settings
1553
+ document.getElementById('vector-memory-toggle').checked = userProfile.preferences.memory.vectorEnabled;
1554
+ document.getElementById('context-limit').value = userProfile.preferences.memory.contextLimit;
1555
+ document.getElementById('similarity-threshold').value = userProfile.preferences.memory.similarityThreshold * 100;
1556
+ document.getElementById('similarity-value').textContent = `${userProfile.preferences.memory.similarityThreshold * 100}%`;
1557
+
1558
+ // API settings
1559
+ document.getElementById('weather-api-toggle').checked = userProfile.preferences.apis.weather;
1560
+ document.getElementById('news-api-toggle').checked = userProfile.preferences.apis.news;
1561
+ document.getElementById('finance-api-toggle').checked = userProfile.preferences.apis.finance;
1562
+ document.getElementById('translate-api-toggle').checked = userProfile.preferences.apis.translate;
1563
+
1564
+ // Privacy settings
1565
+ document.getElementById('store-history-toggle').checked = userProfile.preferences.privacy.storeHistory;
1566
+ document.getElementById('share-data-toggle').checked = userProfile.preferences.privacy.shareData;
1567
+ }
1568
+
1569
+ function saveUserPreferences() {
1570
+ // Voice settings
1571
+ userProfile.preferences.voice.active = document.getElementById('voice-toggle').checked;
1572
+ userProfile.preferences.voice.volume = parseInt(document.getElementById('volume-slider').value);
1573
+ userProfile.preferences.voice.speed = parseFloat(document.getElementById('voice-speed').value);
1574
+
1575
+ // Memory settings
1576
+ userProfile.preferences.memory.vectorEnabled = document.getElementById('vector-memory-toggle').checked;
1577
+ userProfile.preferences.memory.contextLimit = parseInt(document.getElementById('context-limit').value);
1578
+ userProfile.preferences.memory.similarityThreshold = parseInt(document.getElementById('similarity-threshold').value) / 100;
1579
+
1580
+ // API settings
1581
+ userProfile.preferences.apis.weather = document.getElementById('weather-api-toggle').checked;
1582
+ userProfile.preferences.apis.news = document.getElementById('news-api-toggle').checked;
1583
+ userProfile.preferences.apis.finance = document.getElementById('finance-api-toggle').checked;
1584
+ userProfile.preferences.apis.translate = document.getElementById('translate-api-toggle').checked;
1585
+
1586
+ // Privacy settings
1587
+ userProfile.preferences.privacy.storeHistory = document.getElementById('store-history-toggle').checked;
1588
+ userProfile.preferences.privacy.shareData = document.getElementById('share-data-toggle').checked;
1589
+
1590
+ // Show confirmation
1591
+ addIrisResponse("Configurações atualizadas com sucesso!");
1592
+ }
1593
+
1594
+ // Initialize speech synthesis voices
1595
+ if ('speechSynthesis' in window) {
1596
+ speechSynthesis.onvoiceschanged = function() {
1597
+ const voices = speechSynthesis.getVoices();
1598
+ console.log('Voices loaded:', voices);
1599
+ };
1600
+
1601
+ // Chrome needs this to load voices
1602
+ if (speechSynthesis.getVoices().length === 0) {
1603
+ speechSynthesis.addEventListener('voiceschanged', function() {
1604
+ const voices = speechSynthesis.getVoices();
1605
+ console.log('Voices loaded:', voices);
1606
+ });
1607
+ }
1608
+ }
1609
+
1610
+ // Add initial learning message after 5 seconds
1611
+ setTimeout(() => {
1612
+ addIrisResponse("Estou conectada a várias APIs gratuitas e possuo memória vetorial para lembrar do contexto da nossa conversa. Experimente perguntar sobre diversos assuntos!");
1613
+ }, 5000);
1614
+ });
1615
+ </script>
1616
+ <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=Caiobriaego/iriis-py" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1617
+ </html>