@danhachuel/thunderbolt 0.2.83 → 0.2.85
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/MANUAL-INSTALACAO.md +3 -1
- package/README.md +4 -2
- package/app/main.py +43 -13
- package/hermes_ui/languages.py +61 -1
- package/package.json +1 -1
- package/seed/references/guide-supabase.md +61 -0
package/MANUAL-INSTALACAO.md
CHANGED
|
@@ -196,6 +196,8 @@ O Thunderbolt inclui as dez opções de idioma usadas pelo fluxo MoneyPrinterTur
|
|
|
196
196
|
|
|
197
197
|
No topo da área principal, o menu nativo de idioma segue o padrão do MoneyPrinterTurbo e mostra o rótulo **Language** acima do selector. Cada opção apresenta o nome e o código, acompanhados por uma imagem SVG local da bandeira; não depende de emojis nem de siglas da fonte do sistema. A escolha fica guardada como `ui_language` em `storage/state/settings.json` e, quando existe um caminho MoneyPrinterTurbo configurado, é sincronizada com `[ui].language` no `config.toml`. O dashboard inicial e as abas da barra lateral usam o mesmo idioma seleccionado. O toolbar do Streamlit não é manipulado: o indicador de execução, **Deploy** e o menu de três pontos permanecem nativos e clicáveis. Na Criação de Vídeos e em Roteiros, o selector **Script Language** mantém o catálogo de vídeo independente, mas guarda o código curto; essa escolha é sincronizada com `[ui].video_language`.
|
|
198
198
|
|
|
199
|
+
Todas as subabas internas também são traduzidas nos dez idiomas: Blueprints/Brandings, Pesquisa pública/Cadastro manual/Contas cadastradas, Upload/Biblioteca, Importar do YouTube/Canais em lote gmail/Cadastro manual, Criar vídeo/Vídeos, Novo roteiro/letra/Histórico guardado, análise de clusters, edição de cortes, Vídeos/Código Python, as quatro opções de Upload, API Keys/Teste de vozes, Serviços e modelos/Fontes de materiais e Client MCP/Servidor MCP/Skill. A ordem e as chaves internas dos widgets permanecem estáveis.
|
|
200
|
+
|
|
199
201
|
## 4. Diagnóstico antes de iniciar
|
|
200
202
|
|
|
201
203
|
Depois da instalação, execute:
|
|
@@ -351,7 +353,7 @@ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
|
351
353
|
|
|
352
354
|
## 8. Configuração inicial da UI
|
|
353
355
|
|
|
354
|
-
Na primeira execução, a barra lateral apresenta **Início**, **Niche Finder**, **Pipeline**, **Pipeline TikTok**, **Automação**, **Edição**, **AI Influencers** e **Configurações**. O menu expansível **Automação** contém a subaba **Automação Youtube**. O menu expansível **Edição** contém **Limpador de Metadados**, **Cortes** e **Editor Python**. O menu expansível **AI Influencers** contém **Personagens**, **Redes Sociais** e **Tutorial
|
|
356
|
+
Na primeira execução, a barra lateral apresenta **Início**, **Niche Finder**, **Pipeline**, **Pipeline TikTok**, **Automação**, **Edição**, **AI Influencers** e **Configurações**. O menu expansível **Automação** contém a subaba **Automação Youtube**. O menu expansível **Edição** contém **Limpador de Metadados**, **Cortes** e **Editor Python**. O menu expansível **AI Influencers** contém **Personagens**, **Redes Sociais**, **Tutorial Meta** e **Tutorial Supabase**, nessa ordem. O **Tutorial Meta** apresenta o guia de configuração de Instagram e credenciais Meta para automações com n8n. O **Tutorial Supabase** apresenta o guia para criar as tabelas `plans` e `posts` e o bucket `instagram-images`, incluindo a ligação para a fonte original no GitHub; as duas frases promocionais da comunidade foram omitidas. O menu expansível **Niche Finder** contém **Niche Finder Kaggle** e **Niche Finder Apify**. A aba **Niche Finder Kaggle** mantém a análise do dataset Kaggle; **Niche Finder Apify** é uma segunda alternativa independente, com actor, dataset, parâmetros, credencial, execução e resultados próprios. O menu **Pipeline** contém **Criação de Vídeos**, **Criação de Músicas**, **Roteiros** e **Upload**. O menu **Configurações** contém **Canais Youtube**, **Blueprints Youtube**, **MCP**, **Contas Google**, **Configuração API** e **Notificações**. Abra **Configurações > Contas Google** para gerir contas Google/YouTube, cartões, documentos de Upload directo, `sessionInfo`, `INNERTUBE_API_KEY`, contas adicionais e a configuração global do YouTube. Abra **Configurações > Configuração API** para configurar as restantes API Keys, providers, modelos, serviços e o **Teste de vozes**. A página **Configurações > Notificações** está reservada para futuros eventos locais. Para YouTube, preencha primeiro o par **OAuth Client ID + OAuth Client Secret** em **Contas Google** se pretende autorizar uploads. A **YouTube Data API Key** é uma credencial Google Cloud diferente e fica em **Contas Google**, apenas para o método oficial de métricas; Client ID + Client Secret não formam uma API Key.
|
|
355
357
|
|
|
356
358
|
| Configuração | Finalidade |
|
|
357
359
|
|---|---|
|
package/README.md
CHANGED
|
@@ -52,9 +52,11 @@ O Thunderbolt mantém os idiomas históricos da criação de vídeos e acrescent
|
|
|
52
52
|
|
|
53
53
|
No topo da área principal da aplicação existe o menu nativo de idioma no padrão do MoneyPrinterTurbo, sem sobrepor o toolbar do Streamlit. O selector mostra o rótulo visível **Language** acima do campo, cada opção aparece como **nome do idioma + código**, e a bandeira é uma imagem SVG local real, não um emoji ou sigla dependente da fonte do sistema. Ao escolher outra opção, a preferência é guardada em `storage/state/settings.json` como `ui_language`, e a navegação lateral e o dashboard inicial actualizam-se sem alterar o idioma seleccionado para os vídeos. O indicador de execução, o botão **Deploy** e o menu principal do Streamlit permanecem totalmente nativos e clicáveis.
|
|
54
54
|
|
|
55
|
-
## Navegação da UI 0.2.
|
|
55
|
+
## Navegação da UI 0.2.84
|
|
56
56
|
|
|
57
|
-
A barra lateral mantém os níveis principais, nesta ordem: **Início**, **Niche Finder**, **Pipeline**, **Pipeline TikTok**, **Automação**, **Edição**, **AI Influencers** e **Configurações**. **Pipeline** é expansível e contém **Criação de Vídeos**, **Criação de Músicas**, **Roteiros** e **Upload**. **Automação** também é expansível e contém **Automação Youtube**. **Edição** é expansível e contém **Limpador de Metadados**, **Cortes**, **Editor Python** e **Download Mídia**, nessa ordem. **AI Influencers** é expansível e contém **Personagens**, **Redes Sociais** e **Tutorial
|
|
57
|
+
A barra lateral mantém os níveis principais, nesta ordem: **Início**, **Niche Finder**, **Pipeline**, **Pipeline TikTok**, **Automação**, **Edição**, **AI Influencers** e **Configurações**. **Pipeline** é expansível e contém **Criação de Vídeos**, **Criação de Músicas**, **Roteiros** e **Upload**. **Automação** também é expansível e contém **Automação Youtube**. **Edição** é expansível e contém **Limpador de Metadados**, **Cortes**, **Editor Python** e **Download Mídia**, nessa ordem. **AI Influencers** é expansível e contém **Personagens**, **Redes Sociais**, **Tutorial Meta** e **Tutorial Supabase**, nessa ordem. **Niche Finder** é expansível e contém **Niche Finder Kaggle** e **Niche Finder Apify**. **Configurações** é expansível e contém **Canais Youtube**, **Blueprints Youtube**, **MCP**, **Contas Google**, **Configuração API** e **Notificações**. O Início reúne o dashboard e as filas do Pipeline, sem botões de acções rápidas.
|
|
58
|
+
|
|
59
|
+
A subaba **Tutorial Supabase** apresenta o guia de criação das tabelas `plans` e `posts` e do bucket `instagram-images`, com ligação para a fonte original no GitHub. As duas frases promocionais da comunidade foram omitidas. Todas as subabas internas também são localizadas pelo helper nativo de tabs: **Blueprints/Brandings**, **Pesquisa pública/Cadastro manual/Contas cadastradas**, **Upload/Biblioteca**, **Importar do YouTube/Canais em lote gmail/Cadastro manual**, **Criar vídeo/Vídeos**, **Novo roteiro/letra/Histórico guardado**, as três abas de análise de clusters, as quatro abas de cortes, **Vídeos/Código Python**, as quatro opções de Upload, **API Keys/Teste de vozes**, **Serviços e modelos/Fontes de materiais** e **Client MCP/Servidor MCP/Skill**. As chaves técnicas e a ordem funcional permanecem inalteradas.
|
|
58
60
|
|
|
59
61
|
Dentro de **Configurações > Contas Google**, a UI contém os cartões expansíveis de contas Google/YouTube, `sessionInfo`, documentos de Upload directo, `INNERTUBE_API_KEY`, o formulário **Adicionar outra conta Gmail** e a configuração global do YouTube (OAuth Client ID, OAuth Client Secret e YouTube Data API Key). A página **Configuração API** contém as restantes credenciais, providers, modelos, serviços, Nano Banana, TikTok e Postiz.
|
|
60
62
|
|
package/app/main.py
CHANGED
|
@@ -218,6 +218,17 @@ def current_ui_language() -> str:
|
|
|
218
218
|
return normalized
|
|
219
219
|
|
|
220
220
|
|
|
221
|
+
def localized_tab_labels(labels: list[str], language: str | None = None) -> list[str]:
|
|
222
|
+
"""Translate Streamlit tab labels while keeping widget keys and behaviour stable."""
|
|
223
|
+
selected_language = language_code(language or current_ui_language())
|
|
224
|
+
return [ui_text(label, selected_language) for label in labels]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def render_localized_tabs(labels: list[str], language: str | None = None):
|
|
228
|
+
"""Render a tab group with labels translated for the selected UI language."""
|
|
229
|
+
return st.tabs(localized_tab_labels(labels, language))
|
|
230
|
+
|
|
231
|
+
|
|
221
232
|
def save_ui_language(value: str) -> str:
|
|
222
233
|
normalized = language_code(value)
|
|
223
234
|
settings = read_json("settings.json", {})
|
|
@@ -750,7 +761,7 @@ def render_dashboard():
|
|
|
750
761
|
def render_blueprints():
|
|
751
762
|
st.title("Blueprints Youtube")
|
|
752
763
|
st.caption(f"Biblioteca local lida directamente de `{BLUEPRINTS}`")
|
|
753
|
-
blueprint_tab, branding_tab =
|
|
764
|
+
blueprint_tab, branding_tab = render_localized_tabs(["Blueprints", "Brandings"])
|
|
754
765
|
with blueprint_tab:
|
|
755
766
|
st.subheader("Criar blueprint a partir de link")
|
|
756
767
|
with st.form("create_blueprint_from_link"):
|
|
@@ -915,7 +926,7 @@ def render_tiktok_accounts():
|
|
|
915
926
|
settings = read_json("settings.json", {})
|
|
916
927
|
accounts = _tiktok_accounts_from_settings(settings)
|
|
917
928
|
|
|
918
|
-
search_tab, manual_tab, library_tab =
|
|
929
|
+
search_tab, manual_tab, library_tab = render_localized_tabs(["Pesquisa pública", "Cadastro manual", "Contas cadastradas"])
|
|
919
930
|
with search_tab:
|
|
920
931
|
st.subheader("Pesquisar perfil público")
|
|
921
932
|
st.info("A pesquisa consulta apenas a página pública do perfil e pode devolver dados incompletos. Se o TikTok bloquear a consulta, utilize o cadastro manual.")
|
|
@@ -1012,7 +1023,7 @@ def render_tiktok_prompt_masters():
|
|
|
1012
1023
|
st.title("Prompts Master")
|
|
1013
1024
|
st.caption(f"Biblioteca exclusiva para vídeos TikTok. Os ficheiros ficam em `{TIKTOK_PROMPT_MASTERS}` e nunca entram na pasta de Blueprints YouTube.")
|
|
1014
1025
|
|
|
1015
|
-
upload_tab, library_tab =
|
|
1026
|
+
upload_tab, library_tab = render_localized_tabs(["Upload", "Biblioteca"])
|
|
1016
1027
|
with upload_tab:
|
|
1017
1028
|
st.subheader("Adicionar Prompt Master")
|
|
1018
1029
|
st.info("Use ficheiros Markdown `.md`. Cada Prompt Master é guardado como um ficheiro independente no storage TikTok.")
|
|
@@ -1097,7 +1108,7 @@ def render_channels():
|
|
|
1097
1108
|
youtube_account_labels = {"": "Sem conta Google associada"}
|
|
1098
1109
|
youtube_account_labels.update({str(account["id"]): f"{account.get('label', 'Canais YouTube')} — {account.get('email', 'sem e-mail')}" for account in youtube_accounts})
|
|
1099
1110
|
youtube_accounts_by_id = {str(account["id"]): account for account in youtube_accounts}
|
|
1100
|
-
import_tab, batch_tab, manual_tab =
|
|
1111
|
+
import_tab, batch_tab, manual_tab = render_localized_tabs(["Importar do YouTube", "Canais em lote gmail", "Cadastro manual"])
|
|
1101
1112
|
|
|
1102
1113
|
with import_tab:
|
|
1103
1114
|
st.caption("A pesquisa pública funciona sem API Key. A Data API é opcional e fica disponível numa opção separada para métricas oficiais.")
|
|
@@ -1430,7 +1441,7 @@ def render_channels():
|
|
|
1430
1441
|
|
|
1431
1442
|
def render_new_video(page_title: str = "Criação de Vídeos"):
|
|
1432
1443
|
st.title(page_title)
|
|
1433
|
-
create_tab, videos_tab =
|
|
1444
|
+
create_tab, videos_tab = render_localized_tabs(["Criar vídeo", "Vídeos"])
|
|
1434
1445
|
with create_tab:
|
|
1435
1446
|
all_channels = [c for c in read_json("channels.json", []) if isinstance(c, dict)]
|
|
1436
1447
|
active_channels = [c for c in all_channels if c.get("active", True)]
|
|
@@ -1790,7 +1801,7 @@ def render_scripts():
|
|
|
1790
1801
|
script_dir = script_storage_path()
|
|
1791
1802
|
st.info(f"**Ficheiros guardados em:** `{script_dir}` · o conteúdo fica no storage local do Thunderbolt e não é enviado automaticamente para plataformas.")
|
|
1792
1803
|
|
|
1793
|
-
create_tab, history_tab =
|
|
1804
|
+
create_tab, history_tab = render_localized_tabs(["Novo roteiro/letra", "Histórico guardado"])
|
|
1794
1805
|
with create_tab:
|
|
1795
1806
|
all_channels = [channel for channel in read_json("channels.json", []) if isinstance(channel, dict)]
|
|
1796
1807
|
active_channels = [channel for channel in all_channels if channel.get("active", True)]
|
|
@@ -2030,7 +2041,7 @@ def render_niche_finder():
|
|
|
2030
2041
|
keyword = st.text_input("Filtrar palavras-chave nos clusters", key="niche_cluster_keyword", placeholder="Ex.: música, gaming, receitas")
|
|
2031
2042
|
if keyword.strip():
|
|
2032
2043
|
cluster_table = cluster_table[cluster_table["palavras"].str.contains(keyword.strip(), case=False, na=False)]
|
|
2033
|
-
tab_clusters, tab_rules, tab_data =
|
|
2044
|
+
tab_clusters, tab_rules, tab_data = render_localized_tabs(["Clusters encontrados", "Regras de associação", "Dados analisados"])
|
|
2034
2045
|
with tab_clusters:
|
|
2035
2046
|
st.dataframe(cluster_table, use_container_width=True, hide_index=True)
|
|
2036
2047
|
if not points.empty:
|
|
@@ -2323,7 +2334,7 @@ def render_cuts():
|
|
|
2323
2334
|
)
|
|
2324
2335
|
|
|
2325
2336
|
source_path = None
|
|
2326
|
-
source_tab, url_tab, generated_tab, folder_tab =
|
|
2337
|
+
source_tab, url_tab, generated_tab, folder_tab = render_localized_tabs(["Upload ficheiro", "URL de vídeo", "Vídeos gerados", "Pasta local"])
|
|
2327
2338
|
with source_tab:
|
|
2328
2339
|
uploaded_video = st.file_uploader(
|
|
2329
2340
|
"Clique para carregar ou arraste um vídeo",
|
|
@@ -2501,7 +2512,7 @@ def render_python_editor():
|
|
|
2501
2512
|
st.caption("Editor local inspirado no PYEdit para scripts Python e edição manual de vídeos do Thunderbolt.")
|
|
2502
2513
|
st.info("Escolha um vídeo gerado, indique uma pasta local ou faça upload de um vídeo. Nenhum código Python é executado nesta aba; as operações de vídeo só começam depois de clicar no botão da operação.")
|
|
2503
2514
|
|
|
2504
|
-
video_tab, code_tab =
|
|
2515
|
+
video_tab, code_tab = render_localized_tabs(["Vídeos", "Código Python"])
|
|
2505
2516
|
with video_tab:
|
|
2506
2517
|
st.subheader("Escolher vídeo")
|
|
2507
2518
|
source_mode = st.radio("Origem", ["Vídeos gerados", "Pasta local", "Upload manual"], horizontal=True, key="python_editor_source_mode")
|
|
@@ -2809,7 +2820,7 @@ def render_upload_direct():
|
|
|
2809
2820
|
|
|
2810
2821
|
def render_upload():
|
|
2811
2822
|
st.title("Upload")
|
|
2812
|
-
upload_tab, direct_tab, postiz_tab, upload_post_tab =
|
|
2823
|
+
upload_tab, direct_tab, postiz_tab, upload_post_tab = render_localized_tabs(["Upload convencional", "Upload directo", "Postiz", "Upload-Post"])
|
|
2813
2824
|
with direct_tab:
|
|
2814
2825
|
render_upload_direct()
|
|
2815
2826
|
with postiz_tab:
|
|
@@ -3459,10 +3470,10 @@ def render_settings():
|
|
|
3459
3470
|
key=f"settings_{key}",
|
|
3460
3471
|
)
|
|
3461
3472
|
|
|
3462
|
-
api_keys_tab, voice_test_tab =
|
|
3473
|
+
api_keys_tab, voice_test_tab = render_localized_tabs(["API Keys", "Teste de vozes"])
|
|
3463
3474
|
|
|
3464
3475
|
with api_keys_tab:
|
|
3465
|
-
api_service_tab, material_sources_tab =
|
|
3476
|
+
api_service_tab, material_sources_tab = render_localized_tabs(["Serviços e modelos", "Fontes de materiais"])
|
|
3466
3477
|
with api_service_tab:
|
|
3467
3478
|
with st.form("settings_form"):
|
|
3468
3479
|
st.subheader("API Keys")
|
|
@@ -3786,11 +3797,28 @@ def render_models_ai_tutorial():
|
|
|
3786
3797
|
return
|
|
3787
3798
|
st.markdown(tutorial_content, unsafe_allow_html=True)
|
|
3788
3799
|
|
|
3800
|
+
def render_supabase_tutorial():
|
|
3801
|
+
tutorial_url = "https://github.com/gyoridavid/ai_agents_az/blob/main/episode_8/guide-supabase.md"
|
|
3802
|
+
tutorial_path = ROOT / "seed" / "references" / "guide-supabase.md"
|
|
3803
|
+
ui_language = current_ui_language()
|
|
3804
|
+
st.title(ui_text("Tutorial Supabase", ui_language))
|
|
3805
|
+
st.caption(ui_text("Guia de configuração do Supabase para automações com n8n.", ui_language))
|
|
3806
|
+
st.markdown(f"[Abrir fonte original no GitHub]({tutorial_url})")
|
|
3807
|
+
try:
|
|
3808
|
+
tutorial_content = tutorial_path.read_text(encoding="utf-8").strip()
|
|
3809
|
+
except OSError:
|
|
3810
|
+
tutorial_content = ""
|
|
3811
|
+
if not tutorial_content:
|
|
3812
|
+
st.error("O conteúdo local do tutorial não está disponível. Consulte a fonte original no GitHub.")
|
|
3813
|
+
return
|
|
3814
|
+
st.markdown(tutorial_content, unsafe_allow_html=True)
|
|
3815
|
+
|
|
3816
|
+
|
|
3789
3817
|
def render_mcp():
|
|
3790
3818
|
st.title("MCP")
|
|
3791
3819
|
st.caption("Clientes externos, servidor MCP do Thunderbolt e a skill local ficam separados para evitar confundir funções diferentes.")
|
|
3792
3820
|
|
|
3793
|
-
client_tab, server_tab, skill_tab =
|
|
3821
|
+
client_tab, server_tab, skill_tab = render_localized_tabs(["Client MCP", "Servidor MCP", "Skill"])
|
|
3794
3822
|
|
|
3795
3823
|
with client_tab:
|
|
3796
3824
|
st.subheader("Client MCP")
|
|
@@ -4074,6 +4102,7 @@ def main():
|
|
|
4074
4102
|
("Personagens", ":material/person:", "Personagens"),
|
|
4075
4103
|
("Redes Sociais", ":material/share:", "Redes Sociais"),
|
|
4076
4104
|
("Tutorial Meta", ":material/menu_book:", "Tutorial Meta"),
|
|
4105
|
+
("Tutorial Supabase", ":material/storage:", "Tutorial Supabase"),
|
|
4077
4106
|
]
|
|
4078
4107
|
settings_items = [
|
|
4079
4108
|
("Canais Youtube", ":material/ondemand_video:", "Canais Youtube"),
|
|
@@ -4181,6 +4210,7 @@ def main():
|
|
|
4181
4210
|
"Download Mídia": render_media_download,
|
|
4182
4211
|
"AI Influencers": lambda: render_edit_placeholder("AI Influencers", "Seleccione uma das abas AI Influencers no menu expansível."),
|
|
4183
4212
|
"Tutorial Meta": render_models_ai_tutorial,
|
|
4213
|
+
"Tutorial Supabase": render_supabase_tutorial,
|
|
4184
4214
|
"Personagens": lambda: render_edit_placeholder("Personagens", "Área reservada para a futura funcionalidade de personagens."),
|
|
4185
4215
|
"Redes Sociais": lambda: render_edit_placeholder("Redes Sociais", "Área reservada para a futura funcionalidade de redes sociais."),
|
|
4186
4216
|
"Upload": render_upload,
|
package/hermes_ui/languages.py
CHANGED
|
@@ -100,7 +100,7 @@ _CORE_UI_TEXT_KEYS = (
|
|
|
100
100
|
"Início", "Niche Finder", "Pipeline", "Pipeline TikTok", "Automação", "Edição", "AI Influencers", "Configurações",
|
|
101
101
|
"Criação de Vídeos", "Criação de Músicas", "Roteiros", "Upload", "Prompts Master", "Contas TikTok", "Automação Youtube",
|
|
102
102
|
"Niche Finder Kaggle", "Niche Finder Apify", "Limpador de Metadados", "Cortes", "Editor Python", "Download Mídia",
|
|
103
|
-
"Personagens", "Redes Sociais", "Tutorial Meta", "Canais Youtube", "Blueprints Youtube", "MCP", "Contas Google",
|
|
103
|
+
"Personagens", "Redes Sociais", "Tutorial Meta", "Tutorial Supabase", "Canais Youtube", "Blueprints Youtube", "MCP", "Contas Google",
|
|
104
104
|
"Configuração API", "Notificações", "Interface local para operação e automação de conteúdo faceless", "Canais", "activos",
|
|
105
105
|
"Tarefas", "total registado", "A fazer", "na pipeline", "Em execução", "a decorrer", "Concluídos", "artefactos prontos",
|
|
106
106
|
"Falhas", "requerem atenção", "Filas locais e dependências da cascata", "Niche", "Blueprints", "Brand", "Script", "Title",
|
|
@@ -140,6 +140,66 @@ UI_TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
|
|
143
|
+
_TAB_LABELS = (
|
|
144
|
+
"Blueprints", "Brandings", "Pesquisa pública", "Cadastro manual", "Contas cadastradas", "Biblioteca",
|
|
145
|
+
"Importar do YouTube", "Canais em lote gmail", "Criar vídeo", "Vídeos", "Novo roteiro/letra", "Histórico guardado",
|
|
146
|
+
"Clusters encontrados", "Regras de associação", "Dados analisados", "Upload ficheiro", "URL de vídeo", "Vídeos gerados",
|
|
147
|
+
"Pasta local", "Código Python", "Upload convencional", "Upload directo", "Postiz", "Upload-Post", "API Keys",
|
|
148
|
+
"Teste de vozes", "Serviços e modelos", "Fontes de materiais", "Client MCP", "Servidor MCP", "Skill",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
TAB_TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
152
|
+
"pt": {label: label for label in _TAB_LABELS},
|
|
153
|
+
"en": {
|
|
154
|
+
"Blueprints": "Blueprints", "Brandings": "Brandings", "Pesquisa pública": "Public search", "Cadastro manual": "Manual registration", "Contas cadastradas": "Registered accounts", "Biblioteca": "Library", "Importar do YouTube": "Import from YouTube", "Canais em lote gmail": "Bulk Gmail channels", "Criar vídeo": "Create video", "Vídeos": "Videos", "Novo roteiro/letra": "New script/lyrics", "Histórico guardado": "Saved history", "Clusters encontrados": "Found clusters", "Regras de associação": "Association rules", "Dados analisados": "Analyzed data", "Upload ficheiro": "Upload file", "URL de vídeo": "Video URL", "Vídeos gerados": "Generated videos", "Pasta local": "Local folder", "Código Python": "Python code", "Upload convencional": "Conventional upload", "Upload directo": "Direct upload", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "API Keys", "Teste de vozes": "Voice testing", "Serviços e modelos": "Services and models", "Fontes de materiais": "Media sources", "Client MCP": "MCP client", "Servidor MCP": "MCP server", "Skill": "Skill",
|
|
155
|
+
},
|
|
156
|
+
"zh": {
|
|
157
|
+
"Blueprints": "蓝图", "Brandings": "品牌", "Pesquisa pública": "公开搜索", "Cadastro manual": "手动注册", "Contas cadastradas": "已注册账户", "Biblioteca": "库", "Importar do YouTube": "从 YouTube 导入", "Canais em lote gmail": "Gmail 批量频道", "Criar vídeo": "创建视频", "Vídeos": "视频", "Novo roteiro/letra": "新建脚本/歌词", "Histórico guardado": "已保存历史", "Clusters encontrados": "找到的聚类", "Regras de associação": "关联规则", "Dados analisados": "分析数据", "Upload ficheiro": "上传文件", "URL de vídeo": "视频 URL", "Vídeos gerados": "已生成视频", "Pasta local": "本地文件夹", "Código Python": "Python 代码", "Upload convencional": "常规上传", "Upload directo": "直接上传", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "API 密钥", "Teste de vozes": "语音测试", "Serviços e modelos": "服务与模型", "Fontes de materiais": "媒体来源", "Client MCP": "MCP 客户端", "Servidor MCP": "MCP 服务器", "Skill": "技能",
|
|
158
|
+
},
|
|
159
|
+
"de": {
|
|
160
|
+
"Blueprints": "Blueprints", "Brandings": "Brandings", "Pesquisa pública": "Öffentliche Suche", "Cadastro manual": "Manuelle Registrierung", "Contas cadastradas": "Registrierte Konten", "Biblioteca": "Bibliothek", "Importar do YouTube": "Von YouTube importieren", "Canais em lote gmail": "Gmail-Kanäle im Stapel", "Criar vídeo": "Video erstellen", "Vídeos": "Videos", "Novo roteiro/letra": "Neues Skript/Liedtext", "Histórico guardado": "Gespeicherter Verlauf", "Clusters encontrados": "Gefundene Cluster", "Regras de associação": "Assoziationsregeln", "Dados analisados": "Analysierte Daten", "Upload ficheiro": "Datei hochladen", "URL de vídeo": "Video-URL", "Vídeos gerados": "Erstellte Videos", "Pasta local": "Lokaler Ordner", "Código Python": "Python-Code", "Upload convencional": "Herkömmlicher Upload", "Upload directo": "Direkter Upload", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "API-Schlüssel", "Teste de vozes": "Stimmtest", "Serviços e modelos": "Dienste und Modelle", "Fontes de materiais": "Medienquellen", "Client MCP": "MCP-Client", "Servidor MCP": "MCP-Server", "Skill": "Skill",
|
|
161
|
+
},
|
|
162
|
+
"vi": {
|
|
163
|
+
"Blueprints": "Blueprint", "Brandings": "Thương hiệu", "Pesquisa pública": "Tìm kiếm công khai", "Cadastro manual": "Đăng ký thủ công", "Contas cadastradas": "Tài khoản đã đăng ký", "Biblioteca": "Thư viện", "Importar do YouTube": "Nhập từ YouTube", "Canais em lote gmail": "Kênh Gmail hàng loạt", "Criar vídeo": "Tạo video", "Vídeos": "Video", "Novo roteiro/letra": "Kịch bản/lời bài hát mới", "Histórico guardado": "Lịch sử đã lưu", "Clusters encontrados": "Cụm được tìm thấy", "Regras de associação": "Quy tắc liên kết", "Dados analisados": "Dữ liệu đã phân tích", "Upload ficheiro": "Tải tệp lên", "URL de vídeo": "URL video", "Vídeos gerados": "Video đã tạo", "Pasta local": "Thư mục cục bộ", "Código Python": "Mã Python", "Upload convencional": "Tải lên thông thường", "Upload directo": "Tải lên trực tiếp", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Khóa API", "Teste de vozes": "Kiểm tra giọng nói", "Serviços e modelos": "Dịch vụ và mô hình", "Fontes de materiais": "Nguồn phương tiện", "Client MCP": "Máy khách MCP", "Servidor MCP": "Máy chủ MCP", "Skill": "Kỹ năng",
|
|
164
|
+
},
|
|
165
|
+
"tr": {
|
|
166
|
+
"Blueprints": "Blueprint'ler", "Brandings": "Markalar", "Pesquisa pública": "Herkese açık arama", "Cadastro manual": "Manuel kayıt", "Contas cadastradas": "Kayıtlı hesaplar", "Biblioteca": "Kütüphane", "Importar do YouTube": "YouTube'dan içe aktar", "Canais em lote gmail": "Toplu Gmail kanalları", "Criar vídeo": "Video oluştur", "Vídeos": "Videolar", "Novo roteiro/letra": "Yeni senaryo/şarkı sözü", "Histórico guardado": "Kayıtlı geçmiş", "Clusters encontrados": "Bulunan kümeler", "Regras de associação": "Birliktelik kuralları", "Dados analisados": "Analiz edilen veriler", "Upload ficheiro": "Dosya yükle", "URL de vídeo": "Video URL'si", "Vídeos gerados": "Oluşturulan videolar", "Pasta local": "Yerel klasör", "Código Python": "Python kodu", "Upload convencional": "Geleneksel yükleme", "Upload directo": "Doğrudan yükleme", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "API anahtarları", "Teste de vozes": "Ses testi", "Serviços e modelos": "Hizmetler ve modeller", "Fontes de materiais": "Medya kaynakları", "Client MCP": "MCP istemcisi", "Servidor MCP": "MCP sunucusu", "Skill": "Beceri",
|
|
167
|
+
},
|
|
168
|
+
"ru": {
|
|
169
|
+
"Blueprints": "Blueprints", "Brandings": "Брендинг", "Pesquisa pública": "Публичный поиск", "Cadastro manual": "Ручная регистрация", "Contas cadastradas": "Зарегистрированные аккаунты", "Biblioteca": "Библиотека", "Importar do YouTube": "Импорт из YouTube", "Canais em lote gmail": "Массовые каналы Gmail", "Criar vídeo": "Создать видео", "Vídeos": "Видео", "Novo roteiro/letra": "Новый сценарий/текст", "Histórico guardado": "Сохранённая история", "Clusters encontrados": "Найденные кластеры", "Regras de associação": "Правила ассоциаций", "Dados analisados": "Анализ данных", "Upload ficheiro": "Загрузить файл", "URL de vídeo": "URL видео", "Vídeos gerados": "Созданные видео", "Pasta local": "Локальная папка", "Código Python": "Код Python", "Upload convencional": "Обычная загрузка", "Upload directo": "Прямая загрузка", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Ключи API", "Teste de vozes": "Тест голосов", "Serviços e modelos": "Сервисы и модели", "Fontes de materiais": "Источники материалов", "Client MCP": "Клиент MCP", "Servidor MCP": "Сервер MCP", "Skill": "Навык",
|
|
170
|
+
},
|
|
171
|
+
"es": {
|
|
172
|
+
"Blueprints": "Blueprints", "Brandings": "Marcas", "Pesquisa pública": "Búsqueda pública", "Cadastro manual": "Registro manual", "Contas cadastradas": "Cuentas registradas", "Biblioteca": "Biblioteca", "Importar do YouTube": "Importar de YouTube", "Canais em lote gmail": "Canales Gmail por lotes", "Criar vídeo": "Crear vídeo", "Vídeos": "Vídeos", "Novo roteiro/letra": "Nuevo guion/letra", "Histórico guardado": "Historial guardado", "Clusters encontrados": "Clústeres encontrados", "Regras de associação": "Reglas de asociación", "Dados analisados": "Datos analizados", "Upload ficheiro": "Subir archivo", "URL de vídeo": "URL del vídeo", "Vídeos gerados": "Vídeos generados", "Pasta local": "Carpeta local", "Código Python": "Código Python", "Upload convencional": "Carga convencional", "Upload directo": "Carga directa", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Claves API", "Teste de vozes": "Prueba de voces", "Serviços e modelos": "Servicios y modelos", "Fontes de materiais": "Fuentes de medios", "Client MCP": "Cliente MCP", "Servidor MCP": "Servidor MCP", "Skill": "Habilidad",
|
|
173
|
+
},
|
|
174
|
+
"id": {
|
|
175
|
+
"Blueprints": "Blueprint", "Brandings": "Branding", "Pesquisa pública": "Pencarian publik", "Cadastro manual": "Pendaftaran manual", "Contas cadastradas": "Akun terdaftar", "Biblioteca": "Pustaka", "Importar do YouTube": "Impor dari YouTube", "Canais em lote gmail": "Kanal Gmail massal", "Criar vídeo": "Buat video", "Vídeos": "Video", "Novo roteiro/letra": "Skrip/lirik baru", "Histórico guardado": "Riwayat tersimpan", "Clusters encontrados": "Cluster ditemukan", "Regras de associação": "Aturan asosiasi", "Dados analisados": "Data yang dianalisis", "Upload ficheiro": "Unggah file", "URL de vídeo": "URL video", "Vídeos gerados": "Video yang dibuat", "Pasta local": "Folder lokal", "Código Python": "Kode Python", "Upload convencional": "Unggah konvensional", "Upload directo": "Unggah langsung", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Kunci API", "Teste de vozes": "Uji suara", "Serviços e modelos": "Layanan dan model", "Fontes de materiais": "Sumber media", "Client MCP": "Klien MCP", "Servidor MCP": "Server MCP", "Skill": "Keahlian",
|
|
176
|
+
},
|
|
177
|
+
"it": {
|
|
178
|
+
"Blueprints": "Blueprint", "Brandings": "Branding", "Pesquisa pública": "Ricerca pubblica", "Cadastro manual": "Registrazione manuale", "Contas cadastradas": "Account registrati", "Biblioteca": "Libreria", "Importar do YouTube": "Importa da YouTube", "Canais em lote gmail": "Canali Gmail in batch", "Criar vídeo": "Crea video", "Vídeos": "Video", "Novo roteiro/letra": "Nuovo copione/testo", "Histórico guardado": "Cronologia salvata", "Clusters encontrados": "Cluster trovati", "Regras de associação": "Regole di associazione", "Dados analisados": "Dati analizzati", "Upload ficheiro": "Carica file", "URL de vídeo": "URL video", "Vídeos gerados": "Video generati", "Pasta local": "Cartella locale", "Código Python": "Codice Python", "Upload convencional": "Caricamento convenzionale", "Upload directo": "Caricamento diretto", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Chiavi API", "Teste de vozes": "Test delle voci", "Serviços e modelos": "Servizi e modelli", "Fontes de materiais": "Fonti multimediali", "Client MCP": "Client MCP", "Servidor MCP": "Server MCP", "Skill": "Skill",
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for _language_code, _tab_translation in TAB_TRANSLATIONS.items():
|
|
183
|
+
UI_TRANSLATIONS[_language_code].update(_tab_translation)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
TUTORIAL_TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
187
|
+
"pt": {"Tutorial Supabase": "Tutorial Supabase", "Guia de configuração do Supabase para automações com n8n.": "Guia de configuração do Supabase para automações com n8n."},
|
|
188
|
+
"en": {"Tutorial Supabase": "Supabase Tutorial", "Guia de configuração do Supabase para automações com n8n.": "Supabase setup guide for n8n automations."},
|
|
189
|
+
"zh": {"Tutorial Supabase": "Supabase 教程", "Guia de configuração do Supabase para automações com n8n.": "用于 n8n 自动化的 Supabase 配置指南。"},
|
|
190
|
+
"de": {"Tutorial Supabase": "Supabase-Tutorial", "Guia de configuração do Supabase para automações com n8n.": "Anleitung zur Supabase-Konfiguration für n8n-Automatisierungen."},
|
|
191
|
+
"vi": {"Tutorial Supabase": "Hướng dẫn Supabase", "Guia de configuração do Supabase para automações com n8n.": "Hướng dẫn cấu hình Supabase cho tự động hóa n8n."},
|
|
192
|
+
"tr": {"Tutorial Supabase": "Supabase Eğitimi", "Guia de configuração do Supabase para automações com n8n.": "n8n otomasyonları için Supabase yapılandırma rehberi."},
|
|
193
|
+
"ru": {"Tutorial Supabase": "Руководство Supabase", "Guia de configuração do Supabase para automações com n8n.": "Руководство по настройке Supabase для автоматизации n8n."},
|
|
194
|
+
"es": {"Tutorial Supabase": "Tutorial de Supabase", "Guia de configuração do Supabase para automações com n8n.": "Guía de configuración de Supabase para automatizaciones con n8n."},
|
|
195
|
+
"id": {"Tutorial Supabase": "Tutorial Supabase", "Guia de configuração do Supabase para automações com n8n.": "Panduan konfigurasi Supabase untuk otomatisasi n8n."},
|
|
196
|
+
"it": {"Tutorial Supabase": "Tutorial Supabase", "Guia de configuração do Supabase para automações com n8n.": "Guida alla configurazione di Supabase per le automazioni n8n."},
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for _language_code, _tutorial_translation in TUTORIAL_TRANSLATIONS.items():
|
|
200
|
+
UI_TRANSLATIONS[_language_code].update(_tutorial_translation)
|
|
201
|
+
|
|
202
|
+
|
|
143
203
|
def ui_text(value: str, language: Any = "pt") -> str:
|
|
144
204
|
code = language_code(language)
|
|
145
205
|
return UI_TRANSLATIONS.get(code, {}).get(value, value)
|
package/package.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Guia para criar e configurar uma conta Supabase
|
|
2
|
+
|
|
3
|
+
Este guia mostra como criar uma conta gratuita no Supabase e preparar as tabelas e o armazenamento necessários para utilizar a base de dados com automações n8n.
|
|
4
|
+
|
|
5
|
+
Comece por abrir o [Supabase](https://supabase.com/) e criar uma nova conta gratuita.
|
|
6
|
+
|
|
7
|
+
## 1. Criar as tabelas da base de dados
|
|
8
|
+
|
|
9
|
+
Quando a conta estiver pronta, abra o `Table Editor`.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
Para criar uma tabela nova, clique no botão `New table`.
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
### Criar a tabela `plans`
|
|
18
|
+
|
|
19
|
+
A tabela `plans` deve ter quatro campos:
|
|
20
|
+
|
|
21
|
+
1. `id` (`int8`) — chave primária; utilize as definições predefinidas.
|
|
22
|
+
2. `period_type` (`text`) — identifica os períodos. Os valores possíveis são `quarter`, `month` e `week`.
|
|
23
|
+
3. `period_index` (`text`) — guarda o índice do período, por exemplo `2025-Q2` para o segundo trimestre de 2025.
|
|
24
|
+
4. `plan_value` (`text`) — guarda o valor efectivo do plano para o período indicado.
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
Quando terminar, clique em `Save`.
|
|
29
|
+
|
|
30
|
+
### Criar a tabela `posts`
|
|
31
|
+
|
|
32
|
+
Crie a tabela `posts` com os seguintes campos:
|
|
33
|
+
|
|
34
|
+
1. `id` (`int8`) — chave primária; utilize as definições predefinidas.
|
|
35
|
+
2. `created_at` (`timestamp`) — valor predefinido `now()`.
|
|
36
|
+
3. `post_summary` (`text`) — guarda o resumo de cada publicação para manter consistência entre publicações.
|
|
37
|
+
4. `image_path` (`text`) — guarda o caminho da imagem gerada e carregada para o bucket do Supabase Storage.
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
## 2. Criar o bucket de Storage
|
|
42
|
+
|
|
43
|
+
No menu do Supabase, clique em `Storage`.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
Clique em `New bucket`.
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
Dê ao bucket o nome `instagram-images` ou outro nome compatível com as regras de nomenclatura. Guarde esse nome, porque será necessário configurá-lo no n8n.
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
Depois, carregue a imagem de referência para o bucket usando o botão `Upload files`.
|
|
56
|
+
|
|
57
|
+

|
|
58
|
+
|
|
59
|
+
A conta Supabase está pronta para ser utilizada pela automação.
|
|
60
|
+
|
|
61
|
+
Fonte original: [guide-supabase.md no GitHub](https://github.com/gyoridavid/ai_agents_az/blob/main/episode_8/guide-supabase.md)
|