@danhachuel/thunderbolt 0.4.89 → 0.4.90
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 +23 -33
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -1311,7 +1311,6 @@ def render_channel_edit_form(channel: dict, youtube_account_ids: list[str], yout
|
|
|
1311
1311
|
edited_language = st.selectbox("Idioma do roteiro", language_options, index=language_options.index(normalize_video_language(channel.get("language") or "pt")) if normalize_video_language(channel.get("language") or "pt") in language_options else 0, format_func=video_language_label)
|
|
1312
1312
|
edited_style = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, index=WIDE_STYLE_OPTIONS.index(channel_video_source_value(channel.get("style_wide"))) if channel_video_source_value(channel.get("style_wide")) in WIDE_STYLE_OPTIONS else 0)
|
|
1313
1313
|
edited_aspect = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, index=CHANNEL_ASPECT_RATIO_OPTIONS.index(str(channel.get("video_aspect_ratio") or "Landscape 16:9")) if str(channel.get("video_aspect_ratio") or "Landscape 16:9") in CHANNEL_ASPECT_RATIO_OPTIONS else 0)
|
|
1314
|
-
edited_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "wide")) if str(channel.get("format") or "wide") in CHANNEL_FORMAT_OPTIONS else 0)
|
|
1315
1314
|
edited_niche = st.text_input("Nicho", value=str(channel.get("niche") or channel_niche_label(channel) if channel_niche_label(channel) != "SEM NICHO CONFIGURADO" else "") )
|
|
1316
1315
|
with edit_cols[1]:
|
|
1317
1316
|
edited_blueprint = st.selectbox("Blueprint Padrão", blueprint_ids, index=blueprint_ids.index(current_blueprint) if current_blueprint in blueprint_ids else 0, format_func=lambda item: blueprint_labels.get(item, item or "Sem Blueprint padrão"))
|
|
@@ -1333,7 +1332,7 @@ def render_channel_edit_form(channel: dict, youtube_account_ids: list[str], yout
|
|
|
1333
1332
|
else:
|
|
1334
1333
|
update_channel(channel_id, {
|
|
1335
1334
|
"name": edited_name.strip(), "url": edited_url.strip(), "handle": edited_handle.strip(), "language": edited_language,
|
|
1336
|
-
"style_wide": channel_video_source_storage(edited_style), "video_aspect_ratio": edited_aspect,
|
|
1335
|
+
"style_wide": channel_video_source_storage(edited_style), "video_aspect_ratio": edited_aspect,
|
|
1337
1336
|
"niche": edited_niche.strip(), "reference_channels": [item.strip() for item in re.split(r"[,|]", edited_niche) if item.strip()],
|
|
1338
1337
|
"default_blueprint_id": edited_blueprint.strip(), "blueprint_id": edited_blueprint.strip(),
|
|
1339
1338
|
"default_voice": edited_voice.strip(), "voice": edited_voice.strip(),
|
|
@@ -2004,7 +2003,6 @@ def render_tiktok_channels():
|
|
|
2004
2003
|
language = st.selectbox("Idioma do roteiro", VIDEO_LANGUAGE_SELECTION_OPTIONS, format_func=video_language_label, key="tiktok_import_language")
|
|
2005
2004
|
source_value = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, key="tiktok_import_source")
|
|
2006
2005
|
aspect_value = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, index=1, key="tiktok_import_aspect")
|
|
2007
|
-
format_value = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=1, key="tiktok_import_format")
|
|
2008
2006
|
niche = st.text_input("Nicho", key="tiktok_import_niche")
|
|
2009
2007
|
prompt = st.selectbox("Prompt Master padrão", prompt_ids, format_func=lambda item: prompt_labels.get(item, item), key="tiktok_import_prompt")
|
|
2010
2008
|
voice = st.selectbox("Narrador/Voz Padrão", voice_options, format_func=lambda item: item or "Sem voz padrão", key="tiktok_import_voice")
|
|
@@ -2015,7 +2013,7 @@ def render_tiktok_channels():
|
|
|
2015
2013
|
if not valid_hhmm(automation_time):
|
|
2016
2014
|
st.error("O horário diário deve estar no formato HH:MM.")
|
|
2017
2015
|
st.stop()
|
|
2018
|
-
channel = create_channel(name.strip(), url.strip(), {"platform": "tiktok", "handle": handle.strip(), "language": language, "niche": niche.strip(), "description": description.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "default_voice": voice, "voice": voice, "style_wide": channel_video_source_storage(source_value), "video_aspect_ratio": aspect_value, "format":
|
|
2016
|
+
channel = create_channel(name.strip(), url.strip(), {"platform": "tiktok", "handle": handle.strip(), "language": language, "niche": niche.strip(), "description": description.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "default_voice": voice, "voice": voice, "style_wide": channel_video_source_storage(source_value), "video_aspect_ratio": aspect_value, "format": "Shorts", "automation_on": automation_on, "automation_time": automation_time.strip(), "metrics_source": "tiktok_public_page", "subscriber_count": imported.get("subscriber_count"), "video_count": imported.get("video_count")})
|
|
2019
2017
|
avatar_url = _tiktok_avatar_url(imported)
|
|
2020
2018
|
update_channel(channel["id"], {"platform": "tiktok", "default_prompt_master": prompt, "prompt_master": prompt, "avatar_url": avatar_url, "thumbnail_url": avatar_url})
|
|
2021
2019
|
st.session_state.pop("tiktok_channel_import", None)
|
|
@@ -2057,27 +2055,20 @@ def render_tiktok_channels():
|
|
|
2057
2055
|
if st.button("Apagar card", key=f"tiktok_import_card_delete_{channel_id}"):
|
|
2058
2056
|
st.session_state[f"tiktok_delete_{channel_id}"] = True
|
|
2059
2057
|
st.rerun()
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
st.rerun()
|
|
2075
|
-
st.caption(f"Fonte do vídeo: {channel_video_source_value(channel.get('style_wide'))}")
|
|
2076
|
-
niche_action = st.columns([1.0, 4.0])
|
|
2077
|
-
with niche_action[0]:
|
|
2078
|
-
if st.button("Editar nicho", key=f"tiktok_import_card_niche_{channel_id}"):
|
|
2079
|
-
st.session_state[f"tiktok_niche_{channel_id}"] = not st.session_state.get(f"tiktok_niche_{channel_id}", False)
|
|
2080
|
-
st.rerun()
|
|
2058
|
+
summary_cols = st.columns(4, gap="small")
|
|
2059
|
+
with summary_cols[0]:
|
|
2060
|
+
st.markdown("**Blueprint Padrão**")
|
|
2061
|
+
st.caption(prompt_labels.get(str(channel.get("default_prompt_master") or channel.get("prompt_master") or ""), "Sem Blueprint padrão"))
|
|
2062
|
+
with summary_cols[1]:
|
|
2063
|
+
st.markdown("**Nicho**")
|
|
2064
|
+
st.caption(channel_niche_label(channel))
|
|
2065
|
+
with summary_cols[2]:
|
|
2066
|
+
st.markdown("**Narrador/Voz Padrão**")
|
|
2067
|
+
st.caption(str(channel.get("default_voice") or channel.get("voice") or "Sem voz padrão"))
|
|
2068
|
+
with summary_cols[3]:
|
|
2069
|
+
st.markdown("**Idioma**")
|
|
2070
|
+
st.caption(video_language_label(normalize_video_language(channel.get("language") or "pt")))
|
|
2071
|
+
st.caption(f"Fonte do vídeo: {channel_video_source_value(channel.get('style_wide'))} · Proporção: {channel.get('video_aspect_ratio') or 'Portrait 9:16'}")
|
|
2081
2072
|
if st.session_state.get(f"tiktok_delete_{channel_id}"):
|
|
2082
2073
|
st.warning("Apagar este canal TikTok e os dados locais associados?")
|
|
2083
2074
|
confirm_cols = st.columns(2)
|
|
@@ -2105,7 +2096,6 @@ def render_tiktok_channels():
|
|
|
2105
2096
|
edit_language = st.selectbox("Idioma do roteiro", VIDEO_LANGUAGE_SELECTION_OPTIONS, index=VIDEO_LANGUAGE_SELECTION_OPTIONS.index(normalize_video_language(channel.get("language") or "pt")) if normalize_video_language(channel.get("language") or "pt") in VIDEO_LANGUAGE_SELECTION_OPTIONS else 0, format_func=video_language_label)
|
|
2106
2097
|
edit_source = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, index=WIDE_STYLE_OPTIONS.index(channel_video_source_value(channel.get("style_wide"))) if channel_video_source_value(channel.get("style_wide")) in WIDE_STYLE_OPTIONS else 0)
|
|
2107
2098
|
edit_aspect = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, index=CHANNEL_ASPECT_RATIO_OPTIONS.index(str(channel.get("video_aspect_ratio") or "Portrait 9:16")) if str(channel.get("video_aspect_ratio") or "Portrait 9:16") in CHANNEL_ASPECT_RATIO_OPTIONS else 1)
|
|
2108
|
-
edit_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "Shorts")) if str(channel.get("format") or "Shorts") in CHANNEL_FORMAT_OPTIONS else 1)
|
|
2109
2099
|
edit_voice = st.selectbox("Narrador/Voz Padrão", voice_options, index=voice_options.index(str(channel.get("default_voice") or channel.get("voice") or "")) if str(channel.get("default_voice") or channel.get("voice") or "") in voice_options else 0, format_func=lambda item: item or "Sem voz padrão")
|
|
2110
2100
|
edit_automation = st.toggle("Automação ON", value=bool(channel.get("automation_on", False)), key=f"tiktok_edit_automation_{channel_id}")
|
|
2111
2101
|
edit_time = st.text_input("Horário diário (HH:MM)", value=str(channel.get("automation_time") or "00:00"))
|
|
@@ -2115,7 +2105,7 @@ def render_tiktok_channels():
|
|
|
2115
2105
|
if not valid_hhmm(edit_time):
|
|
2116
2106
|
st.error("O horário diário deve estar no formato HH:MM.")
|
|
2117
2107
|
else:
|
|
2118
|
-
update_channel(channel_id, {"name": edit_name.strip(), "url": edit_url.strip(), "handle": edit_handle.strip(), "language": edit_language, "default_voice": edit_voice, "voice": edit_voice, "style_wide": channel_video_source_storage(edit_source), "video_aspect_ratio": edit_aspect, "
|
|
2108
|
+
update_channel(channel_id, {"name": edit_name.strip(), "url": edit_url.strip(), "handle": edit_handle.strip(), "language": edit_language, "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"})
|
|
2119
2109
|
st.session_state.pop(f"tiktok_edit_{channel_id}", None)
|
|
2120
2110
|
st.rerun()
|
|
2121
2111
|
with st.expander("Últimos 10 vídeos publicados", expanded=False):
|
|
@@ -2172,7 +2162,6 @@ def render_tiktok_channels():
|
|
|
2172
2162
|
language = st.selectbox("Idioma do roteiro", VIDEO_LANGUAGE_SELECTION_OPTIONS, format_func=video_language_label, key="tiktok_manual_channel_language")
|
|
2173
2163
|
source_value = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, key="tiktok_manual_channel_source")
|
|
2174
2164
|
aspect_value = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, index=1, key="tiktok_manual_channel_aspect")
|
|
2175
|
-
format_value = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=1, key="tiktok_manual_channel_format")
|
|
2176
2165
|
niche = st.text_input("Nicho", key="tiktok_manual_channel_niche")
|
|
2177
2166
|
prompt = st.selectbox("Prompt Master padrão", prompt_ids, format_func=lambda item: prompt_labels.get(item, item), key="tiktok_manual_channel_prompt")
|
|
2178
2167
|
voice = st.selectbox("Narrador/Voz Padrão", voice_options, format_func=lambda item: item or "Sem voz padrão", key="tiktok_manual_channel_voice")
|
|
@@ -2264,7 +2253,6 @@ def render_channels():
|
|
|
2264
2253
|
language = st.selectbox("Idioma do roteiro", VIDEO_LANGUAGE_SELECTION_OPTIONS, index=VIDEO_LANGUAGE_SELECTION_OPTIONS.index(normalize_video_language(imported.get("language") or "pt")) if normalize_video_language(imported.get("language") or "pt") in VIDEO_LANGUAGE_SELECTION_OPTIONS else 0, format_func=video_language_label, key="yt_import_language")
|
|
2265
2254
|
style = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, index=0, key="yt_import_style")
|
|
2266
2255
|
video_aspect_ratio = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, key="yt_import_aspect_ratio")
|
|
2267
|
-
video_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, key="yt_import_format")
|
|
2268
2256
|
blueprint = st.selectbox("Blueprint Padrão", blueprint_ids, index=blueprint_ids.index(imported_blueprint) if imported_blueprint in blueprint_ids else 0, format_func=lambda item: blueprint_labels.get(item, item or "Sem Blueprint padrão"), key="yt_import_blueprint")
|
|
2269
2257
|
voice_options = voice_catalog(imported.get("default_voice") or imported.get("voice", ""))
|
|
2270
2258
|
current_voice = imported.get("default_voice") or imported.get("voice", "")
|
|
@@ -2294,7 +2282,7 @@ def render_channels():
|
|
|
2294
2282
|
"niche": niche.strip(),
|
|
2295
2283
|
"reference_channels": [item.strip() for item in re.split(r"[,|]", niche) if item.strip()],
|
|
2296
2284
|
"language": language,
|
|
2297
|
-
"style_wide": channel_video_source_storage(style), "video_aspect_ratio": video_aspect_ratio, "format":
|
|
2285
|
+
"style_wide": channel_video_source_storage(style), "video_aspect_ratio": video_aspect_ratio, "format": "wide",
|
|
2298
2286
|
"blueprint_id": blueprint.strip(),
|
|
2299
2287
|
"default_blueprint_id": blueprint.strip(),
|
|
2300
2288
|
"default_voice": voice.strip(),
|
|
@@ -5015,15 +5003,14 @@ def render_tiktok_automation():
|
|
|
5015
5003
|
with default_cols[3]:
|
|
5016
5004
|
prompt = st.selectbox("Prompt Master Padrão", prompt_ids, index=prompt_ids.index(channel.get("default_prompt_master", "")) if channel.get("default_prompt_master", "") in prompt_ids else 0, format_func=lambda item: prompt_labels.get(item, item), key=f"tiktok_automation_prompt_{channel_id}")
|
|
5017
5005
|
with default_cols[4]:
|
|
5018
|
-
st.
|
|
5019
|
-
st.caption("TikTok / Shorts")
|
|
5006
|
+
automation_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "Shorts")) if str(channel.get("format") or "Shorts") in CHANNEL_FORMAT_OPTIONS else 1, key=f"tiktok_automation_format_{channel_id}")
|
|
5020
5007
|
with default_cols[5]:
|
|
5021
5008
|
if st.button("Guardar", key=f"tiktok_automation_save_{channel_id}", use_container_width=True, type="primary"):
|
|
5022
5009
|
if not valid_hhmm(schedule_time):
|
|
5023
5010
|
st.error("Use o formato HH:MM, por exemplo 08:30.")
|
|
5024
5011
|
else:
|
|
5025
5012
|
avatar_url = _tiktok_avatar_url(channel)
|
|
5026
|
-
update_channel(channel_id, {"automation_on": bool(enabled), "automation_time": schedule_time.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "platform": "tiktok", "video_aspect_ratio": "Portrait 9:16", "style_wide": "portrait", "avatar_url": avatar_url, "thumbnail_url": avatar_url})
|
|
5013
|
+
update_channel(channel_id, {"automation_on": bool(enabled), "automation_time": schedule_time.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "platform": "tiktok", "format": automation_format, "video_aspect_ratio": "Portrait 9:16", "style_wide": "portrait", "avatar_url": avatar_url, "thumbnail_url": avatar_url})
|
|
5027
5014
|
st.success("Automação TikTok guardada.")
|
|
5028
5015
|
st.rerun()
|
|
5029
5016
|
st.divider()
|
|
@@ -5118,6 +5105,8 @@ def render_automation():
|
|
|
5118
5105
|
st.markdown("**Thumbnail Blueprint**")
|
|
5119
5106
|
st.caption(str(paired_thumbnail.get("name") or "Generic_Thumbnail_Blueprint"))
|
|
5120
5107
|
with default_cols[4]:
|
|
5108
|
+
automation_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "wide")) if str(channel.get("format") or "wide") in CHANNEL_FORMAT_OPTIONS else 0, key=f"automation_format_{channel_id}")
|
|
5109
|
+
with default_cols[5]:
|
|
5121
5110
|
automation_voice = st.selectbox(
|
|
5122
5111
|
"Narrador/Voz Padrão",
|
|
5123
5112
|
voice_options,
|
|
@@ -5133,6 +5122,7 @@ def render_automation():
|
|
|
5133
5122
|
update_channel(channel_id, {
|
|
5134
5123
|
"automation_on": bool(enabled),
|
|
5135
5124
|
"automation_time": schedule_time.strip(),
|
|
5125
|
+
"format": automation_format,
|
|
5136
5126
|
})
|
|
5137
5127
|
set_channel_defaults(channel_id, automation_blueprint, automation_voice)
|
|
5138
5128
|
paired_id = str(paired_thumbnail.get("id") or "Generic_Thumbnail_Blueprint")
|
package/package.json
CHANGED