@danhachuel/thunderbolt 0.6.0 → 0.6.2
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 +48 -2
- package/hermes_ui/domain.py +26 -1
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -703,9 +703,14 @@ def generate_video_content_for_ui(
|
|
|
703
703
|
blueprint: dict[str, Any] | None = None,
|
|
704
704
|
) -> dict[str, Any]:
|
|
705
705
|
"""Generate the subject, script and English keywords in one MoneyPrinter-style action."""
|
|
706
|
-
|
|
706
|
+
entered_subject = str(subject or "").strip()
|
|
707
|
+
subject = entered_subject
|
|
707
708
|
topic_result: dict[str, Any] | None = None
|
|
708
|
-
if
|
|
709
|
+
if entered_subject:
|
|
710
|
+
# Um Video Subject escrito pelo utilizador é sempre o tema editorial;
|
|
711
|
+
# nunca o substituímos por um tópico aleatório gerado pela IA.
|
|
712
|
+
subject = entered_subject
|
|
713
|
+
else:
|
|
709
714
|
selected_blueprint = blueprint if isinstance(blueprint, dict) else blueprint_for_channel(channel)
|
|
710
715
|
topic_result = generate_topic_for_channel(settings, channel, selected_blueprint)
|
|
711
716
|
subject = str(topic_result.get("topic") or "").strip()
|
|
@@ -1311,6 +1316,45 @@ def render_channel_videos(channel: dict) -> None:
|
|
|
1311
1316
|
render_channel_video_editor(video, channel_id)
|
|
1312
1317
|
|
|
1313
1318
|
|
|
1319
|
+
def render_channel_audio_subtitle_defaults(channel: dict) -> None:
|
|
1320
|
+
"""Render and persist the audio/subtitle defaults used by channel automations."""
|
|
1321
|
+
channel_id = str(channel.get("id") or "")
|
|
1322
|
+
subtitle_font = str(channel.get("default_subtitle_font") or SUBTITLE_FONT_OPTIONS[0])
|
|
1323
|
+
subtitle_position = str(channel.get("default_subtitle_position") or SUBTITLE_POSITION_OPTIONS[0])
|
|
1324
|
+
music_source = str(channel.get("default_background_music_source") or "Sem música")
|
|
1325
|
+
music_volume = str(channel.get("default_background_music_volume") or "20%")
|
|
1326
|
+
with st.expander("Configurações de legendas", expanded=False):
|
|
1327
|
+
subtitle_cols = st.columns(2)
|
|
1328
|
+
with subtitle_cols[0]:
|
|
1329
|
+
enable_subtitles = st.checkbox("Enable Subtitles", value=bool(channel.get("default_enable_subtitles", True)), key=f"channel_default_subtitles_{channel_id}")
|
|
1330
|
+
selected_font = st.selectbox("Font", SUBTITLE_FONT_OPTIONS, index=SUBTITLE_FONT_OPTIONS.index(subtitle_font) if subtitle_font in SUBTITLE_FONT_OPTIONS else 0, key=f"channel_default_subtitle_font_{channel_id}")
|
|
1331
|
+
selected_position = st.selectbox("Position", SUBTITLE_POSITION_OPTIONS, index=SUBTITLE_POSITION_OPTIONS.index(subtitle_position) if subtitle_position in SUBTITLE_POSITION_OPTIONS else 0, key=f"channel_default_subtitle_position_{channel_id}")
|
|
1332
|
+
subtitle_color = st.color_picker("Color", str(channel.get("default_subtitle_color") or "#FFFFFF"), key=f"channel_default_subtitle_color_{channel_id}")
|
|
1333
|
+
subtitle_background = st.checkbox("Background", value=bool(channel.get("default_subtitle_background", True)), key=f"channel_default_subtitle_background_{channel_id}")
|
|
1334
|
+
subtitle_background_color = st.color_picker("Background Color", str(channel.get("default_subtitle_background_color") or "#000000"), key=f"channel_default_subtitle_background_color_{channel_id}")
|
|
1335
|
+
subtitle_rounded_background = st.checkbox("Rounded Background", value=bool(channel.get("default_subtitle_rounded_background", False)), key=f"channel_default_subtitle_rounded_background_{channel_id}")
|
|
1336
|
+
with subtitle_cols[1]:
|
|
1337
|
+
subtitle_font_size = st.slider("Font Size", min_value=12, max_value=96, value=int(channel.get("default_subtitle_font_size") or 60), key=f"channel_default_subtitle_font_size_{channel_id}")
|
|
1338
|
+
subtitle_outline = st.color_picker("Outline", str(channel.get("default_subtitle_outline") or "#000000"), key=f"channel_default_subtitle_outline_{channel_id}")
|
|
1339
|
+
subtitle_outline_width = st.slider("Outline Width", min_value=0.0, max_value=5.0, value=float(channel.get("default_subtitle_outline_width") or 1.5), step=0.25, key=f"channel_default_subtitle_outline_width_{channel_id}")
|
|
1340
|
+
if st.button("Guardar configurações de legendas", type="primary", key=f"save_channel_subtitle_defaults_{channel_id}", use_container_width=True):
|
|
1341
|
+
update_channel(channel_id, {
|
|
1342
|
+
"default_enable_subtitles": bool(enable_subtitles), "default_subtitle_font": selected_font, "default_subtitle_position": selected_position,
|
|
1343
|
+
"default_subtitle_color": subtitle_color, "default_subtitle_background": bool(subtitle_background), "default_subtitle_background_color": subtitle_background_color,
|
|
1344
|
+
"default_subtitle_rounded_background": bool(subtitle_rounded_background), "default_subtitle_font_size": int(subtitle_font_size),
|
|
1345
|
+
"default_subtitle_outline": subtitle_outline, "default_subtitle_outline_width": float(subtitle_outline_width),
|
|
1346
|
+
})
|
|
1347
|
+
st.success("Default de legendas guardado para este canal.")
|
|
1348
|
+
st.rerun()
|
|
1349
|
+
with st.expander("Configurações de Audio", expanded=False):
|
|
1350
|
+
selected_music_source = st.selectbox("Fonte da música de fundo", BACKGROUND_MUSIC_SOURCE_OPTIONS, index=BACKGROUND_MUSIC_SOURCE_OPTIONS.index(music_source) if music_source in BACKGROUND_MUSIC_SOURCE_OPTIONS else BACKGROUND_MUSIC_SOURCE_OPTIONS.index("Sem música"), key=f"channel_default_music_source_{channel_id}")
|
|
1351
|
+
selected_music_volume = st.selectbox("Volume da música de fundo", BACKGROUND_MUSIC_VOLUME_OPTIONS, index=BACKGROUND_MUSIC_VOLUME_OPTIONS.index(music_volume) if music_volume in BACKGROUND_MUSIC_VOLUME_OPTIONS else 2, key=f"channel_default_music_volume_{channel_id}")
|
|
1352
|
+
if st.button("Guardar configurações de Audio", type="primary", key=f"save_channel_audio_defaults_{channel_id}", use_container_width=True):
|
|
1353
|
+
update_channel(channel_id, {"default_background_music_source": selected_music_source, "default_background_music_volume": selected_music_volume})
|
|
1354
|
+
st.success("Default de Audio guardado para este canal.")
|
|
1355
|
+
st.rerun()
|
|
1356
|
+
|
|
1357
|
+
|
|
1314
1358
|
def render_channel_edit_form(channel: dict, youtube_account_ids: list[str], youtube_account_labels: dict[str, str], youtube_accounts_by_id: dict[str, dict[str, Any]]) -> None:
|
|
1315
1359
|
channel_id = str(channel["id"])
|
|
1316
1360
|
blueprint_ids, blueprint_labels, current_blueprint, voice_options, current_voice = channel_default_options(channel)
|
|
@@ -2341,6 +2385,7 @@ def render_tiktok_channels():
|
|
|
2341
2385
|
update_channel(channel_id, {"name": edit_name.strip(), "url": edit_url.strip(), "handle": edit_handle.strip(), "language": edit_language, "niche": edit_niche.strip(), "reference_channels": [edit_niche.strip()] if edit_niche.strip() else [], "default_voice": edit_voice, "voice": edit_voice, "style_wide": channel_video_source_storage(edit_source), "video_aspect_ratio": edit_aspect, "automation_on": edit_automation, "automation_time": edit_time.strip(), "description": edit_description.strip(), "platform": "tiktok"})
|
|
2342
2386
|
st.session_state.pop(f"tiktok_edit_{channel_id}", None)
|
|
2343
2387
|
st.rerun()
|
|
2388
|
+
render_channel_audio_subtitle_defaults(channel)
|
|
2344
2389
|
with st.expander("Últimos 10 vídeos publicados", expanded=False):
|
|
2345
2390
|
recent_videos = channel_videos_for(channel, limit=10)
|
|
2346
2391
|
if not recent_videos:
|
|
@@ -3032,6 +3077,7 @@ def render_channels():
|
|
|
3032
3077
|
st.success("Conta Google e DELEGATED_SESSION_ID individual do canal guardados.")
|
|
3033
3078
|
st.rerun()
|
|
3034
3079
|
|
|
3080
|
+
render_channel_audio_subtitle_defaults(channel)
|
|
3035
3081
|
render_channel_videos(channel)
|
|
3036
3082
|
|
|
3037
3083
|
|
package/hermes_ui/domain.py
CHANGED
|
@@ -53,6 +53,18 @@ def create_channel(name: str, url: str = "", metadata: dict[str, Any] | None = N
|
|
|
53
53
|
"style_wide": "pexels",
|
|
54
54
|
"voice": "",
|
|
55
55
|
"default_voice": "",
|
|
56
|
+
"default_enable_subtitles": True,
|
|
57
|
+
"default_subtitle_font": "MicrosoftYaHeiBold.ttc",
|
|
58
|
+
"default_subtitle_position": "Bottom (Recommended)",
|
|
59
|
+
"default_subtitle_color": "#FFFFFF",
|
|
60
|
+
"default_subtitle_background": True,
|
|
61
|
+
"default_subtitle_background_color": "#000000",
|
|
62
|
+
"default_subtitle_rounded_background": False,
|
|
63
|
+
"default_subtitle_font_size": 60,
|
|
64
|
+
"default_subtitle_outline": "#000000",
|
|
65
|
+
"default_subtitle_outline_width": 1.5,
|
|
66
|
+
"default_background_music_source": "Sem música",
|
|
67
|
+
"default_background_music_volume": "20%",
|
|
56
68
|
"delegated_session_id": "",
|
|
57
69
|
"automation_on": False,
|
|
58
70
|
"automation_time": "00:00",
|
|
@@ -164,6 +176,19 @@ def create_tasks_for_batch(batch: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
164
176
|
if thumbnail_path:
|
|
165
177
|
artifacts.setdefault("thumbnail", thumbnail_path)
|
|
166
178
|
initial_stage = "topic" if pending_creative else "script"
|
|
179
|
+
channel_generation_defaults = {
|
|
180
|
+
key.removeprefix("default_"): channel[key]
|
|
181
|
+
for key in (
|
|
182
|
+
"default_enable_subtitles", "default_subtitle_font", "default_subtitle_position", "default_subtitle_color",
|
|
183
|
+
"default_subtitle_background", "default_subtitle_background_color", "default_subtitle_rounded_background",
|
|
184
|
+
"default_subtitle_font_size", "default_subtitle_outline", "default_subtitle_outline_width",
|
|
185
|
+
"default_background_music_source", "default_background_music_volume",
|
|
186
|
+
)
|
|
187
|
+
if key in channel
|
|
188
|
+
}
|
|
189
|
+
configured_generation_settings = options.get("generation_settings") if isinstance(options.get("generation_settings"), dict) else {}
|
|
190
|
+
payload_generation_settings = payload.get("generation_settings") if isinstance(payload.get("generation_settings"), dict) else {}
|
|
191
|
+
generation_settings = {**channel_generation_defaults, **configured_generation_settings, **payload_generation_settings}
|
|
167
192
|
task = {
|
|
168
193
|
"id": make_id("video"),
|
|
169
194
|
"batch_id": batch["id"],
|
|
@@ -183,7 +208,7 @@ def create_tasks_for_batch(batch: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
183
208
|
"music_path": payload.get("music_path", options.get("music_path", "")),
|
|
184
209
|
"music_source": payload.get("music_source", options.get("music_source", "")),
|
|
185
210
|
"background_mode": payload.get("background_mode", options.get("background_mode", "stock")),
|
|
186
|
-
"generation_settings":
|
|
211
|
+
"generation_settings": generation_settings,
|
|
187
212
|
"blueprint_id": payload.get("blueprint_id") or channel.get("default_blueprint_id") or channel.get("blueprint_id", ""),
|
|
188
213
|
"blueprint_name": payload.get("blueprint_name", ""),
|
|
189
214
|
"thumbnail_blueprint_id": payload.get("thumbnail_blueprint_id") or channel.get("default_thumbnail_blueprint_id") or channel.get("thumbnail_blueprint_id") or GENERIC_THUMBNAIL_BLUEPRINT_ID,
|
package/package.json
CHANGED