@danhachuel/thunderbolt 0.4.27 → 0.4.29
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
|
@@ -4055,6 +4055,9 @@ def _thumbnail_editor_context(record: dict[str, Any]) -> tuple[dict[str, Any], d
|
|
|
4055
4055
|
blueprint = blueprint_for_channel(channel)
|
|
4056
4056
|
if not blueprint and record.get("blueprint_id"):
|
|
4057
4057
|
blueprint = {"id": record.get("blueprint_id"), "name": record.get("blueprint_name") or record.get("blueprint_id")}
|
|
4058
|
+
thumbnail_blueprint = thumbnail_blueprint_for_channel({**channel, "thumbnail_blueprint_id": record.get("thumbnail_blueprint_id") or channel.get("thumbnail_blueprint_id", "")})
|
|
4059
|
+
if thumbnail_blueprint.get("content"):
|
|
4060
|
+
blueprint = {**blueprint, "thumbnail_blueprint_rules": thumbnail_blueprint["content"]}
|
|
4058
4061
|
return channel, blueprint
|
|
4059
4062
|
|
|
4060
4063
|
|
|
@@ -4141,7 +4144,9 @@ def render_thumbnails():
|
|
|
4141
4144
|
):
|
|
4142
4145
|
try:
|
|
4143
4146
|
with st.spinner("A gerar a imagem com Nano Banana…"):
|
|
4144
|
-
|
|
4147
|
+
channel, _blueprint = _thumbnail_editor_context(record)
|
|
4148
|
+
thumbnail_blueprint = thumbnail_blueprint_for_channel({**channel, "thumbnail_blueprint_id": record.get("thumbnail_blueprint_id") or channel.get("thumbnail_blueprint_id", "")})
|
|
4149
|
+
_task, generated_path = generate_thumbnail_for_task(task_id, settings, thumbnail_blueprint=thumbnail_blueprint)
|
|
4145
4150
|
record_notification(
|
|
4146
4151
|
"thumbnail_generation_completed",
|
|
4147
4152
|
f"Thumbnail gerada: {record['title']}",
|
|
@@ -235,8 +235,8 @@ def _image_request(card: dict[str, Any], prompt: str) -> Any:
|
|
|
235
235
|
constrained_prompt = _append_generation_constraints(
|
|
236
236
|
prompt,
|
|
237
237
|
kind="image",
|
|
238
|
-
aspect_ratio=
|
|
239
|
-
size=
|
|
238
|
+
aspect_ratio="16:9",
|
|
239
|
+
size="1280x720 minimum",
|
|
240
240
|
)
|
|
241
241
|
if style == "cloudflare":
|
|
242
242
|
return requests.post(endpoint, headers=_headers(card), json={"prompt": constrained_prompt}, timeout=180)
|
|
@@ -278,8 +278,8 @@ def generate_image_for_card(
|
|
|
278
278
|
_append_generation_constraints(
|
|
279
279
|
prompt,
|
|
280
280
|
kind="image",
|
|
281
|
-
aspect_ratio=
|
|
282
|
-
size=
|
|
281
|
+
aspect_ratio="16:9",
|
|
282
|
+
size="1280x720 minimum",
|
|
283
283
|
),
|
|
284
284
|
topic=topic,
|
|
285
285
|
variant_index=variant_index,
|
|
@@ -168,8 +168,10 @@ def generate_thumbnail_image(
|
|
|
168
168
|
)
|
|
169
169
|
|
|
170
170
|
model = str(settings.get("gemini_image_model") or DEFAULT_GEMINI_IMAGE_MODEL).strip()
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
# YouTube thumbnails are never square: do not allow a legacy/provider setting
|
|
172
|
+
# to override the required horizontal canvas.
|
|
173
|
+
aspect_ratio = DEFAULT_ASPECT_RATIO
|
|
174
|
+
image_size = DEFAULT_IMAGE_SIZE
|
|
173
175
|
request_input: str | list[dict[str, str]] = effective_prompt
|
|
174
176
|
if reference_image:
|
|
175
177
|
request_input = [
|
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(
|
|
@@ -97,6 +98,7 @@ def normalize_thumbnail_task(task: dict[str, Any]) -> dict[str, Any]:
|
|
|
97
98
|
"channel_name": str(task.get("channel_name") or "Canal sem nome").strip(),
|
|
98
99
|
"blueprint_id": str(task.get("blueprint_id") or "").strip(),
|
|
99
100
|
"blueprint_name": str(task.get("blueprint_name") or "").strip(),
|
|
101
|
+
"thumbnail_blueprint_id": str(task.get("thumbnail_blueprint_id") or "").strip(),
|
|
100
102
|
"status": str(task.get("thumbnail_status") or "not_generated"),
|
|
101
103
|
"prompt": str(prompt or "").strip(),
|
|
102
104
|
"image_path": _as_path(image_path),
|
|
@@ -242,7 +244,11 @@ def _update_thumbnail_task(task_id: str, callback: Any) -> dict[str, Any]:
|
|
|
242
244
|
return update_json("tasks.json", [], mutate)
|
|
243
245
|
|
|
244
246
|
|
|
245
|
-
def generate_thumbnail_for_task(
|
|
247
|
+
def generate_thumbnail_for_task(
|
|
248
|
+
task_id: str,
|
|
249
|
+
settings: dict[str, Any],
|
|
250
|
+
thumbnail_blueprint: dict[str, Any] | None = None,
|
|
251
|
+
) -> tuple[dict[str, Any], Path]:
|
|
246
252
|
"""Generate an image from the task's current prompt and persist it on the task."""
|
|
247
253
|
tasks = read_json("tasks.json", [])
|
|
248
254
|
if not isinstance(tasks, list):
|
|
@@ -251,9 +257,13 @@ def generate_thumbnail_for_task(task_id: str, settings: dict[str, Any]) -> tuple
|
|
|
251
257
|
if not record["prompt"]:
|
|
252
258
|
raise ThumbnailGenerationError("A thumbnail não tem um prompt de imagem para gerar.")
|
|
253
259
|
_archive_image(str(task_id), record.get("image_path"))
|
|
260
|
+
visual_prompt = record["prompt"]
|
|
261
|
+
rules = str((thumbnail_blueprint or {}).get("content") or "").strip()
|
|
262
|
+
if rules:
|
|
263
|
+
visual_prompt = f"{visual_prompt}\n\nTHUMBNAIL BLUEPRINT — FOLLOW THESE VISUAL RULES:\n{rules}"
|
|
254
264
|
image_path = _generate_image_with_pool(
|
|
255
265
|
settings,
|
|
256
|
-
|
|
266
|
+
visual_prompt,
|
|
257
267
|
topic=record["title"] or record["topic"],
|
|
258
268
|
variant_index=record["variant_index"],
|
|
259
269
|
lettering_text=record.get("thumbnail_text") or "",
|
|
@@ -281,12 +291,19 @@ def regenerate_thumbnail_prompt(
|
|
|
281
291
|
topic = record["topic"] or record["title"]
|
|
282
292
|
if not topic:
|
|
283
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"]
|
|
284
301
|
variant = generate_thumbnail_prompt(
|
|
285
302
|
settings,
|
|
286
303
|
channel or {},
|
|
287
304
|
topic,
|
|
288
305
|
current_prompt=record["prompt"],
|
|
289
|
-
blueprint=
|
|
306
|
+
blueprint=effective_blueprint,
|
|
290
307
|
language=language,
|
|
291
308
|
)
|
|
292
309
|
updated = _update_thumbnail_task(
|
|
@@ -435,4 +452,3 @@ __all__ = [
|
|
|
435
452
|
"regenerate_thumbnail_prompt_and_image",
|
|
436
453
|
"upload_thumbnail_image",
|
|
437
454
|
]
|
|
438
|
-
|
package/package.json
CHANGED