@danhachuel/thunderbolt 0.3.78 → 0.3.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app/main.py CHANGED
@@ -5397,11 +5397,25 @@ def _render_api_test_feedback(settings: dict[str, Any], test_key: str, result: d
5397
5397
  st.error(ui_text("Último teste: chamada falhou", language) + suffix)
5398
5398
 
5399
5399
 
5400
- def _render_api_test_control(settings: dict[str, Any], test_key: str, callback: Any, *, widget_key: str) -> None:
5401
- """Render a form-safe diagnostic button and persist its redacted result."""
5400
+ def _render_api_test_control(
5401
+ settings: dict[str, Any],
5402
+ test_key: str,
5403
+ callback: Any,
5404
+ *,
5405
+ widget_key: str,
5406
+ persist_callback: Any = None,
5407
+ ) -> None:
5408
+ """Render a form-safe diagnostic button and persist its redacted result.
5409
+
5410
+ ``persist_callback`` keeps a card whose fields live in the global form
5411
+ consistent: testing it must not appear successful while its values remain
5412
+ only in the browser session.
5413
+ """
5402
5414
  if st.form_submit_button("Testar chamada API", use_container_width=True, key=widget_key):
5403
5415
  with st.spinner(ui_text("A testar chamada API…", current_ui_language())):
5404
5416
  try:
5417
+ if persist_callback is not None:
5418
+ persist_callback()
5405
5419
  result = callback()
5406
5420
  except Exception:
5407
5421
  result = {"status": "error", "message": "A chamada de diagnóstico falhou."}
@@ -5832,11 +5846,23 @@ def render_settings():
5832
5846
  azure_speech_key = text_setting("Azure Speech key", "azure_speech_key", secret=True)
5833
5847
  _render_credential_status(azure_speech_key)
5834
5848
  azure_speech_region = text_setting("Azure Speech region", "azure_speech_region")
5849
+
5850
+ def save_azure_speech() -> None:
5851
+ settings.update({
5852
+ "azure_speech_key": azure_speech_key.strip(),
5853
+ "azure_speech_region": azure_speech_region.strip(),
5854
+ })
5855
+ write_json("settings.json", settings)
5856
+
5857
+ if st.form_submit_button("Guardar Azure Speech", type="primary", use_container_width=True, key="save_azure_speech"):
5858
+ save_azure_speech()
5859
+ st.success("Azure Speech guardado.")
5835
5860
  _render_api_test_control(
5836
5861
  settings,
5837
5862
  "voice:azure_speech",
5838
5863
  lambda: test_voice_provider("azure_speech", {"azure_speech_key": azure_speech_key, "azure_speech_region": azure_speech_region}),
5839
5864
  widget_key="api_test_voice_azure",
5865
+ persist_callback=save_azure_speech,
5840
5866
  )
5841
5867
 
5842
5868
  with st.container(border=True):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.3.78",
3
+ "version": "0.3.79",
4
4
  "description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
5
5
  "license": "MIT",
6
6
  "main": "scripts/cli.mjs",
package/scripts/cli.mjs CHANGED
@@ -193,6 +193,11 @@ const proxy = http.createServer((request, response) => {
193
193
  });
194
194
 
195
195
  proxy.on("upgrade", (request, clientSocket, head) => {
196
+ // Clientes remotos podem encerrar o WebSocket antes de o Streamlit concluir
197
+ // a resposta. Tratar ECONNRESET impede que o Node termine o launcher.
198
+ clientSocket.on("error", () => {
199
+ if (!clientSocket.destroyed) clientSocket.destroy();
200
+ });
196
201
  const upstreamSocket = net.connect(backendPort, "127.0.0.1", () => {
197
202
  const headers = Object.entries(request.headers)
198
203
  .map(([name, value]) => `${name}: ${Array.isArray(value) ? value.join(", ") : value}`)
@@ -201,10 +206,14 @@ proxy.on("upgrade", (request, clientSocket, head) => {
201
206
  if (head.length) upstreamSocket.write(head);
202
207
  clientSocket.pipe(upstreamSocket).pipe(clientSocket);
203
208
  });
204
- upstreamSocket.on("error", () => clientSocket.destroy());
209
+ upstreamSocket.on("error", () => {
210
+ if (!clientSocket.destroyed) clientSocket.destroy();
211
+ });
205
212
  });
206
213
 
207
- proxy.listen(publicPort, "127.0.0.1", () => {
214
+ // O backend Streamlit fica em 127.0.0.1; apenas o proxy escuta em todas as
215
+ // interfaces para que o encaminhamento seguro do ambiente consiga alcançá-lo.
216
+ proxy.listen(publicPort, () => {
208
217
  console.log(`Thunderbolt: interface disponível em http://localhost:${publicPort}/`);
209
218
  });
210
219
  const worker = spawn(python, ["-m", "hermes_ui.automation_worker"], {