@danhachuel/thunderbolt 0.3.75 → 0.3.77

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Este manual descreve a instalação local da UI Thunderbolt, baseada no MoneyPrinterTurbo, utilizando o pacote npm `@danhachuel/thunderbolt`. O fluxo recomendado instala automaticamente o ambiente Python, as dependências da aplicação, as dependências do MoneyPrinterTurbo, o Streamlit e o suporte FFmpeg através de `imageio-ffmpeg`.
4
4
 
5
- > **Versão deste manual:** 0.3.75
5
+ > **Versão deste manual:** 0.3.77
6
6
  > **Pacote npm:** `@danhachuel/thunderbolt`
7
7
  > **Porta padrão da UI:** `localhost:3030`
8
8
  > **Repositório:** [github.com/DanHachuel/thunderbolt](https://github.com/DanHachuel/thunderbolt)
@@ -132,13 +132,13 @@ Execute:
132
132
  Windows PowerShell ou MobaXterm:
133
133
 
134
134
  ```powershell
135
- npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.75 install
135
+ npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.77 install
136
136
  ```
137
137
 
138
138
  Linux/macOS:
139
139
 
140
140
  ```bash
141
- npx --yes --prefer-online @danhachuel/thunderbolt@0.3.75 install
141
+ npx --yes --prefer-online @danhachuel/thunderbolt@0.3.77 install
142
142
  ```
143
143
 
144
144
  A instalação normal é **segura para actualizações**: preserva `storage`, Blueprints, Brandings, configurações e artefactos do utilizador. Remove apenas `.venv`, o clone técnico do MoneyPrinterTurbo e dependências que serão recriadas. Uma pasta antiga sem dados do utilizador, como `C:\Users\<utilizador>\AppData\Local\hermes` da tentativa incompleta, pode ser removida; uma pasta antiga que contenha Blueprints, Brandings ou storage é preservada e apenas avisada no terminal. Feche processos Python, Node, Streamlit e MobaXterm que estejam a usar as pastas antes de executar.
@@ -146,7 +146,7 @@ A instalação normal é **segura para actualizações**: preserva `storage`, Bl
146
146
  Se quiser apagar absolutamente tudo de forma intencional, use o comando destrutivo separado:
147
147
 
148
148
  ```powershell
149
- npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.75 install --purge-data
149
+ npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.77 install --purge-data
150
150
  ```
151
151
 
152
152
  O parâmetro `--purge-data` apaga Blueprints, Brandings, configurações, storage e artefactos locais. Não o use numa actualização normal.
@@ -437,7 +437,7 @@ A geração Nano Banana usa o contrato actualizado da Interactions API e não en
437
437
 
438
438
  ### 4.3 Navegação da UI
439
439
 
440
- Na primeira execução, a barra lateral apresenta **Início**, **Niche Finder**, **Pipeline Vídeos**, **Pipeline Música**, **Automação**, **Edição**, **AI Influencers** e **Configurações**. O menu expansível **Pipeline Música** contém **Criação de Músicas** e **Upload Música**, cuja página tem as subabas **JewelMusic**, **Pushtunes** e **ytmusicapi**. O menu expansível **Pipeline Vídeos** contém **Criação de Vídeos**, **Backlog Vídeos**, **Roteiros**, **Thumbnails** e **Upload**. 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 Vídeos** contém **Criação de Vídeos**, **Backlog Vídeos**, **Roteiros**, **Thumbnails** e **Upload**. O menu **Pipeline Música** contém **Criação de Músicas** e **Upload Música**. 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` por conta, a `INNERTUBE_API_KEY` global, 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** contém as subabas **Geral** e **Telegram**. A subaba Geral mantém o histórico e as preferências dos eventos locais; a subaba Telegram envia esses mesmos eventos para o Chat ID configurado. A página **Pipeline Música > Upload Música** contém as subabas **JewelMusic**, **Pushtunes** e **ytmusicapi**. 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.
440
+ Na primeira execução, a barra lateral apresenta **Início**, **Automação**, **Niche Finder**, **Canais/Perfis (Vídeos)**, **Pipeline Vídeos**, **Pipeline Música**, **AI Influencers**, **Edição**, **Growth**, **Documentação** e **Configurações**, nessa ordem. O menu expansível **Canais/Perfis (Vídeos)** contém **Canais YouTube**, **Blueprints Youtube**, **Contas TikTok**, **Prompt Masters** e **Facebook Pages**, nessa ordem. **Arquivos Base** foi removido por ficar vazio. O menu expansível **Pipeline Música** contém **Criação de Músicas** e **Upload Música**, cuja página tem as subabas **JewelMusic**, **Pushtunes** e **ytmusicapi**. O menu expansível **Pipeline Vídeos** contém **Criação de Vídeos**, **Backlog Vídeos**, **Roteiros**, **Thumbnails** e **Upload**. 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**, **Editor Python** e **Download Mídia**. O menu expansível **AI Influencers** contém **Personagens**, **Geração de Conteúdo IA**, **Motion Control**, **UGC Products** e **Redes Sociais**. O menu expansível **Niche Finder** contém **Niche Finder Kaggle** e **Niche Finder Apify**. **Growth** contém os analistas de YouTube, TikTok, Instagram, Facebook Pages e Bilibili. **Documentação** contém os tutoriais disponíveis. **Configurações** contém **MCP**, **Notificações**, **Logs** e **Configuração API**.
441
441
 
442
442
  | Configuração | Finalidade |
443
443
  |---|---|
@@ -574,7 +574,7 @@ Ao abrir a página, o Thunderbolt não prepara dados públicos, não descarrega
574
574
 
575
575
  Os parâmetros da UI são número de clusters entre 2 e 10, suporte mínimo entre 0,01 e 0,50, país, engagement, intervalo de datas e tags, todos dentro da área principal da aba. O núcleo normaliza os dados, calcula engagement, aplica filtros, faz transformação logarítmica e standardização, executa K-Means e calcula itemsets/regras com FP-Growth. Não são apresentados resultados até ao primeiro clique em **Analisar Nichos**; o mesmo botão aplica alterações posteriores aos filtros. Os resultados são DataFrames de clusters, itemsets frequentes, regras de associação e dados analisados; o gráfico de dispersão é criado nativamente com Plotly.
576
576
 
577
- As dependências adicionais — `scikit-learn`, `mlxtend`, `plotly`, `seaborn`, `matplotlib` e `kagglehub` — são instaladas pelo procedimento normal de `npx`. Em instalações existentes, execute novamente `npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.75 install`; o instalador detecta e reutiliza o que já estiver válido.
577
+ As dependências adicionais — `scikit-learn`, `mlxtend`, `plotly`, `seaborn`, `matplotlib` e `kagglehub` — são instaladas pelo procedimento normal de `npx`. Em instalações existentes, execute novamente `npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.77 install`; o instalador detecta e reutiliza o que já estiver válido.
578
578
 
579
579
  ### Niche Finder Apify
580
580
 
@@ -811,3 +811,9 @@ O worker local guarda a etapa actual e os artefactos de cada tarefa. Ao reinicia
811
811
 
812
812
  ### Selector de modelos LLM
813
813
  No card **OpenAI / NVIDIA NIM**, o campo **Modelo** é uma lista suspensa. Use **Consultar modelos** para actualizar as opções do endpoint; se o identificador não estiver disponível, escolha **Escrever modelo manualmente**.
814
+
815
+ ## 16. Diagnóstico prioritário do Azure Speech V2
816
+
817
+ Quando Azure Speech SDK V2 estiver seleccionado, o Thunderbolt prepara a narração em segmentos antes de iniciar o MoneyPrinterTurbo. O tamanho interno dos segmentos é reduzido automaticamente para velocidades de fala lentas, o áudio final é validado e a CLI recebe `--custom-audio-file`. A geração é bloqueada se não houver confirmação dos segmentos; isto evita regressar à chamada monolítica do Azure que pode falhar com `maximum media duration of 600000ms`.
818
+
819
+ Na interface, uma tarefa em execução mostra a última actividade do helper e o tempo decorrido da etapa Vídeo. Se ocorrer uma falha, consulte o caminho `LOG_FILE` ou `RESULT_FILE` apresentado no erro. A linha `updated configuration fields` é apenas sincronização inicial de configuração e não é a causa terminal. Nunca copie chaves, cookies, tokens ou o conteúdo integral do roteiro para pedidos de suporte.
package/README.md CHANGED
@@ -107,10 +107,10 @@ No topo da área principal da aplicação existe o menu nativo de idioma no padr
107
107
 
108
108
  A UI suporta os temas **Dark** e **Light** através do menu nativo de três pontos do Streamlit, no local original do toolbar. Não existe um selector Theme adicional dentro da página. A configuração distribuída em `.streamlit/config.toml` disponibiliza as variantes nomeadas **Dark** e **Light**, e o menu nativo continua responsável por alternar entre os modos, seguindo o padrão do [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo). O CSS próprio do Thunderbolt usa cores semânticas, `currentColor` e `color-mix` para acompanhar o tema activo, sem alterar a posição nem a funcionalidade do toolbar, do botão Deploy e do menu principal.
109
109
 
110
- ## Navegação da UI 0.3.75
110
+ ## Navegação da UI 0.3.77
111
111
 
112
- 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 Vídeos** é expansível e contém **Criação de Vídeos**, **Backlog Vídeos**, **Roteiros**, **Thumbnails** e **Upload**. **Pipeline Música** é expansível e contém **Criação de Músicas** e **Upload Música**. **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**, **Geração de Conteúdo IA**, **Motion Control**, **UGC Products**, **Redes Sociais**, **Tutorial Meta** e **Tutorial Supabase**, nessa ordem. A criação de Motion Control e UGC Products ocorre nas páginas standalone e guarda os artefactos localmente; não existem tabs duplicadas dentro de Geração de Conteúdo IA.
113
- **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**, **Notificações**, **Logs** e **Configuração API**, nessa ordem. O Início reúne o dashboard e as filas do Pipeline, sem botões de acções rápidas.
112
+ A barra lateral apresenta os níveis principais nesta ordem: **Início**, **Automação**, **Niche Finder**, **Canais/Perfis (Vídeos)**, **Pipeline Vídeos**, **Pipeline Música**, **AI Influencers**, **Edição**, **Growth**, **Documentação** e **Configurações**. **Canais/Perfis (Vídeos)** é expansível e contém **Canais YouTube**, **Blueprints Youtube**, **Contas TikTok**, **Prompt Masters** e **Facebook Pages**, nessa ordem. O menu **Arquivos Base** foi removido por ficar vazio.
113
+ **Pipeline Vídeos** contém **Criação de Vídeos**, **Backlog Vídeos**, **Roteiros**, **Thumbnails** e **Upload**; **Pipeline Música** contém **Criação de Músicas** e **Upload Música**; **Automação** contém **Automação Youtube**; **Niche Finder** contém **Niche Finder Kaggle** e **Niche Finder Apify**; **AI Influencers** contém **Personagens**, **Geração de Conteúdo IA**, **Motion Control**, **UGC Products** e **Redes Sociais**. O Início reúne o dashboard e as filas do Pipeline, sem botões de acções rápidas.
114
114
 
115
115
  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:
116
116
 
@@ -426,3 +426,9 @@ A pipeline do worker usa agora um orquestrador local em cascata, com artefactos
426
426
 
427
427
  ## Selector de modelos LLM
428
428
  O campo **Modelo** em **Configuração API > API Keys > LLM — providers e modelos** é apresentado como lista suspensa permanente. A lista usa os modelos descobertos pelo endpoint e preserva o modelo guardado; a opção manual continua disponível apenas como fallback explícito.
429
+
430
+ ## Correcção prioritária de geração de vídeo
431
+
432
+ No fluxo MoneyPrinterTurbo, a voz Azure Speech SDK V2 é preparada antes da CLI upstream. O Thunderbolt divide o roteiro em segmentos conservadores ajustados à velocidade, concatena o áudio localmente e só inicia o motor depois de confirmar o ficheiro e a contagem de segmentos. Se essa preparação falhar, a tarefa é interrompida e não existe fallback silencioso para uma chamada monolítica sujeita ao limite de 600000 ms.
433
+
434
+ Durante a execução, o backlog mostra a actividade recente do helper e o tempo da etapa Vídeo. Em caso de falha, a mensagem terminal é extraída do output accionável, enquanto as linhas `using existing project` e `updated configuration fields` deixam de ser tratadas como causa. Os caminhos do log e do manifesto são preservados mesmo quando a falha ocorre antes da criação do MP4.
package/app/main.py CHANGED
@@ -3582,6 +3582,15 @@ def _render_video_task_state(task: dict[str, Any]) -> None:
3582
3582
  st.write(state or "—")
3583
3583
  st.caption(VIDEO_TASK_STATE_LABELS.get(state, state.replace("_", " ").capitalize() or "Desconhecido"))
3584
3584
  st.progress(progress, text=f"{progress}%")
3585
+ helper_status = str(task.get("video_helper_status") or "").strip()
3586
+ if state == "doing" and helper_status:
3587
+ st.caption(f"Actividade: {helper_status[-240:]}")
3588
+ if state == "doing" and task.get("video_elapsed_seconds") is not None:
3589
+ try:
3590
+ elapsed_seconds = max(0, int(task.get("video_elapsed_seconds") or 0))
3591
+ st.caption(f"Tempo da etapa Vídeo: {elapsed_seconds // 60}m {elapsed_seconds % 60:02d}s")
3592
+ except (TypeError, ValueError):
3593
+ pass
3585
3594
  if task.get("error"):
3586
3595
  st.caption(str(task.get("error"))[:240])
3587
3596
 
@@ -6597,13 +6606,11 @@ def main():
6597
6606
  ("Thumbnails", ":material/image:", "Thumbnails"),
6598
6607
  ("Upload", ":material/cloud_upload:", "Upload"),
6599
6608
  ]
6600
- base_files_items = [
6601
- ("Blueprints Youtube", ":material/library_books:", "Blueprints Youtube"),
6602
- ("Prompt Masters", ":material/auto_awesome:", "Prompt Masters"),
6603
- ]
6604
6609
  channel_profile_items = [
6605
6610
  ("Canais YouTube", ":material/ondemand_video:", "Canais YouTube"),
6611
+ ("Blueprints Youtube", ":material/library_books:", "Blueprints Youtube"),
6606
6612
  ("Contas TikTok", ":material/account_circle:", "Contas TikTok"),
6613
+ ("Prompt Masters", ":material/auto_awesome:", "Prompt Masters"),
6607
6614
  ("Facebook Pages", ":material/public:", "Facebook Pages"),
6608
6615
  ]
6609
6616
  music_items = [
@@ -6653,13 +6660,12 @@ def main():
6653
6660
  ("Início", ":material/home:", "Início"),
6654
6661
  ("Automação", ":material/schedule:", "Automação"),
6655
6662
  ("Niche Finder", ":material/search:", "Niche Finder"),
6656
- ("Arquivos Base", ":material/folder:", "Arquivos Base"),
6657
- ("Canais e Perfis de Vídeos", ":material/video_library:", "Canais e Perfis de Vídeos"),
6658
- ("Growth", ":material/analytics:", "Growth"),
6663
+ ("Canais/Perfis (Vídeos)", ":material/video_library:", "Canais/Perfis (Vídeos)"),
6659
6664
  ("Pipeline Vídeos", ":material/account_tree:", "Pipeline Vídeos"),
6660
6665
  ("Pipeline Música", ":material/music_note:", "Pipeline Música"),
6661
6666
  ("AI Influencers", ":material/smart_toy:", "AI Influencers"),
6662
6667
  ("Edição", ":material/edit:", "Edição"),
6668
+ ("Growth", ":material/analytics:", "Growth"),
6663
6669
  ("Documentação", ":material/menu_book:", "Documentação"),
6664
6670
  ("Configurações", ":material/settings:", "Configurações"),
6665
6671
  ]
@@ -6668,8 +6674,7 @@ def main():
6668
6674
  "Niche Finder": niche_finder_items,
6669
6675
  "Pipeline Vídeos": pipeline_video_items,
6670
6676
  "AI Influencers": models_ai_items,
6671
- "Arquivos Base": base_files_items,
6672
- "Canais e Perfis de Vídeos": channel_profile_items,
6677
+ "Canais/Perfis (Vídeos)": channel_profile_items,
6673
6678
  "Pipeline Música": music_items,
6674
6679
  "Edição": edition_items,
6675
6680
  "Growth": growth_items,
@@ -6683,7 +6688,8 @@ def main():
6683
6688
  "Limpador de metadado": "Limpador de Metadados",
6684
6689
  "Pipeline": "Pipeline Vídeos",
6685
6690
  "Música": "Pipeline Música",
6686
- "Pipeline TikTok": "Canais e Perfis de Vídeos",
6691
+ "Pipeline TikTok": "Canais/Perfis (Vídeos)",
6692
+ "Canais e Perfis de Vídeos": "Canais/Perfis (Vídeos)",
6687
6693
  "Prompts Master": "Prompt Masters",
6688
6694
  "Canais": "Canais YouTube",
6689
6695
  "Canais Youtube": "Canais YouTube",
@@ -252,34 +252,34 @@ for _language_code in UI_TRANSLATIONS:
252
252
  # translation path as the legacy pages.
253
253
  UI_NAV_TRANSLATIONS: dict[str, dict[str, str]] = {
254
254
  "pt": {
255
- "Arquivos Base": "Arquivos Base", "Pipeline Vídeos": "Pipeline Vídeos", "Canais e Perfis de Vídeos": "Canais e Perfis de Vídeos", "Canais YouTube": "Canais YouTube", "Facebook Pages": "Facebook Pages", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Backlog Vídeos", "Thumbnails": "Thumbnails", "Música": "Música", "Upload Música": "Upload Música", "Geração de Conteúdo IA": "Geração de Conteúdo IA", "Motion Control": "Motion Control", "UGC Products": "UGC Products", "Growth": "Growth", "Analista Growth Youtube": "Analista Growth Youtube", "Analista Growth Tiktok": "Analista Growth Tiktok", "Analista Growth Instagram": "Analista Growth Instagram", "Analista Facebook Pages": "Analista Facebook Pages", "Analista Bilibili": "Analista Bilibili", "Documentação": "Documentação", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Pipeline Música", "módulos disponíveis": "módulos disponíveis",
255
+ "Arquivos Base": "Arquivos Base", "Pipeline Vídeos": "Pipeline Vídeos", "Canais e Perfis de Vídeos": "Canais e Perfis de Vídeos", "Canais/Perfis (Vídeos)": "Canais e Perfis de Vídeos", "Canais YouTube": "Canais YouTube", "Facebook Pages": "Facebook Pages", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Backlog Vídeos", "Thumbnails": "Thumbnails", "Música": "Música", "Upload Música": "Upload Música", "Geração de Conteúdo IA": "Geração de Conteúdo IA", "Motion Control": "Motion Control", "UGC Products": "UGC Products", "Growth": "Growth", "Analista Growth Youtube": "Analista Growth Youtube", "Analista Growth Tiktok": "Analista Growth Tiktok", "Analista Growth Instagram": "Analista Growth Instagram", "Analista Facebook Pages": "Analista Facebook Pages", "Analista Bilibili": "Analista Bilibili", "Documentação": "Documentação", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Pipeline Música", "módulos disponíveis": "módulos disponíveis",
256
256
  },
257
257
  "en": {
258
- "Arquivos Base": "Base Files", "Pipeline Vídeos": "Video Pipeline", "Canais e Perfis de Vídeos": "Video Channels & Profiles", "Canais YouTube": "YouTube Channels", "Facebook Pages": "Facebook Pages", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Video Backlog", "Thumbnails": "Thumbnails", "Música": "Music", "Upload Música": "Music Upload", "Geração de Conteúdo IA": "AI Content Generation", "Motion Control": "Motion Control", "UGC Products": "UGC Products", "Growth": "Growth", "Analista Growth Youtube": "YouTube Growth Analyst", "Analista Growth Tiktok": "TikTok Growth Analyst", "Analista Growth Instagram": "Instagram Growth Analyst", "Analista Facebook Pages": "Facebook Pages Analyst", "Analista Bilibili": "Bilibili Analyst", "Documentação": "Documentation", "Tutorial Kaggle": "Kaggle Tutorial", "Tutorial Apify": "Apify Tutorial", "Pipeline Música": "Music Pipeline", "módulos disponíveis": "available modules",
258
+ "Arquivos Base": "Base Files", "Pipeline Vídeos": "Video Pipeline", "Canais e Perfis de Vídeos": "Video Channels & Profiles", "Canais/Perfis (Vídeos)": "Video Channels & Profiles", "Canais YouTube": "YouTube Channels", "Facebook Pages": "Facebook Pages", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Video Backlog", "Thumbnails": "Thumbnails", "Música": "Music", "Upload Música": "Music Upload", "Geração de Conteúdo IA": "AI Content Generation", "Motion Control": "Motion Control", "UGC Products": "UGC Products", "Growth": "Growth", "Analista Growth Youtube": "YouTube Growth Analyst", "Analista Growth Tiktok": "TikTok Growth Analyst", "Analista Growth Instagram": "Instagram Growth Analyst", "Analista Facebook Pages": "Facebook Pages Analyst", "Analista Bilibili": "Bilibili Analyst", "Documentação": "Documentation", "Tutorial Kaggle": "Kaggle Tutorial", "Tutorial Apify": "Apify Tutorial", "Pipeline Música": "Music Pipeline", "módulos disponíveis": "available modules",
259
259
  },
260
260
  "zh": {
261
- "Arquivos Base": "基础文件", "Pipeline Vídeos": "视频流程", "Canais e Perfis de Vídeos": "视频频道与资料", "Canais YouTube": "YouTube 频道", "Facebook Pages": "Facebook 页面", "Prompt Masters": "主提示词", "Backlog Vídeos": "视频待办", "Thumbnails": "缩略图", "Música": "音乐", "Upload Música": "音乐上传", "Geração de Conteúdo IA": "AI 内容生成", "Motion Control": "动作控制", "UGC Products": "UGC 产品", "Growth": "增长", "Analista Growth Youtube": "YouTube 增长分析师", "Analista Growth Tiktok": "TikTok 增长分析师", "Analista Growth Instagram": "Instagram 增长分析师", "Analista Facebook Pages": "Facebook Pages 分析师", "Analista Bilibili": "Bilibili 分析师", "Documentação": "文档", "Tutorial Kaggle": "Kaggle 教程", "Tutorial Apify": "Apify 教程", "Pipeline Música": "音乐流程", "módulos disponíveis": "可用模块",
261
+ "Arquivos Base": "基础文件", "Pipeline Vídeos": "视频流程", "Canais e Perfis de Vídeos": "视频频道与资料", "Canais/Perfis (Vídeos)": "视频频道与资料", "Canais YouTube": "YouTube 频道", "Facebook Pages": "Facebook 页面", "Prompt Masters": "主提示词", "Backlog Vídeos": "视频待办", "Thumbnails": "缩略图", "Música": "音乐", "Upload Música": "音乐上传", "Geração de Conteúdo IA": "AI 内容生成", "Motion Control": "动作控制", "UGC Products": "UGC 产品", "Growth": "增长", "Analista Growth Youtube": "YouTube 增长分析师", "Analista Growth Tiktok": "TikTok 增长分析师", "Analista Growth Instagram": "Instagram 增长分析师", "Analista Facebook Pages": "Facebook Pages 分析师", "Analista Bilibili": "Bilibili 分析师", "Documentação": "文档", "Tutorial Kaggle": "Kaggle 教程", "Tutorial Apify": "Apify 教程", "Pipeline Música": "音乐流程", "módulos disponíveis": "可用模块",
262
262
  },
263
263
  "de": {
264
- "Arquivos Base": "Basisdateien", "Pipeline Vídeos": "Video-Pipeline", "Canais e Perfis de Vídeos": "Videokanäle und Profile", "Canais YouTube": "YouTube-Kanäle", "Facebook Pages": "Facebook-Seiten", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Video-Backlog", "Thumbnails": "Thumbnails", "Música": "Musik", "Upload Música": "Musik-Upload", "Geração de Conteúdo IA": "KI-Inhaltserstellung", "Motion Control": "Motion Control", "UGC Products": "UGC-Produkte", "Growth": "Wachstum", "Analista Growth Youtube": "YouTube-Wachstumsanalyst", "Analista Growth Tiktok": "TikTok-Wachstumsanalyst", "Analista Growth Instagram": "Instagram-Wachstumsanalyst", "Analista Facebook Pages": "Facebook-Pages-Analyst", "Analista Bilibili": "Bilibili-Analyst", "Documentação": "Dokumentation", "Tutorial Kaggle": "Kaggle-Tutorial", "Tutorial Apify": "Apify-Tutorial", "Pipeline Música": "Musik-Pipeline", "módulos disponíveis": "verfügbare Module",
264
+ "Arquivos Base": "Basisdateien", "Pipeline Vídeos": "Video-Pipeline", "Canais e Perfis de Vídeos": "Videokanäle und Profile", "Canais/Perfis (Vídeos)": "Videokanäle und Profile", "Canais YouTube": "YouTube-Kanäle", "Facebook Pages": "Facebook-Seiten", "Prompt Masters": "Prompt Masters", "Backlog Vídeos": "Video-Backlog", "Thumbnails": "Thumbnails", "Música": "Musik", "Upload Música": "Musik-Upload", "Geração de Conteúdo IA": "KI-Inhaltserstellung", "Motion Control": "Motion Control", "UGC Products": "UGC-Produkte", "Growth": "Wachstum", "Analista Growth Youtube": "YouTube-Wachstumsanalyst", "Analista Growth Tiktok": "TikTok-Wachstumsanalyst", "Analista Growth Instagram": "Instagram-Wachstumsanalyst", "Analista Facebook Pages": "Facebook-Pages-Analyst", "Analista Bilibili": "Bilibili-Analyst", "Documentação": "Dokumentation", "Tutorial Kaggle": "Kaggle-Tutorial", "Tutorial Apify": "Apify-Tutorial", "Pipeline Música": "Musik-Pipeline", "módulos disponíveis": "verfügbare Module",
265
265
  },
266
266
  "vi": {
267
- "Arquivos Base": "Tệp cơ sở", "Pipeline Vídeos": "Quy trình video", "Canais e Perfis de Vídeos": "Kênh và hồ sơ video", "Canais YouTube": "Kênh YouTube", "Facebook Pages": "Trang Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Danh sách video", "Thumbnails": "Ảnh thu nhỏ", "Música": "Âm nhạc", "Upload Música": "Tải nhạc lên", "Geração de Conteúdo IA": "Tạo nội dung AI", "Motion Control": "Điều khiển chuyển động", "UGC Products": "Sản phẩm UGC", "Growth": "Tăng trưởng", "Analista Growth Youtube": "Chuyên viên phân tích tăng trưởng YouTube", "Analista Growth Tiktok": "Chuyên viên phân tích tăng trưởng TikTok", "Analista Growth Instagram": "Chuyên viên phân tích tăng trưởng Instagram", "Analista Facebook Pages": "Chuyên viên phân tích Facebook Pages", "Analista Bilibili": "Chuyên viên phân tích Bilibili", "Documentação": "Tài liệu", "Tutorial Kaggle": "Hướng dẫn Kaggle", "Tutorial Apify": "Hướng dẫn Apify", "Pipeline Música": "Quy trình âm nhạc", "módulos disponíveis": "mô-đun khả dụng",
267
+ "Arquivos Base": "Tệp cơ sở", "Pipeline Vídeos": "Quy trình video", "Canais e Perfis de Vídeos": "Kênh và hồ sơ video", "Canais/Perfis (Vídeos)": "Kênh và hồ sơ video", "Canais YouTube": "Kênh YouTube", "Facebook Pages": "Trang Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Danh sách video", "Thumbnails": "Ảnh thu nhỏ", "Música": "Âm nhạc", "Upload Música": "Tải nhạc lên", "Geração de Conteúdo IA": "Tạo nội dung AI", "Motion Control": "Điều khiển chuyển động", "UGC Products": "Sản phẩm UGC", "Growth": "Tăng trưởng", "Analista Growth Youtube": "Chuyên viên phân tích tăng trưởng YouTube", "Analista Growth Tiktok": "Chuyên viên phân tích tăng trưởng TikTok", "Analista Growth Instagram": "Chuyên viên phân tích tăng trưởng Instagram", "Analista Facebook Pages": "Chuyên viên phân tích Facebook Pages", "Analista Bilibili": "Chuyên viên phân tích Bilibili", "Documentação": "Tài liệu", "Tutorial Kaggle": "Hướng dẫn Kaggle", "Tutorial Apify": "Hướng dẫn Apify", "Pipeline Música": "Quy trình âm nhạc", "módulos disponíveis": "mô-đun khả dụng",
268
268
  },
269
269
  "tr": {
270
- "Arquivos Base": "Temel Dosyalar", "Pipeline Vídeos": "Video Akışı", "Canais e Perfis de Vídeos": "Video Kanalları ve Profilleri", "Canais YouTube": "YouTube Kanalları", "Facebook Pages": "Facebook Sayfaları", "Prompt Masters": "Prompt Master'lar", "Backlog Vídeos": "Video Bekleme Listesi", "Thumbnails": "Küçük resimler", "Música": "Müzik", "Upload Música": "Müzik Yükleme", "Geração de Conteúdo IA": "Yapay Zekâ İçeriği Oluşturma", "Motion Control": "Hareket Kontrolü", "UGC Products": "UGC Ürünleri", "Growth": "Büyüme", "Analista Growth Youtube": "YouTube Büyüme Analisti", "Analista Growth Tiktok": "TikTok Büyüme Analisti", "Analista Growth Instagram": "Instagram Büyüme Analisti", "Analista Facebook Pages": "Facebook Pages Analisti", "Analista Bilibili": "Bilibili Analisti", "Documentação": "Dokümantasyon", "Tutorial Kaggle": "Kaggle Eğitimi", "Tutorial Apify": "Apify Eğitimi", "Pipeline Música": "Müzik Akışı", "módulos disponíveis": "kullanılabilir modüller",
270
+ "Arquivos Base": "Temel Dosyalar", "Pipeline Vídeos": "Video Akışı", "Canais e Perfis de Vídeos": "Video Kanalları ve Profilleri", "Canais/Perfis (Vídeos)": "Video Kanalları ve Profilleri", "Canais YouTube": "YouTube Kanalları", "Facebook Pages": "Facebook Sayfaları", "Prompt Masters": "Prompt Master'lar", "Backlog Vídeos": "Video Bekleme Listesi", "Thumbnails": "Küçük resimler", "Música": "Müzik", "Upload Música": "Müzik Yükleme", "Geração de Conteúdo IA": "Yapay Zekâ İçeriği Oluşturma", "Motion Control": "Hareket Kontrolü", "UGC Products": "UGC Ürünleri", "Growth": "Büyüme", "Analista Growth Youtube": "YouTube Büyüme Analisti", "Analista Growth Tiktok": "TikTok Büyüme Analisti", "Analista Growth Instagram": "Instagram Büyüme Analisti", "Analista Facebook Pages": "Facebook Pages Analisti", "Analista Bilibili": "Bilibili Analisti", "Documentação": "Dokümantasyon", "Tutorial Kaggle": "Kaggle Eğitimi", "Tutorial Apify": "Apify Eğitimi", "Pipeline Música": "Müzik Akışı", "módulos disponíveis": "kullanılabilir modüller",
271
271
  },
272
272
  "ru": {
273
- "Arquivos Base": "Базовые файлы", "Pipeline Vídeos": "Конвейер видео", "Canais e Perfis de Vídeos": "Каналы и профили видео", "Canais YouTube": "Каналы YouTube", "Facebook Pages": "Страницы Facebook", "Prompt Masters": "Мастер-промпты", "Backlog Vídeos": "Очередь видео", "Thumbnails": "Миниатюры", "Música": "Музыка", "Upload Música": "Загрузка музыки", "Geração de Conteúdo IA": "Генерация контента ИИ", "Motion Control": "Управление движением", "UGC Products": "UGC-продукты", "Growth": "Рост", "Analista Growth Youtube": "Аналитик роста YouTube", "Analista Growth Tiktok": "Аналитик роста TikTok", "Analista Growth Instagram": "Аналитик роста Instagram", "Analista Facebook Pages": "Аналитик Facebook Pages", "Analista Bilibili": "Аналитик Bilibili", "Documentação": "Документация", "Tutorial Kaggle": "Руководство Kaggle", "Tutorial Apify": "Руководство Apify", "Pipeline Música": "Конвейер музыки", "módulos disponíveis": "доступные модули",
273
+ "Arquivos Base": "Базовые файлы", "Pipeline Vídeos": "Конвейер видео", "Canais e Perfis de Vídeos": "Каналы и профили видео", "Canais/Perfis (Vídeos)": "Каналы и профили видео", "Canais YouTube": "Каналы YouTube", "Facebook Pages": "Страницы Facebook", "Prompt Masters": "Мастер-промпты", "Backlog Vídeos": "Очередь видео", "Thumbnails": "Миниатюры", "Música": "Музыка", "Upload Música": "Загрузка музыки", "Geração de Conteúdo IA": "Генерация контента ИИ", "Motion Control": "Управление движением", "UGC Products": "UGC-продукты", "Growth": "Рост", "Analista Growth Youtube": "Аналитик роста YouTube", "Analista Growth Tiktok": "Аналитик роста TikTok", "Analista Growth Instagram": "Аналитик роста Instagram", "Analista Facebook Pages": "Аналитик Facebook Pages", "Analista Bilibili": "Аналитик Bilibili", "Documentação": "Документация", "Tutorial Kaggle": "Руководство Kaggle", "Tutorial Apify": "Руководство Apify", "Pipeline Música": "Конвейер музыки", "módulos disponíveis": "доступные модули",
274
274
  },
275
275
  "es": {
276
- "Arquivos Base": "Archivos base", "Pipeline Vídeos": "Flujo de vídeos", "Canais e Perfis de Vídeos": "Canales y perfiles de vídeo", "Canais YouTube": "Canales de YouTube", "Facebook Pages": "Páginas de Facebook", "Prompt Masters": "Prompts maestros", "Backlog Vídeos": "Cola de vídeos", "Thumbnails": "Miniaturas", "Música": "Música", "Upload Música": "Subir música", "Geração de Conteúdo IA": "Generación de contenido con IA", "Motion Control": "Control de movimiento", "UGC Products": "Productos UGC", "Growth": "Crecimiento", "Analista Growth Youtube": "Analista de crecimiento de YouTube", "Analista Growth Tiktok": "Analista de crecimiento de TikTok", "Analista Growth Instagram": "Analista de crecimiento de Instagram", "Analista Facebook Pages": "Analista de Facebook Pages", "Analista Bilibili": "Analista de Bilibili", "Documentação": "Documentación", "Tutorial Kaggle": "Tutorial de Kaggle", "Tutorial Apify": "Tutorial de Apify", "Pipeline Música": "Flujo de música", "módulos disponíveis": "módulos disponibles",
276
+ "Arquivos Base": "Archivos base", "Pipeline Vídeos": "Flujo de vídeos", "Canais e Perfis de Vídeos": "Canales y perfiles de vídeo", "Canais/Perfis (Vídeos)": "Canales y perfiles de vídeo", "Canais YouTube": "Canales de YouTube", "Facebook Pages": "Páginas de Facebook", "Prompt Masters": "Prompts maestros", "Backlog Vídeos": "Cola de vídeos", "Thumbnails": "Miniaturas", "Música": "Música", "Upload Música": "Subir música", "Geração de Conteúdo IA": "Generación de contenido con IA", "Motion Control": "Control de movimiento", "UGC Products": "Productos UGC", "Growth": "Crecimiento", "Analista Growth Youtube": "Analista de crecimiento de YouTube", "Analista Growth Tiktok": "Analista de crecimiento de TikTok", "Analista Growth Instagram": "Analista de crecimiento de Instagram", "Analista Facebook Pages": "Analista de Facebook Pages", "Analista Bilibili": "Analista de Bilibili", "Documentação": "Documentación", "Tutorial Kaggle": "Tutorial de Kaggle", "Tutorial Apify": "Tutorial de Apify", "Pipeline Música": "Flujo de música", "módulos disponíveis": "módulos disponibles",
277
277
  },
278
278
  "id": {
279
- "Arquivos Base": "File Dasar", "Pipeline Vídeos": "Alur Video", "Canais e Perfis de Vídeos": "Kanal dan Profil Video", "Canais YouTube": "Kanal YouTube", "Facebook Pages": "Halaman Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Antrean Video", "Thumbnails": "Thumbnail", "Música": "Musik", "Upload Música": "Unggah Musik", "Geração de Conteúdo IA": "Pembuatan Konten AI", "Motion Control": "Kontrol Gerakan", "UGC Products": "Produk UGC", "Growth": "Pertumbuhan", "Analista Growth Youtube": "Analis Pertumbuhan YouTube", "Analista Growth Tiktok": "Analis Pertumbuhan TikTok", "Analista Growth Instagram": "Analis Pertumbuhan Instagram", "Analista Facebook Pages": "Analis Facebook Pages", "Analista Bilibili": "Analis Bilibili", "Documentação": "Dokumentasi", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Alur Musik", "módulos disponíveis": "modul tersedia",
279
+ "Arquivos Base": "File Dasar", "Pipeline Vídeos": "Alur Video", "Canais e Perfis de Vídeos": "Kanal dan Profil Video", "Canais/Perfis (Vídeos)": "Kanal dan Profil Video", "Canais YouTube": "Kanal YouTube", "Facebook Pages": "Halaman Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Antrean Video", "Thumbnails": "Thumbnail", "Música": "Musik", "Upload Música": "Unggah Musik", "Geração de Conteúdo IA": "Pembuatan Konten AI", "Motion Control": "Kontrol Gerakan", "UGC Products": "Produk UGC", "Growth": "Pertumbuhan", "Analista Growth Youtube": "Analis Pertumbuhan YouTube", "Analista Growth Tiktok": "Analis Pertumbuhan TikTok", "Analista Growth Instagram": "Analis Pertumbuhan Instagram", "Analista Facebook Pages": "Analis Facebook Pages", "Analista Bilibili": "Analis Bilibili", "Documentação": "Dokumentasi", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Alur Musik", "módulos disponíveis": "modul tersedia",
280
280
  },
281
281
  "it": {
282
- "Arquivos Base": "File di base", "Pipeline Vídeos": "Pipeline video", "Canais e Perfis de Vídeos": "Canali e profili video", "Canais YouTube": "Canali YouTube", "Facebook Pages": "Pagine Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Coda video", "Thumbnails": "Miniature", "Música": "Musica", "Upload Música": "Caricamento musica", "Geração de Conteúdo IA": "Generazione di contenuti IA", "Motion Control": "Controllo del movimento", "UGC Products": "Prodotti UGC", "Growth": "Crescita", "Analista Growth Youtube": "Analista della crescita YouTube", "Analista Growth Tiktok": "Analista della crescita TikTok", "Analista Growth Instagram": "Analista della crescita Instagram", "Analista Facebook Pages": "Analista Facebook Pages", "Analista Bilibili": "Analista Bilibili", "Documentação": "Documentazione", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Pipeline musicale", "módulos disponíveis": "moduli disponibili",
282
+ "Arquivos Base": "File di base", "Pipeline Vídeos": "Pipeline video", "Canais e Perfis de Vídeos": "Canali e profili video", "Canais/Perfis (Vídeos)": "Canali e profili video", "Canais YouTube": "Canali YouTube", "Facebook Pages": "Pagine Facebook", "Prompt Masters": "Prompt Master", "Backlog Vídeos": "Coda video", "Thumbnails": "Miniature", "Música": "Musica", "Upload Música": "Caricamento musica", "Geração de Conteúdo IA": "Generazione di contenuti IA", "Motion Control": "Controllo del movimento", "UGC Products": "Prodotti UGC", "Growth": "Crescita", "Analista Growth Youtube": "Analista della crescita YouTube", "Analista Growth Tiktok": "Analista della crescita TikTok", "Analista Growth Instagram": "Analista della crescita Instagram", "Analista Facebook Pages": "Analista Facebook Pages", "Analista Bilibili": "Analista Bilibili", "Documentação": "Documentazione", "Tutorial Kaggle": "Tutorial Kaggle", "Tutorial Apify": "Tutorial Apify", "Pipeline Música": "Pipeline musicale", "módulos disponíveis": "moduli disponibili",
283
283
  },
284
284
  }
285
285
  for _language_code, _navigation_values in UI_NAV_TRANSLATIONS.items():
@@ -1368,19 +1368,19 @@ for _language_code, _api_test_values in _API_TEST_TRANSLATIONS.items():
1368
1368
  _NEW_UI_TRANSLATIONS: dict[str, dict[str, str]] = {
1369
1369
  "pl": {
1370
1370
  "Início": "Strona główna", "Niche Finder": "Wyszukiwarka nisz", "Pipeline": "Potok", "Pipeline TikTok": "Potok TikTok", "Automação": "Automatyzacja", "Edição": "Edycja", "AI Influencers": "Influencerzy AI", "Configurações": "Ustawienia", "Criação de Vídeos": "Tworzenie wideo", "Criação de Músicas": "Tworzenie muzyki", "Roteiros": "Scenariusze", "Upload": "Przesyłanie", "Prompts Master": "Mistrzowie promptów", "Contas TikTok": "Konta TikTok", "Automação Youtube": "Automatyzacja YouTube", "Niche Finder Kaggle": "Wyszukiwarka nisz Kaggle", "Niche Finder Apify": "Wyszukiwarka nisz Apify", "Limpador de Metadados": "Czyścik metadanych", "Cortes": "Cięcia", "Editor Python": "Edytor Pythona", "Download Mídia": "Pobieranie multimediów", "Personagens": "Postacie", "Redes Sociais": "Sieci społecznościowe", "Tutorial Meta": "Samouczek Meta", "Tutorial Supabase": "Samouczek Supabase", "Canais Youtube": "Kanały YouTube", "Blueprints Youtube": "Blueprinty YouTube", "Contas Google": "Konta Google", "Configuração API": "Konfiguracja API", "Notificações": "Powiadomienia", "Interface local para operação e automação de conteúdo faceless": "Lokalny interfejs do obsługi i automatyzacji treści faceless", "Canais": "Kanały", "activos": "aktywne", "Tarefas": "Zadania", "total registado": "łącznie zarejestrowano", "A fazer": "Do zrobienia", "na pipeline": "w potoku", "Em execução": "Uruchomione", "a decorrer": "w toku", "Concluídos": "Ukończone", "artefactos prontos": "gotowe artefakty", "Falhas": "Błędy", "requerem atenção": "wymagają uwagi", "Filas locais e dependências da cascata": "Lokalne kolejki i zależności potoku", "Niche": "Nisza", "Blueprints": "Blueprinty", "Brand": "Marka", "Script": "Scenariusz", "Title": "Tytuł", "Thumbnail": "Miniatura", "Video": "Wideo", "Edit": "Edytuj", "fila": "kolejka", "na biblioteca": "w bibliotece", "tarefa(s) na fila": "zadanie(a) w kolejce", "Language": "Język", "Theme": "Motyw", "Dark": "Ciemny", "Light": "Jasny",
1371
- "LLM — providers e modelos": "LLM — dostawcy i modele", "Adicionar provider LLM": "Dodaj dostawcę LLM", "Provider LLM": "Dostawca LLM", "Configurar Novo Provedor LLM": "Skonfiguruj nowego dostawcę LLM", "API key": "Klucz API", "Modelo": "Model", "Base URL": "Bazowy adres URL", "Modelo manual": "Model ręczny", "Escrever modelo manualmente": "Wpisz model ręcznie", "Provider activo": "Dostawca aktywny", "LLM Telegram": "LLM Telegram", "Testar chamada API": "Testuj wywołanie API", "Consultar modelos": "Pobierz modele", "Salvar": "Zapisz", "Remover cartão": "Usuń kartę", "Último teste:": "Ostatni test:", "Teste API:": "Test API:", "Missing key": "Brak klucza", "Missing configuration": "Brak konfiguracji", "Configured": "Skonfigurowano", "Local / sem API key": "Lokalny / bez klucza API", "Este provider não exige API key.": "Ten dostawca nie wymaga klucza API.", "Prioridade": "Priorytet", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Użyj tej karty jako głównego dostawcy do generowania tematów, scenariuszy, tytułów i słów kluczowych.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Używaj tej karty wyłącznie do kierowania powiadomień Telegram. Tylko jedna karta może być wybrana.", "Account Id": "Identyfikator konta", "Gateway Id": "Identyfikator bramy", "Api Version": "Wersja API", "Endpoint gerido pelo provider: ": "Punkt końcowy zarządzany przez dostawcę: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Punkt końcowy zgodny z OpenAI; widoczny tylko wtedy, gdy można go skonfigurować.", "ID do modelo usado pelo endpoint Chat Completions.": "Identyfikator modelu używanego przez punkt końcowy Chat Completions.", "Niche Finder — Kaggle": "Wyszukiwarka nisz — Kaggle", "Niche Finder — Apify": "Wyszukiwarka nisz — Apify", "Arquivos Base": "Pliki bazowe", "Pipeline Vídeos": "Potok wideo", "Canais e Perfis de Vídeos": "Kanały i profile wideo", "Canais YouTube": "Kanały YouTube", "Prompt Masters": "Mistrzowie promptów", "Backlog Vídeos": "Backlog wideo", "Thumbnails": "Miniatury", "Música": "Muzyka", "Upload Música": "Prześlij muzykę", "Geração de Conteúdo IA": "Generowanie treści AI", "Growth": "Rozwój", "Analista Growth Youtube": "Analityk rozwoju YouTube", "Analista Growth Tiktok": "Analityk rozwoju TikTok", "Analista Growth Instagram": "Analityk rozwoju Instagram", "Documentação": "Dokumentacja", "Tutorial Kaggle": "Samouczek Kaggle", "Tutorial Apify": "Samouczek Apify", "Pipeline Música": "Potok muzyki", "módulos disponíveis": "dostępne moduły", "Esta é uma chave API global do YouTube: aplica-se a todas as contas Google/YouTube e a todo o sistema. Não é associada a uma conta específica, não faz parte dos documentos de cookies/credenciais e não é editada no separador API Keys.": "To jest globalny klucz API YouTube: dotyczy wszystkich kont Google/YouTube i całego systemu. Nie jest przypisany do konkretnego konta, nie należy do dokumentów cookie/poświadczeń i nie jest edytowany w zakładce Klucze API.", "Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.": "Globalny klucz używany przez bezpośrednie przesyłanie dla wszystkich kont Google/YouTube. Zapisz go w konfiguracji globalnej, oddzielnie od dokumentów cookie.", "Guardar INNERTUBE_API_KEY global": "Zapisz globalny INNERTUBE_API_KEY", "INNERTUBE_API_KEY global guardada para todas as contas Google/YouTube e para todo o sistema.": "Globalny INNERTUBE_API_KEY zapisany dla wszystkich kont Google/YouTube i całego systemu.", "Gerar tópico, roteiro e palavras-chave com IA": "Generuj temat, scenariusz i słowa kluczowe za pomocą AI", "A gerar tópico, roteiro e palavras-chave com IA…": "Generowanie tematu, scenariusza i słów kluczowych za pomocą AI…", "Tema, roteiro e palavras-chave gerados com IA.": "Temat, scenariusz i słowa kluczowe wygenerowane przez AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "Wypełnij pole Video Subject albo użyj przycisku automatycznego generowania pod słowami kluczowymi.", "Refazer thumbnail": "Utwórz miniaturę ponownie", "Salvar rascunho": "Zapisz wersję roboczą", "Rascunho guardado localmente": "Wersja robocza zapisana lokalnie", "Thumbnail refeita com sucesso.": "Miniatura została utworzona ponownie.", "Ver prompt da thumbnail": "Zobacz prompt miniatury", "Sem imagem": "Brak obrazu", "Imagem ainda não gerada": "Obraz nie został jeszcze wygenerowany", "Palavras-chave": "Słowa kluczowe", "Título do rascunho": "Tytuł wersji roboczej", "Gerar de Rascunho": "Generuj z wersji roboczej", "Roteiros guardados": "Zapisane scenariusze", "Seleccione um roteiro": "Wybierz scenariusz", "Configurações a completar": "Ustawienia do uzupełnienia", "Configurações de vídeo": "Ustawienia wideo", "Configurações de áudio": "Ustawienia audio", "Configurações de legendas": "Ustawienia napisów", "Continuar criação": "Kontynuuj tworzenie", "Gerar apenas o vídeo": "Generuj tylko wideo", "Seleccione um canal para continuar.": "Wybierz kanał, aby kontynuować.", "Ainda não existem roteiros guardados.": "Nie ma jeszcze zapisanych scenariuszy.", "Histórico guardado": "Zapisana historia", "Rascunho local": "Lokalna wersja robocza", "Origem": "Źródło", "Brandings": "Brandingi", "Pesquisa pública": "Wyszukiwanie publiczne", "Cadastro manual": "Rejestracja ręczna", "Contas cadastradas": "Zarejestrowane konta", "Biblioteca": "Biblioteka", "Importar do YouTube": "Importuj z YouTube", "Canais em lote gmail": "Kanały zbiorcze Gmail", "Criar vídeo": "Utwórz wideo", "Vídeos": "Wideo", "Novo roteiro/letra": "Nowy scenariusz/tekst", "Clusters encontrados": "Znalezione klastry", "Regras de associação": "Reguły powiązań", "Dados analisados": "Przeanalizowane dane", "Upload ficheiro": "Prześlij plik", "URL de vídeo": "Adres URL wideo", "Vídeos gerados": "Wygenerowane wideo", "Pasta local": "Folder lokalny", "Código Python": "Kod Python", "Upload convencional": "Zwykłe przesyłanie", "Upload directo": "Przesyłanie bezpośrednie", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Klucze API", "Teste de Voz": "Test głosu", "Serviços e modelos": "Usługi i modele", "Fontes de Materiais": "Źródła materiałów", "Client MCP": "Klient MCP", "Servidor MCP": "Serwer MCP", "Skill": "Umiejętność", "Guia de configuração do Supabase para automações com n8n.": "Przewodnik konfiguracji Supabase dla automatyzacji z n8n.", "Adicionar fonte de materiais": "Dodaj źródło materiałów", "Provedor de materiais": "Dostawca materiałów", "Configurar Nova Fonte de Materiais": "Skonfiguruj nowe źródło materiałów", "Fonte activa": "Źródło aktywne", "Usar esta fonte na pipeline": "Używaj tego źródła w potoku", "Esta fonte não usa API key.": "To źródło nie używa klucza API.", "A testar chamada API…": "Testowanie wywołania API…", "Último teste: API Key OK": "Ostatni test: klucz API OK", "Último teste: falta configuração": "Ostatni test: brak konfiguracji", "Último teste: requer autorização ou endpoint seguro": "Ostatni test: wymagana dodatkowa autoryzacja lub bezpieczny punkt końcowy", "Último teste: chamada falhou": "Ostatni test: wywołanie nie powiodło się", "Testar credenciais TTS e música": "Testuj dane uwierzytelniające TTS i muzyki", "Facebook Pages": "Strony Facebook", "Motion Control": "Sterowanie ruchem", "UGC Products": "Produkty UGC",
1371
+ "LLM — providers e modelos": "LLM — dostawcy i modele", "Adicionar provider LLM": "Dodaj dostawcę LLM", "Provider LLM": "Dostawca LLM", "Configurar Novo Provedor LLM": "Skonfiguruj nowego dostawcę LLM", "API key": "Klucz API", "Modelo": "Model", "Base URL": "Bazowy adres URL", "Modelo manual": "Model ręczny", "Escrever modelo manualmente": "Wpisz model ręcznie", "Provider activo": "Dostawca aktywny", "LLM Telegram": "LLM Telegram", "Testar chamada API": "Testuj wywołanie API", "Consultar modelos": "Pobierz modele", "Salvar": "Zapisz", "Remover cartão": "Usuń kartę", "Último teste:": "Ostatni test:", "Teste API:": "Test API:", "Missing key": "Brak klucza", "Missing configuration": "Brak konfiguracji", "Configured": "Skonfigurowano", "Local / sem API key": "Lokalny / bez klucza API", "Este provider não exige API key.": "Ten dostawca nie wymaga klucza API.", "Prioridade": "Priorytet", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Użyj tej karty jako głównego dostawcy do generowania tematów, scenariuszy, tytułów i słów kluczowych.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Używaj tej karty wyłącznie do kierowania powiadomień Telegram. Tylko jedna karta może być wybrana.", "Account Id": "Identyfikator konta", "Gateway Id": "Identyfikator bramy", "Api Version": "Wersja API", "Endpoint gerido pelo provider: ": "Punkt końcowy zarządzany przez dostawcę: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Punkt końcowy zgodny z OpenAI; widoczny tylko wtedy, gdy można go skonfigurować.", "ID do modelo usado pelo endpoint Chat Completions.": "Identyfikator modelu używanego przez punkt końcowy Chat Completions.", "Niche Finder — Kaggle": "Wyszukiwarka nisz — Kaggle", "Niche Finder — Apify": "Wyszukiwarka nisz — Apify", "Arquivos Base": "Pliki bazowe", "Pipeline Vídeos": "Potok wideo", "Canais e Perfis de Vídeos": "Kanały i profile wideo", "Canais/Perfis (Vídeos)": "Kanały i profile wideo", "Canais YouTube": "Kanały YouTube", "Prompt Masters": "Mistrzowie promptów", "Backlog Vídeos": "Backlog wideo", "Thumbnails": "Miniatury", "Música": "Muzyka", "Upload Música": "Prześlij muzykę", "Geração de Conteúdo IA": "Generowanie treści AI", "Growth": "Rozwój", "Analista Growth Youtube": "Analityk rozwoju YouTube", "Analista Growth Tiktok": "Analityk rozwoju TikTok", "Analista Growth Instagram": "Analityk rozwoju Instagram", "Documentação": "Dokumentacja", "Tutorial Kaggle": "Samouczek Kaggle", "Tutorial Apify": "Samouczek Apify", "Pipeline Música": "Potok muzyki", "módulos disponíveis": "dostępne moduły", "Esta é uma chave API global do YouTube: aplica-se a todas as contas Google/YouTube e a todo o sistema. Não é associada a uma conta específica, não faz parte dos documentos de cookies/credenciais e não é editada no separador API Keys.": "To jest globalny klucz API YouTube: dotyczy wszystkich kont Google/YouTube i całego systemu. Nie jest przypisany do konkretnego konta, nie należy do dokumentów cookie/poświadczeń i nie jest edytowany w zakładce Klucze API.", "Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.": "Globalny klucz używany przez bezpośrednie przesyłanie dla wszystkich kont Google/YouTube. Zapisz go w konfiguracji globalnej, oddzielnie od dokumentów cookie.", "Guardar INNERTUBE_API_KEY global": "Zapisz globalny INNERTUBE_API_KEY", "INNERTUBE_API_KEY global guardada para todas as contas Google/YouTube e para todo o sistema.": "Globalny INNERTUBE_API_KEY zapisany dla wszystkich kont Google/YouTube i całego systemu.", "Gerar tópico, roteiro e palavras-chave com IA": "Generuj temat, scenariusz i słowa kluczowe za pomocą AI", "A gerar tópico, roteiro e palavras-chave com IA…": "Generowanie tematu, scenariusza i słów kluczowych za pomocą AI…", "Tema, roteiro e palavras-chave gerados com IA.": "Temat, scenariusz i słowa kluczowe wygenerowane przez AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "Wypełnij pole Video Subject albo użyj przycisku automatycznego generowania pod słowami kluczowymi.", "Refazer thumbnail": "Utwórz miniaturę ponownie", "Salvar rascunho": "Zapisz wersję roboczą", "Rascunho guardado localmente": "Wersja robocza zapisana lokalnie", "Thumbnail refeita com sucesso.": "Miniatura została utworzona ponownie.", "Ver prompt da thumbnail": "Zobacz prompt miniatury", "Sem imagem": "Brak obrazu", "Imagem ainda não gerada": "Obraz nie został jeszcze wygenerowany", "Palavras-chave": "Słowa kluczowe", "Título do rascunho": "Tytuł wersji roboczej", "Gerar de Rascunho": "Generuj z wersji roboczej", "Roteiros guardados": "Zapisane scenariusze", "Seleccione um roteiro": "Wybierz scenariusz", "Configurações a completar": "Ustawienia do uzupełnienia", "Configurações de vídeo": "Ustawienia wideo", "Configurações de áudio": "Ustawienia audio", "Configurações de legendas": "Ustawienia napisów", "Continuar criação": "Kontynuuj tworzenie", "Gerar apenas o vídeo": "Generuj tylko wideo", "Seleccione um canal para continuar.": "Wybierz kanał, aby kontynuować.", "Ainda não existem roteiros guardados.": "Nie ma jeszcze zapisanych scenariuszy.", "Histórico guardado": "Zapisana historia", "Rascunho local": "Lokalna wersja robocza", "Origem": "Źródło", "Brandings": "Brandingi", "Pesquisa pública": "Wyszukiwanie publiczne", "Cadastro manual": "Rejestracja ręczna", "Contas cadastradas": "Zarejestrowane konta", "Biblioteca": "Biblioteka", "Importar do YouTube": "Importuj z YouTube", "Canais em lote gmail": "Kanały zbiorcze Gmail", "Criar vídeo": "Utwórz wideo", "Vídeos": "Wideo", "Novo roteiro/letra": "Nowy scenariusz/tekst", "Clusters encontrados": "Znalezione klastry", "Regras de associação": "Reguły powiązań", "Dados analisados": "Przeanalizowane dane", "Upload ficheiro": "Prześlij plik", "URL de vídeo": "Adres URL wideo", "Vídeos gerados": "Wygenerowane wideo", "Pasta local": "Folder lokalny", "Código Python": "Kod Python", "Upload convencional": "Zwykłe przesyłanie", "Upload directo": "Przesyłanie bezpośrednie", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "Klucze API", "Teste de Voz": "Test głosu", "Serviços e modelos": "Usługi i modele", "Fontes de Materiais": "Źródła materiałów", "Client MCP": "Klient MCP", "Servidor MCP": "Serwer MCP", "Skill": "Umiejętność", "Guia de configuração do Supabase para automações com n8n.": "Przewodnik konfiguracji Supabase dla automatyzacji z n8n.", "Adicionar fonte de materiais": "Dodaj źródło materiałów", "Provedor de materiais": "Dostawca materiałów", "Configurar Nova Fonte de Materiais": "Skonfiguruj nowe źródło materiałów", "Fonte activa": "Źródło aktywne", "Usar esta fonte na pipeline": "Używaj tego źródła w potoku", "Esta fonte não usa API key.": "To źródło nie używa klucza API.", "A testar chamada API…": "Testowanie wywołania API…", "Último teste: API Key OK": "Ostatni test: klucz API OK", "Último teste: falta configuração": "Ostatni test: brak konfiguracji", "Último teste: requer autorização ou endpoint seguro": "Ostatni test: wymagana dodatkowa autoryzacja lub bezpieczny punkt końcowy", "Último teste: chamada falhou": "Ostatni test: wywołanie nie powiodło się", "Testar credenciais TTS e música": "Testuj dane uwierzytelniające TTS i muzyki", "Facebook Pages": "Strony Facebook", "Motion Control": "Sterowanie ruchem", "UGC Products": "Produkty UGC",
1372
1372
  },
1373
1373
  "ga": {
1374
1374
  "Início": "Baile", "Niche Finder": "Aimsitheoir nideoga", "Pipeline": "Píblíne", "Pipeline TikTok": "Píblíne TikTok", "Automação": "Uathoibriú", "Edição": "Eagarthóireacht", "AI Influencers": "Tionchair AI", "Configurações": "Socruithe", "Criação de Vídeos": "Cruthú físeán", "Criação de Músicas": "Cruthú ceoil", "Roteiros": "Scripteanna", "Upload": "Uaslódáil", "Prompts Master": "Máistrí leideanna", "Contas TikTok": "Cuntais TikTok", "Automação Youtube": "Uathoibriú YouTube", "Niche Finder Kaggle": "Aimsitheoir nideoga Kaggle", "Niche Finder Apify": "Aimsitheoir nideoga Apify", "Limpador de Metadados": "Glantóir meiteashonraí", "Cortes": "Ciorruithe", "Editor Python": "Eagarthóir Python", "Download Mídia": "Íoslódáil meán", "Personagens": "Carachtair", "Redes Sociais": "Líonraí sóisialta", "Tutorial Meta": "Teagasc Meta", "Tutorial Supabase": "Teagasc Supabase", "Canais Youtube": "Cainéil YouTube", "Blueprints Youtube": "Blueprints YouTube", "Contas Google": "Cuntais Google", "Configuração API": "Cumraíocht API", "Notificações": "Fógraí", "Interface local para operação e automação de conteúdo faceless": "Comhéadan logánta chun inneachar faceless a oibriú agus a uathoibriú", "Canais": "Cainéil", "activos": "gníomhach", "Tarefas": "Tascanna", "total registado": "iomlán cláraithe", "A fazer": "Le déanamh", "na pipeline": "sa phíblíne", "Em execução": "Ar siúl", "a decorrer": "ar bun", "Concluídos": "Críochnaithe", "artefactos prontos": "déantáin réidh", "Falhas": "Teipeanna", "requerem atenção": "teastaíonn aird", "Filas locais e dependências da cascata": "Scuainí logánta agus spleáchais na píblíne", "Niche": "Nideoige", "Blueprints": "Blueprints", "Brand": "Branda", "Script": "Script", "Title": "Teideal", "Thumbnail": "Mionsamhail", "Video": "Físeán", "Edit": "Cuir in eagar", "fila": "scuaine", "na biblioteca": "sa leabharlann", "tarefa(s) na fila": "tasc(anna) sa scuaine", "Language": "Teanga", "Theme": "Téama", "Dark": "Dorcha", "Light": "Geal",
1375
- "LLM — providers e modelos": "LLM — soláthraithe agus samhlacha", "Adicionar provider LLM": "Cuir soláthraí LLM leis", "Provider LLM": "Soláthraí LLM", "Configurar Novo Provedor LLM": "Cumraigh soláthraí nua LLM", "API key": "Eochair API", "Modelo": "Samhail", "Base URL": "URL bonn", "Modelo manual": "Samhail láimhe", "Escrever modelo manualmente": "Scríobh an tsamhail de láimh", "Provider activo": "Soláthraí gníomhach", "LLM Telegram": "LLM Telegram", "Testar chamada API": "Tástáil glao API", "Consultar modelos": "Faigh samhlacha", "Salvar": "Sábháil", "Remover cartão": "Bain cárta", "Último teste:": "An tástáil is déanaí:", "Teste API:": "Tástáil API:", "Missing key": "Eochair ar iarraidh", "Missing configuration": "Cumraíocht ar iarraidh", "Configured": "Cumraithe", "Local / sem API key": "Logánta / gan eochair API", "Este provider não exige API key.": "Níl eochair API ag teastáil ón soláthraí seo.", "Prioridade": "Príomh-LLM", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Úsáid an cárta seo mar phríomhsholáthraí chun topaicí, scripteanna, teidil agus eochairfhocail a ghiniúint.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Úsáid an cárta seo go heisiach chun fógraí Telegram a ródú. Ní féidir ach cárta amháin a roghnú.", "Account Id": "Aitheantas cuntais", "Gateway Id": "Aitheantas geata", "Api Version": "Leagan API", "Endpoint gerido pelo provider: ": "Críochphointe á bhainistiú ag an soláthraí: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Críochphointe atá comhoiriúnach le OpenAI; taispeántar é nuair is féidir é a chumrú.", "ID do modelo usado pelo endpoint Chat Completions.": "Aitheantas na samhla a úsáideann críochphointe Chat Completions.", "Niche Finder — Kaggle": "Aimsitheoir nideoga — Kaggle", "Niche Finder — Apify": "Aimsitheoir nideoga — Apify", "Arquivos Base": "Comhaid bhunúsacha", "Pipeline Vídeos": "Píblíne físeáin", "Canais e Perfis de Vídeos": "Cainéil agus próifílí físeáin", "Canais YouTube": "Cainéil YouTube", "Prompt Masters": "Máistrí leideanna", "Backlog Vídeos": "Riaráiste físeáin", "Thumbnails": "Mionsamhlacha", "Música": "Ceol", "Upload Música": "Uaslódáil ceol", "Geração de Conteúdo IA": "Giniúint inneachair AI", "Growth": "Fás", "Analista Growth Youtube": "Anailísí fáis YouTube", "Analista Growth Tiktok": "Anailísí fáis TikTok", "Analista Growth Instagram": "Anailísí fáis Instagram", "Documentação": "Doiciméadú", "Tutorial Kaggle": "Teagasc Kaggle", "Tutorial Apify": "Teagasc Apify", "Pipeline Música": "Píblíne ceoil", "módulos disponíveis": "modúil ar fáil", "Esta é uma chave API global do YouTube: aplica-se a todas as contas Google/YouTube e a todo o sistema. Não é associada a uma conta específica, não faz parte dos documentos de cookies/credenciais e não é editada no separador API Keys.": "Is eochair API dhomhanda YouTube í seo: baineann sí le gach cuntas Google/YouTube agus leis an gcóras ar fad. Ní bhaineann sí le cuntas ar leith, ní cuid de dhoiciméid fianán/dintiúr í agus ní chuirtear in eagar í sa chluaisín Eochracha API.", "Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.": "Eochair dhomhanda a úsáideann an tUaslódáil díreach do gach cuntas Google/YouTube. Sábháil sa chumraíocht dhomhanda í, scartha ó na doiciméid fianán.", "Guardar INNERTUBE_API_KEY global": "Sábháil INNERTUBE_API_KEY domhanda", "INNERTUBE_API_KEY global guardada para todas as contas Google/YouTube e para todo o sistema.": "INNERTUBE_API_KEY domhanda sábháilte do gach cuntas Google/YouTube agus don chóras ar fad.", "Gerar tópico, roteiro e palavras-chave com IA": "Gin topaic, script agus eochairfhocail le AI", "A gerar tópico, roteiro e palavras-chave com IA…": "Topaic, script agus eochairfhocail á nginiúint le AI…", "Tema, roteiro e palavras-chave gerados com IA.": "Topaic, script agus eochairfhocail ginte le AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "Líon an réimse Video Subject nó úsáid an cnaipe giniúna uathoibríoch faoi na heochairfhocail.", "Refazer thumbnail": "Athchruthaigh an mionsamhail", "Salvar rascunho": "Sábháil dréacht", "Rascunho guardado localmente": "Dréacht sábháilte go logánta", "Thumbnail refeita com sucesso.": "Athchruthaíodh an mionsamhail go rathúil.", "Ver prompt da thumbnail": "Féach ar leid na mionsamhla", "Sem imagem": "Gan íomhá", "Imagem ainda não gerada": "Níor gineadh íomhá fós", "Palavras-chave": "Eochairfhocail", "Título do rascunho": "Teideal an dréachta", "Gerar de Rascunho": "Gin ón dréacht", "Roteiros guardados": "Scripteanna sábháilte", "Seleccione um roteiro": "Roghnaigh script", "Configurações a completar": "Cumraíochtaí le comhlánú", "Configurações de vídeo": "Cumraíochtaí físeáin", "Configurações de áudio": "Cumraíochtaí fuaime", "Configurações de legendas": "Cumraíochtaí fotheideal", "Continuar criação": "Lean den chruthú", "Gerar apenas o vídeo": "Gin an físeán amháin", "Seleccione um canal para continuar.": "Roghnaigh cainéal chun leanúint ar aghaidh.", "Ainda não existem roteiros guardados.": "Níl aon scripteanna sábháilte ann fós.", "Histórico guardado": "Stair shábháilte", "Rascunho local": "Dréacht logánta", "Origem": "Foinse", "Brandings": "Brandálacha", "Pesquisa pública": "Cuardach poiblí", "Cadastro manual": "Clárú láimhe", "Contas cadastradas": "Cuntais chláraithe", "Biblioteca": "Leabharlann", "Importar do YouTube": "Iompórtáil ó YouTube", "Canais em lote gmail": "Cainéil bhaisc Gmail", "Criar vídeo": "Cruthaigh físeán", "Vídeos": "Físeáin", "Novo roteiro/letra": "Script/liric nua", "Clusters encontrados": "Braislí aimsithe", "Regras de associação": "Rialacha comhlachais", "Dados analisados": "Sonraí anailísithe", "Upload ficheiro": "Uaslódáil comhad", "URL de vídeo": "URL físeáin", "Vídeos gerados": "Físeáin ginte", "Pasta local": "Fillteán logánta", "Código Python": "Cód Python", "Upload convencional": "Uaslódáil traidisiúnta", "Upload directo": "Uaslódáil díreach", "API Keys": "Eochracha API", "Teste de Voz": "Tástáil gutha", "Serviços e modelos": "Seirbhísí agus samhlacha", "Fontes de Materiais": "Foinsí ábhair", "Client MCP": "Cliant MCP", "Servidor MCP": "Freastalaí MCP", "Skill": "Scil", "Guia de configuração do Supabase para automações com n8n.": "Treoir chumraíochta Supabase le haghaidh uathoibrithe le n8n.", "Adicionar fonte de materiais": "Cuir foinse ábhair leis", "Provedor de materiais": "Soláthraí ábhair", "Configurar Nova Fonte de Materiais": "Cumraigh foinse nua ábhair", "Fonte activa": "Foinse ghníomhach", "Usar esta fonte na pipeline": "Úsáid an fhoinse seo sa phíblíne", "Esta fonte não usa API key.": "Ní úsáideann an fhoinse seo eochair API.", "A testar chamada API…": "Glao API á thástáil…", "Último teste: API Key OK": "An tástáil is déanaí: eochair API ceart", "Último teste: falta configuração": "An tástáil is déanaí: cumraíocht ar iarraidh", "Último teste: requer autorização ou endpoint seguro": "An tástáil is déanaí: údarú breise nó críochphointe sábháilte de dhíth", "Último teste: chamada falhou": "An tástáil is déanaí: theip ar an nglao", "Testar credenciais TTS e música": "Tástáil dintiúr TTS agus ceoil", "Facebook Pages": "Leathanaigh Facebook", "Motion Control": "Rialú gluaisne", "UGC Products": "Táirgí UGC",
1375
+ "LLM — providers e modelos": "LLM — soláthraithe agus samhlacha", "Adicionar provider LLM": "Cuir soláthraí LLM leis", "Provider LLM": "Soláthraí LLM", "Configurar Novo Provedor LLM": "Cumraigh soláthraí nua LLM", "API key": "Eochair API", "Modelo": "Samhail", "Base URL": "URL bonn", "Modelo manual": "Samhail láimhe", "Escrever modelo manualmente": "Scríobh an tsamhail de láimh", "Provider activo": "Soláthraí gníomhach", "LLM Telegram": "LLM Telegram", "Testar chamada API": "Tástáil glao API", "Consultar modelos": "Faigh samhlacha", "Salvar": "Sábháil", "Remover cartão": "Bain cárta", "Último teste:": "An tástáil is déanaí:", "Teste API:": "Tástáil API:", "Missing key": "Eochair ar iarraidh", "Missing configuration": "Cumraíocht ar iarraidh", "Configured": "Cumraithe", "Local / sem API key": "Logánta / gan eochair API", "Este provider não exige API key.": "Níl eochair API ag teastáil ón soláthraí seo.", "Prioridade": "Príomh-LLM", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Úsáid an cárta seo mar phríomhsholáthraí chun topaicí, scripteanna, teidil agus eochairfhocail a ghiniúint.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Úsáid an cárta seo go heisiach chun fógraí Telegram a ródú. Ní féidir ach cárta amháin a roghnú.", "Account Id": "Aitheantas cuntais", "Gateway Id": "Aitheantas geata", "Api Version": "Leagan API", "Endpoint gerido pelo provider: ": "Críochphointe á bhainistiú ag an soláthraí: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Críochphointe atá comhoiriúnach le OpenAI; taispeántar é nuair is féidir é a chumrú.", "ID do modelo usado pelo endpoint Chat Completions.": "Aitheantas na samhla a úsáideann críochphointe Chat Completions.", "Niche Finder — Kaggle": "Aimsitheoir nideoga — Kaggle", "Niche Finder — Apify": "Aimsitheoir nideoga — Apify", "Arquivos Base": "Comhaid bhunúsacha", "Pipeline Vídeos": "Píblíne físeáin", "Canais e Perfis de Vídeos": "Cainéil agus próifílí físeáin", "Canais/Perfis (Vídeos)": "Cainéil agus próifílí físeáin", "Canais YouTube": "Cainéil YouTube", "Prompt Masters": "Máistrí leideanna", "Backlog Vídeos": "Riaráiste físeáin", "Thumbnails": "Mionsamhlacha", "Música": "Ceol", "Upload Música": "Uaslódáil ceol", "Geração de Conteúdo IA": "Giniúint inneachair AI", "Growth": "Fás", "Analista Growth Youtube": "Anailísí fáis YouTube", "Analista Growth Tiktok": "Anailísí fáis TikTok", "Analista Growth Instagram": "Anailísí fáis Instagram", "Documentação": "Doiciméadú", "Tutorial Kaggle": "Teagasc Kaggle", "Tutorial Apify": "Teagasc Apify", "Pipeline Música": "Píblíne ceoil", "módulos disponíveis": "modúil ar fáil", "Esta é uma chave API global do YouTube: aplica-se a todas as contas Google/YouTube e a todo o sistema. Não é associada a uma conta específica, não faz parte dos documentos de cookies/credenciais e não é editada no separador API Keys.": "Is eochair API dhomhanda YouTube í seo: baineann sí le gach cuntas Google/YouTube agus leis an gcóras ar fad. Ní bhaineann sí le cuntas ar leith, ní cuid de dhoiciméid fianán/dintiúr í agus ní chuirtear in eagar í sa chluaisín Eochracha API.", "Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.": "Eochair dhomhanda a úsáideann an tUaslódáil díreach do gach cuntas Google/YouTube. Sábháil sa chumraíocht dhomhanda í, scartha ó na doiciméid fianán.", "Guardar INNERTUBE_API_KEY global": "Sábháil INNERTUBE_API_KEY domhanda", "INNERTUBE_API_KEY global guardada para todas as contas Google/YouTube e para todo o sistema.": "INNERTUBE_API_KEY domhanda sábháilte do gach cuntas Google/YouTube agus don chóras ar fad.", "Gerar tópico, roteiro e palavras-chave com IA": "Gin topaic, script agus eochairfhocail le AI", "A gerar tópico, roteiro e palavras-chave com IA…": "Topaic, script agus eochairfhocail á nginiúint le AI…", "Tema, roteiro e palavras-chave gerados com IA.": "Topaic, script agus eochairfhocail ginte le AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "Líon an réimse Video Subject nó úsáid an cnaipe giniúna uathoibríoch faoi na heochairfhocail.", "Refazer thumbnail": "Athchruthaigh an mionsamhail", "Salvar rascunho": "Sábháil dréacht", "Rascunho guardado localmente": "Dréacht sábháilte go logánta", "Thumbnail refeita com sucesso.": "Athchruthaíodh an mionsamhail go rathúil.", "Ver prompt da thumbnail": "Féach ar leid na mionsamhla", "Sem imagem": "Gan íomhá", "Imagem ainda não gerada": "Níor gineadh íomhá fós", "Palavras-chave": "Eochairfhocail", "Título do rascunho": "Teideal an dréachta", "Gerar de Rascunho": "Gin ón dréacht", "Roteiros guardados": "Scripteanna sábháilte", "Seleccione um roteiro": "Roghnaigh script", "Configurações a completar": "Cumraíochtaí le comhlánú", "Configurações de vídeo": "Cumraíochtaí físeáin", "Configurações de áudio": "Cumraíochtaí fuaime", "Configurações de legendas": "Cumraíochtaí fotheideal", "Continuar criação": "Lean den chruthú", "Gerar apenas o vídeo": "Gin an físeán amháin", "Seleccione um canal para continuar.": "Roghnaigh cainéal chun leanúint ar aghaidh.", "Ainda não existem roteiros guardados.": "Níl aon scripteanna sábháilte ann fós.", "Histórico guardado": "Stair shábháilte", "Rascunho local": "Dréacht logánta", "Origem": "Foinse", "Brandings": "Brandálacha", "Pesquisa pública": "Cuardach poiblí", "Cadastro manual": "Clárú láimhe", "Contas cadastradas": "Cuntais chláraithe", "Biblioteca": "Leabharlann", "Importar do YouTube": "Iompórtáil ó YouTube", "Canais em lote gmail": "Cainéil bhaisc Gmail", "Criar vídeo": "Cruthaigh físeán", "Vídeos": "Físeáin", "Novo roteiro/letra": "Script/liric nua", "Clusters encontrados": "Braislí aimsithe", "Regras de associação": "Rialacha comhlachais", "Dados analisados": "Sonraí anailísithe", "Upload ficheiro": "Uaslódáil comhad", "URL de vídeo": "URL físeáin", "Vídeos gerados": "Físeáin ginte", "Pasta local": "Fillteán logánta", "Código Python": "Cód Python", "Upload convencional": "Uaslódáil traidisiúnta", "Upload directo": "Uaslódáil díreach", "API Keys": "Eochracha API", "Teste de Voz": "Tástáil gutha", "Serviços e modelos": "Seirbhísí agus samhlacha", "Fontes de Materiais": "Foinsí ábhair", "Client MCP": "Cliant MCP", "Servidor MCP": "Freastalaí MCP", "Skill": "Scil", "Guia de configuração do Supabase para automações com n8n.": "Treoir chumraíochta Supabase le haghaidh uathoibrithe le n8n.", "Adicionar fonte de materiais": "Cuir foinse ábhair leis", "Provedor de materiais": "Soláthraí ábhair", "Configurar Nova Fonte de Materiais": "Cumraigh foinse nua ábhair", "Fonte activa": "Foinse ghníomhach", "Usar esta fonte na pipeline": "Úsáid an fhoinse seo sa phíblíne", "Esta fonte não usa API key.": "Ní úsáideann an fhoinse seo eochair API.", "A testar chamada API…": "Glao API á thástáil…", "Último teste: API Key OK": "An tástáil is déanaí: eochair API ceart", "Último teste: falta configuração": "An tástáil is déanaí: cumraíocht ar iarraidh", "Último teste: requer autorização ou endpoint seguro": "An tástáil is déanaí: údarú breise nó críochphointe sábháilte de dhíth", "Último teste: chamada falhou": "An tástáil is déanaí: theip ar an nglao", "Testar credenciais TTS e música": "Tástáil dintiúr TTS agus ceoil", "Facebook Pages": "Leathanaigh Facebook", "Motion Control": "Rialú gluaisne", "UGC Products": "Táirgí UGC",
1376
1376
  },
1377
1377
  "ar": {
1378
1378
  "Início": "الصفحة الرئيسية", "Niche Finder": "باحث المجالات", "Pipeline": "خط الإنتاج", "Pipeline TikTok": "خط إنتاج TikTok", "Automação": "الأتمتة", "Edição": "التحرير", "AI Influencers": "مؤثرو الذكاء الاصطناعي", "Configurações": "الإعدادات", "Criação de Vídeos": "إنشاء الفيديو", "Criação de Músicas": "إنشاء الموسيقى", "Roteiros": "السيناريوهات", "Upload": "رفع", "Prompts Master": "محرّكات المطالبات", "Contas TikTok": "حسابات TikTok", "Automação Youtube": "أتمتة YouTube", "Niche Finder Kaggle": "باحث المجالات — Kaggle", "Niche Finder Apify": "باحث المجالات — Apify", "Limpador de Metadados": "منظف البيانات الوصفية", "Cortes": "القصاصات", "Editor Python": "محرر Python", "Download Mídia": "تنزيل الوسائط", "Personagens": "الشخصيات", "Redes Sociais": "الشبكات الاجتماعية", "Tutorial Meta": "دليل Meta", "Tutorial Supabase": "دليل Supabase", "Canais Youtube": "قنوات YouTube", "Blueprints Youtube": "مخططات YouTube", "Contas Google": "حسابات Google", "Configuração API": "إعداد API", "Notificações": "الإشعارات", "Interface local para operação e automação de conteúdo faceless": "واجهة محلية لتشغيل وأتمتة المحتوى دون ظهور", "Canais": "القنوات", "activos": "نشطة", "Tarefas": "المهام", "total registado": "الإجمالي المسجل", "A fazer": "قيد التنفيذ", "na pipeline": "في خط الإنتاج", "Em execução": "قيد التشغيل", "a decorrer": "جارٍ", "Concluídos": "مكتملة", "artefactos prontos": "النتائج الجاهزة", "Falhas": "الأخطاء", "requerem atenção": "تتطلب الانتباه", "Filas locais e dependências da cascata": "قوائم الانتظار المحلية وتبعيات خط الإنتاج", "Niche": "مجال", "Blueprints": "المخططات", "Brand": "العلامة التجارية", "Script": "السيناريو", "Title": "العنوان", "Thumbnail": "الصورة المصغرة", "Video": "الفيديو", "Edit": "تحرير", "fila": "قائمة الانتظار", "na biblioteca": "في المكتبة", "tarefa(s) na fila": "مهمة/مهام في قائمة الانتظار", "Language": "اللغة", "Theme": "السمة", "Dark": "داكن", "Light": "فاتح",
1379
- "LLM — providers e modelos": "LLM — المزوّدون والنماذج", "Adicionar provider LLM": "إضافة مزوّد LLM", "Provider LLM": "مزوّد LLM", "Configurar Novo Provedor LLM": "إعداد مزوّد LLM جديد", "API key": "مفتاح API", "Modelo": "النموذج", "Base URL": "عنوان URL الأساسي", "Modelo manual": "نموذج يدوي", "Escrever modelo manualmente": "اكتب النموذج يدوياً", "Provider activo": "المزوّد النشط", "LLM Telegram": "LLM Telegram", "Testar chamada API": "اختبار استدعاء API", "Consultar modelos": "جلب النماذج", "Salvar": "حفظ", "Remover cartão": "إزالة البطاقة", "Último teste:": "آخر اختبار:", "Teste API:": "اختبار API:", "Missing key": "المفتاح مفقود", "Missing configuration": "الإعداد مفقود", "Configured": "تم الإعداد", "Local / sem API key": "محلي / بلا مفتاح API", "Este provider não exige API key.": "هذا المزوّد لا يتطلب مفتاح API.", "Prioridade": "LLM الرئيسي", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "استخدم هذه البطاقة كمزوّد رئيسي لإنشاء الموضوعات والسيناريوهات والعناوين والكلمات المفتاحية.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "استخدم هذه البطاقة حصرياً لتوجيه إشعارات Telegram. يمكن تحديد بطاقة واحدة فقط.", "Account Id": "معرّف الحساب", "Gateway Id": "معرّف البوابة", "Api Version": "إصدار API", "Endpoint gerido pelo provider: ": "نقطة النهاية التي يديرها المزوّد: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "نقطة نهاية متوافقة مع OpenAI؛ تظهر فقط عند إمكانية إعدادها.", "ID do modelo usado pelo endpoint Chat Completions.": "معرّف النموذج المستخدم في نقطة نهاية Chat Completions.", "Arquivos Base": "الملفات الأساسية", "Pipeline Vídeos": "خط إنتاج الفيديو", "Canais e Perfis de Vídeos": "قنوات وملفات الفيديو", "Canais YouTube": "قنوات YouTube", "Facebook Pages": "صفحات Facebook", "Prompt Masters": "محرّكات المطالبات", "Backlog Vídeos": "تراكم الفيديوهات", "Thumbnails": "الصور المصغرة", "Música": "الموسيقى", "Upload Música": "رفع الموسيقى", "Geração de Conteúdo IA": "إنشاء محتوى بالذكاء الاصطناعي", "Motion Control": "التحكم بالحركة", "UGC Products": "منتجات UGC", "Growth": "النمو", "Analista Growth Youtube": "محلل نمو YouTube", "Analista Growth Tiktok": "محلل نمو TikTok", "Analista Growth Instagram": "محلل نمو Instagram", "Documentação": "التوثيق", "Tutorial Kaggle": "دليل Kaggle", "Tutorial Apify": "دليل Apify", "Pipeline Música": "خط إنتاج الموسيقى", "módulos disponíveis": "الوحدات المتاحة", "Guardar INNERTUBE_API_KEY global": "حفظ INNERTUBE_API_KEY العام", "Gerar tópico, roteiro e palavras-chave com IA": "إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي", "A gerar tópico, roteiro e palavras-chave com IA…": "جارٍ إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي…", "Tema, roteiro e palavras-chave gerados com IA.": "تم إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "املأ حقل Video Subject أو استخدم زر الإنشاء التلقائي أسفل الكلمات المفتاحية.", "Refazer thumbnail": "إعادة إنشاء الصورة المصغرة", "Salvar rascunho": "حفظ المسودة", "Rascunho guardado localmente": "تم حفظ المسودة محلياً", "Thumbnail refeita com sucesso.": "تمت إعادة إنشاء الصورة المصغرة بنجاح.", "Ver prompt da thumbnail": "عرض مطالبة الصورة المصغرة", "Sem imagem": "لا توجد صورة", "Imagem ainda não gerada": "لم يتم إنشاء الصورة بعد", "Palavras-chave": "الكلمات المفتاحية", "Título do rascunho": "عنوان المسودة", "Gerar de Rascunho": "الإنشاء من مسودة", "Roteiros guardados": "السيناريوهات المحفوظة", "Seleccione um roteiro": "اختر سيناريو", "Configurações a completar": "إعدادات يجب إكمالها", "Configurações de vídeo": "إعدادات الفيديو", "Configurações de áudio": "إعدادات الصوت", "Configurações de legendas": "إعدادات الترجمة", "Continuar criação": "متابعة الإنشاء", "Gerar apenas o vídeo": "إنشاء الفيديو فقط", "Seleccione um canal para continuar.": "اختر قناة للمتابعة.", "Ainda não existem roteiros guardados.": "لا توجد سيناريوهات محفوظة بعد.", "Histórico guardado": "السجل المحفوظ", "Rascunho local": "مسودة محلية", "Origem": "المصدر", "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": "سيناريو/كلمات جديدة", "Clusters encontrados": "العناقيد المكتشفة", "Regras de associação": "قواعد الارتباط", "Dados analisados": "البيانات المحللة", "Upload ficheiro": "رفع ملف", "URL de vídeo": "رابط الفيديو", "Vídeos gerados": "الفيديوهات المنشأة", "Pasta local": "المجلد المحلي", "Código Python": "كود Python", "Upload convencional": "رفع تقليدي", "Upload directo": "رفع مباشر", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "مفاتيح API", "Teste de Voz": "اختبار الصوت", "Serviços e modelos": "الخدمات والنماذج", "Fontes de Materiais": "مصادر الوسائط", "Client MCP": "عميل MCP", "Servidor MCP": "خادم MCP", "Skill": "المهارة", "Guia de configuração do Supabase para automações com n8n.": "دليل إعداد Supabase للأتمتة باستخدام n8n.", "Adicionar fonte de materiais": "إضافة مصدر وسائط", "Provedor de materiais": "مزوّد الوسائط", "Configurar Nova Fonte de Materiais": "إعداد مصدر وسائط جديد", "Fonte activa": "المصدر النشط", "Usar esta fonte na pipeline": "استخدم هذا المصدر في خط الإنتاج", "Esta fonte não usa API key.": "لا يستخدم هذا المصدر مفتاح API.", "A testar chamada API…": "جارٍ اختبار استدعاء API…", "Último teste: API Key OK": "آخر اختبار: مفتاح API صالح", "Último teste: falta configuração": "آخر اختبار: الإعداد مفقود", "Último teste: requer autorização ou endpoint seguro": "آخر اختبار: يلزم تفويض إضافي أو نقطة نهاية آمنة", "Último teste: chamada falhou": "آخر اختبار: فشل الاستدعاء", "Testar credenciais TTS e música": "اختبار بيانات اعتماد TTS والموسيقى",
1379
+ "LLM — providers e modelos": "LLM — المزوّدون والنماذج", "Adicionar provider LLM": "إضافة مزوّد LLM", "Provider LLM": "مزوّد LLM", "Configurar Novo Provedor LLM": "إعداد مزوّد LLM جديد", "API key": "مفتاح API", "Modelo": "النموذج", "Base URL": "عنوان URL الأساسي", "Modelo manual": "نموذج يدوي", "Escrever modelo manualmente": "اكتب النموذج يدوياً", "Provider activo": "المزوّد النشط", "LLM Telegram": "LLM Telegram", "Testar chamada API": "اختبار استدعاء API", "Consultar modelos": "جلب النماذج", "Salvar": "حفظ", "Remover cartão": "إزالة البطاقة", "Último teste:": "آخر اختبار:", "Teste API:": "اختبار API:", "Missing key": "المفتاح مفقود", "Missing configuration": "الإعداد مفقود", "Configured": "تم الإعداد", "Local / sem API key": "محلي / بلا مفتاح API", "Este provider não exige API key.": "هذا المزوّد لا يتطلب مفتاح API.", "Prioridade": "LLM الرئيسي", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "استخدم هذه البطاقة كمزوّد رئيسي لإنشاء الموضوعات والسيناريوهات والعناوين والكلمات المفتاحية.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "استخدم هذه البطاقة حصرياً لتوجيه إشعارات Telegram. يمكن تحديد بطاقة واحدة فقط.", "Account Id": "معرّف الحساب", "Gateway Id": "معرّف البوابة", "Api Version": "إصدار API", "Endpoint gerido pelo provider: ": "نقطة النهاية التي يديرها المزوّد: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "نقطة نهاية متوافقة مع OpenAI؛ تظهر فقط عند إمكانية إعدادها.", "ID do modelo usado pelo endpoint Chat Completions.": "معرّف النموذج المستخدم في نقطة نهاية Chat Completions.", "Arquivos Base": "الملفات الأساسية", "Pipeline Vídeos": "خط إنتاج الفيديو", "Canais e Perfis de Vídeos": "قنوات وملفات الفيديو", "Canais/Perfis (Vídeos)": "قنوات وملفات الفيديو", "Canais YouTube": "قنوات YouTube", "Facebook Pages": "صفحات Facebook", "Prompt Masters": "محرّكات المطالبات", "Backlog Vídeos": "تراكم الفيديوهات", "Thumbnails": "الصور المصغرة", "Música": "الموسيقى", "Upload Música": "رفع الموسيقى", "Geração de Conteúdo IA": "إنشاء محتوى بالذكاء الاصطناعي", "Motion Control": "التحكم بالحركة", "UGC Products": "منتجات UGC", "Growth": "النمو", "Analista Growth Youtube": "محلل نمو YouTube", "Analista Growth Tiktok": "محلل نمو TikTok", "Analista Growth Instagram": "محلل نمو Instagram", "Documentação": "التوثيق", "Tutorial Kaggle": "دليل Kaggle", "Tutorial Apify": "دليل Apify", "Pipeline Música": "خط إنتاج الموسيقى", "módulos disponíveis": "الوحدات المتاحة", "Guardar INNERTUBE_API_KEY global": "حفظ INNERTUBE_API_KEY العام", "Gerar tópico, roteiro e palavras-chave com IA": "إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي", "A gerar tópico, roteiro e palavras-chave com IA…": "جارٍ إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي…", "Tema, roteiro e palavras-chave gerados com IA.": "تم إنشاء الموضوع والسيناريو والكلمات المفتاحية بالذكاء الاصطناعي.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "املأ حقل Video Subject أو استخدم زر الإنشاء التلقائي أسفل الكلمات المفتاحية.", "Refazer thumbnail": "إعادة إنشاء الصورة المصغرة", "Salvar rascunho": "حفظ المسودة", "Rascunho guardado localmente": "تم حفظ المسودة محلياً", "Thumbnail refeita com sucesso.": "تمت إعادة إنشاء الصورة المصغرة بنجاح.", "Ver prompt da thumbnail": "عرض مطالبة الصورة المصغرة", "Sem imagem": "لا توجد صورة", "Imagem ainda não gerada": "لم يتم إنشاء الصورة بعد", "Palavras-chave": "الكلمات المفتاحية", "Título do rascunho": "عنوان المسودة", "Gerar de Rascunho": "الإنشاء من مسودة", "Roteiros guardados": "السيناريوهات المحفوظة", "Seleccione um roteiro": "اختر سيناريو", "Configurações a completar": "إعدادات يجب إكمالها", "Configurações de vídeo": "إعدادات الفيديو", "Configurações de áudio": "إعدادات الصوت", "Configurações de legendas": "إعدادات الترجمة", "Continuar criação": "متابعة الإنشاء", "Gerar apenas o vídeo": "إنشاء الفيديو فقط", "Seleccione um canal para continuar.": "اختر قناة للمتابعة.", "Ainda não existem roteiros guardados.": "لا توجد سيناريوهات محفوظة بعد.", "Histórico guardado": "السجل المحفوظ", "Rascunho local": "مسودة محلية", "Origem": "المصدر", "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": "سيناريو/كلمات جديدة", "Clusters encontrados": "العناقيد المكتشفة", "Regras de associação": "قواعد الارتباط", "Dados analisados": "البيانات المحللة", "Upload ficheiro": "رفع ملف", "URL de vídeo": "رابط الفيديو", "Vídeos gerados": "الفيديوهات المنشأة", "Pasta local": "المجلد المحلي", "Código Python": "كود Python", "Upload convencional": "رفع تقليدي", "Upload directo": "رفع مباشر", "Postiz": "Postiz", "Upload-Post": "Upload-Post", "API Keys": "مفاتيح API", "Teste de Voz": "اختبار الصوت", "Serviços e modelos": "الخدمات والنماذج", "Fontes de Materiais": "مصادر الوسائط", "Client MCP": "عميل MCP", "Servidor MCP": "خادم MCP", "Skill": "المهارة", "Guia de configuração do Supabase para automações com n8n.": "دليل إعداد Supabase للأتمتة باستخدام n8n.", "Adicionar fonte de materiais": "إضافة مصدر وسائط", "Provedor de materiais": "مزوّد الوسائط", "Configurar Nova Fonte de Materiais": "إعداد مصدر وسائط جديد", "Fonte activa": "المصدر النشط", "Usar esta fonte na pipeline": "استخدم هذا المصدر في خط الإنتاج", "Esta fonte não usa API key.": "لا يستخدم هذا المصدر مفتاح API.", "A testar chamada API…": "جارٍ اختبار استدعاء API…", "Último teste: API Key OK": "آخر اختبار: مفتاح API صالح", "Último teste: falta configuração": "آخر اختبار: الإعداد مفقود", "Último teste: requer autorização ou endpoint seguro": "آخر اختبار: يلزم تفويض إضافي أو نقطة نهاية آمنة", "Último teste: chamada falhou": "آخر اختبار: فشل الاستدعاء", "Testar credenciais TTS e música": "اختبار بيانات اعتماد TTS والموسيقى",
1380
1380
  },
1381
1381
  "he": {
1382
1382
  "Início": "דף הבית", "Niche Finder": "מאתר נישות", "Pipeline": "צינור עבודה", "Pipeline TikTok": "צינור TikTok", "Automação": "אוטומציה", "Edição": "עריכה", "AI Influencers": "משפיעני AI", "Configurações": "הגדרות", "Criação de Vídeos": "יצירת וידאו", "Criação de Músicas": "יצירת מוזיקה", "Roteiros": "תסריטים", "Upload": "העלאה", "Prompts Master": "מאסטרים של פרומפטים", "Contas TikTok": "חשבונות TikTok", "Automação Youtube": "אוטומציית YouTube", "Niche Finder Kaggle": "מאתר נישות Kaggle", "Niche Finder Apify": "מאתר נישות Apify", "Limpador de Metadados": "מנקה מטא־נתונים", "Cortes": "חיתוכים", "Editor Python": "עורך Python", "Download Mídia": "הורדת מדיה", "Personagens": "דמויות", "Redes Sociais": "רשתות חברתיות", "Tutorial Meta": "מדריך Meta", "Tutorial Supabase": "מדריך Supabase", "Canais Youtube": "ערוצי YouTube", "Blueprints Youtube": "שרטוטי YouTube", "Contas Google": "חשבונות Google", "Configuração API": "הגדרת API", "Notificações": "התראות", "Interface local para operação e automação de conteúdo faceless": "ממשק מקומי להפעלה ולאוטומציה של תוכן ללא הופעה", "Canais": "ערוצים", "activos": "פעילים", "Tarefas": "משימות", "total registado": "סה״כ רשומים", "A fazer": "לביצוע", "na pipeline": "בצינור העבודה", "Em execução": "בהרצה", "a decorrer": "בתהליך", "Concluídos": "הושלמו", "artefactos prontos": "תוצרים מוכנים", "Falhas": "כשלים", "requerem atenção": "דורשים תשומת לב", "Filas locais e dependências da cascata": "תורים מקומיים ותלויות בצינור", "Niche": "נישה", "Blueprints": "שרטוטים", "Brand": "מותג", "Script": "תסריט", "Title": "כותרת", "Thumbnail": "תמונה ממוזערת", "Video": "וידאו", "Edit": "עריכה", "fila": "תור", "na biblioteca": "בספרייה", "tarefa(s) na fila": "משימה/משימות בתור", "Language": "שפה", "Theme": "ערכת נושא", "Dark": "כהה", "Light": "בהיר",
1383
- "LLM — providers e modelos": "LLM — ספקים ומודלים", "Adicionar provider LLM": "הוסף ספק LLM", "Provider LLM": "ספק LLM", "Configurar Novo Provedor LLM": "הגדרת ספק LLM חדש", "API key": "מפתח API", "Modelo": "מודל", "Base URL": "כתובת URL בסיסית", "Modelo manual": "מודל ידני", "Escrever modelo manualmente": "כתיבת מודל ידנית", "Provider activo": "ספק פעיל", "LLM Telegram": "LLM Telegram", "Testar chamada API": "בדיקת קריאת API", "Consultar modelos": "קבלת מודלים", "Salvar": "שמירה", "Remover cartão": "הסרת כרטיס", "Último teste:": "בדיקה אחרונה:", "Teste API:": "בדיקת API:", "Missing key": "מפתח חסר", "Missing configuration": "הגדרה חסרה", "Configured": "מוגדר", "Local / sem API key": "מקומי / ללא מפתח API", "Este provider não exige API key.": "ספק זה אינו דורש מפתח API.", "Prioridade": "LLM ראשי", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "השתמש בכרטיס זה כספק הראשי ליצירת נושאים, תסריטים, כותרות ומילות מפתח.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "השתמש בכרטיס זה אך ורק לניתוב התראות Telegram. ניתן לבחור כרטיס אחד בלבד.", "Account Id": "מזהה חשבון", "Gateway Id": "מזהה שער", "Api Version": "גרסת API", "Endpoint gerido pelo provider: ": "נקודת קצה בניהול הספק: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "נקודת קצה תואמת OpenAI; מוצגת רק כאשר ניתן להגדירה.", "ID do modelo usado pelo endpoint Chat Completions.": "מזהה המודל שבו משתמשת נקודת הקצה Chat Completions.", "Arquivos Base": "קבצי בסיס", "Pipeline Vídeos": "צינור וידאו", "Canais e Perfis de Vídeos": "ערוצי ופרופילי וידאו", "Canais YouTube": "ערוצי YouTube", "Facebook Pages": "דפי Facebook", "Prompt Masters": "מאסטרים של פרומפטים", "Backlog Vídeos": "צבר וידאו", "Thumbnails": "תמונות ממוזערות", "Música": "מוזיקה", "Upload Música": "העלאת מוזיקה", "Geração de Conteúdo IA": "יצירת תוכן AI", "Motion Control": "בקרת תנועה", "UGC Products": "מוצרי UGC", "Growth": "צמיחה", "Analista Growth Youtube": "אנליסט צמיחת YouTube", "Analista Growth Tiktok": "אנליסט צמיחת TikTok", "Analista Growth Instagram": "אנליסט צמיחת Instagram", "Documentação": "תיעוד", "Tutorial Kaggle": "מדריך Kaggle", "Tutorial Apify": "מדריך Apify", "Pipeline Música": "צינור מוזיקה", "módulos disponíveis": "מודולים זמינים", "Guardar INNERTUBE_API_KEY global": "שמירת INNERTUBE_API_KEY גלובלי", "Gerar tópico, roteiro e palavras-chave com IA": "יצירת נושא, תסריט ומילות מפתח בעזרת AI", "A gerar tópico, roteiro e palavras-chave com IA…": "יוצר נושא, תסריט ומילות מפתח בעזרת AI…", "Tema, roteiro e palavras-chave gerados com IA.": "הנושא, התסריט ומילות המפתח נוצרו בעזרת AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "מלא את השדה Video Subject או השתמש בלחצן היצירה האוטומטית שמתחת למילות המפתח.", "Refazer thumbnail": "יצירת תמונה ממוזערת מחדש", "Salvar rascunho": "שמירת טיוטה", "Rascunho guardado localmente": "הטיוטה נשמרה מקומית", "Thumbnail refeita com sucesso.": "התמונה הממוזערת נוצרה מחדש בהצלחה.", "Ver prompt da thumbnail": "צפייה בפרומפט התמונה הממוזערת", "Sem imagem": "אין תמונה", "Imagem ainda não gerada": "התמונה עדיין לא נוצרה", "Palavras-chave": "מילות מפתח", "Título do rascunho": "כותרת הטיוטה", "Gerar de Rascunho": "יצירה מטיוטה", "Roteiros guardados": "תסריטים שמורים", "Seleccione um roteiro": "בחירת תסריט", "Configurações a completar": "הגדרות להשלמה", "Configurações de vídeo": "הגדרות וידאו", "Configurações de áudio": "הגדרות שמע", "Configurações de legendas": "הגדרות כתוביות", "Continuar criação": "המשך יצירה", "Gerar apenas o vídeo": "יצירת הווידאו בלבד", "Seleccione um canal para continuar.": "בחר ערוץ כדי להמשיך.", "Ainda não existem roteiros guardados.": "עדיין אין תסריטים שמורים.", "Histórico guardado": "היסטוריה שמורה", "Rascunho local": "טיוטה מקומית", "Origem": "מקור", "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": "תסריט/מילים חדשים", "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": "העלאה ישירה", "API Keys": "מפתחות API", "Teste de Voz": "בדיקת קול", "Serviços e modelos": "שירותים ומודלים", "Fontes de Materiais": "מקורות מדיה", "Client MCP": "לקוח MCP", "Servidor MCP": "שרת MCP", "Skill": "מיומנות", "Guia de configuração do Supabase para automações com n8n.": "מדריך להגדרת Supabase לאוטומציות עם n8n.", "Adicionar fonte de materiais": "הוספת מקור מדיה", "Provedor de materiais": "ספק מדיה", "Configurar Nova Fonte de Materiais": "הגדרת מקור מדיה חדש", "Fonte activa": "מקור פעיל", "Usar esta fonte na pipeline": "שימוש במקור זה בצינור", "Esta fonte não usa API key.": "מקור זה אינו משתמש במפתח API.", "A testar chamada API…": "בודק קריאת API…", "Último teste: API Key OK": "בדיקה אחרונה: מפתח API תקין", "Último teste: falta configuração": "בדיקה אחרונה: חסרה הגדרה", "Último teste: requer autorização ou endpoint seguro": "בדיקה אחרונה: נדרש אישור נוסף או נקודת קצה בטוחה", "Último teste: chamada falhou": "בדיקה אחרונה: הקריאה נכשלה", "Testar credenciais TTS e música": "בדיקת פרטי הגישה של TTS ומוזיקה",
1383
+ "LLM — providers e modelos": "LLM — ספקים ומודלים", "Adicionar provider LLM": "הוסף ספק LLM", "Provider LLM": "ספק LLM", "Configurar Novo Provedor LLM": "הגדרת ספק LLM חדש", "API key": "מפתח API", "Modelo": "מודל", "Base URL": "כתובת URL בסיסית", "Modelo manual": "מודל ידני", "Escrever modelo manualmente": "כתיבת מודל ידנית", "Provider activo": "ספק פעיל", "LLM Telegram": "LLM Telegram", "Testar chamada API": "בדיקת קריאת API", "Consultar modelos": "קבלת מודלים", "Salvar": "שמירה", "Remover cartão": "הסרת כרטיס", "Último teste:": "בדיקה אחרונה:", "Teste API:": "בדיקת API:", "Missing key": "מפתח חסר", "Missing configuration": "הגדרה חסרה", "Configured": "מוגדר", "Local / sem API key": "מקומי / ללא מפתח API", "Este provider não exige API key.": "ספק זה אינו דורש מפתח API.", "Prioridade": "LLM ראשי", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "השתמש בכרטיס זה כספק הראשי ליצירת נושאים, תסריטים, כותרות ומילות מפתח.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "השתמש בכרטיס זה אך ורק לניתוב התראות Telegram. ניתן לבחור כרטיס אחד בלבד.", "Account Id": "מזהה חשבון", "Gateway Id": "מזהה שער", "Api Version": "גרסת API", "Endpoint gerido pelo provider: ": "נקודת קצה בניהול הספק: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "נקודת קצה תואמת OpenAI; מוצגת רק כאשר ניתן להגדירה.", "ID do modelo usado pelo endpoint Chat Completions.": "מזהה המודל שבו משתמשת נקודת הקצה Chat Completions.", "Arquivos Base": "קבצי בסיס", "Pipeline Vídeos": "צינור וידאו", "Canais e Perfis de Vídeos": "ערוצי ופרופילי וידאו", "Canais/Perfis (Vídeos)": "ערוצי ופרופילי וידאו", "Canais YouTube": "ערוצי YouTube", "Facebook Pages": "דפי Facebook", "Prompt Masters": "מאסטרים של פרומפטים", "Backlog Vídeos": "צבר וידאו", "Thumbnails": "תמונות ממוזערות", "Música": "מוזיקה", "Upload Música": "העלאת מוזיקה", "Geração de Conteúdo IA": "יצירת תוכן AI", "Motion Control": "בקרת תנועה", "UGC Products": "מוצרי UGC", "Growth": "צמיחה", "Analista Growth Youtube": "אנליסט צמיחת YouTube", "Analista Growth Tiktok": "אנליסט צמיחת TikTok", "Analista Growth Instagram": "אנליסט צמיחת Instagram", "Documentação": "תיעוד", "Tutorial Kaggle": "מדריך Kaggle", "Tutorial Apify": "מדריך Apify", "Pipeline Música": "צינור מוזיקה", "módulos disponíveis": "מודולים זמינים", "Guardar INNERTUBE_API_KEY global": "שמירת INNERTUBE_API_KEY גלובלי", "Gerar tópico, roteiro e palavras-chave com IA": "יצירת נושא, תסריט ומילות מפתח בעזרת AI", "A gerar tópico, roteiro e palavras-chave com IA…": "יוצר נושא, תסריט ומילות מפתח בעזרת AI…", "Tema, roteiro e palavras-chave gerados com IA.": "הנושא, התסריט ומילות המפתח נוצרו בעזרת AI.", "Preencha o campo Video Subject ou use o botão de geração automática abaixo das keywords.": "מלא את השדה Video Subject או השתמש בלחצן היצירה האוטומטית שמתחת למילות המפתח.", "Refazer thumbnail": "יצירת תמונה ממוזערת מחדש", "Salvar rascunho": "שמירת טיוטה", "Rascunho guardado localmente": "הטיוטה נשמרה מקומית", "Thumbnail refeita com sucesso.": "התמונה הממוזערת נוצרה מחדש בהצלחה.", "Ver prompt da thumbnail": "צפייה בפרומפט התמונה הממוזערת", "Sem imagem": "אין תמונה", "Imagem ainda não gerada": "התמונה עדיין לא נוצרה", "Palavras-chave": "מילות מפתח", "Título do rascunho": "כותרת הטיוטה", "Gerar de Rascunho": "יצירה מטיוטה", "Roteiros guardados": "תסריטים שמורים", "Seleccione um roteiro": "בחירת תסריט", "Configurações a completar": "הגדרות להשלמה", "Configurações de vídeo": "הגדרות וידאו", "Configurações de áudio": "הגדרות שמע", "Configurações de legendas": "הגדרות כתוביות", "Continuar criação": "המשך יצירה", "Gerar apenas o vídeo": "יצירת הווידאו בלבד", "Seleccione um canal para continuar.": "בחר ערוץ כדי להמשיך.", "Ainda não existem roteiros guardados.": "עדיין אין תסריטים שמורים.", "Histórico guardado": "היסטוריה שמורה", "Rascunho local": "טיוטה מקומית", "Origem": "מקור", "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": "תסריט/מילים חדשים", "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": "העלאה ישירה", "API Keys": "מפתחות API", "Teste de Voz": "בדיקת קול", "Serviços e modelos": "שירותים ומודלים", "Fontes de Materiais": "מקורות מדיה", "Client MCP": "לקוח MCP", "Servidor MCP": "שרת MCP", "Skill": "מיומנות", "Guia de configuração do Supabase para automações com n8n.": "מדריך להגדרת Supabase לאוטומציות עם n8n.", "Adicionar fonte de materiais": "הוספת מקור מדיה", "Provedor de materiais": "ספק מדיה", "Configurar Nova Fonte de Materiais": "הגדרת מקור מדיה חדש", "Fonte activa": "מקור פעיל", "Usar esta fonte na pipeline": "שימוש במקור זה בצינור", "Esta fonte não usa API key.": "מקור זה אינו משתמש במפתח API.", "A testar chamada API…": "בודק קריאת API…", "Último teste: API Key OK": "בדיקה אחרונה: מפתח API תקין", "Último teste: falta configuração": "בדיקה אחרונה: חסרה הגדרה", "Último teste: requer autorização ou endpoint seguro": "בדיקה אחרונה: נדרש אישור נוסף או נקודת קצה בטוחה", "Último teste: chamada falhou": "בדיקה אחרונה: הקריאה נכשלה", "Testar credenciais TTS e música": "בדיקת פרטי הגישה של TTS ומוזיקה",
1384
1384
  },
1385
1385
  }
1386
1386
 
@@ -310,12 +310,20 @@ def _helper_output_value(output: str, key: str) -> str:
310
310
 
311
311
 
312
312
  def _redact_helper_output(text: str) -> str:
313
- for key in ("MPT_LLM_API_KEY", "MPT_PEXELS_API_KEY", "MPT_PIXABAY_API_KEY"):
313
+ for key in ("MPT_LLM_API_KEY", "MPT_PEXELS_API_KEY", "MPT_PIXABAY_API_KEY", "AZURE_SPEECH_KEY", "AZURE_SPEECH_REGION"):
314
314
  secret = os.environ.get(key, "").strip()
315
315
  if secret:
316
316
  text = text.replace(secret, "[redacted]")
317
317
  return text
318
318
 
319
+ def _terminal_helper_detail(output: str) -> str:
320
+ """Return the last actionable helper lines, not startup/configuration noise."""
321
+ lines = [_redact_helper_output(line).strip() for line in str(output or "").splitlines()]
322
+ lines = [line for line in lines if line]
323
+ noise_markers = ("using existing project:", "updated configuration fields:", "starting video generation, task id:")
324
+ actionable = [line for line in lines if not any(marker in line.casefold() for marker in noise_markers)]
325
+ return "\n".join((actionable or lines)[-12:]).strip()
326
+
319
327
 
320
328
  def _helper_failure_markers(output: str) -> dict[str, Any]:
321
329
  missing = [item.strip() for item in re.findall(r"(?m)^MISSING=(.+)$", output) if item.strip()]
@@ -378,6 +386,16 @@ def _failure_attribution(
378
386
  "failure_stage": stage,
379
387
  }
380
388
 
389
+ if stage == "video" and any(marker in combined for marker in ("azure speech sdk v2", "azure speech v2", "azure_tts_v2")):
390
+ return {
391
+ "failure_api": "Azure Speech SDK V2 API",
392
+ "failure_provider": "azure_speech",
393
+ "failure_service": "Narração TTS — segmentação Azure",
394
+ "failure_route": route,
395
+ "failure_config_fields": "",
396
+ "failure_stage": stage,
397
+ }
398
+
381
399
  if stage == "video" and any(marker in combined for marker in ("edge_tts", "edge tts", "azure_tts_v1", "azure speech")):
382
400
  return {
383
401
  "failure_api": "Azure Speech / edge_tts API",
@@ -707,10 +725,13 @@ def _moneyprinter_cli_args(task: dict[str, Any], route: str, settings: dict[str,
707
725
  args.append("--match-materials-to-script")
708
726
 
709
727
  voice_mode = str(generation_settings.get("voiceover_mode") or "").strip().casefold()
728
+ azure_service = str(generation_settings.get("voiceover_service") or "").strip().casefold()
710
729
  voice = str(task.get("voice") or generation_settings.get("voice") or "").strip()
711
730
  if voice_mode == "none" or voice_mode == "upload":
712
731
  args.extend(["--voice-name", "no-voice"])
713
- elif voice:
732
+ elif voice or azure_service in {"azure speech sdk v2", "azure speech", "azure tts v2", "azure speech sdk"}:
733
+ if not voice:
734
+ voice = "en-US-JennyNeural"
714
735
  if _uses_azure_speech_sdk_v2(generation_settings, settings):
715
736
  voice = _azure_speech_v2_voice_name(voice)
716
737
  args.extend(["--voice-name", voice])
@@ -847,6 +868,7 @@ def _run_video_helper(task: dict[str, Any]) -> Path:
847
868
  reader.start()
848
869
  output_finished = False
849
870
  last_heartbeat = 0.0
871
+ last_output_line = ""
850
872
  try:
851
873
  while True:
852
874
  try:
@@ -854,6 +876,7 @@ def _run_video_helper(task: dict[str, Any]) -> Path:
854
876
  if line is None:
855
877
  output_finished = True
856
878
  elif line:
879
+ last_output_line = _redact_helper_output(line).strip()
857
880
  output_lines.append(line)
858
881
  except queue.Empty:
859
882
  pass
@@ -870,6 +893,7 @@ def _run_video_helper(task: dict[str, Any]) -> Path:
870
893
  _update(
871
894
  task_id,
872
895
  progress=video_progress,
896
+ video_helper_status=last_output_line[-500:] if last_output_line else "",
873
897
  video_elapsed_seconds=int(elapsed),
874
898
  )
875
899
  _worker_heartbeat(
@@ -877,6 +901,7 @@ def _run_video_helper(task: dict[str, Any]) -> Path:
877
901
  status="running",
878
902
  stage="video",
879
903
  progress=video_progress,
904
+ video_helper_status=last_output_line[-500:] if last_output_line else "",
880
905
  video_elapsed_seconds=int(elapsed),
881
906
  )
882
907
  last_heartbeat = elapsed
@@ -897,10 +922,13 @@ def _run_video_helper(task: dict[str, Any]) -> Path:
897
922
  _persist_video_diagnostics(task, output)
898
923
  if result_code == 10:
899
924
  metadata = _failure_attribution(task, settings, "video", output=output)
925
+ detail = _terminal_helper_detail(output)
900
926
  message = "A geração de vídeo precisa de credenciais adicionais do MoneyPrinterTurbo"
927
+ if detail:
928
+ message += f". Detalhe do helper: {detail}"
901
929
  raise PipelineError(_failure_message(message, metadata), failure_metadata=metadata)
902
930
  if result_code != 0:
903
- detail = _redact_helper_output(output[-1200:]).strip() or "erro sem detalhes devolvidos pelo helper"
931
+ detail = _terminal_helper_detail(output) or "erro sem detalhes devolvidos pelo helper"
904
932
  metadata = _failure_attribution(task, settings, "video", error=detail, output=output)
905
933
  message = f"MoneyPrinterTurbo falhou na etapa Vídeo: {detail}"
906
934
  raise PipelineError(_failure_message(message, metadata), failure_metadata=metadata)
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
+ import os
5
+ import tempfile
4
6
  from typing import Any
5
7
 
6
8
  from hermes_ui.languages import language_code
@@ -177,6 +179,28 @@ def build_moneyprinter_config(settings: dict[str, Any], existing: dict[str, Any]
177
179
  return config
178
180
 
179
181
 
182
+ def _atomic_write_text(target: Path, text: str) -> None:
183
+ """Replace TOML atomically so a failed write cannot truncate the prior file."""
184
+ temporary_path: Path | None = None
185
+ try:
186
+ with tempfile.NamedTemporaryFile(
187
+ mode="w", encoding="utf-8", dir=str(target.parent),
188
+ prefix=f".{target.name}.", suffix=".tmp", delete=False,
189
+ ) as handle:
190
+ temporary_path = Path(handle.name)
191
+ handle.write(text)
192
+ handle.flush()
193
+ os.fsync(handle.fileno())
194
+ os.replace(temporary_path, target)
195
+ except Exception:
196
+ if temporary_path is not None:
197
+ try:
198
+ temporary_path.unlink(missing_ok=True)
199
+ except OSError:
200
+ pass
201
+ raise
202
+
203
+
180
204
  def sync_moneyprinter_config(settings: dict[str, Any], moneyprinter_path: str) -> Path | None:
181
205
  if not moneyprinter_path or toml is None:
182
206
  return None
@@ -191,5 +215,5 @@ def sync_moneyprinter_config(settings: dict[str, Any], moneyprinter_path: str) -
191
215
  except Exception:
192
216
  existing = {}
193
217
  payload = build_moneyprinter_config(settings, existing)
194
- target.write_text(toml.dumps(payload), encoding="utf-8")
218
+ _atomic_write_text(target, toml.dumps(payload))
195
219
  return target
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.3.75",
3
+ "version": "0.3.77",
4
4
  "description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
5
5
  "license": "MIT",
6
6
  "main": "scripts/cli.mjs",
@@ -1,10 +1,10 @@
1
- """Generate long Azure Speech V2 audio by synthesizing safe sequential chunks.
1
+ """Generate long Azure Speech V2 audio through conservative sequential chunks.
2
2
 
3
- This helper runs inside the MoneyPrinterTurbo uv project so it can use the
4
- same Azure Speech SDK and audio dependencies as the installed engine. Secrets
5
- are read only from environment variables and are never printed.
3
+ The Azure real-time TTS endpoint limits the produced audio of one request to
4
+ 10 minutes. This helper deliberately stays far below that limit, adjusts the
5
+ text budget for slow voices, and concatenates the completed segments locally.
6
+ Secrets are read only from environment variables and are never printed.
6
7
  """
7
-
8
8
  from __future__ import annotations
9
9
 
10
10
  import argparse
@@ -18,12 +18,19 @@ from tempfile import TemporaryDirectory
18
18
  from xml.sax.saxutils import escape
19
19
 
20
20
 
21
- MAX_CHUNK_CHARACTERS = 1800
21
+ # Azure documents a 600000 ms maximum for real-time TTS. This is an internal
22
+ # character budget, not a claim that characters map to a fixed duration. The
23
+ # deliberately conservative ceiling leaves room for slow voices, pauses and
24
+ # punctuation before the service limit can be approached.
25
+ MAX_CHUNK_CHARACTERS = 900
26
+ MIN_CHUNK_CHARACTERS = 180
22
27
  RETRY_COUNT = 3
23
28
 
24
29
 
25
30
  def _build_parser() -> argparse.ArgumentParser:
26
- parser = argparse.ArgumentParser(description="Synthesize Azure Speech V2 audio in safe chunks.")
31
+ parser = argparse.ArgumentParser(
32
+ description="Synthesize Azure Speech V2 audio in conservative chunks."
33
+ )
27
34
  parser.add_argument("--text-file", type=Path, required=True)
28
35
  parser.add_argument("--output", type=Path, required=True)
29
36
  parser.add_argument("--voice", required=True)
@@ -57,18 +64,27 @@ def _split_long_piece(piece: str, limit: int) -> list[str]:
57
64
  return chunks
58
65
 
59
66
 
60
- def split_text(text: str, limit: int = MAX_CHUNK_CHARACTERS) -> list[str]:
61
- """Split paragraphs and sentences without sending a 10-minute request."""
67
+ def split_text(text: str, limit: int | None = None) -> list[str]:
68
+ """Split paragraphs and sentences without sending an oversized request."""
69
+ try:
70
+ effective_limit = int(limit if limit is not None else MAX_CHUNK_CHARACTERS)
71
+ except (TypeError, ValueError):
72
+ effective_limit = MAX_CHUNK_CHARACTERS
73
+ effective_limit = max(1, effective_limit)
62
74
  normalized = re.sub(r"\r\n?", "\n", text).strip()
63
75
  if not normalized:
64
76
  return []
65
- pieces = [part.strip() for part in re.split(r"\n+|(?<=[.!?。!?;;])\s+", normalized) if part.strip()]
77
+ pieces = [
78
+ part.strip()
79
+ for part in re.split(r"\n+|(?<=[.!?。!?;;])\s+", normalized)
80
+ if part.strip()
81
+ ]
66
82
  chunks: list[str] = []
67
83
  current = ""
68
84
  for piece in pieces:
69
- for fragment in _split_long_piece(piece, limit):
85
+ for fragment in _split_long_piece(piece, effective_limit):
70
86
  candidate = f"{current} {fragment}".strip()
71
- if current and len(candidate) > limit:
87
+ if current and len(candidate) > effective_limit:
72
88
  chunks.append(current)
73
89
  current = fragment
74
90
  else:
@@ -86,8 +102,20 @@ def _normalise_rate(value: float) -> float:
86
102
  return max(0.25, min(4.0, rate))
87
103
 
88
104
 
105
+ def chunk_character_limit(rate: float) -> int:
106
+ """Return a conservative text budget adjusted to the requested speech rate."""
107
+ normalized_rate = _normalise_rate(rate)
108
+ # A slow rate stretches the audio, so reduce the text budget proportionally.
109
+ # A fast rate is capped: the service limit is not a reason to send huge SSML.
110
+ return max(
111
+ MIN_CHUNK_CHARACTERS,
112
+ min(MAX_CHUNK_CHARACTERS, int(round(MAX_CHUNK_CHARACTERS * normalized_rate))),
113
+ )
114
+
115
+
89
116
  def _build_ssml(text: str, voice: str, rate: float) -> str:
90
- locale = "-".join(voice.split("-", 2)[:2]) if len(voice.split("-", 2)) >= 2 else "en-US"
117
+ parts = voice.split("-", 2)
118
+ locale = "-".join(parts[:2]) if len(parts) >= 2 else "en-US"
91
119
  return (
92
120
  '<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" '
93
121
  f'xml:lang="{escape(locale)}">'
@@ -97,35 +125,51 @@ def _build_ssml(text: str, voice: str, rate: float) -> str:
97
125
  )
98
126
 
99
127
 
100
- def _synthesise_chunk(speechsdk, text: str, voice: str, rate: float, target: Path) -> None:
128
+ def _synthesise_chunk(
129
+ speechsdk, text: str, voice: str, rate: float, target: Path
130
+ ) -> None:
101
131
  speech_key = os.environ.get("AZURE_SPEECH_KEY", "").strip()
102
132
  region = os.environ.get("AZURE_SPEECH_REGION", "").strip()
103
133
  if not speech_key or not region:
104
- raise RuntimeError("Azure Speech SDK V2 requer AZURE_SPEECH_KEY e AZURE_SPEECH_REGION.")
134
+ raise RuntimeError(
135
+ "Azure Speech SDK V2 requer AZURE_SPEECH_KEY e AZURE_SPEECH_REGION."
136
+ )
105
137
  speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=region)
106
138
  speech_config.speech_synthesis_voice_name = voice
107
139
  speech_config.set_speech_synthesis_output_format(
108
140
  speechsdk.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3
109
141
  )
110
- audio_config = speechsdk.audio.AudioOutputConfig(filename=str(target), use_default_speaker=False)
111
- synthesizer = speechsdk.SpeechSynthesizer(audio_config=audio_config, speech_config=speech_config)
142
+ audio_config = speechsdk.audio.AudioOutputConfig(
143
+ filename=str(target), use_default_speaker=False
144
+ )
145
+ synthesizer = speechsdk.SpeechSynthesizer(
146
+ audio_config=audio_config, speech_config=speech_config
147
+ )
112
148
  try:
113
149
  result = synthesizer.speak_ssml_async(_build_ssml(text, voice, rate)).get()
114
150
  finally:
115
151
  synthesizer.close()
116
152
  if result.reason != speechsdk.ResultReason.SynthesizingAudioCompleted:
117
- details = getattr(getattr(result, "cancellation_details", None), "error_details", "")
153
+ details = getattr(
154
+ getattr(result, "cancellation_details", None), "error_details", ""
155
+ )
118
156
  reason = str(details or getattr(result, "reason", "unknown"))
119
- raise RuntimeError(f"Azure Speech SDK V2 não concluiu um segmento: {reason[:500]}")
157
+ raise RuntimeError(
158
+ f"Azure Speech SDK V2 não concluiu um segmento: {reason[:500]}"
159
+ )
120
160
  if not target.is_file() or target.stat().st_size <= 0:
121
- raise RuntimeError("Azure Speech SDK V2 terminou sem produzir o áudio do segmento.")
161
+ raise RuntimeError(
162
+ "Azure Speech SDK V2 terminou sem produzir o áudio do segmento."
163
+ )
122
164
 
123
165
 
124
166
  def generate(text: str, voice: str, rate: float, output: Path) -> int:
125
167
  import azure.cognitiveservices.speech as speechsdk
126
168
  from pydub import AudioSegment
127
169
 
128
- ffmpeg_binary = os.environ.get("IMAGEIO_FFMPEG_EXE", "").strip() or shutil.which("ffmpeg")
170
+ ffmpeg_binary = os.environ.get("IMAGEIO_FFMPEG_EXE", "").strip() or shutil.which(
171
+ "ffmpeg"
172
+ )
129
173
  if not ffmpeg_binary:
130
174
  try:
131
175
  import imageio_ffmpeg
@@ -133,16 +177,21 @@ def generate(text: str, voice: str, rate: float, output: Path) -> int:
133
177
  ffmpeg_binary = imageio_ffmpeg.get_ffmpeg_exe()
134
178
  except Exception:
135
179
  ffmpeg_binary = ""
136
- if ffmpeg_binary:
137
- AudioSegment.converter = ffmpeg_binary
138
- else:
139
- raise RuntimeError("FFmpeg não está disponível para concatenar os segmentos Azure Speech V2.")
140
-
141
- chunks = split_text(text)
180
+ if not ffmpeg_binary:
181
+ raise RuntimeError(
182
+ "FFmpeg não está disponível para concatenar os segmentos Azure Speech V2."
183
+ )
184
+ AudioSegment.converter = ffmpeg_binary
185
+
186
+ normalized_rate = _normalise_rate(rate)
187
+ limit = chunk_character_limit(normalized_rate)
188
+ chunks = split_text(text, limit=limit)
142
189
  if not chunks:
143
190
  raise RuntimeError("O roteiro não contém texto para síntese Azure Speech.")
144
191
  output.parent.mkdir(parents=True, exist_ok=True)
145
- with TemporaryDirectory(prefix="azure-v2-chunks-", dir=str(output.parent)) as temporary:
192
+ with TemporaryDirectory(
193
+ prefix="azure-v2-chunks-", dir=str(output.parent)
194
+ ) as temporary:
146
195
  temporary_path = Path(temporary)
147
196
  segment_paths: list[Path] = []
148
197
  for index, chunk in enumerate(chunks, start=1):
@@ -150,21 +199,28 @@ def generate(text: str, voice: str, rate: float, output: Path) -> int:
150
199
  last_error: Exception | None = None
151
200
  for attempt in range(1, RETRY_COUNT + 1):
152
201
  try:
153
- _synthesise_chunk(speechsdk, chunk, voice, rate, segment_path)
202
+ segment_path.unlink(missing_ok=True)
203
+ _synthesise_chunk(
204
+ speechsdk, chunk, voice, normalized_rate, segment_path
205
+ )
154
206
  last_error = None
155
207
  break
156
- except Exception as exc: # Azure SDK exposes provider-specific exception classes.
208
+ except Exception as exc: # Azure SDK exposes provider-specific classes.
157
209
  last_error = exc
158
210
  if attempt < RETRY_COUNT:
159
211
  time.sleep(2 ** (attempt - 1))
160
212
  if last_error is not None:
161
- raise RuntimeError(f"Falha no segmento Azure Speech {index}/{len(chunks)}: {last_error}") from last_error
213
+ raise RuntimeError(
214
+ f"Falha no segmento Azure Speech {index}/{len(chunks)}: {last_error}"
215
+ ) from last_error
162
216
  segment_paths.append(segment_path)
217
+ print(f"AZURE_CHUNK_PROGRESS={index}/{len(chunks)}", flush=True)
163
218
 
164
219
  combined = AudioSegment.empty()
165
220
  for segment_path in segment_paths:
166
221
  combined += AudioSegment.from_file(segment_path, format="mp3")
167
222
  combined.export(output, format="mp3", bitrate="192k")
223
+
168
224
  if not output.is_file() or output.stat().st_size <= 0:
169
225
  raise RuntimeError("A concatenação Azure Speech V2 não produziu áudio válido.")
170
226
  return len(chunks)
@@ -180,6 +236,7 @@ def main(argv: list[str] | None = None) -> int:
180
236
  return 1
181
237
  print(f"AZURE_CHUNKED_AUDIO={args.output.resolve()}")
182
238
  print(f"AZURE_CHUNK_COUNT={count}")
239
+ print(f"AZURE_CHUNK_CHARACTER_LIMIT={chunk_character_limit(args.rate)}")
183
240
  return 0
184
241
 
185
242
 
@@ -24,6 +24,7 @@ PROJECT_ARCHIVE_URL = (
24
24
  "https://github.com/harry0703/MoneyPrinterTurbo/archive/refs/heads/main.zip"
25
25
  )
26
26
  DEFAULT_ROOT = Path.home() / "MoneyPrinterTurbo"
27
+ CHUNKED_SYNTHESIS_TIMEOUT_SECONDS = 15 * 60
27
28
  DEFAULT_VOICE_NAME = "zh-CN-XiaoxiaoNeural-Female"
28
29
  NEEDS_INPUT_EXIT_CODE = 10
29
30
  SUPPORTED_SOURCES = {"pexels", "pixabay", "coverr", "local"}
@@ -72,6 +73,33 @@ def log(message: str) -> None:
72
73
  print(f"[MoneyPrinterTurbo] {message}", flush=True)
73
74
 
74
75
 
76
+ def _atomic_write_text(path: Path, text: str) -> None:
77
+ """Replace a text file atomically so an interrupted Windows write keeps the old file."""
78
+ path.parent.mkdir(parents=True, exist_ok=True)
79
+ temporary_path: Path | None = None
80
+ try:
81
+ with tempfile.NamedTemporaryFile(
82
+ mode="w",
83
+ encoding="utf-8",
84
+ dir=str(path.parent),
85
+ prefix=f".{path.name}.",
86
+ suffix=".tmp",
87
+ delete=False,
88
+ ) as handle:
89
+ temporary_path = Path(handle.name)
90
+ handle.write(text)
91
+ handle.flush()
92
+ os.fsync(handle.fileno())
93
+ os.replace(temporary_path, path)
94
+ except Exception:
95
+ if temporary_path is not None:
96
+ try:
97
+ temporary_path.unlink(missing_ok=True)
98
+ except OSError:
99
+ pass
100
+ raise
101
+
102
+
75
103
  def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
76
104
  parser = argparse.ArgumentParser(
77
105
  description="Install MoneyPrinterTurbo and generate a final video from a topic."
@@ -239,7 +267,7 @@ def apply_environment_config(config_path: Path) -> None:
239
267
  if pixabay_keys:
240
268
  text = _replace_config_value(text, "pixabay_api_keys", pixabay_keys)
241
269
  changes.append("pixabay_api_keys")
242
- config_path.write_text(text, encoding="utf-8")
270
+ _atomic_write_text(config_path, text)
243
271
  log("updated configuration fields: " + ", ".join(changes))
244
272
 
245
273
 
@@ -279,7 +307,7 @@ def reuse_existing_llm_provider(config_path: Path) -> str:
279
307
  for provider in reusable_providers:
280
308
  if _provider_is_ready(text, provider):
281
309
  text = _replace_config_value(text, "llm_provider", provider)
282
- config_path.write_text(text, encoding="utf-8")
310
+ _atomic_write_text(config_path, text)
283
311
  log(f"reusing configured LLM provider: {provider}")
284
312
  return provider
285
313
  return current_provider
@@ -325,12 +353,10 @@ def _forwarded_option_value(cli_args: list[str], option: str) -> str:
325
353
  def _azure_v2_voice(cli_args: list[str]) -> str:
326
354
  """Return the unmarked Azure voice when this invocation requests Azure V2."""
327
355
  voice = _forwarded_option_value(cli_args, "--voice-name")
328
- if "-V2-" not in voice and not voice.endswith("-V2"):
356
+ if "-v2" not in voice.casefold():
329
357
  return ""
330
- base_voice = re.sub(r"-V2(?=-|$)", "", voice, count=1).strip()
331
- return re.sub(r"-(?:Female|Male)$", "", base_voice, flags=re.IGNORECASE).strip()
332
-
333
-
358
+ base_voice = re.sub("-v2", "", voice, count=1, flags=re.IGNORECASE).strip()
359
+ return re.sub(r"-(Female|Male)$", "", base_voice, flags=re.IGNORECASE).strip()
334
360
  def _voice_rate(cli_args: list[str]) -> float:
335
361
  value = _forwarded_option_value(cli_args, "--voice-rate")
336
362
  try:
@@ -358,7 +384,7 @@ def _prepare_azure_v2_chunked_audio(
358
384
  text_file = task_dir / "azure-v2-script.txt"
359
385
  audio_file = task_dir / "azure-v2-audio.mp3"
360
386
  text_file.parent.mkdir(parents=True, exist_ok=True)
361
- text_file.write_text(text.strip(), encoding="utf-8")
387
+ _atomic_write_text(text_file, text.strip() + "\n")
362
388
  chunk_script = Path(__file__).with_name("azure_tts_chunked.py")
363
389
  command = [
364
390
  uv,
@@ -382,24 +408,55 @@ def _prepare_azure_v2_chunked_audio(
382
408
  ffmpeg_path = _toml_section_value(config_path, "app", "ffmpeg_path")
383
409
  if ffmpeg_path:
384
410
  environment["IMAGEIO_FFMPEG_EXE"] = ffmpeg_path
385
- log("synthesizing Azure Speech V2 in safe chunks before MoneyPrinterTurbo")
386
- result = subprocess.run(
387
- command,
388
- cwd=root,
389
- env=environment,
390
- stdout=subprocess.PIPE,
391
- stderr=subprocess.STDOUT,
392
- text=True,
393
- errors="replace",
394
- check=False,
395
- )
411
+ try:
412
+ result = subprocess.run(
413
+ command,
414
+ cwd=root,
415
+ env=environment,
416
+ stdout=subprocess.PIPE,
417
+ stderr=subprocess.STDOUT,
418
+ text=True,
419
+ errors="replace",
420
+ check=False,
421
+ timeout=CHUNKED_SYNTHESIS_TIMEOUT_SECONDS,
422
+ )
423
+ except subprocess.TimeoutExpired as exc:
424
+ raise SkillError(
425
+ "A síntese segmentada Azure Speech SDK V2 excedeu 15 minutos; "
426
+ "a chamada monolítica não será usada."
427
+ ) from exc
428
+ chunk_match = re.search(r"(?m)^AZURE_CHUNK_COUNT=(\d+)$", result.stdout or "")
429
+ if not chunk_match:
430
+ detail = "\n".join((result.stdout or "").splitlines()[-12:]).strip()
431
+ detail = detail.replace(speech_key, "[redacted]").replace(speech_region, "[redacted]")
432
+ raise SkillError(
433
+ "Azure Speech SDK V2 não confirmou segmentos e áudio customizado. "
434
+ + (detail or "O helper não devolveu detalhes.")
435
+ )
396
436
  if result.returncode != 0 or not audio_file.is_file() or audio_file.stat().st_size <= 0:
397
437
  detail = "\n".join((result.stdout or "").splitlines()[-12:]).strip()
438
+ detail = detail.replace(speech_key, "[redacted]").replace(speech_region, "[redacted]")
398
439
  raise SkillError(
399
440
  "Azure Speech SDK V2 falhou na síntese segmentada. "
400
441
  + (detail or "O helper não devolveu detalhes.")
401
442
  )
402
- return audio_file
443
+ chunk_count = int(chunk_match.group(1))
444
+ if chunk_count <= 0:
445
+ raise SkillError("Azure Speech SDK V2 não confirmou segmentos de áudio válidos.")
446
+ _atomic_write_text(
447
+ audio_file.with_suffix(".json"),
448
+ json.dumps(
449
+ {
450
+ "status": "completed",
451
+ "audio_file": str(audio_file.resolve()),
452
+ "chunk_count": chunk_count,
453
+ },
454
+ ensure_ascii=False,
455
+ indent=2,
456
+ ) + "\n",
457
+ )
458
+ log(f"Azure Speech V2 segmentado: {chunk_count} segmentos; áudio customizado preparado")
459
+ return audio_file.resolve()
403
460
 
404
461
 
405
462
  def missing_config(config_path: Path, cli_args: list[str]) -> tuple[str, list[str]]:
@@ -524,7 +581,7 @@ def validate_pexels_config(config_path: Path, cli_args: list[str]) -> bool:
524
581
  if valid_keys:
525
582
  if valid_keys != keys:
526
583
  text = _replace_config_value(text, "pexels_api_keys", valid_keys)
527
- config_path.write_text(text, encoding="utf-8")
584
+ _atomic_write_text(config_path, text)
528
585
  log(
529
586
  "Pexels key validation completed: "
530
587
  f"valid={len(valid_keys)}, rejected={rejected_count}, "
@@ -621,7 +678,9 @@ def generate_video(
621
678
  else ["--voice-name", DEFAULT_VOICE_NAME]
622
679
  )
623
680
  forwarded_args = list(cli_args)
624
- if not has_cli_option(forwarded_args, "--custom-audio-file"):
681
+ azure_v2_requested = bool(_azure_v2_voice(forwarded_args))
682
+ custom_audio_requested = has_cli_option(forwarded_args, "--custom-audio-file")
683
+ if azure_v2_requested and not custom_audio_requested:
625
684
  chunked_audio = _prepare_azure_v2_chunked_audio(
626
685
  root,
627
686
  config_path,
@@ -629,8 +688,20 @@ def generate_video(
629
688
  forwarded_args,
630
689
  uv,
631
690
  )
632
- if chunked_audio is not None:
633
- forwarded_args.extend(["--custom-audio-file", str(chunked_audio)])
691
+ if chunked_audio is None or not chunked_audio.is_file() or chunked_audio.stat().st_size <= 0:
692
+ raise SkillError(
693
+ "Azure Speech SDK V2 não produziu áudio segmentado; "
694
+ "a geração foi interrompida para não usar a chamada monolítica."
695
+ )
696
+ forwarded_args.extend(["--custom-audio-file", str(chunked_audio.resolve())])
697
+ elif azure_v2_requested and custom_audio_requested:
698
+ custom_audio_value = _forwarded_option_value(forwarded_args, "--custom-audio-file")
699
+ custom_audio_path = Path(custom_audio_value).expanduser()
700
+ if not custom_audio_value or not custom_audio_path.is_file() or custom_audio_path.stat().st_size <= 0:
701
+ raise SkillError(
702
+ "Azure Speech SDK V2 recebeu um áudio customizado inválido; "
703
+ "a geração foi interrompida para não usar a chamada monolítica."
704
+ )
634
705
  command = [
635
706
  uv,
636
707
  "run",
@@ -750,6 +821,18 @@ def main(argv: list[str] | None = None) -> int:
750
821
  root, args.subject, args.cli_args
751
822
  )
752
823
  except (OSError, SkillError, urllib.error.URLError, zipfile.BadZipFile) as exc:
824
+ manifest_path = result_manifest_path(root)
825
+ try:
826
+ manifest_payload = json.loads(manifest_path.read_text(encoding="utf-8")) if manifest_path.is_file() else {}
827
+ except (OSError, json.JSONDecodeError):
828
+ manifest_payload = {}
829
+ if manifest_payload.get("status") == "running":
830
+ manifest_payload.update({"status": "failed", "error": str(exc)[:1000]})
831
+ write_result_manifest(root, manifest_payload)
832
+ for output_key, manifest_key in (("TASK_DIR", "task_dir"), ("LOG_FILE", "log_file"), ("RESULT_FILE", "result_file")):
833
+ value = str(manifest_payload.get(manifest_key) or "").strip()
834
+ if value:
835
+ print(f"{output_key}={value}", file=sys.stderr)
753
836
  print(f"MPT_ERROR={exc}", file=sys.stderr)
754
837
  return 1
755
838