KEXEL commited on
Commit
079552f
·
verified ·
1 Parent(s): f66a529
Files changed (1) hide show
  1. index.html +315 -19
index.html CHANGED
@@ -1,19 +1,315 @@
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
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Chat com Gemini AI</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ .chat-message.user {
12
+ background-color: #3b82f6;
13
+ color: white;
14
+ border-radius: 18px 18px 0 18px;
15
+ }
16
+
17
+ .chat-message.ai {
18
+ background-color: #f3f4f6;
19
+ color: #1f2937;
20
+ border-radius: 18px 18px 18px 0;
21
+ }
22
+
23
+ .typing-indicator span {
24
+ display: inline-block;
25
+ width: 8px;
26
+ height: 8px;
27
+ border-radius: 50%;
28
+ background-color: #9ca3af;
29
+ margin: 0 2px;
30
+ animation: bounce 1.5s infinite ease-in-out;
31
+ }
32
+
33
+ .typing-indicator span:nth-child(2) {
34
+ animation-delay: 0.2s;
35
+ }
36
+
37
+ .typing-indicator span:nth-child(3) {
38
+ animation-delay: 0.4s;
39
+ }
40
+
41
+ @keyframes bounce {
42
+
43
+ 0%,
44
+ 100% {
45
+ transform: translateY(0);
46
+ }
47
+
48
+ 50% {
49
+ transform: translateY(-5px);
50
+ }
51
+ }
52
+
53
+ #chat-container {
54
+ height: calc(100vh - 140px);
55
+ }
56
+
57
+ @media (max-width: 640px) {
58
+ #chat-container {
59
+ height: calc(100vh - 120px);
60
+ }
61
+ }
62
+ </style>
63
+ </head>
64
+
65
+ <body class="bg-gray-100 font-sans">
66
+ <div class="container mx-auto max-w-4xl px-4 py-6">
67
+ <!-- Cabeçalho -->
68
+ <header class="flex items-center justify-between mb-6">
69
+ <div class="flex items-center space-x-3">
70
+ <div
71
+ class="w-10 h-10 rounded-full bg-gradient-to-r from-blue-500 to-purple-600 flex items-center justify-center">
72
+ <i class="fas fa-robot text-white"></i>
73
+ </div>
74
+ <h1 class="text-2xl font-bold text-gray-800">Chat com Gemini AI</h1>
75
+ </div>
76
+ <div class="relative">
77
+ <button id="api-key-btn"
78
+ class="px-4 py-2 bg-white border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition">
79
+ <i class="fas fa-key mr-2"></i>Chave API
80
+ </button>
81
+ <div id="api-key-modal"
82
+ class="hidden absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-xl z-10 p-4 border border-gray-200">
83
+ <h3 class="font-medium text-gray-900 mb-2">Insira sua Chave da API Gemini</h3>
84
+ <input type="password" id="api-key-input" placeholder="Sua chave API"
85
+ class="w-full px-3 py-2 border border-gray-300 rounded-md mb-3">
86
+ <div class="flex justify-end space-x-2">
87
+ <button id="cancel-api-key"
88
+ class="px-3 py-1 text-gray-600 hover:text-gray-800">Cancelar</button>
89
+ <button id="save-api-key"
90
+ class="px-3 py-1 bg-blue-600 text-white rounded-md hover:bg-blue-700">Salvar</button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </header>
95
+
96
+ <!-- Container do Chat -->
97
+ <div id="chat-container" class="bg-white rounded-xl shadow-md overflow-hidden flex flex-col">
98
+ <!-- Mensagens -->
99
+ <div id="chat-messages" class="flex-1 overflow-y-auto p-4 space-y-4">
100
+ <div class="chat-message ai max-w-[80%] p-4">
101
+ <div class="font-medium flex items-center mb-1">
102
+ <div
103
+ class="w-6 h-6 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 flex items-center justify-center mr-2">
104
+ <i class="fas fa-robot text-white text-xs"></i>
105
+ </div>
106
+ <span>Gemini AI</span>
107
+ </div>
108
+ <p>Olá! Eu sou o Gemini, seu assistente de IA. Como posso te ajudar hoje?</p>
109
+ </div>
110
+ </div>
111
+
112
+ <!-- Área de Entrada -->
113
+ <div class="border-t border-gray-200 p-4 bg-gray-50">
114
+ <form id="message-form" class="flex space-x-2">
115
+ <input type="text" id="message-input" placeholder="Digite sua mensagem..."
116
+ class="flex-1 px-4 py-3 border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
117
+ autocomplete="off">
118
+ <button type="submit"
119
+ class="w-12 h-12 rounded-full bg-blue-600 text-white flex items-center justify-center hover:bg-blue-700 transition">
120
+ <i class="fas fa-paper-plane"></i>
121
+ </button>
122
+ </form>
123
+ <div class="text-xs text-gray-500 mt-2 px-2">
124
+ O Gemini pode exibir informações imprecisas, inclusive sobre pessoas, então verifique suas
125
+ respostas.
126
+ </div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+
131
+ <script>
132
+ document.addEventListener('DOMContentLoaded', function () {
133
+ // Elementos DOM
134
+ const chatMessages = document.getElementById('chat-messages');
135
+ const messageForm = document.getElementById('message-form');
136
+ const messageInput = document.getElementById('message-input');
137
+ const apiKeyBtn = document.getElementById('api-key-btn');
138
+ const apiKeyModal = document.getElementById('api-key-modal');
139
+ const apiKeyInput = document.getElementById('api-key-input');
140
+ const saveApiKeyBtn = document.getElementById('save-api-key');
141
+ const cancelApiKeyBtn = document.getElementById('cancel-api-key');
142
+
143
+ // Estado
144
+ let apiKey = localStorage.getItem('gemini-api-key') || '';
145
+ let isWaitingForResponse = false;
146
+
147
+ // Inicialização
148
+ if (apiKey) {
149
+ apiKeyInput.value = apiKey;
150
+ }
151
+
152
+ // Event Listeners
153
+ apiKeyBtn.addEventListener('click', toggleApiKeyModal);
154
+ saveApiKeyBtn.addEventListener('click', saveApiKey);
155
+ cancelApiKeyBtn.addEventListener('click', toggleApiKeyModal);
156
+ messageForm.addEventListener('submit', handleSubmit);
157
+
158
+ // Clicar fora do modal para fechar
159
+ document.addEventListener('click', function (e) {
160
+ if (!apiKeyModal.contains(e.target) && e.target !== apiKeyBtn) {
161
+ apiKeyModal.classList.add('hidden');
162
+ }
163
+ });
164
+
165
+ // Funções
166
+ function toggleApiKeyModal() {
167
+ apiKeyModal.classList.toggle('hidden');
168
+ }
169
+
170
+ function saveApiKey() {
171
+ apiKey = apiKeyInput.value.trim();
172
+ localStorage.setItem('gemini-api-key', apiKey);
173
+ toggleApiKeyModal();
174
+ addSystemMessage(apiKey ? 'Chave API salva com sucesso!' : 'Chave API removida.');
175
+ }
176
+
177
+ function addSystemMessage(text) {
178
+ const messageDiv = document.createElement('div');
179
+ messageDiv.className = 'text-center text-sm text-gray-500 my-2';
180
+ messageDiv.textContent = text;
181
+ chatMessages.appendChild(messageDiv);
182
+ scrollToBottom();
183
+ }
184
+
185
+ async function handleSubmit(e) {
186
+ e.preventDefault();
187
+
188
+ const message = messageInput.value.trim();
189
+ if (!message) return;
190
+
191
+ if (!apiKey) {
192
+ addSystemMessage('Por favor, configure sua chave da API Gemini primeiro.');
193
+ toggleApiKeyModal();
194
+ return;
195
+ }
196
+
197
+ if (isWaitingForResponse) {
198
+ addSystemMessage('Por favor, aguarde a resposta atual ser concluída.');
199
+ return;
200
+ }
201
+
202
+ // Adiciona mensagem do usuário
203
+ addMessage(message, 'user');
204
+ messageInput.value = '';
205
+
206
+ // Mostra indicador de digitação
207
+ showTypingIndicator();
208
+ isWaitingForResponse = true;
209
+
210
+ try {
211
+ const response = await fetchGeminiResponse(message);
212
+ removeTypingIndicator();
213
+ addMessage(response, 'ai');
214
+ } catch (error) {
215
+ removeTypingIndicator();
216
+ addSystemMessage(`Erro: ${error.message}`);
217
+ } finally {
218
+ isWaitingForResponse = false;
219
+ }
220
+ }
221
+
222
+ function addMessage(text, sender) {
223
+ const messageDiv = document.createElement('div');
224
+ messageDiv.className = `chat-message ${sender} max-w-[80%] p-4`;
225
+
226
+ const senderName = sender === 'user' ? 'Você' : 'Gemini AI';
227
+ const iconClass = sender === 'user' ? 'fas fa-user' : 'fas fa-robot';
228
+ const iconBg = sender === 'user'
229
+ ? 'bg-gradient-to-r from-blue-400 to-blue-600'
230
+ : 'bg-gradient-to-r from-purple-500 to-pink-500';
231
+
232
+ messageDiv.innerHTML = `
233
+ <div class="font-medium flex items-center mb-1">
234
+ <div class="w-6 h-6 rounded-full ${iconBg} flex items-center justify-center mr-2">
235
+ <i class="${iconClass} text-white text-xs"></i>
236
+ </div>
237
+ <span>${senderName}</span>
238
+ </div>
239
+ <p>${text}</p>
240
+ `;
241
+
242
+ chatMessages.appendChild(messageDiv);
243
+ scrollToBottom();
244
+ }
245
+
246
+ function showTypingIndicator() {
247
+ const typingDiv = document.createElement('div');
248
+ typingDiv.id = 'typing-indicator';
249
+ typingDiv.className = 'chat-message ai max-w-[80%] p-4';
250
+
251
+ typingDiv.innerHTML = `
252
+ <div class="font-medium flex items-center mb-1">
253
+ <div class="w-6 h-6 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 flex items-center justify-center mr-2">
254
+ <i class="fas fa-robot text-white text-xs"></i>
255
+ </div>
256
+ <span>Gemini AI</span>
257
+ </div>
258
+ <div class="typing-indicator">
259
+ <span></span>
260
+ <span></span>
261
+ <span></span>
262
+ </div>
263
+ `;
264
+
265
+ chatMessages.appendChild(typingDiv);
266
+ scrollToBottom();
267
+ }
268
+
269
+ function removeTypingIndicator() {
270
+ const typingIndicator = document.getElementById('typing-indicator');
271
+ if (typingIndicator) {
272
+ typingIndicator.remove();
273
+ }
274
+ }
275
+
276
+ function scrollToBottom() {
277
+ chatMessages.scrollTop = chatMessages.scrollHeight;
278
+ }
279
+
280
+ async function fetchGeminiResponse(prompt) {
281
+ if (!apiKey) {
282
+ throw new Error('Chave API não configurada');
283
+ }
284
+
285
+ const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${apiKey}`;
286
+
287
+ const requestBody = {
288
+ contents: [{
289
+ parts: [{
290
+ text: prompt
291
+ }]
292
+ }]
293
+ };
294
+
295
+ const response = await fetch(apiUrl, {
296
+ method: 'POST',
297
+ headers: {
298
+ 'Content-Type': 'application/json'
299
+ },
300
+ body: JSON.stringify(requestBody)
301
+ });
302
+
303
+ if (!response.ok) {
304
+ const errorData = await response.json();
305
+ throw new Error(errorData.error?.message || 'Falha ao obter resposta do Gemini');
306
+ }
307
+
308
+ const data = await response.json();
309
+ return data.candidates?.[0]?.content?.parts?.[0]?.text || "Desculpe, não consegui gerar uma resposta.";
310
+ }
311
+ });
312
+ </script>
313
+ </body>
314
+
315
+ </html>