@danhachuel/thunderbolt 0.4.60 → 0.4.62
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 +7 -2
- package/hermes_ui/media_generation.py +39 -1
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -81,7 +81,7 @@ from hermes_ui.thumbnails import (
|
|
|
81
81
|
)
|
|
82
82
|
from hermes_ui.draft_video import DRAFT_SETTING_SECTIONS, missing_content_fields, missing_setting_sections, normalise_saved_script, setting_widget_suffixes
|
|
83
83
|
from hermes_ui.creative_generation import CreativeGenerationError, generate_creative_package, generate_thumbnail_prompt, generate_title_and_keywords, generate_topic_for_channel, generate_video_description, generate_video_keywords, generate_video_update_metadata
|
|
84
|
-
from hermes_ui.media_generation import MediaGenerationError, generate_image_for_card, generate_video_for_card
|
|
84
|
+
from hermes_ui.media_generation import MediaGenerationError, format_media_generation_error, generate_image_for_card, generate_video_for_card
|
|
85
85
|
from integrations.platforms import IntegrationResult, TikTokAdapter, YouTubeAdapter, fetch_channel_videos_public
|
|
86
86
|
from integrations.tiktok_public import fetch_public_tiktok_profile, normalize_tiktok_reference
|
|
87
87
|
from integrations.youtube_update import YOUTUBE_UPDATE_VIDEO, YouTubeVideoUpdater
|
|
@@ -2328,7 +2328,10 @@ def render_channels():
|
|
|
2328
2328
|
|
|
2329
2329
|
st.divider()
|
|
2330
2330
|
st.subheader("Canais cadastrados")
|
|
2331
|
-
registered_channels =
|
|
2331
|
+
registered_channels = [
|
|
2332
|
+
channel for channel in read_json("channels.json", [])
|
|
2333
|
+
if isinstance(channel, dict) and str(channel.get("platform") or "youtube").strip().lower() != "tiktok"
|
|
2334
|
+
]
|
|
2332
2335
|
if not registered_channels:
|
|
2333
2336
|
st.info("Nenhum canal cadastrado.")
|
|
2334
2337
|
else:
|
|
@@ -4662,6 +4665,8 @@ def render_thumbnails():
|
|
|
4662
4665
|
)
|
|
4663
4666
|
st.success("Lettering refeito; a imagem original foi usada como base.")
|
|
4664
4667
|
st.rerun()
|
|
4668
|
+
except MediaGenerationError as exc:
|
|
4669
|
+
st.error(format_media_generation_error(exc, operation="refazer o lettering da thumbnail"))
|
|
4665
4670
|
except ThumbnailGenerationError as exc:
|
|
4666
4671
|
st.error(str(exc))
|
|
4667
4672
|
|
|
@@ -12,6 +12,7 @@ import binascii
|
|
|
12
12
|
import json
|
|
13
13
|
import mimetypes
|
|
14
14
|
import os
|
|
15
|
+
import re
|
|
15
16
|
import shutil
|
|
16
17
|
import subprocess
|
|
17
18
|
import tempfile
|
|
@@ -49,6 +50,35 @@ class MediaGenerationError(RuntimeError):
|
|
|
49
50
|
self.provider_errors = list(provider_errors or [])
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
def format_media_generation_error(exc: MediaGenerationError, *, operation: str = "gerar a imagem") -> str:
|
|
54
|
+
"""Return a concise Portuguese diagnostic instead of exposing only a traceback."""
|
|
55
|
+
text = str(exc or "").strip()
|
|
56
|
+
errors = list(exc.provider_errors or [])
|
|
57
|
+
if errors:
|
|
58
|
+
status_codes = [int(match.group(1)) for item in errors for match in [re.search(r"\bHTTP\s+(\d{3})\b", str(item), re.IGNORECASE)] if match]
|
|
59
|
+
if any(code in {401, 403} for code in status_codes):
|
|
60
|
+
code = f"IMG_AUTH_HTTP_{next(code for code in status_codes if code in {401, 403})}"
|
|
61
|
+
cause = "a API key está ausente, inválida ou sem permissão para este provider"
|
|
62
|
+
action = "confirme a API key, o endpoint e as permissões em Configurações > Configuração API > API Keys"
|
|
63
|
+
elif any(code == 402 for code in status_codes):
|
|
64
|
+
code, cause, action = "IMG_QUOTA_HTTP_402", "o provider recusou a chamada por quota, créditos ou facturação", "confirme o saldo/plano do provider ou seleccione outro provider activo"
|
|
65
|
+
elif any(code == 404 for code in status_codes):
|
|
66
|
+
code, cause, action = "IMG_ENDPOINT_HTTP_404", "o endpoint ou modelo configurado não existe", "confirme a Base URL e o Modelo no cartão do provider"
|
|
67
|
+
elif any(code in {408, 429} for code in status_codes):
|
|
68
|
+
code = f"IMG_RATE_LIMIT_HTTP_{next(code for code in status_codes if code in {408, 429})}"
|
|
69
|
+
cause = "o provider está limitado ou não respondeu dentro do tempo permitido"
|
|
70
|
+
action = "aguarde alguns instantes, reduza a frequência ou use outro provider activo"
|
|
71
|
+
elif any(code >= 500 for code in status_codes):
|
|
72
|
+
code, cause, action = "IMG_PROVIDER_HTTP_5XX", "o serviço do provider devolveu um erro temporário", "tente novamente mais tarde ou use outro provider activo"
|
|
73
|
+
else:
|
|
74
|
+
code, cause, action = "IMG_PROVIDER_REQUEST_FAILED", "o provider rejeitou a chamada", "confirme o modelo, endpoint, formato da API key e os campos obrigatórios"
|
|
75
|
+
details = "; ".join(str(item)[:220] for item in errors)
|
|
76
|
+
return f"Não foi possível {operation}. Código: {code}. Causa provável: {cause}. Acção: {action}. Detalhes: {details}"
|
|
77
|
+
if "Não existem providers activos" in text:
|
|
78
|
+
return f"Não foi possível {operation}. Código: IMG_NO_ACTIVE_PROVIDER. Causa provável: não existe nenhum provider activo no pool de imagem. Acção: active um cartão em Configurações > Configuração API > LLM — providers e modelos / Imagem e Video IA."
|
|
79
|
+
return f"Não foi possível {operation}. Código: IMG_GENERATION_FAILED. Causa: {text or 'o provider não devolveu uma imagem utilizável'}. Acção: confirme a configuração do provider e tente novamente."
|
|
80
|
+
|
|
81
|
+
|
|
52
82
|
AGNES_IMAGE_MODEL = "agnes-image-2.1-flash"
|
|
53
83
|
AGNES_IMAGE_TIMEOUT_SECONDS = 120
|
|
54
84
|
|
|
@@ -330,7 +360,15 @@ def generate_image_for_card(
|
|
|
330
360
|
try:
|
|
331
361
|
routed = route_json_request(settings, pool=POOL_IMAGE, cards=[card], request=request)
|
|
332
362
|
except ProviderRoutingError as exc:
|
|
333
|
-
|
|
363
|
+
attempts = list(getattr(exc, "attempts", []) or [])
|
|
364
|
+
provider_errors = []
|
|
365
|
+
for attempt in attempts:
|
|
366
|
+
provider = str(attempt.get("provider") or "provider")
|
|
367
|
+
status_code = attempt.get("status_code")
|
|
368
|
+
error = str(attempt.get("error") or "falha sem detalhe")
|
|
369
|
+
prefix = f"HTTP {int(status_code)}: " if status_code else ""
|
|
370
|
+
provider_errors.append(f"{provider}: {prefix}{error[:180]}")
|
|
371
|
+
raise MediaGenerationError(str(exc), provider_errors=provider_errors) from exc
|
|
334
372
|
image_bytes, url = _image_value(routed.payload)
|
|
335
373
|
if not image_bytes and not url:
|
|
336
374
|
request_id = _image_request_id(routed.payload)
|
package/package.json
CHANGED