@danhachuel/thunderbolt 0.3.46 → 0.3.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANUAL-INSTALACAO.md +6 -6
- package/README.md +3 -1
- package/app/main.py +17 -14
- package/hermes_ui/languages.py +14 -14
- package/hermes_ui/llm_providers.py +53 -20
- package/hermes_ui/provider_routing.py +23 -10
- package/package.json +1 -1
package/MANUAL-INSTALACAO.md
CHANGED
|
@@ -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.
|
|
5
|
+
> **Versão deste manual:** 0.3.47
|
|
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)
|
|
@@ -100,13 +100,13 @@ Execute:
|
|
|
100
100
|
Windows PowerShell ou MobaXterm:
|
|
101
101
|
|
|
102
102
|
```powershell
|
|
103
|
-
npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.
|
|
103
|
+
npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.47 install
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
Linux/macOS:
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
|
-
npx --yes --prefer-online @danhachuel/thunderbolt@0.3.
|
|
109
|
+
npx --yes --prefer-online @danhachuel/thunderbolt@0.3.47 install
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
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.
|
|
@@ -114,7 +114,7 @@ A instalação normal é **segura para actualizações**: preserva `storage`, Bl
|
|
|
114
114
|
Se quiser apagar absolutamente tudo de forma intencional, use o comando destrutivo separado:
|
|
115
115
|
|
|
116
116
|
```powershell
|
|
117
|
-
npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.
|
|
117
|
+
npx.cmd --yes --prefer-online @danhachuel/thunderbolt@0.3.47 install --purge-data
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
O parâmetro `--purge-data` apaga Blueprints, Brandings, configurações, storage e artefactos locais. Não o use numa actualização normal.
|
|
@@ -359,7 +359,7 @@ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
|
359
359
|
|
|
360
360
|
### 4.1 Pools de LLM, imagem e vídeo
|
|
361
361
|
|
|
362
|
-
Em **Configuração API > API Keys**, o expander **LLM — providers e modelos** continua a guardar cartões independentes para os providers textuais. Pode manter várias API keys do mesmo provider em cartões distintos; a geração textual percorre o
|
|
362
|
+
Em **Configuração API > API Keys**, o expander **LLM — providers e modelos** continua a guardar cartões independentes para os providers textuais. O campo **Prioridade** substitui o antigo checkbox **LLM principal**: o cartão com valor **1** é tentado primeiro, depois o **2**, o **3** e assim sucessivamente. Pode manter várias API keys do mesmo provider em cartões distintos; a geração textual percorre o pool por essa ordem e tenta a prioridade seguinte apenas em quota, timeout, erro de transporte ou falha transitória. A chave interna de cartão activo permanece apenas como espelho de compatibilidade das instalações antigas.
|
|
363
363
|
|
|
364
364
|
O bloco **Limite LLM NVIDIA NIM** permite ligar **Activar limitador NVIDIA NIM — 40 RPM**. O valor padrão é 40 pedidos numa janela de 60 segundos. O contador é persistido localmente por cartão/chave e aplica-se à criação manual, aos workers e às automações. A opção vem desligada para não alterar instalações existentes; ligue-a quando o endpoint activo for NVIDIA NIM e a sua conta tiver esse limite.
|
|
365
365
|
|
|
@@ -522,7 +522,7 @@ Ao abrir a página, o Thunderbolt não prepara dados públicos, não descarrega
|
|
|
522
522
|
|
|
523
523
|
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.
|
|
524
524
|
|
|
525
|
-
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.
|
|
525
|
+
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.47 install`; o instalador detecta e reutiliza o que já estiver válido.
|
|
526
526
|
|
|
527
527
|
### Niche Finder Apify
|
|
528
528
|
|
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ No topo da área principal da aplicação existe o menu nativo de idioma no padr
|
|
|
69
69
|
|
|
70
70
|
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.
|
|
71
71
|
|
|
72
|
-
## Navegação da UI 0.3.
|
|
72
|
+
## Navegação da UI 0.3.47
|
|
73
73
|
|
|
74
74
|
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**, **Redes Sociais**, **Tutorial Meta** e **Tutorial Supabase**, nessa ordem. **Niche Finder** é expansível e contém **Niche Finder Kaggle** e **Niche Finder Apify**. **Configurações** é expansível e contém **Canais Youtube**, **Blueprints Youtube**, **MCP**, **Contas Google**, **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.
|
|
75
75
|
|
|
@@ -85,6 +85,8 @@ Em **Configuração API > API Keys**, a subaba **Fontes de materiais** segue o p
|
|
|
85
85
|
|
|
86
86
|
A subaba **Serviços e modelos** mantém as credenciais de providers e serviços que não são fontes de materiais. A chave `gemini_image_api_key` da Nano Banana continua separada de `gemini_api_key` do LLM textual. `INNERTUBE_API_KEY` permanece exclusivamente em **Configurações > Contas Google**, no bloco de configuração global fora dos cartões, e não é duplicada em API Keys.
|
|
87
87
|
|
|
88
|
+
Nos cartões de **LLM — providers e modelos**, o campo **Prioridade** define a ordem de tentativa do pool textual. O valor **1** é usado primeiro; em quota, timeout, erro de transporte ou falha transitória, o router tenta a prioridade **2**, depois **3** e assim sucessivamente. O checkbox antigo **LLM principal** deixou de existir. A chave interna de cartão activo continua apenas como espelho de compatibilidade para instalações antigas.
|
|
89
|
+
|
|
88
90
|
O expander **Imagem e Video** reúne cartões independentes para **Nano Banana**, **Pollinations.ai**, **Agnes AI**, **Hugging Face Inference API**, **Cloudflare Workers AI**, **InferencePort Proxy**, **阿里云 (Alibaba Cloud Model Studio)**, **KIE AI** e **FAL AI**. Cada cartão permite configurar API key/token quando necessário, modelo, Base URL, activar o provider, escolher participação no **Pool Imagem** e/ou **Pool Vídeo**, definir prioridade e executar **Testar Chamada API**. Os parâmetros técnicos de composição, como **Image Size** e **Aspect Ratio**, não são apresentados nem editáveis nos cartões: ficam como defaults internos e são acrescentados automaticamente ao prompt da geração de imagem e/ou vídeo. O InferencePort usa por defeito `http://localhost:8080/v1` e não exige chave; o Cloudflare requer Account ID; os restantes providers devem ser preenchidos de acordo com a conta e endpoint disponibilizados pelo serviço.
|
|
89
91
|
|
|
90
92
|
O router mantém três pools independentes: **LLM textual**, **imagem** e **vídeo**. O failover só passa ao cartão seguinte em quota, timeout, erro de transporte ou HTTP transitório; erros de credencial, endpoint/modelo inexistente ou payload inválido ficam registados e não são mascarados por um provider diferente. O pool de vídeo externo é opcional: quando desligado, o worker continua a usar o motor local MoneyPrinterTurbo; quando ligado, usa apenas os cartões marcados para Pool Vídeo.
|
package/app/main.py
CHANGED
|
@@ -38,7 +38,7 @@ from hermes_ui.cuts import CutsError, download_direct_video_url, generate_clips,
|
|
|
38
38
|
from hermes_ui.mcp import detect_local_service, install_skill_locally, load_integrations, load_server_config, read_packaged_skill, save_server_config, update_integration
|
|
39
39
|
from hermes_ui.mcp_server import server_status, start_server, stop_server
|
|
40
40
|
from hermes_ui.material_sources import apply_material_source_cards_to_settings, ensure_material_source_cards, material_source_catalog, material_source_definition, new_material_card, normalize_material_card, selected_material_source
|
|
41
|
-
from hermes_ui.llm_providers import LLM_CARDS_KEY,
|
|
41
|
+
from hermes_ui.llm_providers import LLM_CARDS_KEY, LLM_PROVIDER_CATALOG, apply_llm_cards_to_settings, ensure_llm_provider_cards, new_llm_card, normalize_llm_card, provider_definition, test_llm_provider_card, stamp_test_result
|
|
42
42
|
from hermes_ui.media_providers import MEDIA_CARDS_KEY, MEDIA_IMAGE_ACTIVE_CARD_KEY, MEDIA_VIDEO_ACTIVE_CARD_KEY, apply_media_provider_cards_to_settings, ensure_media_provider_cards, media_provider_catalog, media_provider_definition, new_media_card, normalize_media_card
|
|
43
43
|
from hermes_ui.music import list_music_files, materialize_suno_audio, request_suno_generation, store_music_file
|
|
44
44
|
from hermes_ui.media_downloader import AUDIO_FORMATS, VIDEO_CONTAINERS, VIDEO_QUALITY_OPTIONS, MediaDownloadError, build_download_options, clear_media_download_history, dependency_status, download_media, list_media_downloads, media_download_file
|
|
@@ -5040,11 +5040,14 @@ def _render_llm_card(settings: dict[str, Any], cards: list[dict[str, Any]], inde
|
|
|
5040
5040
|
with status_cols[0]:
|
|
5041
5041
|
enabled = st.checkbox("Provider activo", value=bool(card.get("enabled", True)), key=f"llm_card_{card_id}_enabled")
|
|
5042
5042
|
with status_cols[1]:
|
|
5043
|
-
|
|
5044
|
-
"
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5043
|
+
priority = st.number_input(
|
|
5044
|
+
"Prioridade",
|
|
5045
|
+
min_value=1,
|
|
5046
|
+
max_value=999,
|
|
5047
|
+
value=max(1, int(card.get("priority", index + 1))),
|
|
5048
|
+
step=1,
|
|
5049
|
+
help="Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, segue para 2, 3 e assim por diante.",
|
|
5050
|
+
key=f"llm_card_{card_id}_priority",
|
|
5048
5051
|
)
|
|
5049
5052
|
with status_cols[2]:
|
|
5050
5053
|
telegram_llm = st.checkbox(
|
|
@@ -5060,29 +5063,28 @@ def _render_llm_card(settings: dict[str, Any], cards: list[dict[str, Any]], inde
|
|
|
5060
5063
|
remove_clicked = st.form_submit_button("Remover cartão", use_container_width=True, key=f"llm_card_{card_id}_remove")
|
|
5061
5064
|
|
|
5062
5065
|
edited = dict(card)
|
|
5063
|
-
edited.update({"api_key": str(api_key or "").strip(), "model": str(model or "").strip(), "base_url": str(base_url or "").strip(), "enabled": bool(enabled), "telegram_llm": bool(telegram_llm), **extra_values})
|
|
5066
|
+
edited.update({"api_key": str(api_key or "").strip(), "model": str(model or "").strip(), "base_url": str(base_url or "").strip(), "enabled": bool(enabled), "priority": max(1, int(priority)), "telegram_llm": bool(telegram_llm), **extra_values})
|
|
5064
5067
|
cards[index] = edited
|
|
5065
5068
|
if test_clicked:
|
|
5066
5069
|
test_result = test_llm_provider_card(edited)
|
|
5067
5070
|
edited["test_result"] = stamp_test_result(test_result)
|
|
5068
|
-
_persist_llm_cards(settings, cards
|
|
5071
|
+
_persist_llm_cards(settings, cards)
|
|
5069
5072
|
elif refresh_clicked:
|
|
5070
5073
|
try:
|
|
5071
5074
|
from integrations.openai_model_discovery import fetch_openai_compatible_models
|
|
5072
5075
|
discovered = fetch_openai_compatible_models(edited.get("api_key", ""), edited.get("base_url", ""))
|
|
5073
5076
|
st.session_state[f"llm_model_catalog_{card_id}"] = discovered
|
|
5074
|
-
_persist_llm_cards(settings, cards
|
|
5077
|
+
_persist_llm_cards(settings, cards)
|
|
5075
5078
|
st.success(f"{len(discovered)} modelo(s) disponíveis neste endpoint.")
|
|
5076
5079
|
except Exception:
|
|
5077
5080
|
st.error("Não foi possível consultar os modelos deste endpoint.")
|
|
5078
5081
|
elif save_clicked:
|
|
5079
|
-
|
|
5080
|
-
_persist_llm_cards(settings, cards, active_id)
|
|
5082
|
+
_persist_llm_cards(settings, cards)
|
|
5081
5083
|
st.success("Cartão LLM guardado.")
|
|
5082
5084
|
st.rerun()
|
|
5083
5085
|
elif remove_clicked:
|
|
5084
5086
|
remaining = [item for item in cards if str(item.get("id")) != card_id]
|
|
5085
|
-
_persist_llm_cards(settings, remaining
|
|
5087
|
+
_persist_llm_cards(settings, remaining)
|
|
5086
5088
|
st.success("Cartão LLM removido.")
|
|
5087
5089
|
st.rerun()
|
|
5088
5090
|
|
|
@@ -5102,7 +5104,7 @@ def render_llm_provider_cards(settings: dict[str, Any], *, embedded: bool = Fals
|
|
|
5102
5104
|
settings.update(migrated)
|
|
5103
5105
|
write_json("settings.json", settings)
|
|
5104
5106
|
with st.expander("LLM — providers e modelos", expanded=False):
|
|
5105
|
-
st.caption("Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys;
|
|
5107
|
+
st.caption("Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; a prioridade 1 é tentada primeiro e o router segue para as prioridades seguintes em falhas elegíveis.")
|
|
5106
5108
|
for index in range(len(cards)):
|
|
5107
5109
|
_render_llm_card(settings, cards, index, embedded=embedded)
|
|
5108
5110
|
st.divider()
|
|
@@ -5121,8 +5123,9 @@ def render_llm_provider_cards(settings: dict[str, Any], *, embedded: bool = Fals
|
|
|
5121
5123
|
)
|
|
5122
5124
|
if add_provider_clicked:
|
|
5123
5125
|
new_card = new_llm_card(provider_to_add, card_id=f"llm-{provider_to_add}-{uuid.uuid4().hex[:8]}")
|
|
5126
|
+
new_card["priority"] = max((int(item.get("priority", index + 1)) for index, item in enumerate(cards)), default=0) + 1
|
|
5124
5127
|
cards.append(new_card)
|
|
5125
|
-
_persist_llm_cards(settings, cards
|
|
5128
|
+
_persist_llm_cards(settings, cards)
|
|
5126
5129
|
st.rerun()
|
|
5127
5130
|
|
|
5128
5131
|
|
package/hermes_ui/languages.py
CHANGED
|
@@ -205,16 +205,16 @@ for _language_code, _llm_extra_values in _LLM_EXTRA_PROVIDER_TRANSLATIONS.items(
|
|
|
205
205
|
UI_TRANSLATIONS[_language_code].update(_llm_extra_values)
|
|
206
206
|
|
|
207
207
|
_LLM_CONTROL_TRANSLATIONS = {
|
|
208
|
-
"pt": {"
|
|
209
|
-
"en": {"
|
|
210
|
-
"zh": {"
|
|
211
|
-
"de": {"
|
|
212
|
-
"vi": {"
|
|
213
|
-
"tr": {"
|
|
214
|
-
"ru": {"
|
|
215
|
-
"es": {"
|
|
216
|
-
"id": {"
|
|
217
|
-
"it": {"
|
|
208
|
+
"pt": {"Prioridade": "Prioridade", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "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.": "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.", "Account Id": "Account ID", "Gateway Id": "Gateway ID", "Api Version": "Versão da API", "Endpoint gerido pelo provider: ": "Endpoint gerido pelo provider: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.", "ID do modelo usado pelo endpoint Chat Completions.": "ID do modelo usado pelo endpoint Chat Completions.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo."},
|
|
209
|
+
"en": {"Prioridade": "Priority", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Use this card as the primary provider for topics, scripts, titles and keywords.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Use this card exclusively for Telegram notification routing. Only one card can be selected.", "Account Id": "Account ID", "Gateway Id": "Gateway ID", "Api Version": "API version", "Endpoint gerido pelo provider: ": "Provider-managed endpoint: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "This field appears only for providers with a configurable OpenAI-compatible endpoint.", "ID do modelo usado pelo endpoint Chat Completions.": "Model ID used by the Chat Completions endpoint.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Configure each provider in an independent card. You can repeat a provider for multiple API keys; the active card is used for content generation."},
|
|
210
|
+
"zh": {"Prioridade": "优先级", "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": "账户 ID", "Gateway Id": "网关 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 端点使用的模型 ID。", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "在独立卡片中配置每个提供商。可为同一提供商添加多个 API 密钥;内容生成使用活动卡片。"},
|
|
211
|
+
"de": {"Prioridade": "Priorität", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Diese Karte als primären Anbieter für Themen, Skripte, Titel und Keywords verwenden.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Diese Karte ausschließlich für die Telegram-Benachrichtigungsweiterleitung verwenden. Nur eine Karte kann ausgewählt werden.", "Account Id": "Konto-ID", "Gateway Id": "Gateway-ID", "Api Version": "API-Version", "Endpoint gerido pelo provider: ": "Vom Anbieter verwalteter Endpunkt: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Dieses Feld erscheint nur bei Anbietern mit konfigurierbarem OpenAI-kompatiblem Endpunkt.", "ID do modelo usado pelo endpoint Chat Completions.": "Vom Chat-Completions-Endpunkt verwendete Modell-ID.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Jeden Anbieter in einer eigenen Karte konfigurieren. Anbieter können für mehrere API-Schlüssel wiederholt werden; die aktive Karte wird für die Inhaltserstellung verwendet."},
|
|
212
|
+
"vi": {"Prioridade": "Ưu tiên", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Dùng thẻ này làm nhà cung cấp chính cho chủ đề, kịch bản, tiêu đề và từ khóa.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Chỉ dùng thẻ này để định tuyến thông báo Telegram. Chỉ được chọn một thẻ.", "Account Id": "ID tài khoản", "Gateway Id": "ID cổng", "Api Version": "Phiên bản API", "Endpoint gerido pelo provider: ": "Endpoint do nhà cung cấp quản lý: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Chỉ hiển thị trường này với nhà cung cấp có endpoint OpenAI tương thích tùy chỉnh.", "ID do modelo usado pelo endpoint Chat Completions.": "ID mô hình được endpoint Chat Completions sử dụng.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Định cấu hình từng nhà cung cấp trong thẻ riêng. Có thể lặp lại nhà cung cấp cho nhiều khóa API; thẻ đang hoạt động được dùng để tạo nội dung."},
|
|
213
|
+
"tr": {"Prioridade": "Öncelik", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Konu, senaryo, başlık ve anahtar kelimeler için bu kartı birincil sağlayıcı olarak kullanın.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Bu kartı yalnızca Telegram bildirim yönlendirmesi için kullanın. Yalnızca bir kart seçilebilir.", "Account Id": "Hesap Kimliği", "Gateway Id": "Ağ Geçidi Kimliği", "Api Version": "API sürümü", "Endpoint gerido pelo provider: ": "Sağlayıcı tarafından yönetilen uç nokta: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Bu alan yalnızca yapılandırılabilir OpenAI uyumlu uç noktası olan sağlayıcılarda görünür.", "ID do modelo usado pelo endpoint Chat Completions.": "Chat Completions uç noktası tarafından kullanılan model kimliği.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Her sağlayıcıyı bağımsız bir kartta yapılandırın. Bir sağlayıcı birden fazla API anahtarı için tekrarlanabilir; etkin kart içerik üretiminde kullanılır."},
|
|
214
|
+
"ru": {"Prioridade": "Приоритет", "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": "ID аккаунта", "Gateway Id": "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.": "ID модели, используемый эндпоинтом Chat Completions.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Настройте каждого провайдера в отдельной карточке. Провайдера можно повторить для нескольких API-ключей; активная карточка используется для генерации контента."},
|
|
215
|
+
"es": {"Prioridade": "Prioridad", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Usar esta tarjeta como proveedor principal para temas, guiones, títulos y palabras clave.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Usar esta tarjeta exclusivamente para enrutar notificaciones de Telegram. Solo se puede seleccionar una tarjeta.", "Account Id": "ID de cuenta", "Gateway Id": "ID de puerta de enlace", "Api Version": "Versión de API", "Endpoint gerido pelo provider: ": "Endpoint gestionado por el proveedor: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Este campo solo aparece para proveedores con un endpoint OpenAI compatible configurable.", "ID do modelo usado pelo endpoint Chat Completions.": "ID del modelo usado por el endpoint Chat Completions.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Configura cada proveedor en una tarjeta independiente. Puedes repetir un proveedor para varias claves API; la tarjeta activa se usa para generar contenido."},
|
|
216
|
+
"id": {"Prioridade": "Prioritas", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Gunakan kartu ini sebagai penyedia utama untuk topik, skrip, judul, dan kata kunci.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Gunakan kartu ini khusus untuk perutean notifikasi Telegram. Hanya satu kartu yang dapat dipilih.", "Account Id": "ID akun", "Gateway Id": "ID gateway", "Api Version": "Versi API", "Endpoint gerido pelo provider: ": "Endpoint yang dikelola penyedia: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Bidang ini hanya tampil untuk penyedia dengan endpoint OpenAI-compatible yang dapat dikonfigurasi.", "ID do modelo usado pelo endpoint Chat Completions.": "ID model yang digunakan endpoint Chat Completions.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Konfigurasikan setiap penyedia dalam kartu terpisah. Penyedia dapat diulang untuk beberapa kunci API; kartu aktif digunakan untuk pembuatan konten."},
|
|
217
|
+
"it": {"Prioridade": "Priorità", "Ordem de tentativa do pool LLM: 1 é o primeiro; em falha elegível, seguem-se as prioridades seguintes.": "Usa questa scheda come provider principale per argomenti, copioni, titoli e parole chiave.", "Usar este cartão exclusivamente para o roteamento de notificações Telegram. Apenas um cartão pode ficar seleccionado.": "Usa questa scheda esclusivamente per il routing delle notifiche Telegram. È possibile selezionare una sola scheda.", "Account Id": "ID account", "Gateway Id": "ID gateway", "Api Version": "Versione API", "Endpoint gerido pelo provider: ": "Endpoint gestito dal provider: ", "Endpoint OpenAI-compatible deste provider; só aparece quando é configurável.": "Il campo appare solo per provider con endpoint OpenAI compatibile configurabile.", "ID do modelo usado pelo endpoint Chat Completions.": "ID del modello usato dall'endpoint Chat Completions.", "Configure cada provider num cartão independente. Pode repetir o mesmo provider para manter várias API keys; o cartão activo é usado pela geração de conteúdo.": "Configura ogni provider in una scheda indipendente. Puoi ripetere un provider per più chiavi API; la scheda attiva viene usata per generare contenuti."},
|
|
218
218
|
}
|
|
219
219
|
for _language_code, _llm_control_values in _LLM_CONTROL_TRANSLATIONS.items():
|
|
220
220
|
UI_TRANSLATIONS[_language_code].update(_llm_control_values)
|
|
@@ -1357,19 +1357,19 @@ for _language_code, _api_test_values in _API_TEST_TRANSLATIONS.items():
|
|
|
1357
1357
|
_NEW_UI_TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
1358
1358
|
"pl": {
|
|
1359
1359
|
"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",
|
|
1360
|
-
"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.", "
|
|
1360
|
+
"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",
|
|
1361
1361
|
},
|
|
1362
1362
|
"ga": {
|
|
1363
1363
|
"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",
|
|
1364
|
-
"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.", "
|
|
1364
|
+
"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",
|
|
1365
1365
|
},
|
|
1366
1366
|
"ar": {
|
|
1367
1367
|
"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": "فاتح",
|
|
1368
|
-
"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.", "
|
|
1368
|
+
"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 والموسيقى",
|
|
1369
1369
|
},
|
|
1370
1370
|
"he": {
|
|
1371
1371
|
"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": "בהיר",
|
|
1372
|
-
"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.", "
|
|
1372
|
+
"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 ומוזיקה",
|
|
1373
1373
|
},
|
|
1374
1374
|
}
|
|
1375
1375
|
|
|
@@ -22,6 +22,7 @@ LLM_ACTIVE_CARD_KEY = "llm_active_card_id"
|
|
|
22
22
|
LLM_TELEGRAM_CARD_KEY = "llm_telegram_card_id"
|
|
23
23
|
DEFAULT_LLM_PROVIDER = "openai"
|
|
24
24
|
DEFAULT_LLM_CARD_ID = "llm-openai-default"
|
|
25
|
+
DEFAULT_LLM_PRIORITY = 1
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
@dataclass(frozen=True, slots=True)
|
|
@@ -160,7 +161,7 @@ def _legacy_value(settings: Mapping[str, Any], provider: str, suffix: str) -> st
|
|
|
160
161
|
return str(settings.get(f"{prefix}_{suffix}") or "").strip()
|
|
161
162
|
|
|
162
163
|
|
|
163
|
-
def _legacy_card(settings: Mapping[str, Any], provider: str, card_id: str) -> dict[str, Any]:
|
|
164
|
+
def _legacy_card(settings: Mapping[str, Any], provider: str, card_id: str, *, priority: int = DEFAULT_LLM_PRIORITY) -> dict[str, Any]:
|
|
164
165
|
definition = provider_definition(provider)
|
|
165
166
|
code = normalize_provider_code(provider)
|
|
166
167
|
base_url = _legacy_value(settings, code, "base_url") or definition.default_base_url
|
|
@@ -179,6 +180,7 @@ def _legacy_card(settings: Mapping[str, Any], provider: str, card_id: str) -> di
|
|
|
179
180
|
"model": model,
|
|
180
181
|
"base_url": base_url,
|
|
181
182
|
"enabled": True,
|
|
183
|
+
"priority": max(1, int(priority)),
|
|
182
184
|
"telegram_llm": False,
|
|
183
185
|
**extra,
|
|
184
186
|
}
|
|
@@ -194,6 +196,7 @@ def new_llm_card(provider: Any, *, card_id: str | None = None) -> dict[str, Any]
|
|
|
194
196
|
"model": "",
|
|
195
197
|
"base_url": definition.default_base_url,
|
|
196
198
|
"enabled": True,
|
|
199
|
+
"priority": DEFAULT_LLM_PRIORITY,
|
|
197
200
|
"telegram_llm": False,
|
|
198
201
|
**{field: "" for field in definition.extra_fields},
|
|
199
202
|
}
|
|
@@ -212,6 +215,13 @@ def _clean_test_result(value: Any) -> dict[str, Any]:
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
|
|
218
|
+
def _normalise_priority(value: Any, fallback: int = DEFAULT_LLM_PRIORITY) -> int:
|
|
219
|
+
try:
|
|
220
|
+
return max(1, int(value))
|
|
221
|
+
except (TypeError, ValueError):
|
|
222
|
+
return max(1, int(fallback or DEFAULT_LLM_PRIORITY))
|
|
223
|
+
|
|
224
|
+
|
|
215
225
|
def normalize_llm_card(card: Any, index: int = 0) -> dict[str, Any]:
|
|
216
226
|
source = dict(card) if isinstance(card, Mapping) else {}
|
|
217
227
|
code = normalize_provider_code(source.get("provider") or source.get("provider_code"))
|
|
@@ -225,6 +235,7 @@ def normalize_llm_card(card: Any, index: int = 0) -> dict[str, Any]:
|
|
|
225
235
|
"model": str(source.get("model") or source.get("model_name") or "").strip(),
|
|
226
236
|
"base_url": str(source.get("base_url") or "").strip() or definition.default_base_url,
|
|
227
237
|
"enabled": bool(source.get("enabled", True)),
|
|
238
|
+
"priority": _normalise_priority(source.get("priority", index + 1), index + 1),
|
|
228
239
|
"telegram_llm": bool(source.get("telegram_llm", source.get("llm_telegram", False))),
|
|
229
240
|
}
|
|
230
241
|
for field in definition.extra_fields:
|
|
@@ -251,9 +262,15 @@ def ensure_llm_provider_cards(settings: Mapping[str, Any]) -> tuple[dict[str, An
|
|
|
251
262
|
cards = [normalize_llm_card(item, index) for index, item in enumerate(raw_cards)] if isinstance(raw_cards, list) else []
|
|
252
263
|
changed = not isinstance(raw_cards, list)
|
|
253
264
|
|
|
265
|
+
selected_provider = normalize_provider_code(result.get("llm_provider") or DEFAULT_LLM_PROVIDER)
|
|
266
|
+
legacy_selected_provider = selected_provider != DEFAULT_LLM_PROVIDER and _card_has_legacy_configuration(result, selected_provider)
|
|
267
|
+
active_id = str(result.get(LLM_ACTIVE_CARD_KEY) or "").strip()
|
|
268
|
+
|
|
254
269
|
# O primeiro card OpenAI/NVIDIA NIM é estrutural e nunca é removido pela migração.
|
|
270
|
+
# Quando uma configuração legada apontava para outro provider, esse provider
|
|
271
|
+
# recebe prioridade 1 e o cartão estrutural fica logo a seguir.
|
|
255
272
|
if not any(card.get("provider") == DEFAULT_LLM_PROVIDER for card in cards):
|
|
256
|
-
cards.insert(0, _legacy_card(result, DEFAULT_LLM_PROVIDER, DEFAULT_LLM_CARD_ID))
|
|
273
|
+
cards.insert(0, _legacy_card(result, DEFAULT_LLM_PROVIDER, DEFAULT_LLM_CARD_ID, priority=2 if legacy_selected_provider else 1))
|
|
257
274
|
changed = True
|
|
258
275
|
elif cards[0].get("provider") != DEFAULT_LLM_PROVIDER:
|
|
259
276
|
openai_card = next(card for card in cards if card.get("provider") == DEFAULT_LLM_PROVIDER)
|
|
@@ -261,26 +278,36 @@ def ensure_llm_provider_cards(settings: Mapping[str, Any]) -> tuple[dict[str, An
|
|
|
261
278
|
cards.insert(0, openai_card)
|
|
262
279
|
changed = True
|
|
263
280
|
|
|
264
|
-
selected_provider = normalize_provider_code(result.get("llm_provider") or DEFAULT_LLM_PROVIDER)
|
|
265
281
|
if not str(result.get("llm_provider") or "").strip():
|
|
266
282
|
result["llm_provider"] = DEFAULT_LLM_PROVIDER
|
|
267
283
|
changed = True
|
|
268
284
|
# A migração preserva uma configuração explícita antiga que ainda não tinha card.
|
|
269
|
-
if
|
|
285
|
+
if legacy_selected_provider:
|
|
270
286
|
if not any(card.get("provider") == selected_provider for card in cards):
|
|
271
|
-
cards.append(_legacy_card(result, selected_provider, f"llm-{selected_provider}-legacy"))
|
|
287
|
+
cards.append(_legacy_card(result, selected_provider, f"llm-{selected_provider}-legacy", priority=1))
|
|
272
288
|
changed = True
|
|
273
289
|
|
|
290
|
+
# Instalações anteriores só tinham um cartão activo. Transformamos essa
|
|
291
|
+
# escolha na prioridade 1 uma única vez, sem apagar a preferência do utilizador.
|
|
292
|
+
if isinstance(raw_cards, list) and not any(isinstance(item, Mapping) and "priority" in item for item in raw_cards):
|
|
293
|
+
preferred_id = active_id or next((str(card.get("id")) for card in cards if card.get("provider") == selected_provider), "")
|
|
294
|
+
if preferred_id:
|
|
295
|
+
for card in cards:
|
|
296
|
+
old_priority = int(card.get("priority", DEFAULT_LLM_PRIORITY))
|
|
297
|
+
card["priority"] = 1 if str(card.get("id")) == preferred_id else max(2, old_priority)
|
|
298
|
+
changed = True
|
|
299
|
+
|
|
300
|
+
cards = _ordered_cards(cards)
|
|
274
301
|
serialized_before = raw_cards if isinstance(raw_cards, list) else None
|
|
275
302
|
if serialized_before != cards:
|
|
276
303
|
changed = True
|
|
277
304
|
result[LLM_CARDS_KEY] = cards
|
|
278
305
|
|
|
279
|
-
active_id = str(result.get(LLM_ACTIVE_CARD_KEY) or "").strip()
|
|
280
306
|
ids = {str(card.get("id")) for card in cards}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
307
|
+
ordered = _ordered_cards(cards)
|
|
308
|
+
first_enabled = next((card for card in ordered if card.get("enabled", True)), ordered[0])
|
|
309
|
+
if active_id != str(first_enabled["id"]):
|
|
310
|
+
result[LLM_ACTIVE_CARD_KEY] = str(first_enabled["id"])
|
|
284
311
|
changed = True
|
|
285
312
|
if not any(card.get("telegram_llm") for card in cards):
|
|
286
313
|
if result.get(LLM_TELEGRAM_CARD_KEY):
|
|
@@ -294,19 +321,23 @@ def ensure_llm_provider_cards(settings: Mapping[str, Any]) -> tuple[dict[str, An
|
|
|
294
321
|
return result, changed
|
|
295
322
|
|
|
296
323
|
|
|
324
|
+
def _ordered_cards(cards: list[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
|
325
|
+
indexed = [(index, normalize_llm_card(card, index)) for index, card in enumerate(cards)]
|
|
326
|
+
indexed.sort(key=lambda pair: (pair[1].get("priority", pair[0] + 1), pair[0]))
|
|
327
|
+
return [card for _index, card in indexed]
|
|
328
|
+
|
|
329
|
+
|
|
297
330
|
def llm_cards(settings: Mapping[str, Any]) -> list[dict[str, Any]]:
|
|
298
331
|
migrated, _ = ensure_llm_provider_cards(settings)
|
|
299
|
-
|
|
332
|
+
cards = migrated.get(LLM_CARDS_KEY, [])
|
|
333
|
+
return _ordered_cards(cards) if isinstance(cards, list) else []
|
|
300
334
|
|
|
301
335
|
|
|
302
336
|
def active_llm_card(settings: Mapping[str, Any]) -> dict[str, Any]:
|
|
303
337
|
migrated, _ = ensure_llm_provider_cards(settings)
|
|
304
338
|
cards = migrated.get(LLM_CARDS_KEY, [])
|
|
305
|
-
|
|
306
|
-
for card in
|
|
307
|
-
if str(card.get("id")) == active_id and card.get("enabled", True):
|
|
308
|
-
return dict(card)
|
|
309
|
-
for card in cards:
|
|
339
|
+
ordered = _ordered_cards(cards) if isinstance(cards, list) else []
|
|
340
|
+
for card in ordered:
|
|
310
341
|
if card.get("enabled", True):
|
|
311
342
|
return dict(card)
|
|
312
343
|
return new_llm_card(DEFAULT_LLM_PROVIDER, card_id=DEFAULT_LLM_CARD_ID)
|
|
@@ -322,7 +353,7 @@ def telegram_llm_card(settings: Mapping[str, Any]) -> dict[str, Any] | None:
|
|
|
322
353
|
def apply_llm_cards_to_settings(
|
|
323
354
|
settings: Mapping[str, Any], cards: list[Mapping[str, Any]], active_card_id: str = ""
|
|
324
355
|
) -> dict[str, Any]:
|
|
325
|
-
"""Persist cards and mirror
|
|
356
|
+
"""Persist priority-ordered cards and mirror priority 1 to the legacy runtime contract."""
|
|
326
357
|
result = dict(settings)
|
|
327
358
|
normalized = [normalize_llm_card(item, index) for index, item in enumerate(cards)]
|
|
328
359
|
if not normalized or not any(card.get("provider") == DEFAULT_LLM_PROVIDER for card in normalized):
|
|
@@ -334,10 +365,12 @@ def apply_llm_cards_to_settings(
|
|
|
334
365
|
for card in normalized:
|
|
335
366
|
card["telegram_llm"] = bool(telegram and card["id"] == telegram["id"])
|
|
336
367
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
368
|
+
if active_card_id and not any(isinstance(item, Mapping) and "priority" in item for item in cards):
|
|
369
|
+
for card in normalized:
|
|
370
|
+
old_priority = int(card.get("priority", DEFAULT_LLM_PRIORITY))
|
|
371
|
+
card["priority"] = 1 if str(card.get("id")) == str(active_card_id) else max(2, old_priority)
|
|
372
|
+
ordered = _ordered_cards(normalized)
|
|
373
|
+
active = next((card for card in ordered if card.get("enabled", True)), ordered[0])
|
|
341
374
|
result[LLM_CARDS_KEY] = normalized
|
|
342
375
|
result[LLM_ACTIVE_CARD_KEY] = active["id"]
|
|
343
376
|
result[LLM_TELEGRAM_CARD_KEY] = telegram["id"] if telegram else ""
|
|
@@ -276,17 +276,18 @@ def classify_response(response: Any) -> None:
|
|
|
276
276
|
|
|
277
277
|
|
|
278
278
|
def enabled_cards(settings: Mapping[str, Any], pool: str) -> list[dict[str, Any]]:
|
|
279
|
-
"""Return cards in priority order;
|
|
279
|
+
"""Return cards in deterministic priority order; media pools keep active-card preference."""
|
|
280
280
|
if pool == POOL_LLM:
|
|
281
281
|
migrated, _ = ensure_llm_provider_cards(settings)
|
|
282
282
|
raw_cards = migrated.get("llm_provider_cards", [])
|
|
283
283
|
cards = [normalize_llm_card(item, index) for index, item in enumerate(raw_cards)] if isinstance(raw_cards, list) else []
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
284
|
+
enabled = [(index, card) for index, card in enumerate(cards) if bool(card.get("enabled", True))]
|
|
285
|
+
enabled.sort(key=lambda pair: (int(pair[1].get("priority", 1)), pair[0]))
|
|
286
|
+
return [card for _index, card in enabled]
|
|
287
|
+
raw_cards = settings.get("media_provider_cards", [])
|
|
288
|
+
cards = [dict(item) for item in raw_cards if isinstance(item, Mapping)] if isinstance(raw_cards, list) else []
|
|
289
|
+
active_key = "media_image_active_card_id" if pool == POOL_IMAGE else "media_video_active_card_id"
|
|
290
|
+
active_id = str(settings.get(active_key) or "")
|
|
290
291
|
enabled = [card for card in cards if bool(card.get("enabled", True))]
|
|
291
292
|
if active_id:
|
|
292
293
|
enabled.sort(key=lambda item: 0 if str(item.get("id")) == active_id else 1)
|
|
@@ -363,16 +364,28 @@ def route_json_request(
|
|
|
363
364
|
max_attempts: int | None = None,
|
|
364
365
|
cooldown_seconds: float | None = None,
|
|
365
366
|
) -> RoutedResponse:
|
|
366
|
-
"""Execute a JSON request over eligible cards with
|
|
367
|
+
"""Execute a JSON request over eligible cards with classified priority failover."""
|
|
367
368
|
if pool not in POOLS:
|
|
368
369
|
raise ProviderRoutingError(f"Pool de providers inválido: {pool}")
|
|
369
370
|
candidates = [dict(item) for item in (cards if cards is not None else enabled_cards(settings, pool))]
|
|
371
|
+
if pool == POOL_LLM:
|
|
372
|
+
candidates = [
|
|
373
|
+
card
|
|
374
|
+
for _index, card in sorted(
|
|
375
|
+
enumerate(candidates),
|
|
376
|
+
key=lambda pair: (int(pair[1].get("priority", pair[0] + 1)), pair[0]),
|
|
377
|
+
)
|
|
378
|
+
]
|
|
370
379
|
if not candidates:
|
|
371
380
|
raise ProviderRoutingError(f"Não existem providers activos no pool {pool}.")
|
|
372
381
|
try:
|
|
373
|
-
|
|
382
|
+
if pool == POOL_LLM and max_attempts is None:
|
|
383
|
+
maximum = len(candidates)
|
|
384
|
+
else:
|
|
385
|
+
configured_max_attempts = max_attempts if max_attempts is not None else settings.get("provider_max_attempts")
|
|
386
|
+
maximum = max(1, min(len(candidates), int(configured_max_attempts or DEFAULT_MAX_ATTEMPTS)))
|
|
374
387
|
except (TypeError, ValueError):
|
|
375
|
-
maximum = min(len(candidates), DEFAULT_MAX_ATTEMPTS)
|
|
388
|
+
maximum = len(candidates) if pool == POOL_LLM else min(len(candidates), DEFAULT_MAX_ATTEMPTS)
|
|
376
389
|
cooldown = float(cooldown_seconds if cooldown_seconds is not None else settings.get("provider_cooldown_seconds", DEFAULT_COOLDOWN_SECONDS))
|
|
377
390
|
attempts: list[dict[str, Any]] = []
|
|
378
391
|
for card in candidates[:maximum]:
|
package/package.json
CHANGED