@danhachuel/thunderbolt 0.3.52 → 0.3.53
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 +19 -5
- package/README.md +14 -3
- package/THIRD-PARTY-NOTICES.md +4 -0
- package/app/influencers_ui.py +400 -0
- package/app/main.py +36 -6
- package/hermes_ui/api_key_tests.py +10 -0
- package/hermes_ui/influencers.py +569 -0
- package/hermes_ui/languages.py +5 -0
- package/hermes_ui/media_generation.py +75 -3
- package/hermes_ui/media_providers.py +10 -0
- package/hermes_ui/notifications.py +2 -0
- package/hermes_ui/storage.py +7 -1
- package/package.json +3 -1
- package/requirements.txt +1 -0
- package/seed/references/ai_influencers_schema.sql +69 -0
- package/seed/references/guide-supabase.md +9 -1
package/app/main.py
CHANGED
|
@@ -31,6 +31,7 @@ from app.modules.niche_finder.apify import ApifyError, DEFAULT_ACTOR_ID, abort_a
|
|
|
31
31
|
from app.modules.niche_finder.core import NicheAnalysisError, run_niche_analysis
|
|
32
32
|
from app.modules.niche_finder.data_loader import DatasetError, download_kaggle_dataset
|
|
33
33
|
from app.modules.niche_finder.summarizer import summarize_items
|
|
34
|
+
from app.influencers_ui import render_ai_influencer_characters, render_ai_influencer_content, render_ai_influencer_motion_control, render_ai_influencers_api_status
|
|
34
35
|
from hermes_ui.blueprints import create_blueprint_from_link, list_branding_files, save_generated_blueprint
|
|
35
36
|
from hermes_ui.metadata_cleaner import build_description, clean_video_metadata, list_edit_records, metadata_manifest, normalize_tags, save_edit_record, store_external_video
|
|
36
37
|
from hermes_ui.python_editor import AUDIO_EXTENSIONS, VIDEO_EXTENSIONS, PythonEditorError, change_speed, editor_manifest, extract_audio, list_edit_records as list_python_editor_records, list_generated_videos, list_scripts, list_video_files, read_script, remove_audio, replace_audio, resize_video, save_edit_record as save_python_editor_record, save_script, store_uploaded_asset, trim_video
|
|
@@ -39,13 +40,14 @@ from hermes_ui.mcp import detect_local_service, install_skill_locally, load_inte
|
|
|
39
40
|
from hermes_ui.mcp_server import server_status, start_server, stop_server
|
|
40
41
|
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
42
|
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
|
-
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
|
+
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_cards_for_pool, media_provider_catalog, media_provider_definition, new_media_card, normalize_media_card
|
|
43
44
|
from hermes_ui.music import list_music_files, materialize_suno_audio, request_suno_generation, store_music_file, store_voiceover_file
|
|
44
45
|
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
|
|
45
46
|
from hermes_ui.notifications import clear_notifications, list_notifications, mark_all_notifications_read, mark_notification_read, notification_event_catalog, notification_preferences, record_notification, reconcile_persisted_notifications, save_notification_preferences, unread_notification_count
|
|
47
|
+
from hermes_ui.influencers import BACKEND_OPTIONS, DOCUMENT_EXTENSIONS, IMAGE_EXTENSIONS, backend_name, backend_status, get_repository, test_backend
|
|
46
48
|
from hermes_ui.logs import list_logs, logs_to_rows
|
|
47
49
|
from hermes_ui.languages import LANGUAGE_CODES, VIDEO_LANGUAGE_CODES, LANGUAGE_FLAG_DATA_URIS, language_code, language_label, ui_language_menu_label, ui_text, video_language_label, video_language_options
|
|
48
|
-
from hermes_ui.api_key_tests import test_apify_credentials, test_kaggle_credentials, test_material_source_credentials, test_media_provider_card, test_nano_banana_credentials, test_postiz_credentials, test_telegram_credentials, test_tiktok_credentials, test_upload_post_credentials, test_voice_provider
|
|
50
|
+
from hermes_ui.api_key_tests import test_apify_credentials, test_influencer_database, test_kaggle_credentials, test_material_source_credentials, test_media_provider_card, test_nano_banana_credentials, test_postiz_credentials, test_telegram_credentials, test_tiktok_credentials, test_upload_post_credentials, test_voice_provider
|
|
49
51
|
from hermes_ui.tutorials import tutorial_body, tutorial_caption, tutorial_title
|
|
50
52
|
|
|
51
53
|
from hermes_ui.script_documents import list_script_documents, read_script_document, save_script_document, script_storage_path
|
|
@@ -63,6 +65,7 @@ from hermes_ui.thumbnails import (
|
|
|
63
65
|
)
|
|
64
66
|
from hermes_ui.draft_video import DRAFT_SETTING_SECTIONS, missing_content_fields, missing_setting_sections, normalise_saved_script, setting_widget_suffixes
|
|
65
67
|
from hermes_ui.creative_generation import CreativeGenerationError, generate_creative_package, generate_thumbnail_prompt, generate_title_and_keywords, generate_topic_for_channel, generate_video_keywords
|
|
68
|
+
from hermes_ui.media_generation import MediaGenerationError, generate_image_for_card, generate_video_for_card
|
|
66
69
|
from integrations.platforms import IntegrationResult, TikTokAdapter, YouTubeAdapter, fetch_channel_videos_public
|
|
67
70
|
from integrations.tiktok_public import fetch_public_tiktok_profile, normalize_tiktok_reference
|
|
68
71
|
from integrations.postiz import PostizAdapter
|
|
@@ -5383,7 +5386,7 @@ def render_settings():
|
|
|
5383
5386
|
key=f"settings_{key}",
|
|
5384
5387
|
)
|
|
5385
5388
|
|
|
5386
|
-
api_keys_tab, google_accounts_tab, material_sources_tab, voice_test_tab = render_localized_tabs(["API Keys", "Contas Google", "Fontes de Materiais", "Teste de Voz"])
|
|
5389
|
+
api_keys_tab, google_accounts_tab, material_sources_tab, ai_influencers_tab, voice_test_tab = render_localized_tabs(["API Keys", "Contas Google", "Fontes de Materiais", "AI Influencers", "Teste de Voz"])
|
|
5387
5390
|
|
|
5388
5391
|
with api_keys_tab:
|
|
5389
5392
|
with st.container(border=True):
|
|
@@ -5434,6 +5437,20 @@ def render_settings():
|
|
|
5434
5437
|
|
|
5435
5438
|
render_media_provider_cards(settings, embedded=True)
|
|
5436
5439
|
|
|
5440
|
+
with st.expander("Banco de Dados Influencers", expanded=False):
|
|
5441
|
+
st.caption("Escolha um backend para personagens e conteúdos. Supabase é o padrão remoto; SQLite mantém tudo localmente. O teste é read-only e não cria nem elimina registos.")
|
|
5442
|
+
influencer_db_backend = st.selectbox("Backend da base de dados de AI Influencers", list(BACKEND_OPTIONS), index=0 if str(settings.get("influencer_db_backend") or "Supabase") == "Supabase" else 1, key="settings_influencer_db_backend")
|
|
5443
|
+
db_cols = st.columns(2)
|
|
5444
|
+
with db_cols[0]:
|
|
5445
|
+
influencer_supabase_url = text_setting("Supabase Project URL", "influencer_supabase_url", help_text="URL do projecto, por exemplo https://project-id.supabase.co")
|
|
5446
|
+
influencer_supabase_key = text_setting("Supabase API key", "influencer_supabase_key", secret=True, help_text="Use uma chave com as permissões RLS adequadas. Nunca é colocada no GitHub ou nos logs.")
|
|
5447
|
+
influencer_supabase_bucket = text_setting("Supabase Storage bucket", "influencer_supabase_bucket", help_text="Bucket usado para imagens e documentos, por defeito ai-influencers.")
|
|
5448
|
+
with db_cols[1]:
|
|
5449
|
+
influencer_sqlite_path = text_setting("SQLite ficheiro local", "influencer_sqlite_path", help_text="Caminho absoluto ou relativo ao projecto. Por defeito: storage/state/ai_influencers.db")
|
|
5450
|
+
st.caption("SQLite usa a biblioteca standard do Python e cria o schema automaticamente ao testar ou usar o backend.")
|
|
5451
|
+
db_test_clicked = st.form_submit_button("Testar ligação do backend", use_container_width=True, key="api_test_influencer_database")
|
|
5452
|
+
st.caption("Para Supabase, aplique primeiro seed/references/ai_influencers_schema.sql no SQL Editor e configure o bucket/políticas RLS.")
|
|
5453
|
+
|
|
5437
5454
|
with st.expander("Voz, TTS e música — Azure Speech, restantes serviços e Suno", expanded=False):
|
|
5438
5455
|
st.caption("Cada serviço está separado no seu próprio cartão. Os botões de teste ficam dentro do cartão correspondente e fazem apenas diagnóstico, sem gerar áudio ou música.")
|
|
5439
5456
|
|
|
@@ -5581,6 +5598,15 @@ def render_settings():
|
|
|
5581
5598
|
widget_key="api_test_postiz",
|
|
5582
5599
|
)
|
|
5583
5600
|
|
|
5601
|
+
if db_test_clicked:
|
|
5602
|
+
test_settings = dict(settings)
|
|
5603
|
+
test_settings.update({"influencer_db_backend": influencer_db_backend, "influencer_supabase_url": influencer_supabase_url, "influencer_supabase_key": influencer_supabase_key, "influencer_supabase_bucket": influencer_supabase_bucket, "influencer_sqlite_path": influencer_sqlite_path})
|
|
5604
|
+
db_result = test_backend(test_settings)
|
|
5605
|
+
if db_result.get("ok"):
|
|
5606
|
+
st.success(db_result.get("message") or "Backend disponível.")
|
|
5607
|
+
else:
|
|
5608
|
+
st.error(db_result.get("message") or "O backend não está disponível.")
|
|
5609
|
+
|
|
5584
5610
|
save_all_settings = st.form_submit_button("Guardar configurações do Thunderbolt", type="primary")
|
|
5585
5611
|
if save_all_settings:
|
|
5586
5612
|
settings.update({
|
|
@@ -5588,6 +5614,7 @@ def render_settings():
|
|
|
5588
5614
|
"kaggle_username": kaggle_username.strip(), "kaggle_api_key": kaggle_api_key.strip(), "kaggle_kernel_slug": kaggle_kernel_slug.strip() or "thunderbolt-niche-finder",
|
|
5589
5615
|
"apify_api_token": apify_api_token.strip(), "apify_actor_id": apify_actor_id.strip() or DEFAULT_ACTOR_ID, "apify_poll_interval_seconds": int(apify_poll_interval), "apify_run_timeout_seconds": int(apify_run_timeout),
|
|
5590
5616
|
"llm_rpm_limit_enabled": bool(llm_rpm_limit_enabled), "llm_rpm_limit": int(llm_rpm_limit), "llm_rpm_window_seconds": int(llm_rpm_window_seconds),
|
|
5617
|
+
"influencer_db_backend": influencer_db_backend, "influencer_supabase_url": influencer_supabase_url.strip(), "influencer_supabase_key": influencer_supabase_key.strip(), "influencer_supabase_bucket": influencer_supabase_bucket.strip() or "ai-influencers", "influencer_sqlite_path": influencer_sqlite_path.strip() or "storage/state/ai_influencers.db",
|
|
5591
5618
|
"azure_speech_key": azure_speech_key, "azure_speech_region": azure_speech_region,
|
|
5592
5619
|
"siliconflow_tts_api_key": siliconflow_tts_api_key, "minimax_tts_api_key": minimax_tts_api_key,
|
|
5593
5620
|
"minimax_tts_base_url": minimax_tts_base_url, "minimax_tts_model_id": minimax_tts_model_id, "minimax_tts_voice_id": minimax_tts_voice_id,
|
|
@@ -5617,6 +5644,9 @@ def render_settings():
|
|
|
5617
5644
|
with material_sources_tab:
|
|
5618
5645
|
render_material_source_api_keys(settings)
|
|
5619
5646
|
|
|
5647
|
+
with ai_influencers_tab:
|
|
5648
|
+
render_ai_influencers_api_status(settings)
|
|
5649
|
+
|
|
5620
5650
|
with voice_test_tab:
|
|
5621
5651
|
st.subheader("Teste de Voz")
|
|
5622
5652
|
st.caption("Este painel é exclusivamente um preview. O áudio gerado não altera vídeos, tarefas, Blueprints ou a configuração da pipeline.")
|
|
@@ -6340,9 +6370,9 @@ def main():
|
|
|
6340
6370
|
"Editor Python": render_python_editor,
|
|
6341
6371
|
"Download Mídia": render_media_download,
|
|
6342
6372
|
"AI Influencers": lambda: render_edit_placeholder("AI Influencers", "Seleccione uma das abas AI Influencers no menu expansível."),
|
|
6343
|
-
"Personagens": lambda:
|
|
6344
|
-
"Geração de Conteúdo IA": lambda:
|
|
6345
|
-
"Motion Control":
|
|
6373
|
+
"Personagens": lambda: render_ai_influencer_characters(read_json("settings.json", {})),
|
|
6374
|
+
"Geração de Conteúdo IA": lambda: render_ai_influencer_content(read_json("settings.json", {})),
|
|
6375
|
+
"Motion Control": render_ai_influencer_motion_control,
|
|
6346
6376
|
"UGC Products": lambda: render_edit_placeholder("UGC Products", ""),
|
|
6347
6377
|
"Redes Sociais": lambda: render_edit_placeholder("Redes Sociais", "Área reservada para a futura funcionalidade de redes sociais."),
|
|
6348
6378
|
"Analista Growth Youtube": lambda: render_edit_placeholder("Analista Growth Youtube", ""),
|
|
@@ -272,6 +272,15 @@ def test_material_source_credentials(provider: str, api_key: str) -> dict[str, A
|
|
|
272
272
|
return _unsupported("Este provider de materiais não expõe um endpoint de diagnóstico seguro no cartão actual.")
|
|
273
273
|
|
|
274
274
|
|
|
275
|
+
def test_influencer_database(settings: Mapping[str, Any]) -> dict[str, Any]:
|
|
276
|
+
"""Verify the configured AI Influencers backend without generating or deleting data."""
|
|
277
|
+
try:
|
|
278
|
+
from hermes_ui.influencers import test_backend
|
|
279
|
+
return test_backend(settings)
|
|
280
|
+
except Exception:
|
|
281
|
+
return _result("error", "Não foi possível verificar o backend AI Influencers.")
|
|
282
|
+
|
|
283
|
+
|
|
275
284
|
def test_voice_provider(provider: str, settings: dict[str, Any]) -> dict[str, Any]:
|
|
276
285
|
"""Dispatch a non-generating check for one provider in the voice/music group."""
|
|
277
286
|
provider = str(provider or "").strip().lower()
|
|
@@ -297,6 +306,7 @@ __all__ = [
|
|
|
297
306
|
"test_azure_speech_credentials",
|
|
298
307
|
"test_elevenlabs_credentials",
|
|
299
308
|
"test_kaggle_credentials",
|
|
309
|
+
"test_influencer_database",
|
|
300
310
|
"test_material_source_credentials",
|
|
301
311
|
"test_minimax_credentials",
|
|
302
312
|
"test_nano_banana_credentials",
|