@danhachuel/thunderbolt 0.4.28 → 0.4.30
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 +49 -5
- package/hermes_ui/thumbnails.py +10 -2
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -6135,6 +6135,25 @@ def _persist_media_cards(settings: dict[str, Any], cards: list[dict[str, Any]],
|
|
|
6135
6135
|
return updated
|
|
6136
6136
|
|
|
6137
6137
|
|
|
6138
|
+
def _fetch_media_models(card: dict[str, Any]) -> list[str]:
|
|
6139
|
+
"""Consultar modelos do provider, incluindo o catálogo nativo Gemini."""
|
|
6140
|
+
provider = str(card.get("provider") or "").strip().lower()
|
|
6141
|
+
if provider == "nano_banana":
|
|
6142
|
+
base_url = str(card.get("base_url") or "https://generativelanguage.googleapis.com/v1beta").rstrip("/")
|
|
6143
|
+
response = requests.get(
|
|
6144
|
+
f"{base_url}/models",
|
|
6145
|
+
params={"key": str(card.get("api_key") or "").strip()},
|
|
6146
|
+
headers={"Accept": "application/json"},
|
|
6147
|
+
timeout=12,
|
|
6148
|
+
)
|
|
6149
|
+
response.raise_for_status()
|
|
6150
|
+
payload = response.json()
|
|
6151
|
+
models = payload.get("models") if isinstance(payload, dict) else []
|
|
6152
|
+
return sorted({str(item.get("name", "")).removeprefix("models/") for item in models if isinstance(item, dict) and item.get("name")}, key=str.casefold)
|
|
6153
|
+
from integrations.openai_model_discovery import fetch_openai_compatible_models
|
|
6154
|
+
return fetch_openai_compatible_models(str(card.get("api_key") or ""), str(card.get("base_url") or ""))
|
|
6155
|
+
|
|
6156
|
+
|
|
6138
6157
|
def _render_media_provider_card(settings: dict[str, Any], cards: list[dict[str, Any]], index: int, *, embedded: bool = False) -> None:
|
|
6139
6158
|
card = normalize_media_card(cards[index], index)
|
|
6140
6159
|
cards[index] = card
|
|
@@ -6160,7 +6179,23 @@ def _render_media_provider_card(settings: dict[str, Any], cards: list[dict[str,
|
|
|
6160
6179
|
st.caption("Este provider não exige API key.")
|
|
6161
6180
|
api_key = ""
|
|
6162
6181
|
with model_col:
|
|
6163
|
-
|
|
6182
|
+
model_catalog = st.session_state.get(f"media_model_catalog_{card_id}", [])
|
|
6183
|
+
if not isinstance(model_catalog, list):
|
|
6184
|
+
model_catalog = []
|
|
6185
|
+
current_model = str(card.get("model") or "").strip()
|
|
6186
|
+
discovered_models = [str(item).strip() for item in model_catalog if str(item).strip()]
|
|
6187
|
+
options = ["__select_model__", *list(dict.fromkeys(discovered_models))]
|
|
6188
|
+
if current_model and current_model not in options:
|
|
6189
|
+
options.insert(1, current_model)
|
|
6190
|
+
selected_model = st.selectbox(
|
|
6191
|
+
"Modelo",
|
|
6192
|
+
options,
|
|
6193
|
+
index=options.index(current_model) if current_model in options else 0,
|
|
6194
|
+
format_func=lambda value: "Seleccione um modelo" if value == "__select_model__" else value,
|
|
6195
|
+
help="Consulte o catálogo do provider e seleccione um modelo disponível.",
|
|
6196
|
+
key=f"media_card_{card_id}_model_select",
|
|
6197
|
+
)
|
|
6198
|
+
model = "" if selected_model == "__select_model__" else selected_model
|
|
6164
6199
|
base_url = st.text_input("Base URL", value=str(card.get("base_url") or definition.default_base_url), key=f"media_card_{card_id}_base_url")
|
|
6165
6200
|
extra_values: dict[str, str] = {}
|
|
6166
6201
|
if definition.extra_fields:
|
|
@@ -6177,17 +6212,26 @@ def _render_media_provider_card(settings: dict[str, Any], cards: list[dict[str,
|
|
|
6177
6212
|
supports_video = st.checkbox("Pool Vídeo", value=bool(card.get("supports_video", definition.supports_video)), key=f"media_card_{card_id}_video")
|
|
6178
6213
|
with status_cols[3]:
|
|
6179
6214
|
priority = st.number_input("Prioridade", min_value=0, max_value=999, value=int(card.get("priority", index)), step=1, key=f"media_card_{card_id}_priority")
|
|
6180
|
-
action_cols = st.columns(
|
|
6215
|
+
action_cols = st.columns(4)
|
|
6181
6216
|
with action_cols[0]:
|
|
6182
|
-
|
|
6217
|
+
refresh_clicked = st.form_submit_button("Consultar Modelos", use_container_width=True, key=f"media_card_{card_id}_refresh")
|
|
6183
6218
|
with action_cols[1]:
|
|
6184
|
-
|
|
6219
|
+
test_clicked = st.form_submit_button("Testar Chamada API", use_container_width=True, key=f"media_card_{card_id}_test")
|
|
6185
6220
|
with action_cols[2]:
|
|
6221
|
+
save_clicked = st.form_submit_button("Salvar", type="primary", use_container_width=True, key=f"media_card_{card_id}_save")
|
|
6222
|
+
with action_cols[3]:
|
|
6186
6223
|
remove_clicked = st.form_submit_button("Remover provider", use_container_width=True, key=f"media_card_{card_id}_remove")
|
|
6187
6224
|
edited = dict(card)
|
|
6188
6225
|
edited.update({"api_key": str(api_key or "").strip(), "model": str(model or "").strip(), "base_url": str(base_url or "").strip(), "enabled": bool(enabled), "supports_image": bool(supports_image), "supports_video": bool(supports_video), "priority": int(priority), **extra_values})
|
|
6189
6226
|
cards[index] = edited
|
|
6190
|
-
if
|
|
6227
|
+
if refresh_clicked:
|
|
6228
|
+
try:
|
|
6229
|
+
discovered = _fetch_media_models(edited)
|
|
6230
|
+
st.session_state[f"media_model_catalog_{card_id}"] = discovered
|
|
6231
|
+
st.success(f"{len(discovered)} modelo(s) disponíveis neste endpoint.")
|
|
6232
|
+
except Exception:
|
|
6233
|
+
st.error("Não foi possível consultar os modelos deste provider. Confirme a API key e a Base URL.")
|
|
6234
|
+
elif test_clicked:
|
|
6191
6235
|
result = test_media_provider_card(edited)
|
|
6192
6236
|
edited["test_result"] = stamp_test_result(result)
|
|
6193
6237
|
_persist_media_cards(settings, cards, str(settings.get(MEDIA_IMAGE_ACTIVE_CARD_KEY) or ""), str(settings.get(MEDIA_VIDEO_ACTIVE_CARD_KEY) or ""))
|
package/hermes_ui/thumbnails.py
CHANGED
|
@@ -10,8 +10,9 @@ from typing import Any
|
|
|
10
10
|
from .creative_generation import generate_thumbnail_prompt
|
|
11
11
|
from .media_generation import generate_image_from_pool
|
|
12
12
|
from .media_providers import media_cards_for_pool
|
|
13
|
-
from .storage import STORAGE, now, read_json, update_json
|
|
13
|
+
from .storage import STORAGE, ensure_storage, now, read_json, update_json
|
|
14
14
|
from .thumbnail_generation import ThumbnailGenerationError, generate_thumbnail_image
|
|
15
|
+
from .thumbnail_blueprints import thumbnail_blueprint_for_channel
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def _generate_image_with_pool(
|
|
@@ -290,12 +291,19 @@ def regenerate_thumbnail_prompt(
|
|
|
290
291
|
topic = record["topic"] or record["title"]
|
|
291
292
|
if not topic:
|
|
292
293
|
raise ThumbnailGenerationError("A tarefa não tem tópico para refazer o prompt da thumbnail.")
|
|
294
|
+
ensure_storage()
|
|
295
|
+
visual_blueprint = thumbnail_blueprint_for_channel(
|
|
296
|
+
{**(channel or {}), "thumbnail_blueprint_id": record.get("thumbnail_blueprint_id") or (channel or {}).get("thumbnail_blueprint_id", "")}
|
|
297
|
+
)
|
|
298
|
+
effective_blueprint = {**(blueprint or {})}
|
|
299
|
+
if visual_blueprint.get("content"):
|
|
300
|
+
effective_blueprint["thumbnail_blueprint_rules"] = visual_blueprint["content"]
|
|
293
301
|
variant = generate_thumbnail_prompt(
|
|
294
302
|
settings,
|
|
295
303
|
channel or {},
|
|
296
304
|
topic,
|
|
297
305
|
current_prompt=record["prompt"],
|
|
298
|
-
blueprint=
|
|
306
|
+
blueprint=effective_blueprint,
|
|
299
307
|
language=language,
|
|
300
308
|
)
|
|
301
309
|
updated = _update_thumbnail_task(
|
package/package.json
CHANGED