salomonsky commited on
Commit
334e3ad
·
verified ·
1 Parent(s): d4bd867

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +39 -9
index.html CHANGED
@@ -713,7 +713,12 @@
713
  if (level3Slider) level3Slider.disabled = false;
714
 
715
  // Permitir sembrar también en modo anónimo (no se guardará en la nube)
716
- visualizeButton.addEventListener('click', handleAnalysisAndVisualization);
 
 
 
 
 
717
  if (isAnonymous) {
718
  console.log('Modo anónimo: podrás visualizar neuronas, pero no se guardarán en Firestore.');
719
  topicInput.placeholder = 'Ingresa un tema para sembrar (modo anónimo)';
@@ -794,14 +799,25 @@
794
  renderer.render(scene, camera);
795
  }
796
 
797
- // Fetch helper with backoff
798
- async function fetchWithBackoff(url, options, retries = 3, delay = 1000) {
 
 
 
 
 
 
 
 
 
 
 
799
  try {
800
- return await fetch(url, options);
801
  } catch (err) {
802
  if (retries > 0) {
803
  await new Promise(resolve => setTimeout(resolve, delay));
804
- return fetchWithBackoff(url, options, retries - 1, delay * 2);
805
  } else {
806
  throw err;
807
  }
@@ -896,7 +912,7 @@
896
  method: 'POST',
897
  headers: { 'Content-Type': 'application/json' },
898
  body: JSON.stringify({ model: modelId, payload })
899
- });
900
  if (proxyResp.ok) {
901
  return await proxyResp.json();
902
  } else {
@@ -918,7 +934,7 @@
918
  method: 'POST',
919
  headers: { 'Content-Type': 'application/json' },
920
  body: JSON.stringify(payload)
921
- });
922
  if (!directResp.ok) {
923
  const errorBody = await directResp.text();
924
  console.error('Error en la API de Gemini (fallback):', directResp.status, errorBody);
@@ -949,7 +965,16 @@
949
  }
950
 
951
  button.disabled = true;
952
- button.innerText = 'Analizando...';
 
 
 
 
 
 
 
 
 
953
 
954
  progressBar.style.transition = 'none';
955
  progressBar.style.width = '0%';
@@ -1006,8 +1031,13 @@
1006
  } catch (error) {
1007
  console.error("Error en handleAnalysisAndVisualization:", error);
1008
  } finally {
 
1009
  button.disabled = false;
1010
- button.innerText = 'Sembrar';
 
 
 
 
1011
  // Limpiar el input para permitir nueva siembra inmediata
1012
  const ti = document.getElementById('topicInput');
1013
  if (ti) ti.value = '';
 
713
  if (level3Slider) level3Slider.disabled = false;
714
 
715
  // Permitir sembrar también en modo anónimo (no se guardará en la nube)
716
+ // Evitar múltiples bindings si la escena se reinstala
717
+ if (!visualizeButton.dataset.bound) {
718
+ visualizeButton.dataset.originalHtml = visualizeButton.innerHTML;
719
+ visualizeButton.addEventListener('click', handleAnalysisAndVisualization);
720
+ visualizeButton.dataset.bound = '1';
721
+ }
722
  if (isAnonymous) {
723
  console.log('Modo anónimo: podrás visualizar neuronas, pero no se guardarán en Firestore.');
724
  topicInput.placeholder = 'Ingresa un tema para sembrar (modo anónimo)';
 
799
  renderer.render(scene, camera);
800
  }
801
 
802
+ // Fetch helper with timeout + backoff
803
+ async function fetchWithTimeout(url, options = {}, timeoutMs = 25000) {
804
+ const controller = new AbortController();
805
+ const id = setTimeout(() => controller.abort(), timeoutMs);
806
+ try {
807
+ const resp = await fetch(url, { ...options, signal: controller.signal });
808
+ return resp;
809
+ } finally {
810
+ clearTimeout(id);
811
+ }
812
+ }
813
+
814
+ async function fetchWithBackoff(url, options, retries = 2, delay = 1000, timeoutMs = 25000) {
815
  try {
816
+ return await fetchWithTimeout(url, options, timeoutMs);
817
  } catch (err) {
818
  if (retries > 0) {
819
  await new Promise(resolve => setTimeout(resolve, delay));
820
+ return fetchWithBackoff(url, options, retries - 1, delay * 2, timeoutMs);
821
  } else {
822
  throw err;
823
  }
 
912
  method: 'POST',
913
  headers: { 'Content-Type': 'application/json' },
914
  body: JSON.stringify({ model: modelId, payload })
915
+ }, /*retries*/ 1, /*delay*/ 1000, /*timeoutMs*/ 25000);
916
  if (proxyResp.ok) {
917
  return await proxyResp.json();
918
  } else {
 
934
  method: 'POST',
935
  headers: { 'Content-Type': 'application/json' },
936
  body: JSON.stringify(payload)
937
+ }, /*retries*/ 2, /*delay*/ 1000, /*timeoutMs*/ 25000);
938
  if (!directResp.ok) {
939
  const errorBody = await directResp.text();
940
  console.error('Error en la API de Gemini (fallback):', directResp.status, errorBody);
 
965
  }
966
 
967
  button.disabled = true;
968
+ // Guardar HTML original si no existe y colocar estado "Analizando..."
969
+ if (!button.dataset.originalHtml) button.dataset.originalHtml = button.innerHTML;
970
+ button.innerHTML = 'Analizando...';
971
+
972
+ // Watchdog: si algo se queda colgado, restaurar UI en 30s
973
+ const watchdog = setTimeout(() => {
974
+ try { button.disabled = false; } catch {}
975
+ try { if (button.dataset.originalHtml) button.innerHTML = button.dataset.originalHtml; } catch {}
976
+ try { progressBarContainer.style.display = 'none'; } catch {}
977
+ }, 30000);
978
 
979
  progressBar.style.transition = 'none';
980
  progressBar.style.width = '0%';
 
1031
  } catch (error) {
1032
  console.error("Error en handleAnalysisAndVisualization:", error);
1033
  } finally {
1034
+ clearTimeout(watchdog);
1035
  button.disabled = false;
1036
+ if (button.dataset.originalHtml) {
1037
+ button.innerHTML = button.dataset.originalHtml;
1038
+ } else {
1039
+ button.innerText = 'Sembrar';
1040
+ }
1041
  // Limpiar el input para permitir nueva siembra inmediata
1042
  const ti = document.getElementById('topicInput');
1043
  if (ti) ti.value = '';