mega-brain-ai 1.1.0
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.
Potentially problematic release.
This version of mega-brain-ai might be problematic. Click here for more details.
- package/.claude/CLAUDE.md +155 -0
- package/.claude/commands/agents.md +161 -0
- package/.claude/commands/ask.md +117 -0
- package/.claude/commands/benchmark.md +224 -0
- package/.claude/commands/chat.md +343 -0
- package/.claude/commands/compare.md +116 -0
- package/.claude/commands/conclave.md +194 -0
- package/.claude/commands/config.md +133 -0
- package/.claude/commands/council.md +194 -0
- package/.claude/commands/create-agent.md +452 -0
- package/.claude/commands/debate.md +157 -0
- package/.claude/commands/documentation/create-architecture-documentation.md +175 -0
- package/.claude/commands/dossiers.md +180 -0
- package/.claude/commands/evolve.md +223 -0
- package/.claude/commands/extract-dna.md +170 -0
- package/.claude/commands/extract-knowledge.md +507 -0
- package/.claude/commands/inbox.md +296 -0
- package/.claude/commands/ingest-empresa.md +191 -0
- package/.claude/commands/ingest.md +182 -0
- package/.claude/commands/jarvis-briefing.md +67 -0
- package/.claude/commands/jarvis-control.md +169 -0
- package/.claude/commands/jarvis-full.md +181 -0
- package/.claude/commands/jarvis.md +212 -0
- package/.claude/commands/ler-drive.md +212 -0
- package/.claude/commands/log.md +158 -0
- package/.claude/commands/loop.md +133 -0
- package/.claude/commands/loops.md +73 -0
- package/.claude/commands/mission-autopilot.md +538 -0
- package/.claude/commands/mission.md +353 -0
- package/.claude/commands/process-inbox.md +148 -0
- package/.claude/commands/process-jarvis.md +3036 -0
- package/.claude/commands/process-video.md +131 -0
- package/.claude/commands/rag-search.md +78 -0
- package/.claude/commands/resume.md +33 -0
- package/.claude/commands/save.md +38 -0
- package/.claude/commands/scan-inbox.md +125 -0
- package/.claude/commands/setup.md +99 -0
- package/.claude/commands/system-digest.md +243 -0
- package/.claude/commands/verify.md +182 -0
- package/.claude/commands/view-dna.md +169 -0
- package/.claude/hooks/agent_doctor.py +433 -0
- package/.claude/hooks/agent_memory_persister.py +203 -0
- package/.claude/hooks/auto_formatter.py +158 -0
- package/.claude/hooks/checkpoint_writer.py +244 -0
- package/.claude/hooks/claude_md_guard.py +146 -0
- package/.claude/hooks/creation_validator.py +357 -0
- package/.claude/hooks/enforce_dual_location.py +501 -0
- package/.claude/hooks/enforce_plan_mode.py +220 -0
- package/.claude/hooks/inbox_age_alert.py +367 -0
- package/.claude/hooks/jarvis_briefing.py +506 -0
- package/.claude/hooks/ledger_updater.py +301 -0
- package/.claude/hooks/memory_hints_injector.py +251 -0
- package/.claude/hooks/memory_updater.py +202 -0
- package/.claude/hooks/multi_agent_hook.py +464 -0
- package/.claude/hooks/notification_system.py +120 -0
- package/.claude/hooks/pattern_analyzer.py +526 -0
- package/.claude/hooks/pending_tracker.py +188 -0
- package/.claude/hooks/post_batch_cascading.py +1740 -0
- package/.claude/hooks/post_output_validator.py +358 -0
- package/.claude/hooks/post_tool_use.py +120 -0
- package/.claude/hooks/post_write_validator.py +200 -0
- package/.claude/hooks/quality_watchdog.py +394 -0
- package/.claude/hooks/ralph_wiggum.py +277 -0
- package/.claude/hooks/session-source-sync.py +218 -0
- package/.claude/hooks/session_autosave_v2.py +1135 -0
- package/.claude/hooks/session_end.py +203 -0
- package/.claude/hooks/session_start.py +939 -0
- package/.claude/hooks/skill_indexer.py +48 -0
- package/.claude/hooks/skill_router.py +358 -0
- package/.claude/hooks/stop_hook_completeness.py +178 -0
- package/.claude/hooks/subagent_tracker.py +163 -0
- package/.claude/hooks/token_checkpoint.py +584 -0
- package/.claude/hooks/user_prompt_submit.py +125 -0
- package/.claude/rules/ANTHROPIC-STANDARDS.md +384 -0
- package/.claude/rules/CLAUDE-LITE.md +201 -0
- package/.claude/rules/RULE-GROUP-1.md +320 -0
- package/.claude/rules/RULE-GROUP-2.md +307 -0
- package/.claude/rules/RULE-GROUP-3.md +248 -0
- package/.claude/rules/RULE-GROUP-4.md +427 -0
- package/.claude/rules/RULE-GROUP-5.md +388 -0
- package/.claude/rules/RULE-GROUP-6.md +387 -0
- package/.claude/rules/logging.md +53 -0
- package/.claude/rules/mcp-governance.md +128 -0
- package/.claude/rules/pipeline.md +60 -0
- package/.claude/rules/state-management.md +93 -0
- package/.claude/scripts/apply-tags.py +77 -0
- package/.claude/scripts/batch-extract-transcriptions.py +132 -0
- package/.claude/scripts/build-complete-index.py +250 -0
- package/.claude/scripts/build-planilha-index.py +170 -0
- package/.claude/scripts/complete-tag-matching.py +250 -0
- package/.claude/scripts/deduplicate-inbox.py +139 -0
- package/.claude/scripts/docx-xml-extractor.py +141 -0
- package/.claude/scripts/extract-docx-text.py +58 -0
- package/.claude/scripts/extract-single-transcription.py +74 -0
- package/.claude/scripts/extract_docx_from_gdrive.py +77 -0
- package/.claude/scripts/organized-downloader.py +246 -0
- package/.claude/scripts/planilha-tagger.py +187 -0
- package/.claude/scripts/revert-tags.py +70 -0
- package/.claude/scripts/source-sync.py +265 -0
- package/.claude/scripts/tag-inbox-files.py +276 -0
- package/.claude/scripts/tag-inbox-v2.py +253 -0
- package/.claude/scripts/test-extraction.py +35 -0
- package/.claude/scripts/test-full-extraction.py +74 -0
- package/.claude/skills/00-SKILL-CREATOR/SKILL.md +186 -0
- package/.claude/skills/01-SKILL-DOCS-MEGABRAIN/SKILL.md +251 -0
- package/.claude/skills/02-SKILL-PYTHON-MEGABRAIN/SKILL.md +323 -0
- package/.claude/skills/03-SKILL-AGENT-CREATION/SKILL.md +374 -0
- package/.claude/skills/04-SKILL-KNOWLEDGE-EXTRACTION/SKILL.md +318 -0
- package/.claude/skills/05-SKILL-PIPELINE-JARVIS/SKILL.md +430 -0
- package/.claude/skills/06-SKILL-BRAINSTORMING/SKILL.md +72 -0
- package/.claude/skills/07-SKILL-DISPATCHING-PARALLEL-AGENTS/SKILL.md +193 -0
- package/.claude/skills/08-SKILL-EXECUTING-PLANS/SKILL.md +114 -0
- package/.claude/skills/09-SKILL-WRITING-PLANS/SKILL.md +184 -0
- package/.claude/skills/10-SKILL-VERIFICATION-BEFORE-COMPLETION/SKILL.md +130 -0
- package/.claude/skills/11-SKILL-USING-SUPERPOWERS/SKILL.md +105 -0
- package/.claude/skills/DETECTION-PROTOCOL.md +217 -0
- package/.claude/skills/README.md +240 -0
- package/.claude/skills/SKILL-REGISTRY.md +284 -0
- package/.claude/skills/SKILL-SUGGESTIONS.md +114 -0
- package/.claude/skills/_TEMPLATES/SKILL-WRITER-GUIDE.md +385 -0
- package/.claude/skills/chronicler/SKILL.md +146 -0
- package/.claude/skills/chronicler/chronicler_core.py +468 -0
- package/.claude/skills/code-review/SKILL.md +160 -0
- package/.claude/skills/council/SKILL.md +210 -0
- package/.claude/skills/executor/SKILL.md +161 -0
- package/.claude/skills/fase-2-5-tagging/SKILL.md +182 -0
- package/.claude/skills/feature-dev/SKILL.md +154 -0
- package/.claude/skills/finance-agent/SKILL.md +137 -0
- package/.claude/skills/frontend-design/SKILL.md +165 -0
- package/.claude/skills/gdrive-transcription-downloader/SKILL.md +249 -0
- package/.claude/skills/gemini-fallback/SKILL.md +67 -0
- package/.claude/skills/gemini-fallback/gemini_fetch.py +0 -0
- package/.claude/skills/gha/SKILL.md +96 -0
- package/.claude/skills/gha/gha_diagnostic.py +227 -0
- package/.claude/skills/github-workflow/SKILL.md +190 -0
- package/.claude/skills/hookify/SKILL.md +134 -0
- package/.claude/skills/hybrid-source-reading/SKILL.md +265 -0
- package/.claude/skills/jarvis/SKILL.md +546 -0
- package/.claude/skills/jarvis-briefing/SKILL.md +340 -0
- package/.claude/skills/ler-planilha/SKILL.md +281 -0
- package/.claude/skills/plugin-dev/SKILL.md +176 -0
- package/.claude/skills/pr-review-toolkit/SKILL.md +178 -0
- package/.claude/skills/resume/SKILL.md +61 -0
- package/.claude/skills/save/SKILL.md +87 -0
- package/.claude/skills/skill-writer/SKILL.md +153 -0
- package/.claude/skills/skill-writer/examples.md +191 -0
- package/.claude/skills/skill-writer/troubleshooting.md +205 -0
- package/.claude/skills/smart-download-tagger/SKILL.md +148 -0
- package/.claude/skills/source-sync/SKILL.md +240 -0
- package/.claude/skills/sync-docs/SKILL.md +193 -0
- package/.claude/skills/sync-docs/config.json +37 -0
- package/.claude/skills/sync-docs/gdrive_sync.py +358 -0
- package/.claude/skills/sync-docs/reauth.py +71 -0
- package/.claude/skills/talent-agent/SKILL.md +183 -0
- package/.claude/skills/verify/SKILL.md +154 -0
- package/.claude/skills/verify/verify_runner.py +0 -0
- package/.claude/skills/verify-6-levels/SKILL.md +234 -0
- package/.claude/templates/BATCH-LOG-TEMPLATE.md +221 -0
- package/.claudeignore +9 -0
- package/.gitattributes +4 -0
- package/.github/layer1-allowlist.txt +80 -0
- package/.github/layer2-manifest.txt +40 -0
- package/.gitignore +219 -0
- package/README.md +1210 -0
- package/agents/_templates/INDEX.md +741 -0
- package/agents/_templates/TEMPLATE-AGENT-MD-ULTRA-ROBUSTO-V3.md +2399 -0
- package/agents/boardroom/CHECKLIST-MASTER.md +281 -0
- package/agents/boardroom/INTEGRATION-GUIDE.md +406 -0
- package/agents/boardroom/README.md +238 -0
- package/agents/boardroom/config/BOARDROOM-CONFIG.md +186 -0
- package/agents/boardroom/config/TTS-INTEGRATION.md +258 -0
- package/agents/boardroom/config/VOICE-PROFILES.md +624 -0
- package/agents/boardroom/config/voice_mapping.json +128 -0
- package/agents/boardroom/scripts/audio_generator.py +375 -0
- package/agents/boardroom/scripts/audio_generator_edge.py +353 -0
- package/agents/boardroom/scripts/jarvis_boardroom_hook.py +415 -0
- package/agents/boardroom/scripts/notebooklm_generator.py +578 -0
- package/agents/boardroom/templates/EPISODE-TEMPLATE.md +367 -0
- package/agents/boardroom/templates/scene-templates/SCENE-AGENT-DEBATE.md +252 -0
- package/agents/boardroom/templates/scene-templates/SCENE-COUNCIL.md +270 -0
- package/agents/boardroom/templates/scene-templates/SCENE-DNA-CONSULTATION.md +126 -0
- package/agents/boardroom/templates/scene-templates/SCENE-QUESTION.md +174 -0
- package/agents/boardroom/workflows/WORKFLOW-AUDIO-GENERATION.md +421 -0
- package/agents/constitution/BASE-CONSTITUTION.md +254 -0
- package/agents/council/CRITIC.md +197 -0
- package/agents/council/DEVILS-ADVOCATE.md +274 -0
- package/agents/council/SYNTHESIZER.md +293 -0
- package/agents/council/advogado-do-diabo/AGENT.md +489 -0
- package/agents/council/advogado-do-diabo/SOUL.md +100 -0
- package/agents/council/critico-metodologico/AGENT.md +670 -0
- package/agents/council/critico-metodologico/SOUL.md +107 -0
- package/agents/council/sintetizador/AGENT.md +558 -0
- package/agents/council/sintetizador/SOUL.md +94 -0
- package/agents/persons/_example/AGENT-EXAMPLE.md +42 -0
- package/agents/persons/_example/DNA-EXAMPLE.yaml +61 -0
- package/agents/protocols/AGENT-COGNITION-PROTOCOL.md +779 -0
- package/agents/protocols/AGENT-INTEGRITY-PROTOCOL.md +692 -0
- package/agents/protocols/BATCH-VISUAL-PROTOCOL.md +841 -0
- package/agents/protocols/DNA-CONFIG-TEMPLATE.yaml +181 -0
- package/agents/protocols/DNA-EXTRACTION-PROTOCOL.md +370 -0
- package/agents/protocols/EPISTEMIC-PROTOCOL.md +333 -0
- package/agents/protocols/LOG-STRUCTURE-PROTOCOL.md +65 -0
- package/agents/protocols/MEMORY-PROTOCOL.md +567 -0
- package/agents/protocols/NARRATIVE-SYNTHESIS-PROTOCOL.md +278 -0
- package/agents/protocols/PHASE-4-VERIFICATION-CHECKPOINT.md +146 -0
- package/agents/protocols/SOUL-TEMPLATE.md +416 -0
- package/agents/protocols/TEMPLATE-EVOLUTION-PROTOCOL.md +544 -0
- package/agents/protocols/VISUAL-DIFF-PROTOCOL.md +159 -0
- package/agents/sua-empresa/README.md +44 -0
- package/agents/sua-empresa/_example/jds/EXAMPLE-JD.md +42 -0
- package/agents/sua-empresa/_example/org/EXAMPLE-ORG.md +32 -0
- package/agents/sua-empresa/_example/roles/EXAMPLE-ROLE.md +38 -0
- package/bin/cli.js +2 -0
- package/bin/lib/ascii-art.js +234 -0
- package/bin/lib/installer.js +402 -0
- package/bin/lib/setup-wizard.js +95 -0
- package/bin/lib/validate-email.js +109 -0
- package/bin/mega-brain.js +97 -0
- package/bin/push.js +342 -0
- package/bin/templates/env.example +38 -0
- package/inbox/.gitkeep +0 -0
- package/integrations/README.md +46 -0
- package/integrations/mcps/MCP-REGISTRY.md +56 -0
- package/integrations/mcps/excalidraw/CONFIG.md +56 -0
- package/integrations/mcps/gdrive/CONFIG.md +38 -0
- package/knowledge/dna/.gitkeep +0 -0
- package/knowledge/dossiers/persons/.gitkeep +0 -0
- package/knowledge/dossiers/persons/DOSSIER-EXAMPLE.md +49 -0
- package/knowledge/dossiers/system/.gitkeep +0 -0
- package/knowledge/dossiers/themes/.gitkeep +0 -0
- package/knowledge/playbooks/.gitkeep +0 -0
- package/knowledge/playbooks/PLAYBOOK-EXAMPLE.md +50 -0
- package/knowledge/sources/.gitkeep +0 -0
- package/logs/.gitkeep +0 -0
- package/package.json +128 -0
- package/processing/canonical/.gitkeep +0 -0
- package/processing/chunks/.gitkeep +0 -0
- package/processing/insights/.gitkeep +0 -0
- package/processing/narratives/.gitkeep +0 -0
- package/reference/CONSELHO.md +337 -0
- package/reference/CONTEXT7_README.md +28 -0
- package/reference/JARVIS-LOGGING-PROTOCOL.md +380 -0
- package/reference/QUICK-START.md +197 -0
- package/reference/README-RALPH-CASCATEAMENTO.md +207 -0
- package/reference/TEMPLATE-MASTER.md +727 -0
- package/reference/prds/prd-jarvis-mega-brain-v3.md +1305 -0
- package/reference/templates/phase5/IMPLEMENTATION-GUIDE.md +355 -0
- package/reference/templates/phase5/MOGA-BRAIN-PHASE5-TEMPLATES.md +1284 -0
- package/reference/templates/phase5/README.md +165 -0
- package/reference/workflow-claude-code-boris-cherny-continuous-claude.md +2232 -0
- package/system/database/001_moneyclub_buyers.sql +160 -0
- package/system/database/002_premium_token.sql +97 -0
- package/system/database/apply-migration.mjs +129 -0
- package/system/docs/MEGA-BRAIN-DEMO-COMPLETA.md +1226 -0
- package/system/docs/MEGA-BRAIN-MANIFESTO-COMPLETO.md +1054 -0
- package/system/docs/MOGA-BRAIN-EXPLICACAO-COMPLETA.md +791 -0
- package/system/docs/STRATEGIC-INTEGRATION-GUIDE.md +725 -0
- package/system/docs/architecture/01-system-context.md +136 -0
- package/system/docs/architecture/02-components.md +225 -0
- package/system/docs/architecture/03-data-flow.md +235 -0
- package/system/docs/architecture/04-integrations.md +283 -0
- package/system/docs/architecture/README.md +71 -0
- package/system/docs/architecture/diagrams/component-diagram.mmd +50 -0
- package/system/docs/architecture/diagrams/data-flow.mmd +39 -0
- package/system/docs/architecture/diagrams/system-overview.mmd +68 -0
- package/system/protocols/AGENT-AUTHORITY.md +217 -0
- package/system/protocols/CONSTITUICAO-BASE.md +115 -0
- package/system/protocols/CONSTITUTION.md +231 -0
- package/system/protocols/GOVERNANCE-MAP.md +123 -0
- package/system/protocols/HOOK-SECURITY-THREAT-MODEL.md +152 -0
- package/system/protocols/ORQUESTRACAO-PROTOCOL.md +215 -0
- package/system/protocols/_archive/CHUNKING-PROTOCOL.md +207 -0
- package/system/protocols/_archive/ENTITY-RESOLUTION-PROTOCOL.md +269 -0
- package/system/protocols/_archive/INSIGHT-EXTRACTION-PROTOCOL.md +257 -0
- package/system/protocols/_archive/NARRATIVE-SYNTHESIS-PROTOCOL.md +290 -0
- package/system/protocols/agents/AGENT-INTERACTION.md +315 -0
- package/system/protocols/agents/CORTEX-PROTOCOL.md +520 -0
- package/system/protocols/agents/EPISTEMIC-PROTOCOL.md +465 -0
- package/system/protocols/agents/MEMORY-PROTOCOL.md +366 -0
- package/system/protocols/agents/WAR-ROOM.md +355 -0
- package/system/protocols/company/COMPANY-DOCUMENT-PROTOCOL.md +793 -0
- package/system/protocols/company/COMPANY-ENRICHMENT-PROTOCOL.md +679 -0
- package/system/protocols/conclave/CONCLAVE-LOG-TEMPLATE-v2.md +309 -0
- package/system/protocols/conclave/CONCLAVE-PROTOCOL.md +518 -0
- package/system/protocols/conclave/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
- package/system/protocols/conclave/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
- package/system/protocols/conclave/DEBATE-PROTOCOL.md +323 -0
- package/system/protocols/council/COUNCIL-LOG-TEMPLATE-v2.md +309 -0
- package/system/protocols/council/COUNCIL-PROTOCOL.md +518 -0
- package/system/protocols/council/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
- package/system/protocols/council/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
- package/system/protocols/council/DEBATE-PROTOCOL.md +323 -0
- package/system/protocols/dna/DNA-EXTRACTION-PROTOCOL.md +1214 -0
- package/system/protocols/dna/ENRICHMENT-PROTOCOL.md +408 -0
- package/system/protocols/dna/REASONING-MODEL-PROTOCOL.md +331 -0
- package/system/protocols/pipeline/DOSSIER-COMPILATION-PROTOCOL.md +790 -0
- package/system/protocols/pipeline/NARRATIVE-METABOLISM-PROTOCOL.md +292 -0
- package/system/protocols/pipeline/PIPELINE-JARVIS-v2.1.md +606 -0
- package/system/protocols/pipeline/PROMPT-1.1-CHUNKING.md +154 -0
- package/system/protocols/pipeline/PROMPT-1.2-ENTITY-RESOLUTION.md +186 -0
- package/system/protocols/pipeline/PROMPT-2.1-DNA-TAGS-INCREMENT.md +208 -0
- package/system/protocols/pipeline/PROMPT-2.1-INSIGHT-EXTRACTION.md +191 -0
- package/system/protocols/pipeline/PROMPT-3.1-NARRATIVE-SYNTHESIS.md +331 -0
- package/system/protocols/pipeline/SOURCES-COMPILATION-PROTOCOL.md +340 -0
- package/system/protocols/system/AUTO-LOG-PROTOCOL.md +369 -0
- package/system/protocols/system/CHECKPOINT-ENFORCEMENT.md +176 -0
- package/system/protocols/system/ENFORCEMENT.md +435 -0
- package/system/protocols/system/LOG-TEMPLATES.md +1068 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Voice IDs configurados com vozes públicas do ElevenLabs",
|
|
3
|
+
"_instructions": "Para alterar: elevenlabs.io/voice-library → escolha voz → copie voice_id",
|
|
4
|
+
"_api_key_note": "ELEVENLABS_API_KEY deve ser configurada como variável de ambiente",
|
|
5
|
+
|
|
6
|
+
"NARRATOR": {
|
|
7
|
+
"voice_id": "pNInz6obpgDQGcFmaJgB",
|
|
8
|
+
"description": "Voz grave, calma, sussurrada - Narrador principal (Adam)",
|
|
9
|
+
"settings": {
|
|
10
|
+
"stability": 0.7,
|
|
11
|
+
"similarity_boost": 0.8,
|
|
12
|
+
"style": 0.3
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
"CITADOR": {
|
|
17
|
+
"voice_id": "ErXwobaYiN019PkySvjV",
|
|
18
|
+
"description": "Voz neutra, sem emoção - Citações de fonte (Antoni)",
|
|
19
|
+
"settings": {
|
|
20
|
+
"stability": 0.9,
|
|
21
|
+
"similarity_boost": 0.9,
|
|
22
|
+
"style": 0.0
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
"HORMOZI": {
|
|
27
|
+
"voice_id": "VR6AewLTigWG4xSOukaG",
|
|
28
|
+
"description": "Voz masculina confiante, rápida - Alex Hormozi (Arnold)",
|
|
29
|
+
"language": "en",
|
|
30
|
+
"settings": {
|
|
31
|
+
"stability": 0.5,
|
|
32
|
+
"similarity_boost": 0.75,
|
|
33
|
+
"style": 0.6
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
"COLE_GORDON": {
|
|
38
|
+
"voice_id": "TxGEqnHWrfWFTfGW9XjX",
|
|
39
|
+
"description": "Voz masculina grave, controlada - Cole Gordon (Josh)",
|
|
40
|
+
"language": "en",
|
|
41
|
+
"settings": {
|
|
42
|
+
"stability": 0.8,
|
|
43
|
+
"similarity_boost": 0.8,
|
|
44
|
+
"style": 0.2
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
"BRUNSON": {
|
|
49
|
+
"voice_id": "yoZ06aMxZJJ28mfd3POQ",
|
|
50
|
+
"description": "Voz masculina energética - Russell Brunson (Sam)",
|
|
51
|
+
"language": "en",
|
|
52
|
+
"settings": {
|
|
53
|
+
"stability": 0.4,
|
|
54
|
+
"similarity_boost": 0.7,
|
|
55
|
+
"style": 0.8
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
"CRO": {
|
|
60
|
+
"voice_id": "N2lVS1w4EtoT3dr4eOWO",
|
|
61
|
+
"description": "Voz assertiva, impaciente - Chief Revenue Officer (Callum)",
|
|
62
|
+
"settings": {
|
|
63
|
+
"stability": 0.5,
|
|
64
|
+
"similarity_boost": 0.7,
|
|
65
|
+
"style": 0.5
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
"CFO": {
|
|
70
|
+
"voice_id": "pNInz6obpgDQGcFmaJgB",
|
|
71
|
+
"description": "Voz grave, seca - Chief Financial Officer (Adam)",
|
|
72
|
+
"settings": {
|
|
73
|
+
"stability": 0.8,
|
|
74
|
+
"similarity_boost": 0.8,
|
|
75
|
+
"style": 0.2
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
"CMO": {
|
|
80
|
+
"voice_id": "IKne3meq5aSn9XLyUdCD",
|
|
81
|
+
"description": "Voz articulada - Chief Marketing Officer (Charlie)",
|
|
82
|
+
"settings": {
|
|
83
|
+
"stability": 0.6,
|
|
84
|
+
"similarity_boost": 0.75,
|
|
85
|
+
"style": 0.4
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
"COO": {
|
|
90
|
+
"voice_id": "ODq5zmih8GrVes37Dizd",
|
|
91
|
+
"description": "Voz firme, pragmática - Chief Operating Officer (Patrick)",
|
|
92
|
+
"settings": {
|
|
93
|
+
"stability": 0.7,
|
|
94
|
+
"similarity_boost": 0.75,
|
|
95
|
+
"style": 0.3
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
"METHODOLOGICAL-CRITIC": {
|
|
100
|
+
"voice_id": "XB0fDUnXU5powFXDhCwa",
|
|
101
|
+
"description": "Voz inquisitiva - Council Critic (Charlotte)",
|
|
102
|
+
"settings": {
|
|
103
|
+
"stability": 0.6,
|
|
104
|
+
"similarity_boost": 0.75,
|
|
105
|
+
"style": 0.4
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
"DEVILS-ADVOCATE": {
|
|
110
|
+
"voice_id": "g5CIjZEefAph4nQFvHAz",
|
|
111
|
+
"description": "Voz provocadora - Council Advocate (Ethan)",
|
|
112
|
+
"settings": {
|
|
113
|
+
"stability": 0.5,
|
|
114
|
+
"similarity_boost": 0.7,
|
|
115
|
+
"style": 0.6
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
"SYNTHESIZER": {
|
|
120
|
+
"voice_id": "21m00Tcm4TlvDq8ikWAM",
|
|
121
|
+
"description": "Voz serena, ponderada - Council Synthesizer (Rachel)",
|
|
122
|
+
"settings": {
|
|
123
|
+
"stability": 0.8,
|
|
124
|
+
"similarity_boost": 0.8,
|
|
125
|
+
"style": 0.2
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
BOARDROOM WARFARE - Audio Generator
|
|
4
|
+
Gera arquivos de áudio a partir de scripts .md
|
|
5
|
+
|
|
6
|
+
Uso:
|
|
7
|
+
python audio_generator.py <script.md> [--output <output.mp3>]
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
import json
|
|
13
|
+
import argparse
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from dotenv import load_dotenv
|
|
16
|
+
|
|
17
|
+
# Carregar .env do diretorio raiz do projeto
|
|
18
|
+
_env_path = Path(__file__).parent.parent.parent / ".env"
|
|
19
|
+
if _env_path.exists():
|
|
20
|
+
load_dotenv(_env_path)
|
|
21
|
+
print(f"[OK] .env carregado de: {_env_path}")
|
|
22
|
+
from typing import List, Dict, Tuple
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
|
|
26
|
+
# Imports condicionais para TTS
|
|
27
|
+
try:
|
|
28
|
+
from elevenlabs import ElevenLabs
|
|
29
|
+
ELEVENLABS_AVAILABLE = True
|
|
30
|
+
except ImportError:
|
|
31
|
+
ELEVENLABS_AVAILABLE = False
|
|
32
|
+
print("[!] ElevenLabs nao instalado. Use: pip install elevenlabs")
|
|
33
|
+
|
|
34
|
+
elevenlabs_client = None
|
|
35
|
+
|
|
36
|
+
# Configurar ffmpeg/ffprobe ANTES de importar pydub (Windows requirement)
|
|
37
|
+
_ffmpeg_bin = Path(r"C:\ffmpeg\bin")
|
|
38
|
+
_ffmpeg_path = _ffmpeg_bin / "ffmpeg.exe"
|
|
39
|
+
_ffprobe_path = _ffmpeg_bin / "ffprobe.exe"
|
|
40
|
+
|
|
41
|
+
if _ffmpeg_path.exists() and _ffprobe_path.exists():
|
|
42
|
+
# Metodo 1: Environment variables (Windows primary method)
|
|
43
|
+
os.environ["FFMPEG_BINARY"] = str(_ffmpeg_path)
|
|
44
|
+
os.environ["FFPROBE_BINARY"] = str(_ffprobe_path)
|
|
45
|
+
# Metodo 2: Add to PATH
|
|
46
|
+
os.environ["PATH"] = str(_ffmpeg_bin) + os.pathsep + os.environ.get("PATH", "")
|
|
47
|
+
print(f"[OK] ffmpeg configurado: {_ffmpeg_path}")
|
|
48
|
+
print(f"[OK] ffprobe configurado: {_ffprobe_path}")
|
|
49
|
+
else:
|
|
50
|
+
print("[!] ffmpeg/ffprobe nao encontrados no caminho esperado")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
from pydub import AudioSegment
|
|
54
|
+
PYDUB_AVAILABLE = True
|
|
55
|
+
# Metodo 3: Class attributes (backup method)
|
|
56
|
+
AudioSegment.converter = str(_ffmpeg_path)
|
|
57
|
+
AudioSegment.ffprobe = str(_ffprobe_path)
|
|
58
|
+
except ImportError:
|
|
59
|
+
PYDUB_AVAILABLE = False
|
|
60
|
+
print("[!] pydub nao instalado. Use: pip install pydub")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ═══════════════════════════════════════════════════════════════
|
|
64
|
+
# CONFIGURAÇÃO
|
|
65
|
+
# ═══════════════════════════════════════════════════════════════
|
|
66
|
+
|
|
67
|
+
CONFIG_PATH = Path(__file__).parent.parent / "config" / "voice_mapping.json"
|
|
68
|
+
OUTPUT_PATH = Path(__file__).parent.parent / "outputs" / "AUDIO"
|
|
69
|
+
TEMP_PATH = Path(__file__).parent.parent / "outputs" / "temp"
|
|
70
|
+
|
|
71
|
+
# Criar pastas se não existirem
|
|
72
|
+
OUTPUT_PATH.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class Segment:
|
|
78
|
+
"""Representa um segmento de áudio a ser gerado."""
|
|
79
|
+
index: int
|
|
80
|
+
speaker: str
|
|
81
|
+
text: str
|
|
82
|
+
instruction: str = ""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ═══════════════════════════════════════════════════════════════
|
|
86
|
+
# PARSING DO SCRIPT
|
|
87
|
+
# ═══════════════════════════════════════════════════════════════
|
|
88
|
+
|
|
89
|
+
def parse_script(script_path: Path) -> List[Segment]:
|
|
90
|
+
"""
|
|
91
|
+
Parse um script .md e extrai os segmentos de fala.
|
|
92
|
+
|
|
93
|
+
Formato esperado:
|
|
94
|
+
[PERSONAGEM]
|
|
95
|
+
(instrução opcional)
|
|
96
|
+
"Texto da fala"
|
|
97
|
+
"""
|
|
98
|
+
segments = []
|
|
99
|
+
|
|
100
|
+
with open(script_path, 'r', encoding='utf-8') as f:
|
|
101
|
+
content = f.read()
|
|
102
|
+
|
|
103
|
+
# Regex para capturar falas
|
|
104
|
+
# [PERSONAGEM]\n(instrução)?\n"texto" ou texto sem aspas
|
|
105
|
+
pattern = r'\[([A-Z_-]+)\]\s*(?:\(([^)]+)\))?\s*\n([^[\n]+(?:\n(?!\[)[^[\n]+)*)'
|
|
106
|
+
|
|
107
|
+
matches = re.findall(pattern, content)
|
|
108
|
+
|
|
109
|
+
for i, (speaker, instruction, text) in enumerate(matches):
|
|
110
|
+
# Limpar texto
|
|
111
|
+
text = text.strip()
|
|
112
|
+
text = re.sub(r'^["\']|["\']$', '', text) # Remove aspas
|
|
113
|
+
text = re.sub(r'\[PAUSA.*?\]', '', text) # Remove marcações de pausa (serão tratadas depois)
|
|
114
|
+
text = re.sub(r'\[SOM:.*?\]', '', text) # Remove marcações de som
|
|
115
|
+
text = text.strip()
|
|
116
|
+
|
|
117
|
+
if text:
|
|
118
|
+
segments.append(Segment(
|
|
119
|
+
index=i,
|
|
120
|
+
speaker=speaker.strip(),
|
|
121
|
+
text=text,
|
|
122
|
+
instruction=instruction.strip() if instruction else ""
|
|
123
|
+
))
|
|
124
|
+
|
|
125
|
+
return segments
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def extract_pauses(script_path: Path) -> List[Tuple[int, float]]:
|
|
129
|
+
"""
|
|
130
|
+
Extrai marcações de pausa do script.
|
|
131
|
+
|
|
132
|
+
Retorna lista de (posição, duração_segundos)
|
|
133
|
+
"""
|
|
134
|
+
pauses = []
|
|
135
|
+
|
|
136
|
+
with open(script_path, 'r', encoding='utf-8') as f:
|
|
137
|
+
content = f.read()
|
|
138
|
+
|
|
139
|
+
# Encontra [PAUSA X seg]
|
|
140
|
+
pattern = r'\[PAUSA\s+(\d+)\s*seg\]'
|
|
141
|
+
|
|
142
|
+
for match in re.finditer(pattern, content):
|
|
143
|
+
# Posição aproximada no texto
|
|
144
|
+
position = match.start()
|
|
145
|
+
duration = int(match.group(1))
|
|
146
|
+
pauses.append((position, duration))
|
|
147
|
+
|
|
148
|
+
return pauses
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# ═══════════════════════════════════════════════════════════════
|
|
152
|
+
# GERAÇÃO DE ÁUDIO
|
|
153
|
+
# ═══════════════════════════════════════════════════════════════
|
|
154
|
+
|
|
155
|
+
def load_voice_mapping() -> Dict:
|
|
156
|
+
"""Carrega mapeamento de vozes do arquivo de configuração."""
|
|
157
|
+
if CONFIG_PATH.exists():
|
|
158
|
+
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
|
|
159
|
+
return json.load(f)
|
|
160
|
+
else:
|
|
161
|
+
print(f"[!] Arquivo de configuracao nao encontrado: {CONFIG_PATH}")
|
|
162
|
+
print(" Usando mapeamento padrão.")
|
|
163
|
+
return get_default_voice_mapping()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_default_voice_mapping() -> Dict:
|
|
167
|
+
"""Retorna mapeamento padrão (voice_ids precisam ser configurados)."""
|
|
168
|
+
return {
|
|
169
|
+
"NARRATOR": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.7, "similarity_boost": 0.8, "style": 0.3}},
|
|
170
|
+
"CITADOR": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.9, "similarity_boost": 0.9, "style": 0.0}},
|
|
171
|
+
"HORMOZI": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.5, "similarity_boost": 0.75, "style": 0.6}},
|
|
172
|
+
"COLE_GORDON": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.8, "similarity_boost": 0.8, "style": 0.2}},
|
|
173
|
+
"COLE GORDON": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.8, "similarity_boost": 0.8, "style": 0.2}},
|
|
174
|
+
"BRUNSON": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.4, "similarity_boost": 0.7, "style": 0.8}},
|
|
175
|
+
"CRO": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.5, "similarity_boost": 0.7, "style": 0.5}},
|
|
176
|
+
"CFO": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.8, "similarity_boost": 0.8, "style": 0.2}},
|
|
177
|
+
"CMO": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.6, "similarity_boost": 0.75, "style": 0.4}},
|
|
178
|
+
"COO": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.7, "similarity_boost": 0.75, "style": 0.3}},
|
|
179
|
+
"METHODOLOGICAL-CRITIC": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.6, "similarity_boost": 0.75, "style": 0.4}},
|
|
180
|
+
"DEVILS-ADVOCATE": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.5, "similarity_boost": 0.7, "style": 0.6}},
|
|
181
|
+
"SYNTHESIZER": {"voice_id": "NOT_CONFIGURED", "settings": {"stability": 0.8, "similarity_boost": 0.8, "style": 0.2}},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def generate_audio_segment(segment: Segment, voice_mapping: Dict) -> bytes:
|
|
186
|
+
"""
|
|
187
|
+
Gera áudio para um segmento usando ElevenLabs.
|
|
188
|
+
"""
|
|
189
|
+
if not ELEVENLABS_AVAILABLE:
|
|
190
|
+
raise RuntimeError("ElevenLabs não está instalado")
|
|
191
|
+
|
|
192
|
+
# Normalizar nome do speaker
|
|
193
|
+
speaker_key = segment.speaker.upper().replace(" ", "_")
|
|
194
|
+
|
|
195
|
+
# Buscar configuração da voz
|
|
196
|
+
voice_config = voice_mapping.get(speaker_key)
|
|
197
|
+
if not voice_config:
|
|
198
|
+
print(f"[!] Voz nao configurada para: {segment.speaker}")
|
|
199
|
+
print(f" Usando NARRATOR como fallback")
|
|
200
|
+
voice_config = voice_mapping.get("NARRATOR")
|
|
201
|
+
|
|
202
|
+
if voice_config["voice_id"] == "NOT_CONFIGURED":
|
|
203
|
+
raise RuntimeError(f"voice_id não configurado para: {segment.speaker}")
|
|
204
|
+
|
|
205
|
+
# Gerar áudio
|
|
206
|
+
audio = elevenlabs_client.text_to_speech.convert(
|
|
207
|
+
voice_id=voice_config["voice_id"],
|
|
208
|
+
text=segment.text,
|
|
209
|
+
model_id="eleven_multilingual_v2",
|
|
210
|
+
voice_settings={
|
|
211
|
+
"stability": voice_config["settings"]["stability"],
|
|
212
|
+
"similarity_boost": voice_config["settings"]["similarity_boost"],
|
|
213
|
+
"style": voice_config["settings"].get("style", 0.0),
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
return b"".join(audio)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def generate_silence(duration_seconds: float) -> AudioSegment:
|
|
221
|
+
"""Gera segmento de silêncio."""
|
|
222
|
+
return AudioSegment.silent(duration=int(duration_seconds * 1000))
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# ═══════════════════════════════════════════════════════════════
|
|
226
|
+
# PIPELINE PRINCIPAL
|
|
227
|
+
# ═══════════════════════════════════════════════════════════════
|
|
228
|
+
|
|
229
|
+
def generate_episode_audio(script_path: Path, output_path: Path = None) -> Path:
|
|
230
|
+
"""
|
|
231
|
+
Pipeline completo de geração de áudio.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
script_path: Caminho para o script .md
|
|
235
|
+
output_path: Caminho para o arquivo de saída (opcional)
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Path do arquivo de áudio gerado
|
|
239
|
+
"""
|
|
240
|
+
if not PYDUB_AVAILABLE:
|
|
241
|
+
raise RuntimeError("pydub não está instalado")
|
|
242
|
+
|
|
243
|
+
print(f"\n{'='*60}")
|
|
244
|
+
print("[MOVIE] BOARDROOM WARFARE - GERACAO DE AUDIO")
|
|
245
|
+
print(f"{'='*60}\n")
|
|
246
|
+
|
|
247
|
+
# 1. Parse do script
|
|
248
|
+
print("[DOC] Parsing do script...")
|
|
249
|
+
segments = parse_script(script_path)
|
|
250
|
+
print(f" {len(segments)} segmentos encontrados")
|
|
251
|
+
|
|
252
|
+
# 2. Carregar mapeamento de vozes
|
|
253
|
+
print("\n[MASK] Carregando mapeamento de vozes...")
|
|
254
|
+
voice_mapping = load_voice_mapping()
|
|
255
|
+
|
|
256
|
+
# 3. Verificar API key
|
|
257
|
+
global elevenlabs_client
|
|
258
|
+
api_key = os.getenv("ELEVENLABS_API_KEY")
|
|
259
|
+
if not api_key:
|
|
260
|
+
raise RuntimeError("ELEVENLABS_API_KEY não configurada")
|
|
261
|
+
elevenlabs_client = ElevenLabs(api_key=api_key)
|
|
262
|
+
print(" [OK] API Key configurada")
|
|
263
|
+
|
|
264
|
+
# 4. Gerar segmentos de audio
|
|
265
|
+
print("\n[AUDIO] Gerando segmentos de audio...")
|
|
266
|
+
audio_segments = []
|
|
267
|
+
|
|
268
|
+
for i, segment in enumerate(segments):
|
|
269
|
+
print(f" [{i+1}/{len(segments)}] {segment.speaker}: {segment.text[:50]}...")
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
audio_bytes = generate_audio_segment(segment, voice_mapping)
|
|
273
|
+
|
|
274
|
+
# Salvar temporariamente
|
|
275
|
+
temp_file = TEMP_PATH / f"segment_{i:04d}.mp3"
|
|
276
|
+
with open(temp_file, 'wb') as f:
|
|
277
|
+
f.write(audio_bytes)
|
|
278
|
+
|
|
279
|
+
# Carregar como AudioSegment
|
|
280
|
+
audio_segment = AudioSegment.from_mp3(temp_file)
|
|
281
|
+
audio_segments.append(audio_segment)
|
|
282
|
+
|
|
283
|
+
print(f" [OK] {len(audio_segment)}ms")
|
|
284
|
+
|
|
285
|
+
except Exception as e:
|
|
286
|
+
print(f" [X] Erro: {e}")
|
|
287
|
+
# Adicionar silêncio como placeholder
|
|
288
|
+
audio_segments.append(generate_silence(2))
|
|
289
|
+
|
|
290
|
+
# 5. Concatenar
|
|
291
|
+
print("\n[LINK] Concatenando segmentos...")
|
|
292
|
+
final_audio = AudioSegment.empty()
|
|
293
|
+
|
|
294
|
+
for i, segment_audio in enumerate(audio_segments):
|
|
295
|
+
final_audio += segment_audio
|
|
296
|
+
# Adicionar pequena pausa entre falas
|
|
297
|
+
final_audio += generate_silence(0.5)
|
|
298
|
+
|
|
299
|
+
# 6. Exportar
|
|
300
|
+
if output_path is None:
|
|
301
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
302
|
+
script_name = script_path.stem
|
|
303
|
+
output_path = OUTPUT_PATH / f"{script_name}_{timestamp}.mp3"
|
|
304
|
+
|
|
305
|
+
print(f"\n[SAVE] Exportando para: {output_path}")
|
|
306
|
+
final_audio.export(output_path, format="mp3", bitrate="192k")
|
|
307
|
+
|
|
308
|
+
# 7. Limpar arquivos temporarios
|
|
309
|
+
print("\n[CLEAN] Limpando arquivos temporarios...")
|
|
310
|
+
for temp_file in TEMP_PATH.glob("segment_*.mp3"):
|
|
311
|
+
temp_file.unlink()
|
|
312
|
+
|
|
313
|
+
# 8. Resumo
|
|
314
|
+
duration_minutes = len(final_audio) / 1000 / 60
|
|
315
|
+
print(f"\n{'='*60}")
|
|
316
|
+
print("[OK] AUDIO GERADO COM SUCESSO")
|
|
317
|
+
print(f"{'='*60}")
|
|
318
|
+
print(f" [FILE] Arquivo: {output_path}")
|
|
319
|
+
print(f" [TIME] Duracao: {duration_minutes:.1f} minutos")
|
|
320
|
+
print(f" [MASK] Vozes: {len(set(s.speaker for s in segments))}")
|
|
321
|
+
print(f"{'='*60}\n")
|
|
322
|
+
|
|
323
|
+
return output_path
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# ═══════════════════════════════════════════════════════════════
|
|
327
|
+
# CLI
|
|
328
|
+
# ═══════════════════════════════════════════════════════════════
|
|
329
|
+
|
|
330
|
+
def main():
|
|
331
|
+
parser = argparse.ArgumentParser(
|
|
332
|
+
description="Gera áudio a partir de scripts Boardroom Warfare"
|
|
333
|
+
)
|
|
334
|
+
parser.add_argument(
|
|
335
|
+
"script",
|
|
336
|
+
type=Path,
|
|
337
|
+
help="Caminho para o script .md"
|
|
338
|
+
)
|
|
339
|
+
parser.add_argument(
|
|
340
|
+
"--output", "-o",
|
|
341
|
+
type=Path,
|
|
342
|
+
default=None,
|
|
343
|
+
help="Caminho para o arquivo de saída"
|
|
344
|
+
)
|
|
345
|
+
parser.add_argument(
|
|
346
|
+
"--dry-run",
|
|
347
|
+
action="store_true",
|
|
348
|
+
help="Apenas parse o script, não gera áudio"
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
args = parser.parse_args()
|
|
352
|
+
|
|
353
|
+
if not args.script.exists():
|
|
354
|
+
print(f"[X] Script nao encontrado: {args.script}")
|
|
355
|
+
return 1
|
|
356
|
+
|
|
357
|
+
if args.dry_run:
|
|
358
|
+
print("[SEARCH] Modo dry-run: apenas parsing")
|
|
359
|
+
segments = parse_script(args.script)
|
|
360
|
+
print(f"\n{len(segments)} segmentos encontrados:\n")
|
|
361
|
+
for s in segments:
|
|
362
|
+
print(f" [{s.speaker}] {s.text[:60]}...")
|
|
363
|
+
return 0
|
|
364
|
+
|
|
365
|
+
try:
|
|
366
|
+
output_path = generate_episode_audio(args.script, args.output)
|
|
367
|
+
print(f"\n[HEADPHONE] Para ouvir: {output_path}")
|
|
368
|
+
return 0
|
|
369
|
+
except Exception as e:
|
|
370
|
+
print(f"\n[X] Erro: {e}")
|
|
371
|
+
return 1
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
if __name__ == "__main__":
|
|
375
|
+
exit(main())
|