@danhachuel/thunderbolt 0.4.27 → 0.4.28

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
- _task, generated_path = generate_thumbnail_for_task(task_id, settings)
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=str(card.get("aspect_ratio") or ""),
239
- size=str(card.get("image_size") or ""),
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=str(card.get("aspect_ratio") or ""),
282
- size=str(card.get("image_size") or ""),
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
- aspect_ratio = str(settings.get("gemini_image_aspect_ratio") or DEFAULT_ASPECT_RATIO).strip()
172
- image_size = str(settings.get("gemini_image_size") or DEFAULT_IMAGE_SIZE).strip()
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 = [
@@ -97,6 +97,7 @@ def normalize_thumbnail_task(task: dict[str, Any]) -> dict[str, Any]:
97
97
  "channel_name": str(task.get("channel_name") or "Canal sem nome").strip(),
98
98
  "blueprint_id": str(task.get("blueprint_id") or "").strip(),
99
99
  "blueprint_name": str(task.get("blueprint_name") or "").strip(),
100
+ "thumbnail_blueprint_id": str(task.get("thumbnail_blueprint_id") or "").strip(),
100
101
  "status": str(task.get("thumbnail_status") or "not_generated"),
101
102
  "prompt": str(prompt or "").strip(),
102
103
  "image_path": _as_path(image_path),
@@ -242,7 +243,11 @@ def _update_thumbnail_task(task_id: str, callback: Any) -> dict[str, Any]:
242
243
  return update_json("tasks.json", [], mutate)
243
244
 
244
245
 
245
- def generate_thumbnail_for_task(task_id: str, settings: dict[str, Any]) -> tuple[dict[str, Any], Path]:
246
+ def generate_thumbnail_for_task(
247
+ task_id: str,
248
+ settings: dict[str, Any],
249
+ thumbnail_blueprint: dict[str, Any] | None = None,
250
+ ) -> tuple[dict[str, Any], Path]:
246
251
  """Generate an image from the task's current prompt and persist it on the task."""
247
252
  tasks = read_json("tasks.json", [])
248
253
  if not isinstance(tasks, list):
@@ -251,9 +256,13 @@ def generate_thumbnail_for_task(task_id: str, settings: dict[str, Any]) -> tuple
251
256
  if not record["prompt"]:
252
257
  raise ThumbnailGenerationError("A thumbnail não tem um prompt de imagem para gerar.")
253
258
  _archive_image(str(task_id), record.get("image_path"))
259
+ visual_prompt = record["prompt"]
260
+ rules = str((thumbnail_blueprint or {}).get("content") or "").strip()
261
+ if rules:
262
+ visual_prompt = f"{visual_prompt}\n\nTHUMBNAIL BLUEPRINT — FOLLOW THESE VISUAL RULES:\n{rules}"
254
263
  image_path = _generate_image_with_pool(
255
264
  settings,
256
- record["prompt"],
265
+ visual_prompt,
257
266
  topic=record["title"] or record["topic"],
258
267
  variant_index=record["variant_index"],
259
268
  lettering_text=record.get("thumbnail_text") or "",
@@ -435,4 +444,3 @@ __all__ = [
435
444
  "regenerate_thumbnail_prompt_and_image",
436
445
  "upload_thumbnail_image",
437
446
  ]
438
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.4.27",
3
+ "version": "0.4.28",
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",