@danhachuel/thunderbolt 0.7.48 → 0.7.50
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
|
@@ -6424,7 +6424,6 @@ def _render_facebook_automation_cards() -> None:
|
|
|
6424
6424
|
def render_facebook_automation() -> None:
|
|
6425
6425
|
st.title("Automação Facebook")
|
|
6426
6426
|
st.caption("Fluxo local de posts: Ideia/Tema → LLM → Artigo → Google Imagens ou IA → textos e legendas → Upload pela Meta Graph API.")
|
|
6427
|
-
st.info("Esta página não usa planilhas nem Google Drive. Os artigos, imagens, legendas e estados ficam no armazenamento local do Thunderbolt.")
|
|
6428
6427
|
pages = _facebook_pages_for_automation()
|
|
6429
6428
|
settings = read_json("settings.json", {})
|
|
6430
6429
|
if not pages:
|
|
@@ -324,11 +324,17 @@ def _image_endpoint(card: Mapping[str, Any]) -> str:
|
|
|
324
324
|
raise MediaGenerationError(f"O provider {card.get('provider')} não tem endpoint de imagem configurado.")
|
|
325
325
|
|
|
326
326
|
|
|
327
|
-
def _thumbnail_aspect_ratio(
|
|
327
|
+
def _thumbnail_aspect_ratio(
|
|
328
|
+
thumbnail_blueprint: Mapping[str, Any] | None,
|
|
329
|
+
prompt: str = "",
|
|
330
|
+
explicit_aspect_ratio: str = "",
|
|
331
|
+
) -> str:
|
|
332
|
+
if explicit_aspect_ratio in {"16:9", "9:16"}:
|
|
333
|
+
return explicit_aspect_ratio
|
|
328
334
|
return infer_thumbnail_aspect_ratio(prompt, dict(thumbnail_blueprint or {}))
|
|
329
335
|
|
|
330
336
|
|
|
331
|
-
def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", lettering_text: str = "", lettering_prompt: str = "", thumbnail_blueprint: Mapping[str, Any] | None = None) -> Any:
|
|
337
|
+
def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", lettering_text: str = "", lettering_prompt: str = "", thumbnail_blueprint: Mapping[str, Any] | None = None, aspect_ratio: str = "") -> Any:
|
|
332
338
|
provider = str(card.get("provider") or "").strip().lower()
|
|
333
339
|
style = str(card.get("api_style") or media_provider_definition(provider).api_style)
|
|
334
340
|
endpoint = _image_endpoint(card)
|
|
@@ -338,12 +344,12 @@ def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", letter
|
|
|
338
344
|
lettering_text=lettering_text,
|
|
339
345
|
lettering_prompt=lettering_prompt,
|
|
340
346
|
)
|
|
341
|
-
|
|
342
|
-
requested_size = ("1024x1792" if
|
|
347
|
+
resolved_aspect_ratio = _thumbnail_aspect_ratio(thumbnail_blueprint, prompt, aspect_ratio)
|
|
348
|
+
requested_size = ("1024x1792" if resolved_aspect_ratio == "9:16" else "1792x1024") if provider == "pollinations" else ("720x1280 minimum" if resolved_aspect_ratio == "9:16" else "1280x720 minimum")
|
|
343
349
|
constrained_prompt = _append_generation_constraints(
|
|
344
350
|
image_prompt,
|
|
345
351
|
kind="image",
|
|
346
|
-
aspect_ratio=
|
|
352
|
+
aspect_ratio=resolved_aspect_ratio,
|
|
347
353
|
size=requested_size,
|
|
348
354
|
)
|
|
349
355
|
constrained_prompt = _fit_provider_prompt(constrained_prompt, provider)
|
|
@@ -360,7 +366,7 @@ def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", letter
|
|
|
360
366
|
if style == "kie":
|
|
361
367
|
body = {
|
|
362
368
|
"model": _model(card),
|
|
363
|
-
"input": {"prompt": constrained_prompt, "aspect_ratio":
|
|
369
|
+
"input": {"prompt": constrained_prompt, "aspect_ratio": resolved_aspect_ratio, "resolution": "1K"},
|
|
364
370
|
}
|
|
365
371
|
return requests.post(endpoint, headers=_headers(card), json=body, timeout=180)
|
|
366
372
|
if provider == "agnes":
|
|
@@ -368,7 +374,7 @@ def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", letter
|
|
|
368
374
|
"model": _model(card) or AGNES_IMAGE_MODEL,
|
|
369
375
|
"prompt": constrained_prompt,
|
|
370
376
|
"size": "1K",
|
|
371
|
-
"ratio":
|
|
377
|
+
"ratio": resolved_aspect_ratio,
|
|
372
378
|
"return_base64": True,
|
|
373
379
|
"extra_body": {"response_format": "b64_json"},
|
|
374
380
|
}
|
|
@@ -377,12 +383,12 @@ def _image_request(card: dict[str, Any], prompt: str, *, topic: str = "", letter
|
|
|
377
383
|
return requests.post(
|
|
378
384
|
endpoint,
|
|
379
385
|
headers=_headers(card),
|
|
380
|
-
json={"model": _model(card), "prompt": constrained_prompt, "n": 1, "aspect_ratio":
|
|
386
|
+
json={"model": _model(card), "prompt": constrained_prompt, "n": 1, "aspect_ratio": resolved_aspect_ratio},
|
|
381
387
|
timeout=180,
|
|
382
388
|
)
|
|
383
389
|
body = {"model": _model(card), "prompt": constrained_prompt, "n": 1, "response_format": "b64_json"}
|
|
384
390
|
if provider == "pollinations":
|
|
385
|
-
body["size"] = "1024x1792" if
|
|
391
|
+
body["size"] = "1024x1792" if resolved_aspect_ratio == "9:16" else "1792x1024"
|
|
386
392
|
return requests.post(endpoint, headers=_headers(card), json=body, timeout=180)
|
|
387
393
|
|
|
388
394
|
|
|
@@ -397,6 +403,7 @@ def generate_image_for_card(
|
|
|
397
403
|
lettering_prompt: str = "",
|
|
398
404
|
reference_image: Path | None = None,
|
|
399
405
|
thumbnail_blueprint: Mapping[str, Any] | None = None,
|
|
406
|
+
aspect_ratio: str = "",
|
|
400
407
|
) -> Path:
|
|
401
408
|
"""Generate one image with the selected media card."""
|
|
402
409
|
card = _hydrate_media_card(settings, card)
|
|
@@ -439,7 +446,7 @@ def generate_image_for_card(
|
|
|
439
446
|
)
|
|
440
447
|
except Exception as exc:
|
|
441
448
|
raise MediaGenerationError(str(exc)) from exc
|
|
442
|
-
aspect_ratio = _thumbnail_aspect_ratio(thumbnail_blueprint, prompt)
|
|
449
|
+
aspect_ratio = _thumbnail_aspect_ratio(thumbnail_blueprint, prompt, aspect_ratio)
|
|
443
450
|
if provider == "nano_banana":
|
|
444
451
|
merged = dict(settings)
|
|
445
452
|
merged["gemini_image_api_key"] = _api_key(card)
|
|
@@ -498,7 +505,7 @@ def generate_image_for_card(
|
|
|
498
505
|
raise MediaGenerationError(f"Hugging Face text-to-image falhou: {str(exc)[:240]}") from exc
|
|
499
506
|
|
|
500
507
|
def request(current: dict[str, Any]) -> Any:
|
|
501
|
-
return _image_request(current, prompt, topic=topic, lettering_text=lettering_text, lettering_prompt=lettering_prompt, thumbnail_blueprint=thumbnail_blueprint)
|
|
508
|
+
return _image_request(current, prompt, topic=topic, lettering_text=lettering_text, lettering_prompt=lettering_prompt, thumbnail_blueprint=thumbnail_blueprint, aspect_ratio=aspect_ratio)
|
|
502
509
|
|
|
503
510
|
try:
|
|
504
511
|
routed = route_json_request(settings, pool=POOL_IMAGE, cards=[card], request=request)
|
|
@@ -542,6 +549,7 @@ def generate_image_from_pool(
|
|
|
542
549
|
reference_image: Path | None = None,
|
|
543
550
|
thumbnail_only: bool = False,
|
|
544
551
|
thumbnail_blueprint: Mapping[str, Any] | None = None,
|
|
552
|
+
aspect_ratio: str = "",
|
|
545
553
|
) -> Path:
|
|
546
554
|
"""Try eligible image cards in priority order, without cross-pool fallback."""
|
|
547
555
|
cards = media_cards_for_pool(settings, "image", thumbnail_only=True) if thumbnail_only else media_cards_for_pool(settings, "image")
|
|
@@ -560,6 +568,7 @@ def generate_image_from_pool(
|
|
|
560
568
|
lettering_prompt=lettering_prompt,
|
|
561
569
|
reference_image=reference_image,
|
|
562
570
|
thumbnail_blueprint=thumbnail_blueprint,
|
|
571
|
+
aspect_ratio=aspect_ratio,
|
|
563
572
|
)
|
|
564
573
|
except MediaGenerationError as exc:
|
|
565
574
|
errors.append(f"{card.get('provider')}: {str(exc)[:180]}")
|
|
@@ -33,7 +33,7 @@ from hermes_ui.media_generation import MediaGenerationError, _append_generation_
|
|
|
33
33
|
from hermes_ui.media_providers import FULL_IA_VIDEO_PROVIDER_CODES, media_cards_for_pool, media_provider_definition
|
|
34
34
|
from hermes_ui.material_sources import material_api_keys, material_source_cards, selected_material_source
|
|
35
35
|
from hermes_ui.thumbnail_generation import ThumbnailGenerationError, generate_thumbnail_image, infer_thumbnail_aspect_ratio
|
|
36
|
-
from hermes_ui.thumbnail_blueprints import thumbnail_blueprint_for_channel
|
|
36
|
+
from hermes_ui.thumbnail_blueprints import thumbnail_aspect_ratio_for_channel_task, thumbnail_blueprint_for_channel
|
|
37
37
|
from hermes_ui.voice_preview import synthesize_preview
|
|
38
38
|
|
|
39
39
|
PIPELINE_LOCK_FILENAME = "pipeline_worker.lock"
|
|
@@ -86,6 +86,7 @@ def _generate_pipeline_thumbnail(
|
|
|
86
86
|
lettering_text: str = "",
|
|
87
87
|
lettering_prompt: str = "",
|
|
88
88
|
thumbnail_blueprint: dict[str, Any] | None = None,
|
|
89
|
+
aspect_ratio: str = "",
|
|
89
90
|
) -> Path:
|
|
90
91
|
"""Use the image pool while keeping the legacy single-Nano call seam."""
|
|
91
92
|
cards = media_cards_for_pool(settings, "image")
|
|
@@ -97,7 +98,7 @@ def _generate_pipeline_thumbnail(
|
|
|
97
98
|
variant_index=variant_index,
|
|
98
99
|
lettering_text=lettering_text,
|
|
99
100
|
lettering_prompt=lettering_prompt,
|
|
100
|
-
aspect_ratio=infer_thumbnail_aspect_ratio(prompt, thumbnail_blueprint),
|
|
101
|
+
aspect_ratio=aspect_ratio or infer_thumbnail_aspect_ratio(prompt, thumbnail_blueprint),
|
|
101
102
|
)
|
|
102
103
|
return generate_image_from_pool(
|
|
103
104
|
settings,
|
|
@@ -107,6 +108,7 @@ def _generate_pipeline_thumbnail(
|
|
|
107
108
|
lettering_text=lettering_text,
|
|
108
109
|
lettering_prompt=lettering_prompt,
|
|
109
110
|
thumbnail_blueprint=thumbnail_blueprint,
|
|
111
|
+
aspect_ratio=aspect_ratio,
|
|
110
112
|
)
|
|
111
113
|
|
|
112
114
|
|
|
@@ -1356,6 +1358,7 @@ def _run_task(task: dict[str, Any]) -> dict[str, Any]:
|
|
|
1356
1358
|
blueprint = {"id": str(task.get("blueprint_id") or ""), "name": str(task.get("blueprint_name") or task.get("blueprint_id") or "")}
|
|
1357
1359
|
visual_format = task.get("format") or ("portrait" if str(task.get("platform") or "").casefold() in {"tiktok", "instagram"} else "wide")
|
|
1358
1360
|
visual_blueprint = thumbnail_blueprint_for_channel(channel, visual_format)
|
|
1361
|
+
thumbnail_aspect_ratio = thumbnail_aspect_ratio_for_channel_task(channel, task, visual_blueprint)
|
|
1359
1362
|
if visual_blueprint.get("content"):
|
|
1360
1363
|
blueprint = {**blueprint, "thumbnail_blueprint_rules": visual_blueprint["content"]}
|
|
1361
1364
|
route = _normalise_video_route(task, settings)
|
|
@@ -1549,8 +1552,8 @@ def _run_task(task: dict[str, Any]) -> dict[str, Any]:
|
|
|
1549
1552
|
"keywords": keywords,
|
|
1550
1553
|
"thumbnail": variant,
|
|
1551
1554
|
"requirements": {
|
|
1552
|
-
"aspect_ratio":
|
|
1553
|
-
"resolution": "
|
|
1555
|
+
"aspect_ratio": thumbnail_aspect_ratio,
|
|
1556
|
+
"resolution": "1024x1792" if thumbnail_aspect_ratio == "9:16" else "1792x1024",
|
|
1554
1557
|
"max_elements": 3,
|
|
1555
1558
|
"max_overlay_words": 4,
|
|
1556
1559
|
"lettering_required": True,
|
|
@@ -1589,6 +1592,7 @@ def _run_task(task: dict[str, Any]) -> dict[str, Any]:
|
|
|
1589
1592
|
lettering_text=str(variant.get("overlay_text") or ""),
|
|
1590
1593
|
lettering_prompt=str(variant.get("lettering_prompt") or ""),
|
|
1591
1594
|
thumbnail_blueprint=blueprint,
|
|
1595
|
+
aspect_ratio=thumbnail_aspect_ratio,
|
|
1592
1596
|
)
|
|
1593
1597
|
except (MediaGenerationError, ThumbnailGenerationError) as exc:
|
|
1594
1598
|
raise PipelineError(f"A thumbnail não foi gerada; o vídeo já está disponível em {video_path}: {exc}") from exc
|
|
@@ -89,6 +89,47 @@ def thumbnail_blueprint_for_task(channel: Mapping[str, Any], task: Mapping[str,
|
|
|
89
89
|
return thumbnail_blueprint_for_channel({**channel, "thumbnail_blueprint_id": ""}, format_value)
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
def thumbnail_aspect_ratio_for_channel_task(
|
|
93
|
+
channel: Mapping[str, Any] | None,
|
|
94
|
+
task: Mapping[str, Any] | None = None,
|
|
95
|
+
blueprint: Mapping[str, Any] | None = None,
|
|
96
|
+
) -> str:
|
|
97
|
+
"""Resolve thumbnail orientation consistently for new and persisted tasks.
|
|
98
|
+
|
|
99
|
+
A channel-specific blueprint remains authoritative. When no specific blueprint
|
|
100
|
+
exists, platform defaults are used: TikTok/Instagram are portrait and YouTube
|
|
101
|
+
is landscape. This deliberately ignores stale generic blueprint ids persisted
|
|
102
|
+
on older YouTube tasks.
|
|
103
|
+
"""
|
|
104
|
+
channel = channel or {}
|
|
105
|
+
task = task or {}
|
|
106
|
+
selected = dict(blueprint or {})
|
|
107
|
+
direct = str(
|
|
108
|
+
channel.get("default_thumbnail_blueprint_id")
|
|
109
|
+
or channel.get("thumbnail_blueprint_id")
|
|
110
|
+
or task.get("thumbnail_blueprint_id")
|
|
111
|
+
or ""
|
|
112
|
+
).strip()
|
|
113
|
+
generic_ids = {
|
|
114
|
+
"Generic_Thumbnail_Blueprint",
|
|
115
|
+
HORIZONTAL_GENERIC_THUMBNAIL_BLUEPRINT_ID,
|
|
116
|
+
VERTICAL_GENERIC_THUMBNAIL_BLUEPRINT_ID,
|
|
117
|
+
}
|
|
118
|
+
if not selected and direct and direct not in generic_ids:
|
|
119
|
+
selected = resolve_thumbnail_blueprint(direct)
|
|
120
|
+
if selected.get("content") and direct not in generic_ids:
|
|
121
|
+
return "9:16" if _contains_vertical_rules(selected.get("content")) else "16:9"
|
|
122
|
+
|
|
123
|
+
platform = str(channel.get("platform") or task.get("platform") or "").strip().casefold()
|
|
124
|
+
if platform in {"tiktok", "instagram", "instagram reels"}:
|
|
125
|
+
return "9:16"
|
|
126
|
+
return "16:9"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _contains_vertical_rules(value: Any) -> bool:
|
|
130
|
+
return bool(re.search(r"\b9\s*:\s*16\b|\bvertical\b|\bportrait\b", str(value or ""), flags=re.IGNORECASE))
|
|
131
|
+
|
|
132
|
+
|
|
92
133
|
def thumbnail_blueprint_for_blueprint(blueprint_id: Any, format_value: Any = "") -> dict[str, Any]:
|
|
93
134
|
"""Resolve the visual pair for a script Blueprint, falling back to Generic."""
|
|
94
135
|
paired_id = _pair_state().get(str(blueprint_id or "").strip(), "")
|
|
@@ -190,7 +190,7 @@ def generate_thumbnail_image(
|
|
|
190
190
|
reference_image: str | Path | None = None,
|
|
191
191
|
lettering_text: str = "",
|
|
192
192
|
lettering_prompt: str = "",
|
|
193
|
-
aspect_ratio: str =
|
|
193
|
+
aspect_ratio: str | None = None,
|
|
194
194
|
) -> Path:
|
|
195
195
|
api_key = str(settings.get("gemini_image_api_key") or "").strip()
|
|
196
196
|
if not api_key:
|
|
@@ -204,7 +204,7 @@ def generate_thumbnail_image(
|
|
|
204
204
|
lettering_text=lettering_text,
|
|
205
205
|
lettering_prompt=lettering_prompt,
|
|
206
206
|
)
|
|
207
|
-
effective_aspect_ratio = infer_thumbnail_aspect_ratio(clean_prompt
|
|
207
|
+
effective_aspect_ratio = aspect_ratio if aspect_ratio in {"16:9", "9:16"} else infer_thumbnail_aspect_ratio(clean_prompt)
|
|
208
208
|
|
|
209
209
|
model = str(settings.get("gemini_image_model") or DEFAULT_GEMINI_IMAGE_MODEL).strip()
|
|
210
210
|
image_size = DEFAULT_IMAGE_SIZE
|
package/hermes_ui/thumbnails.py
CHANGED
|
@@ -12,7 +12,7 @@ from .media_generation import generate_image_from_pool
|
|
|
12
12
|
from .media_providers import media_cards_for_pool
|
|
13
13
|
from .storage import STORAGE, ensure_storage, now, read_json, update_json, write_json
|
|
14
14
|
from .thumbnail_generation import ThumbnailGenerationError, generate_thumbnail_image, infer_thumbnail_aspect_ratio
|
|
15
|
-
from .thumbnail_blueprints import thumbnail_blueprint_for_task
|
|
15
|
+
from .thumbnail_blueprints import thumbnail_aspect_ratio_for_channel_task, thumbnail_blueprint_for_task
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def _generate_image_with_pool(
|
|
@@ -25,6 +25,7 @@ def _generate_image_with_pool(
|
|
|
25
25
|
lettering_prompt: str = "",
|
|
26
26
|
reference_image: Path | None = None,
|
|
27
27
|
thumbnail_blueprint: dict[str, Any] | None = None,
|
|
28
|
+
aspect_ratio: str = "",
|
|
28
29
|
) -> Path:
|
|
29
30
|
"""Use the legacy Nano adapter when it is the only active image card.
|
|
30
31
|
|
|
@@ -41,7 +42,7 @@ def _generate_image_with_pool(
|
|
|
41
42
|
reference_image=reference_image,
|
|
42
43
|
lettering_text=lettering_text,
|
|
43
44
|
lettering_prompt=lettering_prompt,
|
|
44
|
-
aspect_ratio=infer_thumbnail_aspect_ratio(prompt, thumbnail_blueprint),
|
|
45
|
+
aspect_ratio=aspect_ratio or infer_thumbnail_aspect_ratio(prompt, thumbnail_blueprint),
|
|
45
46
|
)
|
|
46
47
|
return generate_image_from_pool(
|
|
47
48
|
settings,
|
|
@@ -53,6 +54,7 @@ def _generate_image_with_pool(
|
|
|
53
54
|
lettering_prompt=lettering_prompt,
|
|
54
55
|
thumbnail_only=True,
|
|
55
56
|
thumbnail_blueprint=thumbnail_blueprint,
|
|
57
|
+
aspect_ratio=aspect_ratio,
|
|
56
58
|
)
|
|
57
59
|
|
|
58
60
|
|
|
@@ -271,6 +273,7 @@ def generate_thumbnail_for_task(
|
|
|
271
273
|
and bool(item.get("enabled", True))
|
|
272
274
|
for item in configured_cards
|
|
273
275
|
) if isinstance(configured_cards, list) else False
|
|
276
|
+
channel = {}
|
|
274
277
|
if not effective_blueprint:
|
|
275
278
|
channels = read_json("channels.json", [])
|
|
276
279
|
channel = next(
|
|
@@ -278,6 +281,7 @@ def generate_thumbnail_for_task(
|
|
|
278
281
|
{},
|
|
279
282
|
) if isinstance(channels, list) else {}
|
|
280
283
|
effective_blueprint = thumbnail_blueprint_for_task(channel, task)
|
|
284
|
+
aspect_ratio = thumbnail_aspect_ratio_for_channel_task(channel, task, effective_blueprint)
|
|
281
285
|
rules = str(effective_blueprint.get("content") or "").strip()
|
|
282
286
|
if canva_selected and not rules:
|
|
283
287
|
raise ThumbnailGenerationError("A tarefa não tem um Thumbnail Blueprint local válido.")
|
|
@@ -291,6 +295,7 @@ def generate_thumbnail_for_task(
|
|
|
291
295
|
lettering_text=record.get("thumbnail_text") or "",
|
|
292
296
|
lettering_prompt=record.get("lettering_prompt") or "",
|
|
293
297
|
thumbnail_blueprint=effective_blueprint,
|
|
298
|
+
aspect_ratio=aspect_ratio,
|
|
294
299
|
)
|
|
295
300
|
updated = _update_thumbnail_task(
|
|
296
301
|
task_id,
|
|
@@ -353,6 +358,7 @@ def regenerate_thumbnail_prompt_and_image(
|
|
|
353
358
|
{},
|
|
354
359
|
) if isinstance(channels, list) else {}
|
|
355
360
|
effective_blueprint = thumbnail_blueprint_for_task(channel, task)
|
|
361
|
+
aspect_ratio = thumbnail_aspect_ratio_for_channel_task(channel, task, effective_blueprint)
|
|
356
362
|
_archive_image(str(task_id), record.get("image_path"))
|
|
357
363
|
image_path = _generate_image_with_pool(
|
|
358
364
|
settings,
|
|
@@ -362,6 +368,7 @@ def regenerate_thumbnail_prompt_and_image(
|
|
|
362
368
|
lettering_text=str((variant or {}).get("overlay_text") or ""),
|
|
363
369
|
lettering_prompt=str((variant or {}).get("lettering_prompt") or ""),
|
|
364
370
|
thumbnail_blueprint=effective_blueprint,
|
|
371
|
+
aspect_ratio=aspect_ratio,
|
|
365
372
|
)
|
|
366
373
|
updated = _update_thumbnail_task(
|
|
367
374
|
task_id,
|
|
@@ -429,6 +436,7 @@ def regenerate_thumbnail_lettering(
|
|
|
429
436
|
"Não adicionar logótipos, marcas de água ou outros elementos."
|
|
430
437
|
)
|
|
431
438
|
_archive_image(str(task_id), previous_image)
|
|
439
|
+
lettering_blueprint = thumbnail_blueprint_for_task(resolved_channel, task)
|
|
432
440
|
image_path = _generate_image_with_pool(
|
|
433
441
|
settings,
|
|
434
442
|
combined_prompt,
|
|
@@ -437,7 +445,8 @@ def regenerate_thumbnail_lettering(
|
|
|
437
445
|
reference_image=previous_image,
|
|
438
446
|
lettering_text=exact_headline,
|
|
439
447
|
lettering_prompt=edit_prompt,
|
|
440
|
-
thumbnail_blueprint=
|
|
448
|
+
thumbnail_blueprint=lettering_blueprint,
|
|
449
|
+
aspect_ratio=thumbnail_aspect_ratio_for_channel_task(resolved_channel, task, lettering_blueprint),
|
|
441
450
|
)
|
|
442
451
|
variant = _variant_for_record(record)
|
|
443
452
|
variant["image_prompt"] = base_prompt
|
package/package.json
CHANGED