amauricunha commited on
Commit
b442dad
·
verified ·
1 Parent(s): 227440d

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +114 -11
index.html CHANGED
@@ -15,7 +15,7 @@
15
  .btn-primary:hover:not(:disabled) { background-color: #4338ca; }
16
  .spinner { border: 2px solid rgba(255,255,255,0.3); width: 20px; height: 20px; border-radius: 50%; border-left-color: #fff; animation: spin 1s ease infinite; }
17
  @keyframes spin { to { transform: rotate(360deg); } }
18
- .flashcard-container { perspective: 1000px; position: relative; } /* Posição relativa para o botão de excluir */
19
  .flashcard-inner { position: relative; width: 100%; transition: transform 0.6s; transform-style: preserve-3d; }
20
  .flashcard-container.flipped .flashcard-inner { transform: rotateY(180deg); }
21
  .flashcard-front, .flashcard-back { position: absolute; width: 100%; height:100%; backface-visibility: hidden; border: 1px solid #e5e7eb; border-radius: 12px; padding: 20px; display: flex; flex-direction: column; justify-content: space-between; }
@@ -84,6 +84,30 @@
84
  <p class="text-gray-500 italic">Sua imagem aparecerá aqui.</p>
85
  </div>
86
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  <div class="card">
89
  <h2 class="text-xl font-semibold mb-4 text-gray-700">Configurações de IA</h2>
@@ -92,13 +116,13 @@
92
  <label for="modelSelector" class="block text-sm font-medium text-gray-700">Modelo de IA (Flashcards)</label>
93
  <select id="modelSelector" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 rounded-md shadow-sm">
94
  <optgroup label="Google Gemini">
95
- <option value="gemini:gemini-1.5-flash-latest">Gemini 1.5 Flash (Rápido)</option>
96
- <option value="gemini:gemini-1.5-pro-latest">Gemini 1.5 Pro (Avançado)</option>
97
  </optgroup>
98
  <optgroup label="Groq (Ultra Rápido)">
99
  <option value="groq:llama-3.1-8b-instant">Llama 3.1 8B</option>
100
- <option value="groq:mixtral-8x7b-32768">Mixtral 8x7b (Balanceado)</option>
101
- <option value="groq:gemma-7b-it">Gemma 7B (Confiável)</option>
102
  </optgroup>
103
  </select>
104
  </div>
@@ -146,6 +170,10 @@
146
  const imagePromptInput = document.getElementById('imagePromptInput');
147
  const generateImageBtn = document.getElementById('generateImageBtn');
148
  const imageResultContainer = document.getElementById('imageResultContainer');
 
 
 
 
149
 
150
  let chatHistory = [];
151
  let recognition;
@@ -156,6 +184,7 @@
156
  const len = textEditor.innerText.length;
157
  charCount.textContent = `${len}/10000`;
158
  playButton.disabled = len === 0;
 
159
  });
160
  textEditor.addEventListener('mouseup', () => {
161
  createCardButton.disabled = !window.getSelection().toString().trim();
@@ -320,6 +349,84 @@
320
  generateImageBtn.textContent = 'Gerar';
321
  }
322
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
  // --- LÓGICA DE GERAÇÃO DE FLASHCARD ---
325
  async function createFlashcard(word, context, definition = null) {
@@ -408,27 +515,23 @@
408
 
409
  flashcardList.prepend(container);
410
  container.addEventListener('click', (e) => {
411
- // Evita virar o card se um botão dentro dele for clicado
412
  if(e.target.tagName !== 'BUTTON' && !e.target.closest('button')) {
413
  container.classList.toggle('flipped');
414
  }
415
  });
416
  }
417
 
418
- // --- NOVA FUNÇÃO PARA EXCLUIR FLASHCARD ---
419
  function deleteFlashcard(cardId, event) {
420
- event.stopPropagation(); // Impede que o evento de clique se propague para o card (evitando que ele vire)
421
  const cardToDelete = document.getElementById(cardId);
422
  if (cardToDelete) {
423
  cardToDelete.remove();
424
  }
425
- // Mostra a mensagem de "sem cards" se a lista ficar vazia
426
- if (flashcardList.children.length === 1) { // Apenas a mensagem <p> restará
427
  noCardsMessage.classList.remove('hidden');
428
  }
429
  }
430
 
431
- // --- LÓGICA DE PRÁTICA DE PRONÚNCIA ---
432
  async function handlePronunciationPractice(button, targetText, event) {
433
  event.stopPropagation();
434
  const feedbackArea = button.closest('.flashcard-back').querySelector('[data-feedback-area]');
 
15
  .btn-primary:hover:not(:disabled) { background-color: #4338ca; }
16
  .spinner { border: 2px solid rgba(255,255,255,0.3); width: 20px; height: 20px; border-radius: 50%; border-left-color: #fff; animation: spin 1s ease infinite; }
17
  @keyframes spin { to { transform: rotate(360deg); } }
18
+ .flashcard-container { perspective: 1000px; position: relative; }
19
  .flashcard-inner { position: relative; width: 100%; transition: transform 0.6s; transform-style: preserve-3d; }
20
  .flashcard-container.flipped .flashcard-inner { transform: rotateY(180deg); }
21
  .flashcard-front, .flashcard-back { position: absolute; width: 100%; height:100%; backface-visibility: hidden; border: 1px solid #e5e7eb; border-radius: 12px; padding: 20px; display: flex; flex-direction: column; justify-content: space-between; }
 
84
  <p class="text-gray-500 italic">Sua imagem aparecerá aqui.</p>
85
  </div>
86
  </div>
87
+
88
+ <div class="card">
89
+ <h2 class="text-xl font-semibold mb-4 text-gray-700">5. Atividades de Escrita e Tradução</h2>
90
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
91
+ <div>
92
+ <label for="activityTypeSelector" class="block text-sm font-medium text-gray-700">Tipo de Atividade</label>
93
+ <select id="activityTypeSelector" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 rounded-md shadow-sm">
94
+ <option value="translation_pt_en">Tradução (PT para EN)</option>
95
+ <option value="email_writing">Escrever E-mail Formal</option>
96
+ <option value="summary_writing">Resumir o Texto</option>
97
+ </select>
98
+ </div>
99
+ <div class="flex items-end">
100
+ <button id="generateActivityButton" onclick="generateActivity()" class="btn btn-primary w-full">Gerar Atividade</button>
101
+ </div>
102
+ </div>
103
+ <div class="mt-4 border-t pt-4">
104
+ <button id="translateFullTextButton" onclick="translateFullText()" class="btn btn-primary bg-gray-500 hover:bg-gray-600 w-full" disabled>Traduzir Texto Completo para PT</button>
105
+ </div>
106
+ <div id="activityOutput" class="mt-4 p-4 border rounded-lg bg-gray-50 min-h-[100px] whitespace-pre-wrap">
107
+ <p class="text-gray-500 italic">Seu exercício aparecerá aqui.</p>
108
+ </div>
109
+ </div>
110
+
111
 
112
  <div class="card">
113
  <h2 class="text-xl font-semibold mb-4 text-gray-700">Configurações de IA</h2>
 
116
  <label for="modelSelector" class="block text-sm font-medium text-gray-700">Modelo de IA (Flashcards)</label>
117
  <select id="modelSelector" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 rounded-md shadow-sm">
118
  <optgroup label="Google Gemini">
119
+ <option value="gemini:gemini-1.5-flash-latest">Gemini 2.5 Flash</option>
120
+ <option value="gemini:gemini-1.5-pro-latest">Gemini 2.5 Pro</option>
121
  </optgroup>
122
  <optgroup label="Groq (Ultra Rápido)">
123
  <option value="groq:llama-3.1-8b-instant">Llama 3.1 8B</option>
124
+ <option value="groq:llama-3.1-70b-versatile">Llama 3.1 70B</option>
125
+ <option value="groq:openai/gpt-oss-120b">OpenAI GPT-OSS 120B</option>
126
  </optgroup>
127
  </select>
128
  </div>
 
170
  const imagePromptInput = document.getElementById('imagePromptInput');
171
  const generateImageBtn = document.getElementById('generateImageBtn');
172
  const imageResultContainer = document.getElementById('imageResultContainer');
173
+ const activityTypeSelector = document.getElementById('activityTypeSelector');
174
+ const generateActivityButton = document.getElementById('generateActivityButton');
175
+ const activityOutput = document.getElementById('activityOutput');
176
+ const translateFullTextButton = document.getElementById('translateFullTextButton');
177
 
178
  let chatHistory = [];
179
  let recognition;
 
184
  const len = textEditor.innerText.length;
185
  charCount.textContent = `${len}/10000`;
186
  playButton.disabled = len === 0;
187
+ translateFullTextButton.disabled = len === 0;
188
  });
189
  textEditor.addEventListener('mouseup', () => {
190
  createCardButton.disabled = !window.getSelection().toString().trim();
 
349
  generateImageBtn.textContent = 'Gerar';
350
  }
351
  }
352
+
353
+ // --- LÓGICA DE ATIVIDADES DE ESCRITA E TRADUÇÃO ---
354
+ async function generateActivity() {
355
+ const activityType = activityTypeSelector.value;
356
+ const context = contextSelector.value;
357
+ const sourceText = textEditor.innerText;
358
+
359
+ generateActivityButton.disabled = true;
360
+ generateActivityButton.innerHTML = '<div class="spinner mr-2"></div> Gerando...';
361
+ activityOutput.innerHTML = '<p class="text-gray-500 italic">Gerando seu exercício...</p>';
362
+
363
+ let prompt = "";
364
+ if (activityType === 'translation_pt_en') {
365
+ prompt = `Baseado no contexto '${context}', crie uma frase em português para eu traduzir para o inglês.`;
366
+ } else if (activityType === 'email_writing') {
367
+ prompt = `Crie um cenário para eu escrever um e-mail formal, relacionado ao contexto '${context}'.`;
368
+ } else if (activityType === 'summary_writing') {
369
+ if (!sourceText) {
370
+ alert("Por favor, cole um texto no editor para gerar a atividade de resumo.");
371
+ activityOutput.innerHTML = '<p class="text-red-500">Cole um texto acima primeiro.</p>';
372
+ generateActivityButton.disabled = false;
373
+ generateActivityButton.textContent = 'Gerar Atividade';
374
+ return;
375
+ }
376
+ prompt = `Resuma o seguinte texto em uma frase: "${sourceText}"`;
377
+ }
378
+
379
+ try {
380
+ const response = await fetch('/explain-proxy', {
381
+ method: 'POST',
382
+ headers: { 'Content-Type': 'application/json' },
383
+ body: JSON.stringify({
384
+ model: modelSelector.value,
385
+ context_focus: context,
386
+ custom_prompt: prompt
387
+ })
388
+ });
389
+ if (!response.ok) throw new Error((await response.json()).error);
390
+ const data = await response.json();
391
+ activityOutput.textContent = data.explanation;
392
+ } catch (error) {
393
+ activityOutput.innerHTML = `<p class="text-red-600 font-semibold">Falha ao gerar atividade: ${error.message}</p>`;
394
+ } finally {
395
+ generateActivityButton.disabled = false;
396
+ generateActivityButton.textContent = 'Gerar Atividade';
397
+ }
398
+ }
399
+
400
+ async function translateFullText() {
401
+ const text = textEditor.innerText;
402
+ if (!text) return;
403
+
404
+ translateFullTextButton.disabled = true;
405
+ translateFullTextButton.innerHTML = '<div class="spinner mr-2"></div> Traduzindo...';
406
+
407
+ const prompt = `Traduza o seguinte texto para o português de forma clara e natural: "${text}"`;
408
+
409
+ try {
410
+ const response = await fetch('/explain-proxy', {
411
+ method: 'POST',
412
+ headers: { 'Content-Type': 'application/json' },
413
+ body: JSON.stringify({
414
+ model: modelSelector.value,
415
+ context_focus: contextSelector.value,
416
+ custom_prompt: prompt
417
+ })
418
+ });
419
+ if (!response.ok) throw new Error((await response.json()).error);
420
+ const data = await response.json();
421
+ alert("Tradução Completa:\n\n" + data.explanation);
422
+ } catch (error) {
423
+ alert(`Falha na tradução: ${error.message}`);
424
+ } finally {
425
+ translateFullTextButton.disabled = false;
426
+ translateFullTextButton.textContent = 'Traduzir Texto Completo para PT';
427
+ }
428
+ }
429
+
430
 
431
  // --- LÓGICA DE GERAÇÃO DE FLASHCARD ---
432
  async function createFlashcard(word, context, definition = null) {
 
515
 
516
  flashcardList.prepend(container);
517
  container.addEventListener('click', (e) => {
 
518
  if(e.target.tagName !== 'BUTTON' && !e.target.closest('button')) {
519
  container.classList.toggle('flipped');
520
  }
521
  });
522
  }
523
 
 
524
  function deleteFlashcard(cardId, event) {
525
+ event.stopPropagation();
526
  const cardToDelete = document.getElementById(cardId);
527
  if (cardToDelete) {
528
  cardToDelete.remove();
529
  }
530
+ if (flashcardList.children.length === 1) {
 
531
  noCardsMessage.classList.remove('hidden');
532
  }
533
  }
534
 
 
535
  async function handlePronunciationPractice(button, targetText, event) {
536
  event.stopPropagation();
537
  const feedbackArea = button.closest('.flashcard-back').querySelector('[data-feedback-area]');