@danhachuel/thunderbolt 0.5.25 → 0.5.27
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 +17 -1
- package/hermes_ui/media_providers.py +18 -2
- package/package.json +40 -6
- package/CHANGELOG.md +0 -21
package/app/main.py
CHANGED
|
@@ -7285,6 +7285,22 @@ def render_media_provider_cards(settings: dict[str, Any], *, embedded: bool = Fa
|
|
|
7285
7285
|
with st.expander("Imagem e Video IA", expanded=False):
|
|
7286
7286
|
full_ia_labels = ", ".join(media_provider_definition(code).label for code in FULL_IA_VIDEO_PROVIDER_CODES)
|
|
7287
7287
|
st.caption(f"Configure providers de imagem e vídeo em cartões independentes. O router usa apenas o pool correspondente e faz failover entre providers activos. Pool Full IA: {full_ia_labels}.")
|
|
7288
|
+
image_cards = [card for card in cards if card.get("supports_image")]
|
|
7289
|
+
video_cards = [card for card in cards if card.get("supports_video")]
|
|
7290
|
+
selector_cols = st.columns(3)
|
|
7291
|
+
image_options = [""] + [str(card.get("id")) for card in image_cards]
|
|
7292
|
+
video_options = [""] + [str(card.get("id")) for card in video_cards]
|
|
7293
|
+
with selector_cols[0]:
|
|
7294
|
+
image_active_id = st.selectbox("Provider principal de imagem", image_options, index=image_options.index(str(settings.get(MEDIA_IMAGE_ACTIVE_CARD_KEY) or "")) if str(settings.get(MEDIA_IMAGE_ACTIVE_CARD_KEY) or "") in image_options else 0, format_func=lambda value: "Automático / primeiro activo" if not value else next((media_provider_definition(card.get("provider")).label for card in image_cards if str(card.get("id")) == value), value), key="media_image_active_selector")
|
|
7295
|
+
with selector_cols[1]:
|
|
7296
|
+
video_active_id = st.selectbox("Provider principal de vídeo", video_options, index=video_options.index(str(settings.get(MEDIA_VIDEO_ACTIVE_CARD_KEY) or "")) if str(settings.get(MEDIA_VIDEO_ACTIVE_CARD_KEY) or "") in video_options else 0, format_func=lambda value: "Não usar pool externo" if not value else next((media_provider_definition(card.get("provider")).label for card in video_cards if str(card.get("id")) == value), value), key="media_video_active_selector")
|
|
7297
|
+
with selector_cols[2]:
|
|
7298
|
+
video_pool_enabled = st.checkbox("Usar pool de vídeo externo", value=bool(settings.get("media_video_pool_enabled", False)), key="media_video_pool_enabled_ui")
|
|
7299
|
+
if st.button("Salvar selecção dos pools", use_container_width=True, key="save_media_pool_selection") if not embedded else st.form_submit_button("Salvar selecção dos pools", use_container_width=True, key="save_media_pool_selection"):
|
|
7300
|
+
settings["media_video_pool_enabled"] = bool(video_pool_enabled)
|
|
7301
|
+
_persist_media_cards(settings, cards, image_active_id, video_active_id)
|
|
7302
|
+
st.success("Selecção dos pools guardada.")
|
|
7303
|
+
st.rerun()
|
|
7288
7304
|
for index in range(len(cards)):
|
|
7289
7305
|
_render_media_provider_card(settings, cards, index, embedded=embedded)
|
|
7290
7306
|
st.divider()
|
|
@@ -7294,7 +7310,7 @@ def render_media_provider_cards(settings: dict[str, Any], *, embedded: bool = Fa
|
|
|
7294
7310
|
add_clicked = st.form_submit_button("Adicionar provider de imagem/vídeo", use_container_width=True, key="add_media_provider_card") if embedded else st.button("Adicionar provider de imagem/vídeo", use_container_width=True, key="add_media_provider_card")
|
|
7295
7311
|
if add_clicked:
|
|
7296
7312
|
cards.append(new_media_card(provider_to_add, card_id=f"media-{provider_to_add}-{uuid.uuid4().hex[:8]}"))
|
|
7297
|
-
_persist_media_cards(settings, cards,
|
|
7313
|
+
_persist_media_cards(settings, cards, image_active_id, video_active_id)
|
|
7298
7314
|
st.success("Novo provider de imagem/vídeo adicionado.")
|
|
7299
7315
|
st.rerun()
|
|
7300
7316
|
|
|
@@ -251,6 +251,13 @@ def normalize_media_card(card: Any, index: int = 0) -> dict[str, Any]:
|
|
|
251
251
|
return result
|
|
252
252
|
|
|
253
253
|
|
|
254
|
+
def _ordered_media_cards(cards: list[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
|
255
|
+
"""Ordenar os cartões pela prioridade, preservando a ordem em caso de empate."""
|
|
256
|
+
indexed = [(index, normalize_media_card(card, index)) for index, card in enumerate(cards)]
|
|
257
|
+
indexed.sort(key=lambda pair: (int(pair[1].get("priority", pair[0])), pair[0]))
|
|
258
|
+
return [card for _index, card in indexed]
|
|
259
|
+
|
|
260
|
+
|
|
254
261
|
def new_media_card(provider: Any, *, card_id: str | None = None) -> dict[str, Any]:
|
|
255
262
|
code = str(provider or "").strip().lower()
|
|
256
263
|
if code not in _MEDIA_BY_CODE:
|
|
@@ -294,6 +301,10 @@ def ensure_media_provider_cards(settings: Mapping[str, Any]) -> tuple[dict[str,
|
|
|
294
301
|
)
|
|
295
302
|
)
|
|
296
303
|
changed = True
|
|
304
|
+
ordered_cards = _ordered_media_cards(cards)
|
|
305
|
+
if ordered_cards != cards:
|
|
306
|
+
changed = True
|
|
307
|
+
cards = ordered_cards
|
|
297
308
|
result[MEDIA_CARDS_KEY] = cards
|
|
298
309
|
|
|
299
310
|
for pool, key, capability in (
|
|
@@ -321,6 +332,7 @@ def apply_media_provider_cards_to_settings(settings: Mapping[str, Any], cards: l
|
|
|
321
332
|
normalized = [normalize_media_card(item, index) for index, item in enumerate(cards)]
|
|
322
333
|
if not normalized:
|
|
323
334
|
normalized = [new_media_card("nano_banana", card_id="media-nano-banana-default")]
|
|
335
|
+
normalized = _ordered_media_cards(normalized)
|
|
324
336
|
result[MEDIA_CARDS_KEY] = normalized
|
|
325
337
|
for key, wanted, capability in (
|
|
326
338
|
(MEDIA_IMAGE_ACTIVE_CARD_KEY, image_active_id, "supports_image"),
|
|
@@ -346,9 +358,13 @@ def apply_media_provider_cards_to_settings(settings: Mapping[str, Any], cards: l
|
|
|
346
358
|
def media_cards_for_pool(settings: Mapping[str, Any], pool: str, *, thumbnail_only: bool = False) -> list[dict[str, Any]]:
|
|
347
359
|
migrated, _ = ensure_media_provider_cards(settings)
|
|
348
360
|
capability = "supports_image" if pool == "image" else "supports_video" if pool == "video" else "supports_text"
|
|
361
|
+
active_key = MEDIA_IMAGE_ACTIVE_CARD_KEY if pool == "image" else MEDIA_VIDEO_ACTIVE_CARD_KEY if pool == "video" else ""
|
|
362
|
+
active_id = str(migrated.get(active_key) or "")
|
|
349
363
|
cards = [dict(item) for item in migrated.get(MEDIA_CARDS_KEY, []) if item.get("enabled", True) and item.get(capability)]
|
|
350
364
|
if pool == "image" and not thumbnail_only:
|
|
351
365
|
cards = [card for card in cards if not card.get("thumbnail_only")]
|
|
352
|
-
# A prioridade
|
|
353
|
-
|
|
366
|
+
# A prioridade é o contrato principal do failover. O cartão activo legado
|
|
367
|
+
# só serve de desempate entre cartões com a mesma prioridade, para não
|
|
368
|
+
# ignorar uma escolha explícita do utilizador por causa de estado antigo.
|
|
369
|
+
cards.sort(key=lambda card: (int(card.get("priority", 0)), 0 if str(card.get("id")) == active_id else 1))
|
|
354
370
|
return cards
|
package/package.json
CHANGED
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danhachuel/thunderbolt",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.27",
|
|
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",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"bin": {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
8
|
+
"bin": {
|
|
9
|
+
"thunderbolt": "scripts/cli.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"app/main.py",
|
|
13
|
+
"app/influencers_ui.py",
|
|
14
|
+
"app/modules/**/*.py",
|
|
15
|
+
"hermes_ui/*.py",
|
|
16
|
+
"integrations/*.py",
|
|
17
|
+
"integrations/data/*.json",
|
|
18
|
+
"scripts/*.mjs",
|
|
19
|
+
"scripts/*.py",
|
|
20
|
+
"seed/prompt_masters/**/*.md",
|
|
21
|
+
"seed/blueprints/**/*.json",
|
|
22
|
+
"seed/blueprints/**/*.md",
|
|
23
|
+
"seed/skills/*.md",
|
|
24
|
+
"seed/skills/*.py",
|
|
25
|
+
"seed/references/*.md",
|
|
26
|
+
"seed/references/*.sql",
|
|
27
|
+
"README.md",
|
|
28
|
+
"MANUAL-INSTALACAO.md",
|
|
29
|
+
"THIRD-PARTY-NOTICES.md",
|
|
30
|
+
"requirements.txt",
|
|
31
|
+
"sitecustomize.py",
|
|
32
|
+
"package.json",
|
|
33
|
+
".streamlit/config.toml"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"postinstall": "node scripts/npx-cache-compat.mjs",
|
|
37
|
+
"start": "node scripts/cli.mjs",
|
|
38
|
+
"check": "node scripts/cli.mjs --check",
|
|
39
|
+
"pack:check": "npm pack --dry-run"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
}
|
|
13
47
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.5.17
|
|
4
|
-
|
|
5
|
-
Removidos da secção Imagem e Video IA os selectores de provider principal de imagem, provider principal de vídeo e a checkbox de pool de vídeo externo. A ordem dos pools passa a ser definida pelos campos de Prioridade nos próprios cartões.
|
|
6
|
-
|
|
7
|
-
## 0.5.16
|
|
8
|
-
|
|
9
|
-
Adicionado um handler SIGINT no entry point do Streamlit que encerra o processo de forma controlada antes do handler de shutdown do Streamlit chamar `click.secho`, eliminando o caminho que provocava `LookupError: unknown encoding: utf-16-le` ao pressionar Ctrl+C no Windows.
|
|
10
|
-
|
|
11
|
-
## 0.5.15 (normalizado pelo npm para 0.5.15)
|
|
12
|
-
|
|
13
|
-
Aplicada a correcção definitiva do caminho de saída do Click no Windows, com shim UTF-8 carregado antes do Streamlit e teste de regressão para stdout com encoding `utf-16-le`.
|
|
14
|
-
|
|
15
|
-
## 0.5.09 (normalizado pelo npm para 0.5.9)
|
|
16
|
-
|
|
17
|
-
Adicionado um shim de compatibilidade que intercepta a escrita de saída do Click antes do carregamento do Streamlit e grava directamente em UTF-8, evitando o caminho nativo que volta a procurar `utf-16-le` durante o shutdown do Windows. Incluídos testes com um console simulado em `utf-16-le`.
|
|
18
|
-
|
|
19
|
-
## 0.5.08 (normalizado pelo npm para 0.5.8)
|
|
20
|
-
|
|
21
|
-
Corrigido o erro `LookupError: unknown encoding: utf-16-le` que podia ocorrer durante o shutdown do Streamlit no Windows. O launcher Node agora materializa as variáveis de encoding e `CLICK_NO_WIN_CONSOLE` no processo pai antes de iniciar Python; os workers de automação e pipeline também aplicam as mesmas definições antes dos imports restantes.
|