@danhachuel/thunderbolt 0.2.62 → 0.2.64
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 +79 -29
- package/hermes_ui/storage.py +61 -0
- package/package.json +2 -1
- package/scripts/install.mjs +16 -0
- package/seed/prompt_masters/2Dstickman.md +193 -0
- package/seed/prompt_masters/3Dskeletoncharacter.md +1 -0
- package/seed/prompt_masters/ANIMALMOUNTEDCAMERA.md +299 -0
- package/seed/prompt_masters/ASMR.md +74 -0
- package/seed/prompt_masters/ASMRDEBOCACOMDOCES.md +130 -0
- package/seed/prompt_masters/AnimalX-Ray.md +136 -0
- package/seed/prompt_masters/CAREVOLUTION.md +176 -0
- package/seed/prompt_masters/CINEMATICBUNKERSURVIVAL.md +180 -0
- package/seed/prompt_masters/CINEMATICSLUMTRANSFORMATIONENGINE.md +212 -0
- package/seed/prompt_masters/CINEMATOGR/303/201FICOS3D.md +207 -0
- package/seed/prompt_masters/CartoonNostalgia.md +131 -0
- package/seed/prompt_masters/EPOXYFLOORTRANSFORMATION.md +254 -0
- package/seed/prompt_masters/Edgar'sHouseofTerrorsChooseYourStory.md +134 -0
- package/seed/prompt_masters/FOODBABYFACECHARACTER.md +141 -0
- package/seed/prompt_masters/FuitNovels.md +166 -0
- package/seed/prompt_masters/KIDSSTORYCREATOR(PROMODE).md +235 -0
- package/seed/prompt_masters/MatchstickPrompt.md +86 -0
- package/seed/prompt_masters/PERSONAGENSABANDONADOS.md +208 -0
- package/seed/prompt_masters/Pixar-styleanimated.md +193 -0
- package/seed/prompt_masters/RESTORATIONTIMELAPSE.md +262 -0
- package/seed/prompt_masters/RUSTREMOVAL.md +275 -0
- package/seed/prompt_masters/ReceitasIndianas.md +60 -0
- package/seed/prompt_masters/SkyscraperMonster.md +140 -0
- package/seed/prompt_masters/TIMETRAVELVLOG.md +264 -0
- package/seed/prompt_masters/Tarot.md +58 -0
- package/seed/prompt_masters/UFOs(OVNIs).md +63 -0
- package/seed/prompt_masters/VisualCraftSequenceGenerator.md +284 -0
- package/seed/prompt_masters/craftingStorytellingAI.md +79 -0
- package/seed/prompt_masters/hist/303/263riasinfantishoradedormir.md +71 -0
- package/seed/prompt_masters/viralTikTokdance.md +77 -0
- package/storage/tiktok/prompts_master/2Dstickman.md +193 -0
- package/storage/tiktok/prompts_master/3Dskeletoncharacter.md +1 -0
- package/storage/tiktok/prompts_master/ANIMALMOUNTEDCAMERA.md +299 -0
- package/storage/tiktok/prompts_master/ASMRDEBOCACOMDOCES.md +130 -0
- package/storage/tiktok/prompts_master/AnimalX-Ray.md +136 -0
- package/storage/tiktok/prompts_master/CAREVOLUTION.md +176 -0
- package/storage/tiktok/prompts_master/CINEMATICBUNKERSURVIVAL.md +180 -0
- package/storage/tiktok/prompts_master/CINEMATOGR/303/201FICOS3D.md +207 -0
- package/storage/tiktok/prompts_master/CartoonNostalgia.md +131 -0
- package/storage/tiktok/prompts_master/Edgar'sHouseofTerrorsChooseYourStory.md +134 -0
- package/storage/tiktok/prompts_master/FuitNovels.md +166 -0
- package/storage/tiktok/prompts_master/KIDSSTORYCREATOR(PROMODE).md +235 -0
- package/storage/tiktok/prompts_master/MatchstickPrompt.md +86 -0
- package/storage/tiktok/prompts_master/PERSONAGENSABANDONADOS.md +208 -0
- package/storage/tiktok/prompts_master/Pixar-styleanimated.md +193 -0
- package/storage/tiktok/prompts_master/RESTORATIONTIMELAPSE.md +262 -0
- package/storage/tiktok/prompts_master/RUSTREMOVAL.md +275 -0
- package/storage/tiktok/prompts_master/ReceitasIndianas.md +60 -0
- package/storage/tiktok/prompts_master/SkyscraperMonster.md +140 -0
- package/storage/tiktok/prompts_master/TIMETRAVELVLOG.md +264 -0
- package/storage/tiktok/prompts_master/Tarot.md +58 -0
- package/storage/tiktok/prompts_master/UFOs(OVNIs).md +63 -0
- package/storage/tiktok/prompts_master/VisualCraftSequenceGenerator.md +284 -0
- package/storage/tiktok/prompts_master/hist/303/263riasinfantishoradedormir.md +71 -0
- package/storage/tiktok/prompts_master/viralTikTokdance.md +77 -0
package/app/main.py
CHANGED
|
@@ -22,7 +22,7 @@ except (OSError, json.JSONDecodeError):
|
|
|
22
22
|
|
|
23
23
|
from hermes_ui.domain import STAGES, create_batch, create_channel, create_tasks_for_batch, delete_channel, pipeline_summary, set_channel_defaults, transition_task, update_channel, update_channel_video
|
|
24
24
|
from hermes_ui.automation_worker import load_worker_status
|
|
25
|
-
from hermes_ui.storage import BLUEPRINTS, STORAGE, TIKTOK_PROMPT_MASTERS, ensure_storage, list_blueprint_files, list_prompt_master_files, load_blueprint_file, load_prompt_master_file, now, read_json, write_json
|
|
25
|
+
from hermes_ui.storage import BLUEPRINTS, STORAGE, TIKTOK_PROMPT_MASTERS, ensure_storage, get_display_name, list_blueprint_files, list_prompt_master_files, load_blueprint_file, load_prompt_master_file, now, read_json, set_display_name, write_json
|
|
26
26
|
from app.modules.niche_finder.apify import ApifyError, DEFAULT_ACTOR_ID, abort_actor_run, build_actor_input, get_dataset_items, normalize_video_items, start_actor_run, wait_for_actor_run
|
|
27
27
|
from app.modules.niche_finder.core import NicheAnalysisError, run_niche_analysis
|
|
28
28
|
from app.modules.niche_finder.data_loader import DatasetError, download_kaggle_dataset
|
|
@@ -204,6 +204,41 @@ def card(label: str, value: str | int, note: str = ""):
|
|
|
204
204
|
st.markdown(f'<div class="content-card"><div class="content-label">{label}</div><div class="content-value">{value}</div><div class="small-muted">{note}</div></div>', unsafe_allow_html=True)
|
|
205
205
|
|
|
206
206
|
|
|
207
|
+
def _library_card_key(kind: str, path: Path) -> str:
|
|
208
|
+
return hashlib.sha1(f"{kind}:{path.resolve()}".encode("utf-8")).hexdigest()[:12]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _render_library_name_editor(kind: str, path: Path, current_name: str) -> str:
|
|
212
|
+
"""Render the inline name editor while keeping the physical filename unchanged."""
|
|
213
|
+
edit_key = f"rename_{kind}_{_library_card_key(kind, path)}"
|
|
214
|
+
if st.session_state.get(edit_key):
|
|
215
|
+
with st.form(f"{edit_key}_form", border=False):
|
|
216
|
+
edited_name = st.text_input("Nome de apresentação", value=current_name, max_chars=120, key=f"{edit_key}_input")
|
|
217
|
+
save_col, cancel_col = st.columns(2)
|
|
218
|
+
with save_col:
|
|
219
|
+
save_name = st.form_submit_button("Guardar nome", type="primary", use_container_width=True)
|
|
220
|
+
with cancel_col:
|
|
221
|
+
cancel_name = st.form_submit_button("Cancelar", use_container_width=True)
|
|
222
|
+
if save_name:
|
|
223
|
+
try:
|
|
224
|
+
set_display_name(kind, path, edited_name)
|
|
225
|
+
st.session_state.pop(edit_key, None)
|
|
226
|
+
st.success("Nome actualizado.")
|
|
227
|
+
st.rerun()
|
|
228
|
+
except ValueError as exc:
|
|
229
|
+
st.error(str(exc))
|
|
230
|
+
if cancel_name:
|
|
231
|
+
st.session_state.pop(edit_key, None)
|
|
232
|
+
st.rerun()
|
|
233
|
+
return edit_key
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _render_card_pencil(edit_key: str) -> None:
|
|
237
|
+
if st.button("✏️", help="Editar nome de apresentação", key=f"pencil_{edit_key}", type="tertiary", use_container_width=True):
|
|
238
|
+
st.session_state[edit_key] = True
|
|
239
|
+
st.rerun()
|
|
240
|
+
|
|
241
|
+
|
|
207
242
|
def channel_options() -> list[dict]:
|
|
208
243
|
return [c for c in read_json("channels.json", []) if c.get("active", True)]
|
|
209
244
|
|
|
@@ -214,7 +249,7 @@ def blueprint_catalog() -> list[tuple[str, str]]:
|
|
|
214
249
|
try:
|
|
215
250
|
data = load_blueprint_file(path)
|
|
216
251
|
identifier = str(data.get("id") or path.stem)
|
|
217
|
-
label = str(data.get("name") or path.stem)
|
|
252
|
+
label = get_display_name("blueprints", path, str(data.get("name") or data.get("title") or path.stem))
|
|
218
253
|
options.append((identifier, label))
|
|
219
254
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
220
255
|
continue
|
|
@@ -231,11 +266,11 @@ def blueprint_for_channel(channel: dict) -> dict[str, Any]:
|
|
|
231
266
|
data = load_blueprint_file(path)
|
|
232
267
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
233
268
|
continue
|
|
234
|
-
identifiers = {str(data.get("id") or ""), path.stem, str(data.get("name") or "")}
|
|
269
|
+
identifiers = {str(data.get("id") or ""), path.stem, str(data.get("name") or ""), get_display_name("blueprints", path, str(data.get("name") or path.stem))}
|
|
235
270
|
if blueprint_id in identifiers:
|
|
236
271
|
resolved = dict(data)
|
|
237
272
|
resolved.setdefault("id", blueprint_id)
|
|
238
|
-
resolved
|
|
273
|
+
resolved["name"] = get_display_name("blueprints", path, str(data.get("name") or path.stem))
|
|
239
274
|
return resolved
|
|
240
275
|
return {"id": blueprint_id, "name": blueprint_id}
|
|
241
276
|
|
|
@@ -665,14 +700,21 @@ def render_blueprints():
|
|
|
665
700
|
if not files:
|
|
666
701
|
st.info("Ainda não existem blueprints na pasta local.")
|
|
667
702
|
for path in files:
|
|
668
|
-
if search and search.lower() not in path.name.lower():
|
|
669
|
-
continue
|
|
670
703
|
try:
|
|
671
704
|
data = load_blueprint_file(path)
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
705
|
+
fallback_title = str(data.get("channel_name") or data.get("name") or data.get("title") or path.stem)
|
|
706
|
+
title = get_display_name("blueprints", path, fallback_title)
|
|
707
|
+
if search and search.lower() not in f"{title}\n{path.name}".lower():
|
|
708
|
+
continue
|
|
709
|
+
card_key = _library_card_key("blueprints", path)
|
|
710
|
+
header_cols = st.columns([0.93, 0.07], vertical_alignment="center")
|
|
711
|
+
with header_cols[0]:
|
|
712
|
+
with st.expander(f"{title} — {path.relative_to(BLUEPRINTS)}"):
|
|
713
|
+
st.caption(f"Ficheiro: {path}")
|
|
714
|
+
st.json(data)
|
|
715
|
+
with header_cols[1]:
|
|
716
|
+
_render_card_pencil(f"rename_blueprints_{card_key}")
|
|
717
|
+
_render_library_name_editor("blueprints", path, title)
|
|
676
718
|
except Exception as exc:
|
|
677
719
|
with st.expander(f"Inválido — {path.name}"):
|
|
678
720
|
st.error(str(exc))
|
|
@@ -752,7 +794,8 @@ def render_tiktok_prompt_masters():
|
|
|
752
794
|
content = load_prompt_master_file(path)
|
|
753
795
|
except (OSError, ValueError):
|
|
754
796
|
content = ""
|
|
755
|
-
|
|
797
|
+
display_heading = get_display_name("prompt_masters", path, next((line.lstrip("#").strip() for line in content.splitlines() if line.startswith("#")), path.stem))
|
|
798
|
+
if search and search.lower() not in f"{display_heading}\n{path.name}\n{content}".lower():
|
|
756
799
|
continue
|
|
757
800
|
visible_files.append(path)
|
|
758
801
|
if not visible_files:
|
|
@@ -760,24 +803,31 @@ def render_tiktok_prompt_masters():
|
|
|
760
803
|
for path in visible_files:
|
|
761
804
|
try:
|
|
762
805
|
content = load_prompt_master_file(path)
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
with
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
st.
|
|
779
|
-
|
|
780
|
-
|
|
806
|
+
fallback_heading = next((line.lstrip("#").strip() for line in content.splitlines() if line.startswith("#")), path.stem)
|
|
807
|
+
heading = get_display_name("prompt_masters", path, fallback_heading)
|
|
808
|
+
card_key = _library_card_key("prompt_masters", path)
|
|
809
|
+
header_cols = st.columns([0.93, 0.07], vertical_alignment="center")
|
|
810
|
+
with header_cols[0]:
|
|
811
|
+
with st.expander(f"{heading} — {path.name}", expanded=False):
|
|
812
|
+
st.caption(f"Ficheiro TikTok: `{path}`")
|
|
813
|
+
edited_content = st.text_area("Conteúdo Markdown", value=content, height=360, key=f"tiktok_prompt_master_editor_{path.stem}")
|
|
814
|
+
prompt_cols = st.columns(3)
|
|
815
|
+
with prompt_cols[0]:
|
|
816
|
+
if st.button("Guardar alterações", type="primary", use_container_width=True, key=f"save_prompt_master_{path.stem}"):
|
|
817
|
+
path.write_text(edited_content.rstrip() + "\n", encoding="utf-8")
|
|
818
|
+
st.success("Prompt Master actualizado.")
|
|
819
|
+
st.rerun()
|
|
820
|
+
with prompt_cols[1]:
|
|
821
|
+
st.download_button("Descarregar", data=content.encode("utf-8"), file_name=path.name, mime="text/markdown", use_container_width=True, key=f"download_prompt_master_{path.stem}")
|
|
822
|
+
with prompt_cols[2]:
|
|
823
|
+
if st.button("Apagar", use_container_width=True, key=f"delete_prompt_master_{path.stem}"):
|
|
824
|
+
path.unlink(missing_ok=True)
|
|
825
|
+
st.success("Prompt Master removido da biblioteca TikTok.")
|
|
826
|
+
st.rerun()
|
|
827
|
+
st.markdown(content)
|
|
828
|
+
with header_cols[1]:
|
|
829
|
+
_render_card_pencil(f"rename_prompt_masters_{card_key}")
|
|
830
|
+
_render_library_name_editor("prompt_masters", path, heading)
|
|
781
831
|
except (OSError, ValueError) as exc:
|
|
782
832
|
with st.expander(f"Ficheiro inválido — {path.name}"):
|
|
783
833
|
st.error(str(exc))
|
package/hermes_ui/storage.py
CHANGED
|
@@ -15,6 +15,7 @@ BLUEPRINTS = STORAGE / "blueprints"
|
|
|
15
15
|
TIKTOK_PROMPT_MASTERS = STORAGE / "tiktok" / "prompts_master"
|
|
16
16
|
NICHES_DATA = STORAGE / "data" / "niches"
|
|
17
17
|
SEED_BLUEPRINTS = ROOT / "seed" / "blueprints"
|
|
18
|
+
SEED_TIKTOK_PROMPT_MASTERS = ROOT / "seed" / "prompt_masters"
|
|
18
19
|
|
|
19
20
|
DEFAULTS: dict[str, Any] = {
|
|
20
21
|
"channels.json": [],
|
|
@@ -23,6 +24,7 @@ DEFAULTS: dict[str, Any] = {
|
|
|
23
24
|
"queues.json": {"niche": [], "blueprint": [], "brand": [], "script": [], "title": [], "thumbnail": [], "video": [], "edit": [], "upload": []},
|
|
24
25
|
"batches.json": [],
|
|
25
26
|
"uploads.json": [],
|
|
27
|
+
"display_names.json": {"blueprints": {}, "prompt_masters": {}},
|
|
26
28
|
"niche_apify_runs.json": [],
|
|
27
29
|
"metadata_edits.json": [],
|
|
28
30
|
"python_editor_edits.json": [],
|
|
@@ -239,10 +241,22 @@ def seed_blueprints() -> None:
|
|
|
239
241
|
shutil.copy2(source, target)
|
|
240
242
|
|
|
241
243
|
|
|
244
|
+
def seed_prompt_masters() -> None:
|
|
245
|
+
"""Copy packaged TikTok Prompt Masters without overwriting user files."""
|
|
246
|
+
if not SEED_TIKTOK_PROMPT_MASTERS.exists():
|
|
247
|
+
return
|
|
248
|
+
TIKTOK_PROMPT_MASTERS.mkdir(parents=True, exist_ok=True)
|
|
249
|
+
for source in sorted(SEED_TIKTOK_PROMPT_MASTERS.glob("*.md")):
|
|
250
|
+
target = TIKTOK_PROMPT_MASTERS / source.name
|
|
251
|
+
if not target.exists():
|
|
252
|
+
shutil.copy2(source, target)
|
|
253
|
+
|
|
254
|
+
|
|
242
255
|
def ensure_storage() -> None:
|
|
243
256
|
for path in [STATE, BLUEPRINTS / "canais", BLUEPRINTS / "nichos", BLUEPRINTS / "importados", BLUEPRINTS / "brandings", TIKTOK_PROMPT_MASTERS, STORAGE / "brand", STORAGE / "scripts", STORAGE / "thumbnails", STORAGE / "videos", STORAGE / "artifacts", STORAGE / "skills", STORAGE / "metadata_cleaner", STORAGE / "metadata_cleaner" / "outputs", STORAGE / "music", STORAGE / "voice_previews", STORAGE / "python_editor", NICHES_DATA]:
|
|
244
257
|
path.mkdir(parents=True, exist_ok=True)
|
|
245
258
|
seed_blueprints()
|
|
259
|
+
seed_prompt_masters()
|
|
246
260
|
for filename, default in DEFAULTS.items():
|
|
247
261
|
target = STATE / filename
|
|
248
262
|
if not target.exists():
|
|
@@ -293,6 +307,53 @@ def append_json(name: str, item: dict[str, Any]) -> dict[str, Any]:
|
|
|
293
307
|
return item
|
|
294
308
|
|
|
295
309
|
|
|
310
|
+
def _display_name_key(kind: str, path: Path) -> str:
|
|
311
|
+
"""Return a stable storage-relative key without renaming the physical file."""
|
|
312
|
+
resolved = path.resolve()
|
|
313
|
+
if kind == "blueprints":
|
|
314
|
+
root = BLUEPRINTS.resolve()
|
|
315
|
+
try:
|
|
316
|
+
return resolved.relative_to(root).as_posix()
|
|
317
|
+
except ValueError as exc:
|
|
318
|
+
raise ValueError("O ficheiro não pertence ao storage de Blueprints.") from exc
|
|
319
|
+
if kind == "prompt_masters":
|
|
320
|
+
root = TIKTOK_PROMPT_MASTERS.resolve()
|
|
321
|
+
try:
|
|
322
|
+
return resolved.relative_to(root).as_posix()
|
|
323
|
+
except ValueError as exc:
|
|
324
|
+
raise ValueError("O ficheiro não pertence ao storage de Prompt Masters.") from exc
|
|
325
|
+
raise ValueError(f"Tipo de biblioteca inválido: {kind}")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def get_display_name(kind: str, path: Path, fallback: str) -> str:
|
|
329
|
+
names = read_json("display_names.json", {"blueprints": {}, "prompt_masters": {}})
|
|
330
|
+
if not isinstance(names, dict):
|
|
331
|
+
return fallback
|
|
332
|
+
entries = names.get(kind, {})
|
|
333
|
+
if not isinstance(entries, dict):
|
|
334
|
+
return fallback
|
|
335
|
+
value = str(entries.get(_display_name_key(kind, path)) or "").strip()
|
|
336
|
+
return value or fallback
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def set_display_name(kind: str, path: Path, name: str) -> str:
|
|
340
|
+
clean_name = " ".join(str(name).split()).strip()
|
|
341
|
+
if not clean_name:
|
|
342
|
+
raise ValueError("Informe um nome para a biblioteca.")
|
|
343
|
+
if len(clean_name) > 120:
|
|
344
|
+
raise ValueError("O nome deve ter no máximo 120 caracteres.")
|
|
345
|
+
names = read_json("display_names.json", {"blueprints": {}, "prompt_masters": {}})
|
|
346
|
+
if not isinstance(names, dict):
|
|
347
|
+
names = {"blueprints": {}, "prompt_masters": {}}
|
|
348
|
+
entries = names.get(kind)
|
|
349
|
+
if not isinstance(entries, dict):
|
|
350
|
+
entries = {}
|
|
351
|
+
names[kind] = entries
|
|
352
|
+
entries[_display_name_key(kind, path)] = clean_name
|
|
353
|
+
write_json("display_names.json", names)
|
|
354
|
+
return clean_name
|
|
355
|
+
|
|
356
|
+
|
|
296
357
|
def list_blueprint_files() -> list[Path]:
|
|
297
358
|
ensure_storage()
|
|
298
359
|
return sorted(BLUEPRINTS.rglob("*.json"), key=lambda p: p.stat().st_mtime, reverse=True)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danhachuel/thunderbolt",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.64",
|
|
4
4
|
"description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
|
|
5
5
|
"main": "scripts/cli.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"scripts/*.mjs",
|
|
17
17
|
"storage/blueprints/**/*.json",
|
|
18
18
|
"storage/tiktok/prompts_master/**/*.md",
|
|
19
|
+
"seed/prompt_masters/**/*.md",
|
|
19
20
|
"seed/blueprints/**/*.json",
|
|
20
21
|
"seed/skills/*.md",
|
|
21
22
|
"seed/references/*.md",
|
package/scripts/install.mjs
CHANGED
|
@@ -103,6 +103,8 @@ function ensureDirs() {
|
|
|
103
103
|
join(storageRoot, "blueprints", "nichos"),
|
|
104
104
|
join(storageRoot, "blueprints", "importados"),
|
|
105
105
|
join(storageRoot, "blueprints", "brandings"),
|
|
106
|
+
join(storageRoot, "tiktok"),
|
|
107
|
+
join(storageRoot, "tiktok", "prompts_master"),
|
|
106
108
|
join(storageRoot, "metadata_cleaner"),
|
|
107
109
|
join(storageRoot, "metadata_cleaner", "originals"),
|
|
108
110
|
join(storageRoot, "metadata_cleaner", "outputs"),
|
|
@@ -115,6 +117,7 @@ function ensureDirs() {
|
|
|
115
117
|
];
|
|
116
118
|
for (const directory of directories) mkdirSync(directory, { recursive: true });
|
|
117
119
|
copySeedBlueprints(storageRoot);
|
|
120
|
+
copySeedPromptMasters(storageRoot);
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
function copySeedBlueprints(storageRoot) {
|
|
@@ -129,6 +132,19 @@ function copySeedBlueprints(storageRoot) {
|
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
|
|
135
|
+
function copySeedPromptMasters(storageRoot) {
|
|
136
|
+
const seedRoot = join(root, "seed", "prompt_masters");
|
|
137
|
+
const destination = join(storageRoot, "tiktok", "prompts_master");
|
|
138
|
+
if (!existsSync(seedRoot)) return;
|
|
139
|
+
mkdirSync(destination, { recursive: true });
|
|
140
|
+
for (const filename of readdirSync(seedRoot)) {
|
|
141
|
+
if (!filename.endsWith(".md")) continue;
|
|
142
|
+
const source = join(seedRoot, filename);
|
|
143
|
+
const target = join(destination, filename);
|
|
144
|
+
if (!existsSync(target)) copyFileSync(source, target);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
132
148
|
function copyOrMove(source, target, label) {
|
|
133
149
|
if (!existsSync(source) || existsSync(target)) return false;
|
|
134
150
|
mkdirSync(dirname(target), { recursive: true });
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Você é um engenheiro de prompts especializado em geração de prompts de imagem cinematográficos para um estilo 2D stickman documentary desenhado à mão.
|
|
2
|
+
|
|
3
|
+
Seu trabalho é transformar UMA única entrada do usuário (ideia, roteiro curto ou descrição de imagem) em EXATAMENTE 7 prompts de geração de imagem altamente estruturados, seguindo rigorosamente as regras abaixo.
|
|
4
|
+
|
|
5
|
+
O objetivo é gerar prompts consistentes, cinematográficos e visualmente coerentes, com continuidade de mundo, personagens e objetos.
|
|
6
|
+
|
|
7
|
+
REGRAS ABSOLUTAS
|
|
8
|
+
Você deve produzir EXATAMENTE 7 prompts
|
|
9
|
+
Nunca gere mais
|
|
10
|
+
Nunca gere menos
|
|
11
|
+
Cada prompt deve conter 3 partes obrigatórias
|
|
12
|
+
|
|
13
|
+
A) Título do Shot com emoji
|
|
14
|
+
|
|
15
|
+
Formato obrigatório:
|
|
16
|
+
|
|
17
|
+
[EMOJI] — (Main / B-roll / Establishing / Detail) — (Characters Included / No Characters) — [Resumo rápido da ação]
|
|
18
|
+
|
|
19
|
+
Exemplo
|
|
20
|
+
|
|
21
|
+
🎬 — Main — Characters Included — stickman tentando resolver um problema
|
|
22
|
+
|
|
23
|
+
B) Bloco de prompt dentro de código
|
|
24
|
+
|
|
25
|
+
O prompt deve estar dentro de um bloco de código.
|
|
26
|
+
|
|
27
|
+
O texto NÃO pode conter emojis.
|
|
28
|
+
|
|
29
|
+
C) CTA final
|
|
30
|
+
|
|
31
|
+
Cada prompt deve terminar com o mesmo CTA.
|
|
32
|
+
|
|
33
|
+
ESTRUTURA GLOBAL DOS 7 PROMPTS
|
|
34
|
+
|
|
35
|
+
Sempre gerar nesta ordem:
|
|
36
|
+
|
|
37
|
+
1️⃣ Main Scene (Characters Included)
|
|
38
|
+
|
|
39
|
+
2️⃣ B-roll 1 (Characters Included)
|
|
40
|
+
|
|
41
|
+
3️⃣ B-roll 2 (Characters Included)
|
|
42
|
+
|
|
43
|
+
4️⃣ B-roll 3 (Characters Included)
|
|
44
|
+
|
|
45
|
+
5️⃣ B-roll 4 (Characters Included)
|
|
46
|
+
|
|
47
|
+
6️⃣ Establishing Shot (No Characters)
|
|
48
|
+
|
|
49
|
+
7️⃣ Detail Shot (No Characters)
|
|
50
|
+
|
|
51
|
+
REGRA DE CONTINUIDADE VISUAL
|
|
52
|
+
|
|
53
|
+
Todos os prompts devem manter:
|
|
54
|
+
|
|
55
|
+
mesmo personagem
|
|
56
|
+
mesmas roupas
|
|
57
|
+
mesmo ambiente
|
|
58
|
+
mesmos objetos
|
|
59
|
+
mesmo estilo visual
|
|
60
|
+
|
|
61
|
+
Se o usuário fornecer pouca informação, assumir:
|
|
62
|
+
|
|
63
|
+
1 personagem
|
|
64
|
+
roupas simples
|
|
65
|
+
ambiente neutro
|
|
66
|
+
iluminação natural suave
|
|
67
|
+
dia claro
|
|
68
|
+
TEMPLATE — PERSONAGENS (USAR EM 5 PROMPTS)
|
|
69
|
+
|
|
70
|
+
Use este modelo estrutural:
|
|
71
|
+
|
|
72
|
+
A clean 2D cartoon illustration in a simple, minimal cartoon style with a flat digital look.
|
|
73
|
+
|
|
74
|
+
Scene: [ENVIRONMENT], [TIME OF DAY], [WEATHER OR LIGHTING].
|
|
75
|
+
|
|
76
|
+
Camera: [SHOT TYPE], [CAMERA ANGLE], [FRAMING].
|
|
77
|
+
|
|
78
|
+
Characters: [NUMBER] stick-figure characters with BIG ROUND HEADS that are ALWAYS PURE WHITE, tiny dot eyes, minimal simple mouth, simple eyebrows if needed.
|
|
79
|
+
|
|
80
|
+
The body is simple and minimal. Arms, legs, and hands are BLACK stick-line outlines made from simple curved lines, never filled.
|
|
81
|
+
|
|
82
|
+
Clothing and accessories are simple flat shapes with solid colors: [CLOTHING / PROPS].
|
|
83
|
+
|
|
84
|
+
Action: [WHAT IS HAPPENING].
|
|
85
|
+
|
|
86
|
+
Mood: [EMOTION / ATMOSPHERE].
|
|
87
|
+
|
|
88
|
+
Background: simple clean shapes, flat muted colors, solid fills, crisp edges, uniform line weight, clean readable composition.
|
|
89
|
+
|
|
90
|
+
No sketch lines. No brush texture. No paper texture.
|
|
91
|
+
|
|
92
|
+
TEMPLATE — SEM PERSONAGENS (USAR EM 2 PROMPTS)
|
|
93
|
+
|
|
94
|
+
A clean 2D cartoon illustration with a flat digital style matching the same visual look.
|
|
95
|
+
|
|
96
|
+
Subject: [OBJECT OR EMPTY ENVIRONMENT].
|
|
97
|
+
|
|
98
|
+
Scene/Setting: [LOCATION DETAILS], [TIME OF DAY], [LIGHTING].
|
|
99
|
+
|
|
100
|
+
Camera: [SHOT TYPE], [ANGLE], [FRAMING], [DEPTH STYLE].
|
|
101
|
+
|
|
102
|
+
Foreground elements (optional): [OBJECTS / PROPS].
|
|
103
|
+
|
|
104
|
+
Material/style notes: flat digital illustration, solid fills, crisp edges, uniform line weight, minimal detail.
|
|
105
|
+
|
|
106
|
+
No realism, no 3D look, no painterly shading, no watercolor, no paper texture.
|
|
107
|
+
|
|
108
|
+
Key visual elements that must appear:
|
|
109
|
+
|
|
110
|
+
[Detail 1]
|
|
111
|
+
[Detail 2]
|
|
112
|
+
[Detail 3]
|
|
113
|
+
[Detail 4]
|
|
114
|
+
REGRAS DE CINEMATOGRAFIA
|
|
115
|
+
|
|
116
|
+
Varie os enquadramentos:
|
|
117
|
+
|
|
118
|
+
Use combinações como:
|
|
119
|
+
|
|
120
|
+
wide shot
|
|
121
|
+
medium shot
|
|
122
|
+
close-up
|
|
123
|
+
over-the-shoulder
|
|
124
|
+
side angle
|
|
125
|
+
top-down
|
|
126
|
+
low angle
|
|
127
|
+
REGRAS DE B-ROLL
|
|
128
|
+
|
|
129
|
+
Os 4 B-roll devem mostrar:
|
|
130
|
+
|
|
131
|
+
reação do personagem
|
|
132
|
+
ação secundária
|
|
133
|
+
movimento ou transição
|
|
134
|
+
momento de preparação ou reflexão
|
|
135
|
+
REGRAS DE ESTABLISHING SHOT
|
|
136
|
+
|
|
137
|
+
Mostrar:
|
|
138
|
+
|
|
139
|
+
o ambiente inteiro
|
|
140
|
+
sem personagens
|
|
141
|
+
contexto da história
|
|
142
|
+
REGRAS DE DETAIL SHOT
|
|
143
|
+
|
|
144
|
+
Mostrar:
|
|
145
|
+
|
|
146
|
+
um objeto importante
|
|
147
|
+
close-up
|
|
148
|
+
foco narrativo
|
|
149
|
+
FORMATO FINAL DE SAÍDA
|
|
150
|
+
|
|
151
|
+
Cada prompt deve seguir EXATAMENTE este formato:
|
|
152
|
+
|
|
153
|
+
[TÍTULO COM EMOJI]
|
|
154
|
+
|
|
155
|
+
PROMPT COMPLETO
|
|
156
|
+
|
|
157
|
+
✨ You can create these images and videos in OpenArt
|
|
158
|
+
🎙 Add cinematic voice-overs using ElevenLabs
|
|
159
|
+
|
|
160
|
+
PROCESSO INTERNO (NÃO MOSTRAR AO USUÁRIO)
|
|
161
|
+
Identificar tipo de entrada
|
|
162
|
+
ideia
|
|
163
|
+
script
|
|
164
|
+
imagem
|
|
165
|
+
Definir
|
|
166
|
+
personagem
|
|
167
|
+
cenário
|
|
168
|
+
objetos
|
|
169
|
+
ação principal
|
|
170
|
+
Criar storyboard implícito
|
|
171
|
+
Converter storyboard em 7 prompts
|
|
172
|
+
OBJETIVO DE QUALIDADE
|
|
173
|
+
|
|
174
|
+
Os prompts devem:
|
|
175
|
+
|
|
176
|
+
ser claros
|
|
177
|
+
ser consistentes
|
|
178
|
+
evitar ambiguidades
|
|
179
|
+
produzir imagens visualmente coerentes
|
|
180
|
+
funcionar em Midjourney, DALL·E, Stable Diffusion, OpenArt
|
|
181
|
+
RESULTADO ESPERADO
|
|
182
|
+
|
|
183
|
+
A saída deve parecer um mini storyboard cinematográfico completo.
|
|
184
|
+
|
|
185
|
+
Se quiser, também posso te entregar versões ainda mais poderosas, como:
|
|
186
|
+
|
|
187
|
+
Versão 10x mais consistente para IA (Prompt Compiler)
|
|
188
|
+
Versão otimizada para OpenArt
|
|
189
|
+
Versão otimizada para Midjourney
|
|
190
|
+
Versão que gera 30 cenas automáticas
|
|
191
|
+
Versão usada por canais dark de YouTube
|
|
192
|
+
|
|
193
|
+
Todas com consistência >98% de replicação.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are a professional cinematic prompt generator specialized in 3D skeleton character scenes. Your task is to convert any user idea, phrase, script, or concept into a deterministic structured output that always produces the same format and logic with extremely high consistency. The skeleton character must always remain visually identical across all scenes according to an external reference image chosen by the user, maintaining the same proportions, style, and design in every generated prompt. The output must always contain exactly one main cinematic scene followed by five supporting cinematic b-roll prompts that visually expand the story of the main scene. Every prompt must begin strictly with the phrase “Place the skeleton character…” and must describe a clear environment, the skeleton’s action or pose, a cinematic lighting style, and a defined camera angle or shot composition. The prompts must be concise, visual, and optimized for high-quality 3D rendering engines. The main scene establishes the primary action derived from the user’s idea. The five b-roll prompts must represent complementary visual moments such as alternate angles, close-ups, movement shots, environmental interactions, atmospheric shots, or narrative supporting visuals that enrich the story while maintaining the same skeleton character design. Every prompt must explicitly reference cinematic lighting such as soft daylight, dramatic rim lighting, warm interior lighting, sunset lighting, neon glow, volumetric lighting, or moody studio light, and must include a camera perspective such as wide shot, close-up, over-the-shoulder, low angle, tracking shot, medium shot, or cinematic perspective. The environment description should include subtle atmospheric elements when appropriate such as fog, dust particles, reflections, light rays, depth of field, motion blur, or environmental glow to increase realism. All prompts must always end with a phrase indicating that the result is rendered in clean cinematic 3D, highly detailed. The structure, order, and logic of the generated output must remain stable across generations to guarantee near-identical formatting and behavior, ensuring deterministic outputs where the main scene appears first and the five b-roll prompts follow sequentially with the same stylistic logic, maintaining clarity, cinematic language, and structural consistency suitable for AI image and video generation pipelines designed for OpenArt visual creation and ElevenLabs cinematic narration.
|