@danhachuel/thunderbolt 0.5.19 → 0.5.20
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.
|
@@ -27,7 +27,7 @@ def _payload(result: Mapping[str, Any]) -> Any:
|
|
|
27
27
|
|
|
28
28
|
def _items(value: Any) -> list[dict[str, Any]]:
|
|
29
29
|
if isinstance(value, Mapping):
|
|
30
|
-
for key in ("items", "designs", "results"):
|
|
30
|
+
for key in ("items", "designs", "results", "candidates"):
|
|
31
31
|
if isinstance(value.get(key), list):
|
|
32
32
|
return [dict(item) for item in value[key] if isinstance(item, Mapping)]
|
|
33
33
|
for key in ("data", "result", "response"):
|
|
@@ -38,6 +38,25 @@ def _items(value: Any) -> list[dict[str, Any]]:
|
|
|
38
38
|
return []
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def _first_named_id(value: Any, keys: tuple[str, ...]) -> str:
|
|
42
|
+
"""Find an ID by field name without treating unrelated nested IDs as matches."""
|
|
43
|
+
if isinstance(value, Mapping):
|
|
44
|
+
for key in keys:
|
|
45
|
+
candidate = str(value.get(key) or "").strip()
|
|
46
|
+
if candidate:
|
|
47
|
+
return candidate
|
|
48
|
+
for child in value.values():
|
|
49
|
+
found = _first_named_id(child, keys)
|
|
50
|
+
if found:
|
|
51
|
+
return found
|
|
52
|
+
elif isinstance(value, list):
|
|
53
|
+
for child in value:
|
|
54
|
+
found = _first_named_id(child, keys)
|
|
55
|
+
if found:
|
|
56
|
+
return found
|
|
57
|
+
return ""
|
|
58
|
+
|
|
59
|
+
|
|
41
60
|
def _design_id(value: Any) -> str:
|
|
42
61
|
"""Extract a Canva design identifier from REST/MCP result variants."""
|
|
43
62
|
if isinstance(value, Mapping):
|
|
@@ -167,7 +186,41 @@ def run_direct_canva_thumbnail(
|
|
|
167
186
|
content = candidate_content
|
|
168
187
|
break
|
|
169
188
|
if selected is None:
|
|
170
|
-
|
|
189
|
+
generate_name = "generate-design" if "generate-design" in available else "generate_design"
|
|
190
|
+
create_name = "create-design-from-candidate" if "create-design-from-candidate" in available else "create_design_from_candidate"
|
|
191
|
+
if generate_name not in available or create_name not in available:
|
|
192
|
+
raise CanvaMCPError("Os designs Canva encontrados não têm elementos de texto editáveis e esta sessão MCP não disponibiliza geração de design.")
|
|
193
|
+
blueprint_text = str(blueprint.get("content") or "")[:5000]
|
|
194
|
+
generated = _payload(client.call(generate_name, {
|
|
195
|
+
"design_type": "youtube_thumbnail",
|
|
196
|
+
"query": (
|
|
197
|
+
"Create one editable YouTube thumbnail in 16:9 format for this topic: "
|
|
198
|
+
f"{title}. Context: {topic}. Thumbnail prompt: {prompt[:1200]}. "
|
|
199
|
+
"Use clearly editable headline text boxes, a strong background, readable text "
|
|
200
|
+
"background shapes, relevant icons, depth/effects, and high-contrast lettering. "
|
|
201
|
+
"Follow these local Thumbnail Blueprint rules: " + blueprint_text
|
|
202
|
+
),
|
|
203
|
+
"user_intent": "Create an editable YouTube thumbnail with text boxes and visual elements when searched designs are not editable.",
|
|
204
|
+
}))
|
|
205
|
+
job_id = _first_named_id(generated, ("job_id", "jobId"))
|
|
206
|
+
generated_candidates = _items(generated)
|
|
207
|
+
candidate_id = _first_named_id(generated_candidates[0] if generated_candidates else {}, ("candidate_id", "candidateId"))
|
|
208
|
+
if not job_id or not candidate_id:
|
|
209
|
+
raise CanvaMCPError("Canva não devolveu um candidato editável para a thumbnail.")
|
|
210
|
+
created = _payload(client.call(create_name, {
|
|
211
|
+
"job_id": job_id,
|
|
212
|
+
"candidate_id": candidate_id,
|
|
213
|
+
"user_intent": "Create the selected editable YouTube thumbnail candidate in the user's Canva account.",
|
|
214
|
+
}))
|
|
215
|
+
design_id = _design_id(created)
|
|
216
|
+
if not design_id:
|
|
217
|
+
raise CanvaMCPError("Canva não devolveu o ID do design gerado.")
|
|
218
|
+
selected = {"id": design_id}
|
|
219
|
+
content = _payload(client.call(get_name, {
|
|
220
|
+
"design_id": design_id,
|
|
221
|
+
"content_types": ["richtexts"],
|
|
222
|
+
"user_intent": "Inspect the generated editable thumbnail before applying the final lettering.",
|
|
223
|
+
}))
|
|
171
224
|
design_id = _design_id(selected)
|
|
172
225
|
start_name = "start-editing-transaction" if "start-editing-transaction" in available else "start_editing_transaction"
|
|
173
226
|
started = _payload(client.call(start_name, {
|
package/package.json
CHANGED