Compare commits

...
3 Commits
Author SHA1 Message Date
João Henrique 8e74835f1e feat: adicionados editar, duplicar e ativar ou inativar aos perfis
- adicionados editar, duplicar e ativar ou inativar aos perfis de vídeo do catálogo

Resumo:
- 2 arquivos alterados
- 0 novos
- 2 modificados
- 0 removidos

 2 files changed, 51 insertions(+), 3 deletions(-)

Arquivos:
  - code/cep-plugin/main.js
  - code/cep-plugin/styles.css
2026-09-09 11:41:11 -04:00
João Henrique 20d28a53af feat: criado plano executável com actions para aplicar o resumo da
- criado plano executável com actions para aplicar o resumo da entrevista no editor
- corrigida a compressão da barra de abas do painel após a inclusão de Tipos de vídeo
- criada skill para converter seleções de transcrição em actions executáveis no editor

Resumo:
- 3 arquivos alterados
- 2 novos
- 1 modificados
- 0 removidos

 1 file changed, 4 insertions(+), 1 deletion(-)

Arquivos:
  - code/cep-plugin/styles.css
  - code/plugins/premiere-pro/skills/transcript-to-edit-actions/
  - plano-resumo-video-actions.json
2026-09-09 11:31:30 -04:00
João Henrique 6e1bd052fe feat: criada a aba Tipos de vídeo com cinco perfis editoriais pré-
- criada a aba Tipos de vídeo com cinco perfis editoriais pré-cadastrados e catálogo local pronto para integração com o Schedule Light
- ampliado o cadastro vertical dos perfis com objetivos, narrativa, emoção, prioridades, formato, áudio e regras para IA
- criado plano JSON para resumir a entrevista jornalística em até três minutos

Resumo:
- 4 arquivos alterados
- 1 novos
- 3 modificados
- 0 removidos

 3 files changed, 318 insertions(+), 3 deletions(-)

Arquivos:
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/cep-plugin/styles.css
  - plano-resumo-video.json
2026-09-09 11:25:11 -04:00
7 changed files with 571 additions and 4 deletions
+73
View File
@@ -34,6 +34,9 @@
<button class="tab-button" id="tabBtnAnalises" role="tab" aria-selected="false" aria-controls="tabAnalises" onclick="switchTab('analises')" type="button"> <button class="tab-button" id="tabBtnAnalises" role="tab" aria-selected="false" aria-controls="tabAnalises" onclick="switchTab('analises')" type="button">
<span class="tab-icon" aria-hidden="true">⎘</span>Análises <span class="tab-icon" aria-hidden="true">⎘</span>Análises
</button> </button>
<button class="tab-button" id="tabBtnTiposVideo" role="tab" aria-selected="false" aria-controls="tabTiposVideo" onclick="switchTab('tipos-video')" type="button">
<span class="tab-icon" aria-hidden="true">▦</span>Tipos de vídeo
</button>
<button class="tab-button" id="tabBtnBridge" role="tab" aria-selected="false" aria-controls="tabBridge" onclick="switchTab('bridge')" type="button"> <button class="tab-button" id="tabBtnBridge" role="tab" aria-selected="false" aria-controls="tabBridge" onclick="switchTab('bridge')" type="button">
<span class="tab-icon" aria-hidden="true">⇄</span>Conexão <span class="tab-icon" aria-hidden="true">⇄</span>Conexão
</button> </button>
@@ -374,6 +377,76 @@
</section> </section>
</div> </div>
<!-- =========================== TIPOS DE VÍDEO =========================== -->
<div class="tab-panel" id="tabTiposVideo" role="tabpanel" aria-labelledby="tabBtnTiposVideo" hidden>
<p class="tab-intro">Cadastre o padrão editorial que a IA e o editor devem seguir para cada tipo de vídeo. As alterações ficam salvas no catálogo local do Schedule Light.</p>
<section class="card">
<div class="card-head">
<h2>Catálogo de tipos</h2>
<button class="link-button" onclick="tipoVideoNovo()" type="button">+ Novo tipo</button>
</div>
<div id="tiposVideoLista" class="video-type-list" role="list" aria-label="Tipos de vídeo cadastrados"></div>
</section>
<section class="card" id="tipoVideoEditorCard" hidden>
<div class="card-head"><h2 id="tipoVideoEditorTitulo">Novo tipo de vídeo</h2><span class="card-kicker" id="tipoVideoEditorStatus">Rascunho</span></div>
<section class="profile-section"><div class="profile-section-head"><span>1</span><div><strong>Identificação</strong><small>Nome, categoria e status do perfil.</small></div></div>
<label class="field-label" for="tipoVideoNome">Nome do perfil</label><input class="text-field" id="tipoVideoNome" type="text" placeholder="Ex.: Depoimento de cliente">
<label class="field-label" for="tipoVideoDescricao">Descrição</label><textarea id="tipoVideoDescricao" rows="2" placeholder="Para que este vídeo existe e qual resultado deve provocar?"></textarea>
<div class="field-grid"><div><label class="field-label" for="tipoVideoCategoria">Categoria</label><select class="select-field" id="tipoVideoCategoria"><option>Depoimento</option><option>Entrevista</option><option>Storytelling</option><option>Educativo</option><option>Comercial</option><option>Institucional</option></select></div><div><label class="field-label" for="tipoVideoAtivo">Status</label><label class="checkbox-field"><input id="tipoVideoAtivo" type="checkbox"><span>Perfil ativo</span></label></div></div>
</section>
<section class="profile-section"><div class="profile-section-head"><span>2</span><div><strong>Objetivo</strong><small>O resultado que o vídeo deve provocar.</small></div></div>
<label class="field-label" for="tipoVideoObjetivo">Objetivo principal</label><input class="text-field" id="tipoVideoObjetivo" type="text" placeholder="Ex.: Gerar confiança e credibilidade">
<label class="field-label" for="tipoVideoObjetivoSecundario">Objetivo secundário</label><input class="text-field" id="tipoVideoObjetivoSecundario" type="text" placeholder="Ex.: Criar conexão emocional">
<label class="field-label" for="tipoVideoPublico">Público-alvo</label><input class="text-field" id="tipoVideoPublico" type="text" placeholder="Ex.: Clientes em potencial">
<label class="field-label" for="tipoVideoMensagem">Mensagem principal</label><textarea id="tipoVideoMensagem" rows="2" placeholder="Qual mensagem precisa permanecer depois que o vídeo terminar?"></textarea>
</section>
<section class="profile-section"><div class="profile-section-head"><span>3</span><div><strong>Narrativa</strong><small>Como a história deve ser organizada.</small></div></div>
<label class="field-label" for="tipoVideoTipoNarrativa">Tipo de narrativa</label><select class="select-field" id="tipoVideoTipoNarrativa"><option>História pessoal</option><option>Pergunta e resposta</option><option>Jornada / transformação</option><option>Explicação passo a passo</option><option>Problema → solução → benefício</option></select>
<label class="field-label" for="tipoVideoFocoNarrativo">Foco narrativo</label><input class="text-field" id="tipoVideoFocoNarrativo" type="text" placeholder="Ex.: Problema → solução → resultado">
<label class="checkbox-field"><input id="tipoVideoStorytelling" type="checkbox"><span>Priorizar storytelling</span></label>
<label class="field-label" for="tipoVideoEstrutura">Estrutura narrativa</label><textarea id="tipoVideoEstrutura" rows="3" placeholder="Ex.: Gancho → contexto → desenvolvimento → conclusão."></textarea>
</section>
<section class="profile-section"><div class="profile-section-head"><span>4</span><div><strong>Emoção</strong><small>Qual sensação deve ser construída.</small></div></div>
<label class="field-label" for="tipoVideoEmocao">Objetivo emocional</label><input class="text-field" id="tipoVideoEmocao" type="text" placeholder="Confiança, empatia, curiosidade…">
<label class="field-label" for="tipoVideoIntensidade">Intensidade emocional <output id="tipoVideoIntensidadeValor">3 / 5</output></label><input id="tipoVideoIntensidade" type="range" min="1" max="5" step="1" value="3" oninput="tipoVideoAtualizarIntensidade()">
<label class="field-label" for="tipoVideoTom">Tom emocional</label><select class="select-field" id="tipoVideoTom"><option>Positivo</option><option>Inspirador</option><option>Íntimo</option><option>Informativo</option><option>Urgente</option><option>Contemplativo</option></select>
<label class="field-label" for="tipoVideoConstrucaoEmocao">Como construir a emoção</label><textarea id="tipoVideoConstrucaoEmocao" rows="2" placeholder="Ex.: Pausas naturais, B-roll real e trilha discreta."></textarea>
</section>
<section class="profile-section"><div class="profile-section-head"><span>5</span><div><strong>Formato</strong><small>Onde e em quanto tempo o vídeo será consumido.</small></div></div>
<label class="field-label" for="tipoVideoCanais">Formato / canal</label><input class="text-field" id="tipoVideoCanais" type="text" placeholder="Instagram Reels, TikTok, YouTube…">
<label class="field-label" for="tipoVideoProporcao">Orientação preferencial</label><select class="select-field" id="tipoVideoProporcao"><option value="9:16">9:16 — vertical</option><option value="1:1">1:1 — quadrado</option><option value="16:9">16:9 — horizontal</option><option value="adaptavel">Adaptável</option></select>
<div class="field-grid"><div><label class="field-label" for="tipoVideoDuracaoMinima">Duração mínima (segundos)</label><input class="text-field" id="tipoVideoDuracaoMinima" type="number" min="0" step="1"></div><div><label class="field-label" for="tipoVideoDuracao">Duração máxima (segundos)</label><input class="text-field" id="tipoVideoDuracao" type="number" min="1" step="1"></div></div>
</section>
<section class="profile-section"><div class="profile-section-head"><span>6</span><div><strong>Prioridades</strong><small>Ordem de importância quando houver conflito.</small></div></div>
<div id="tipoVideoPrioridades" class="priority-list"></div>
</section>
<section class="profile-section"><div class="profile-section-head"><span>7</span><div><strong>Elementos de edição</strong><small>O que deve ou não aparecer na montagem.</small></div></div>
<label class="checkbox-field"><input id="tipoVideoUsaBroll" type="checkbox"><span>Usar B-roll</span></label><label class="checkbox-field"><input id="tipoVideoUsaLegendas" type="checkbox"><span>Usar legendas</span></label><label class="checkbox-field"><input id="tipoVideoUsaTextos" type="checkbox"><span>Usar textos e títulos</span></label><label class="checkbox-field"><input id="tipoVideoUsaGraficos" type="checkbox"><span>Usar gráficos ou telas explicativas</span></label><label class="checkbox-field"><input id="tipoVideoUsaZoom" type="checkbox"><span>Usar zooms e reenquadramentos</span></label>
<label class="field-label" for="tipoVideoCortes">Critério de cortes</label><textarea id="tipoVideoCortes" rows="3" placeholder="O que cortar, preservar ou acelerar?"></textarea>
<label class="field-label" for="tipoVideoBroll">Orientação de B-roll</label><textarea id="tipoVideoBroll" rows="3" placeholder="Quando usar imagens de apoio e com qual função?"></textarea>
<label class="field-label" for="tipoVideoTexto">Textos, títulos e legendas</label><textarea id="tipoVideoTexto" rows="3" placeholder="Legendas, palavras-chave, títulos, CTA…"></textarea>
</section>
<section class="profile-section"><div class="profile-section-head"><span>8</span><div><strong>Áudio</strong><small>Como a voz, música e efeitos devem conviver.</small></div></div>
<label class="checkbox-field"><input id="tipoVideoUsaMusica" type="checkbox"><span>Usar música</span></label><label class="field-label" for="tipoVideoIntensidadeMusica">Intensidade da música</label><input id="tipoVideoIntensidadeMusica" type="range" min="0" max="100" step="5" value="30" oninput="tipoVideoAtualizarIntensidadeMusica()"><output id="tipoVideoIntensidadeMusicaValor">30%</output>
<label class="field-label" for="tipoVideoPrioridadeVoz">Prioridade da voz</label><select class="select-field" id="tipoVideoPrioridadeVoz"><option>Alta</option><option>Muito alta</option><option>Equilibrada</option></select>
<label class="field-label" for="tipoVideoSom">Tratamento de áudio</label><textarea id="tipoVideoSom" rows="3" placeholder="Trilha, volume, pausas, limpeza e ênfase."></textarea>
</section>
<section class="profile-section"><div class="profile-section-head"><span>9</span><div><strong>Regras e instruções para IA</strong><small>Critérios que devem orientar o plano de edição.</small></div></div>
<label class="field-label" for="tipoVideoDiretriz">Regras de edição</label><textarea id="tipoVideoDiretriz" rows="5" placeholder="Uma regra por linha. Ex.: Preservar a naturalidade da fala."></textarea>
<label class="field-label" for="tipoVideoRestricoes">Restrições de edição</label><textarea id="tipoVideoRestricoes" rows="3" placeholder="O que a IA não deve fazer?"></textarea>
<label class="field-label" for="tipoVideoQualidade">Critérios de qualidade</label><textarea id="tipoVideoQualidade" rows="3" placeholder="Como saberemos que o resultado ficou bom?"></textarea>
</section>
<div class="button-row">
<button class="button button-primary" onclick="tipoVideoSalvar()" type="button">Salvar tipo</button>
<button class="button button-ghost" onclick="tipoVideoCancelar()" type="button">Cancelar</button>
<button class="button button-ghost" onclick="tipoVideoCopiarJson()" type="button">Copiar JSON para IA</button>
</div>
</section>
<p class="field-help" id="tiposVideoStatus">—</p>
</div>
<!-- ============================== CONEXÃO ============================== --> <!-- ============================== CONEXÃO ============================== -->
+256
View File
@@ -30,6 +30,28 @@ function log(msg, cls) {
// reposicionado na aba de origem com etapa atual, barra e tempo decorrido. // reposicionado na aba de origem com etapa atual, barra e tempo decorrido.
var taskState = { active: false, startedAt: 0, timer: null, clearTimer: null, mirror: null, originTab: "silence", originPanelId: "tabSilence", errorText: "" }; var taskState = { active: false, startedAt: 0, timer: null, clearTimer: null, mirror: null, originTab: "silence", originPanelId: "tabSilence", errorText: "" };
var TIPOS_VIDEO_CHAVE = "schedule_light_tipos_video";
var tipoVideoAtualId = null;
var tiposVideoPadrao = [
{ id: "midia-social", nome: "Conteúdo para mídia social", duracao_maxima_segundos: 60, descricao: "Vídeo curto para interromper a rolagem, comunicar uma ideia e estimular uma ação.", canais: "Instagram Reels, TikTok, Shorts", proporcao: "9:16", ritmo: "agil", emocao: "Curiosidade e energia", storytelling: true, estrutura: "Gancho nos primeiros 2 segundos → desenvolvimento em blocos curtos → CTA direto.", cortes: "Cortes rápidos, remover pausas e repetições; preservar frases de impacto. Usar jump cuts com moderação.", broll: "Inserir imagens de apoio a cada mudança de ideia, preferindo planos que reforcem a fala.", texto: "Legendas sempre; destacar palavras-chave na tela e usar título curto. CTA visual no final.", som: "Voz sempre inteligível e à frente da trilha; música energética em volume baixo.", diretriz: "Priorize retenção e clareza. Cada corte deve manter o ritmo e reforçar uma única ideia por vez." },
{ id: "depoimento", nome: "Depoimento de cliente", duracao_maxima_segundos: 120, descricao: "Relato autêntico que gera identificação, confiança e prova social.", canais: "Site, redes sociais, apresentação comercial", proporcao: "adaptavel", ritmo: "equilibrado", emocao: "Empatia e confiança", storytelling: true, estrutura: "Problema vivido → experiência com a solução → transformação → recomendação.", cortes: "Cortar hesitações e desvios sem deixar a fala artificial; manter reações, pausas emocionais e frases espontâneas.", broll: "Cobrir cortes com cenas do cliente usando o produto, ambiente real ou detalhes que comprovem o relato.", texto: "Nome e contexto do depoente; destacar a transformação em frases curtas; legendas completas.", som: "Voz natural, limpa e próxima; trilha emocional discreta, crescendo apenas na transformação.", diretriz: "Proteja a autenticidade do depoimento. A emoção deve vir da fala e das evidências, não de efeitos excessivos." },
{ id: "entrevista", nome: "Entrevista", duracao_maxima_segundos: 600, descricao: "Conversa estruturada para extrair conhecimento, opinião ou história de uma pessoa.", canais: "YouTube, podcast em vídeo, cortes sociais", proporcao: "16:9", ritmo: "equilibrado", emocao: "Interesse e credibilidade", storytelling: true, estrutura: "Apresentação → perguntas essenciais → aprofundamento → síntese e encerramento.", cortes: "Remover redundâncias e silêncios longos; preservar respostas completas, escuta, reação e contexto da pergunta.", broll: "Usar planos de reação, detalhes do ambiente e imagens relacionadas ao tema para quebrar a monotonia.", texto: "Identificação do entrevistado, perguntas resumidas quando necessário, capítulos ou palavras-chave.", som: "Diálogo consistente entre os canais; reduzir ruído e nivelar vozes sem tirar naturalidade.", diretriz: "Mantenha a linha de raciocínio da conversa. Não cortar uma resposta de modo que altere o sentido ou a intenção do entrevistado." },
{ id: "institucional", nome: "Vídeo institucional", duracao_maxima_segundos: 180, descricao: "Apresentação da empresa, marca, cultura ou solução com percepção de valor.", canais: "Site, eventos, apresentações, LinkedIn", proporcao: "16:9", ritmo: "progressivo", emocao: "Segurança e inspiração", storytelling: true, estrutura: "Contexto ou propósito → pessoas e operação → diferenciais → prova → convite para conhecer.", cortes: "Ritmo elegante; evitar excesso de cortes. Alternar entrevistas, planos de ambiente e detalhes de operação.", broll: "B-roll planejado para mostrar pessoas, processos, produto e escala; toda imagem deve provar uma mensagem.", texto: "Títulos limpos, dados essenciais e assinatura da marca; evitar excesso de texto na tela.", som: "Trilha cinematográfica ou institucional discreta; voz firme, clara e com pausas bem preservadas.", diretriz: "Construa confiança e percepção de valor. Use consistência visual e sonora; efeitos só quando ajudarem a mensagem da marca." },
{ id: "educativo-storytelling", nome: "Educativo com storytelling", duracao_maxima_segundos: 240, descricao: "Explicação didática que ensina uma ideia por meio de uma história, caso ou problema concreto.", canais: "YouTube, curso, LinkedIn, redes sociais", proporcao: "adaptavel", ritmo: "progressivo", emocao: "Curiosidade e clareza", storytelling: true, estrutura: "Problema ou pergunta → história/exemplo → explicação → aplicação prática → resumo.", cortes: "Cortar repetições, mas manter a sequência pedagógica; inserir pausas após conceitos importantes.", broll: "Usar diagramas, tela, exemplos e imagens que tornem o conceito visível; sincronizar apoio com a explicação.", texto: "Título do conceito, palavras-chave e resumo final; legendas e marcadores de etapas.", som: "Voz em primeiro plano; trilha quase imperceptível; pequenos efeitos apenas para sinalizar transições.", diretriz: "Ensine uma coisa por vez. O espectador deve entender o conceito sem depender apenas de texto ou de efeitos visuais." }
];
function tipoVideoCompletar(tipo) {
var configuracoes = {
"midia-social": { categoria: "Comercial", objetivo: "Gerar retenção e ação", objetivo_secundario: "Comunicar uma ideia rapidamente", publico: "Público das redes sociais", mensagem: "Uma ideia clara por vídeo.", tipo_narrativa: "Problema → solução → benefício", foco_narrativo: "Gancho e CTA", intensidade: 4, tom: "Positivo", construcao_emocao: "Ritmo ágil, cortes de impacto, legendas e trilha energética.", duracao_minima: 15, prioridades: ["Retenção", "Clareza", "Mensagem", "Ritmo", "Estética"], usa_broll: true, usa_legendas: true, usa_textos: true, usa_graficos: false, usa_zoom: true, usa_musica: true, intensidade_musica: 25, prioridade_voz: "Muito alta", restricoes: "Evitar excesso de informação e cortes sem função.", qualidade: "A abertura prende atenção e a mensagem é compreendida sem áudio." },
"depoimento": { categoria: "Depoimento", objetivo: "Gerar credibilidade e confiança", objetivo_secundario: "Criar identificação emocional", publico: "Clientes em potencial", mensagem: "A experiência real comprova o valor da solução.", tipo_narrativa: "História pessoal", foco_narrativo: "Problema → experiência → transformação → recomendação", intensidade: 3, tom: "Íntimo", construcao_emocao: "Preservar pausas naturais, reações e imagens reais; usar trilha discreta.", duracao_minima: 30, prioridades: ["Autenticidade", "Clareza", "Conexão emocional", "Ritmo", "Estética"], usa_broll: true, usa_legendas: true, usa_textos: true, usa_graficos: false, usa_zoom: false, usa_musica: true, intensidade_musica: 20, prioridade_voz: "Muito alta", restricoes: "Não alterar o sentido das frases nem deixar o depoimento artificial.", qualidade: "A pessoa parece verdadeira e o resultado do relato fica evidente." },
"entrevista": { categoria: "Entrevista", objetivo: "Transmitir conhecimento e autoridade", objetivo_secundario: "Organizar a conversa por temas", publico: "Pessoas interessadas no assunto", mensagem: "O conteúdo da conversa é compreendido com contexto.", tipo_narrativa: "Pergunta e resposta", foco_narrativo: "Pergunta → resposta → aprofundamento", intensidade: 2, tom: "Informativo", construcao_emocao: "Reações, escuta e pausas que preservem a naturalidade da conversa.", duracao_minima: 60, prioridades: ["Clareza", "Conteúdo", "Contexto", "Ritmo", "Estética"], usa_broll: true, usa_legendas: true, usa_textos: true, usa_graficos: false, usa_zoom: true, usa_musica: false, intensidade_musica: 10, prioridade_voz: "Muito alta", restricoes: "Não cortar frases de modo que prejudique o raciocínio do entrevistado.", qualidade: "As respostas mantêm contexto, lógica e informação relevante." },
"institucional": { categoria: "Institucional", objetivo: "Apresentar valor e confiança na marca", objetivo_secundario: "Mostrar pessoas, processo e diferenciais", publico: "Clientes, parceiros e equipe", mensagem: "A marca entrega valor de forma consistente.", tipo_narrativa: "Jornada / transformação", foco_narrativo: "Propósito → pessoas → operação → prova", intensidade: 4, tom: "Inspirador", construcao_emocao: "Trilha progressiva, imagens de pessoas e planos de operação.", duracao_minima: 45, prioridades: ["Confiança", "Mensagem", "Narrativa", "Estética", "Ritmo"], usa_broll: true, usa_legendas: true, usa_textos: true, usa_graficos: true, usa_zoom: false, usa_musica: true, intensidade_musica: 35, prioridade_voz: "Alta", restricoes: "Evitar efeitos decorativos que não reforcem a mensagem da marca.", qualidade: "O vídeo transmite profissionalismo, clareza e percepção de valor." },
"educativo-storytelling": { categoria: "Educativo", objetivo: "Ensinar um assunto com clareza", objetivo_secundario: "Aumentar retenção e aplicação prática", publico: "Pessoas que precisam aprender o assunto", mensagem: "O espectador consegue entender e aplicar o conceito.", tipo_narrativa: "Explicação passo a passo", foco_narrativo: "Problema → exemplo → explicação → aplicação", intensidade: 2, tom: "Informativo", construcao_emocao: "Curiosidade inicial, exemplos visuais e pausas após conceitos importantes.", duracao_minima: 60, prioridades: ["Clareza", "Organização", "Didática", "Retenção", "Estética"], usa_broll: true, usa_legendas: true, usa_textos: true, usa_graficos: true, usa_zoom: true, usa_musica: false, intensidade_musica: 5, prioridade_voz: "Muito alta", restricoes: "Não cortar exemplos ou transições que prejudiquem a explicação.", qualidade: "O conteúdo fica fácil de acompanhar, revisar e aplicar." }
}[tipo.id] || {};
var completo = Object.assign({ ativo: true, categoria: "Personalizado", objetivo: "", objetivo_secundario: "", publico: "", mensagem: "", tipo_narrativa: "História pessoal", foco_narrativo: "", intensidade: 3, tom: "Positivo", construcao_emocao: "", duracao_minima: 0, prioridades: ["Clareza", "Mensagem", "Ritmo", "Conexão emocional", "Estética"], usa_broll: false, usa_legendas: true, usa_textos: false, usa_graficos: false, usa_zoom: false, usa_musica: false, intensidade_musica: 20, prioridade_voz: "Alta", restricoes: "", qualidade: "" }, configuracoes, tipo);
return completo;
}
function taskEl(id) { return document.getElementById(id); } function taskEl(id) { return document.getElementById(id); }
function formatClock(ms) { function formatClock(ms) {
@@ -207,6 +229,7 @@ function switchTab(name) {
{ key: "scanner", panel: "tabScanner", btn: "tabBtnScanner" }, { key: "scanner", panel: "tabScanner", btn: "tabBtnScanner" },
{ key: "retakes", panel: "tabRetakes", btn: "tabBtnRetakes" }, { key: "retakes", panel: "tabRetakes", btn: "tabBtnRetakes" },
{ key: "analises", panel: "tabAnalises", btn: "tabBtnAnalises" }, { key: "analises", panel: "tabAnalises", btn: "tabBtnAnalises" },
{ key: "tipos-video", panel: "tabTiposVideo", btn: "tabBtnTiposVideo" },
{ key: "bridge", panel: "tabBridge", btn: "tabBtnBridge" }, { key: "bridge", panel: "tabBridge", btn: "tabBtnBridge" },
{ key: "models", panel: "tabModels", btn: "tabBtnModels" }, { key: "models", panel: "tabModels", btn: "tabBtnModels" },
{ key: "settings", panel: "tabSettings", btn: "tabBtnSettings" }, { key: "settings", panel: "tabSettings", btn: "tabBtnSettings" },
@@ -226,6 +249,239 @@ function switchTab(name) {
if (name === "scanner") { renderScannerTranscriptionOptions(); loadScannerProfile(); renderScannerHuggingFaceStatus(); } if (name === "scanner") { renderScannerTranscriptionOptions(); loadScannerProfile(); renderScannerHuggingFaceStatus(); }
if (name === "retakes") retakesAoAbrir(); if (name === "retakes") retakesAoAbrir();
if (name === "analises") analisesAoAbrir(); if (name === "analises") analisesAoAbrir();
if (name === "tipos-video") tiposVideoAoAbrir();
}
// ---- Catálogo de tipos de vídeo -------------------------------------------
// A primeira versão usa o armazenamento local do painel. O documento salvo já
// tem formato estável e pode ser migrado para o Schedule Light sem alterar o
// contrato editorial enviado para a IA.
function tiposVideoLer() {
try {
var salvo = JSON.parse(localStorage.getItem(TIPOS_VIDEO_CHAVE) || "null");
if (Array.isArray(salvo) && salvo.length) return salvo.map(tipoVideoCompletar);
var iniciais = tiposVideoPadrao.slice().map(tipoVideoCompletar);
tiposVideoSalvarNoCatalogo(iniciais);
return iniciais;
} catch (_) { return tiposVideoPadrao.slice().map(tipoVideoCompletar); }
}
function tiposVideoSalvarNoCatalogo(lista) {
localStorage.setItem(TIPOS_VIDEO_CHAVE, JSON.stringify(lista));
}
function tiposVideoAoAbrir() {
tiposVideoRenderizarLista();
if (!tipoVideoAtualId) tipoVideoNovo();
}
function tiposVideoRenderizarLista() {
var lista = document.getElementById("tiposVideoLista");
if (!lista) return;
lista.innerHTML = "";
tiposVideoLer().forEach(function (tipo) {
var item = document.createElement("div");
item.className = "video-type-row" + (tipo.id === tipoVideoAtualId ? " is-selected" : "");
item.setAttribute("role", "listitem");
item.innerHTML = '<div class="video-type-copy"><strong></strong><span></span></div><div class="video-type-meta"></div><span class="video-type-status"></span><div class="video-type-actions"><button class="button button-ghost video-type-edit" type="button">Editar</button><button class="button button-ghost video-type-duplicate" type="button">Duplicar</button><button class="button button-ghost video-type-toggle" type="button"></button></div>';
item.querySelector("strong").textContent = tipo.nome;
item.querySelector("span").textContent = tipo.descricao;
item.querySelector(".video-type-meta").textContent = tipo.duracao_maxima_segundos + " s · " + tipo.proporcao + " · " + tipo.canais;
item.querySelector(".video-type-status").textContent = tipo.ativo === false ? "Inativo" : "Ativo";
item.querySelector(".video-type-status").setAttribute("data-state", tipo.ativo === false ? "inactive" : "active");
item.querySelector(".video-type-edit").onclick = function () { tipoVideoEditar(tipo.id); };
item.querySelector(".video-type-duplicate").onclick = function () { tipoVideoDuplicar(tipo.id); };
item.querySelector(".video-type-toggle").textContent = tipo.ativo === false ? "Ativar" : "Inativar";
item.querySelector(".video-type-toggle").onclick = function () { tipoVideoAlternarAtivo(tipo.id); };
item.querySelector(".video-type-copy").onclick = function () { tipoVideoEditar(tipo.id); };
lista.appendChild(item);
});
}
function tipoVideoNovo() {
tipoVideoAtualId = null;
tipoVideoPreencher(tipoVideoCompletar({ id: "", nome: "", duracao_maxima_segundos: 60, descricao: "", canais: "", proporcao: "9:16", ritmo: "equilibrado", emocao: "", storytelling: true, estrutura: "", cortes: "", broll: "", texto: "", som: "", diretriz: "" }));
document.getElementById("tipoVideoEditorTitulo").textContent = "Novo tipo de vídeo";
document.getElementById("tipoVideoEditorStatus").textContent = "Rascunho";
document.getElementById("tipoVideoEditorCard").hidden = false;
tiposVideoRenderizarLista();
}
function tipoVideoEditar(id) {
var tipo = tiposVideoLer().filter(function (item) { return item.id === id; })[0];
if (!tipo) return;
tipoVideoAtualId = id;
tipoVideoPreencher(tipo);
document.getElementById("tipoVideoEditorTitulo").textContent = "Editar tipo de vídeo";
document.getElementById("tipoVideoEditorStatus").textContent = "Cadastrado";
document.getElementById("tipoVideoEditorCard").hidden = false;
tiposVideoRenderizarLista();
}
function tipoVideoPreencher(tipo) {
tipo = tipoVideoCompletar(tipo);
["nome", "descricao", "canais", "proporcao", "ritmo", "emocao", "estrutura", "cortes", "broll", "texto", "som", "diretriz", "categoria", "objetivo", "objetivo_secundario", "publico", "mensagem", "tipo_narrativa", "foco_narrativo", "tom", "construcao_emocao", "restricoes", "qualidade", "prioridade_voz"].forEach(function (campo) {
var elemento = document.getElementById("tipoVideo" + campo.charAt(0).toUpperCase() + campo.slice(1));
if (elemento) elemento.value = tipo[campo] || "";
});
document.getElementById("tipoVideoDuracao").value = tipo.duracao_maxima_segundos || "";
document.getElementById("tipoVideoDuracaoMinima").value = tipo.duracao_minima || "";
document.getElementById("tipoVideoStorytelling").checked = !!tipo.storytelling;
document.getElementById("tipoVideoAtivo").checked = tipo.ativo !== false;
document.getElementById("tipoVideoIntensidade").value = tipo.intensidade || 3;
document.getElementById("tipoVideoIntensidadeMusica").value = tipo.intensidade_musica || 0;
document.getElementById("tipoVideoUsaBroll").checked = !!tipo.usa_broll;
document.getElementById("tipoVideoUsaLegendas").checked = !!tipo.usa_legendas;
document.getElementById("tipoVideoUsaTextos").checked = !!tipo.usa_textos;
document.getElementById("tipoVideoUsaGraficos").checked = !!tipo.usa_graficos;
document.getElementById("tipoVideoUsaZoom").checked = !!tipo.usa_zoom;
document.getElementById("tipoVideoUsaMusica").checked = !!tipo.usa_musica;
tipoVideoRenderizarPrioridades(tipo.prioridades);
tipoVideoAtualizarIntensidade();
tipoVideoAtualizarIntensidadeMusica();
}
function tipoVideoRenderizarPrioridades(prioridades) {
var lista = document.getElementById("tipoVideoPrioridades");
lista.innerHTML = "";
(prioridades || []).slice(0, 5).forEach(function (valor, indice) {
var linha = document.createElement("div");
linha.className = "priority-row";
linha.innerHTML = '<span class="priority-number">' + (indice + 1) + '</span><input class="text-field priority-input" type="text" value="">';
linha.querySelector("input").value = valor;
lista.appendChild(linha);
});
}
function tipoVideoPrioridadesDoFormulario() {
return Array.prototype.slice.call(document.querySelectorAll("#tipoVideoPrioridades .priority-input")).map(function (input) { return input.value.trim(); }).filter(Boolean);
}
function tipoVideoAtualizarIntensidade() {
var valor = document.getElementById("tipoVideoIntensidade");
var saida = document.getElementById("tipoVideoIntensidadeValor");
if (valor && saida) saida.textContent = valor.value + " / 5";
}
function tipoVideoAtualizarIntensidadeMusica() {
var valor = document.getElementById("tipoVideoIntensidadeMusica");
var saida = document.getElementById("tipoVideoIntensidadeMusicaValor");
if (valor && saida) saida.textContent = valor.value + "%";
}
function tipoVideoDoFormulario() {
var nome = document.getElementById("tipoVideoNome").value.trim();
if (!nome) throw new Error("Informe o nome do tipo de vídeo.");
var base = tipoVideoAtualId ? tiposVideoLer().filter(function (item) { return item.id === tipoVideoAtualId; })[0] : null;
return {
id: tipoVideoAtualId || (nome.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") + "-" + Date.now()),
nome: nome,
descricao: document.getElementById("tipoVideoDescricao").value.trim(),
ativo: document.getElementById("tipoVideoAtivo").checked,
categoria: document.getElementById("tipoVideoCategoria").value,
objetivo: document.getElementById("tipoVideoObjetivo").value.trim(),
objetivo_secundario: document.getElementById("tipoVideoObjetivoSecundario").value.trim(),
publico: document.getElementById("tipoVideoPublico").value.trim(),
mensagem: document.getElementById("tipoVideoMensagem").value.trim(),
tipo_narrativa: document.getElementById("tipoVideoTipoNarrativa").value,
foco_narrativo: document.getElementById("tipoVideoFocoNarrativo").value.trim(),
intensidade: Number(document.getElementById("tipoVideoIntensidade").value) || 3,
tom: document.getElementById("tipoVideoTom").value,
construcao_emocao: document.getElementById("tipoVideoConstrucaoEmocao").value.trim(),
duracao_maxima_segundos: Number(document.getElementById("tipoVideoDuracao").value) || 0,
duracao_minima: Number(document.getElementById("tipoVideoDuracaoMinima").value) || 0,
canais: document.getElementById("tipoVideoCanais").value.trim(),
proporcao: document.getElementById("tipoVideoProporcao").value,
ritmo: document.getElementById("tipoVideoRitmo").value,
emocao: document.getElementById("tipoVideoEmocao").value.trim(),
storytelling: document.getElementById("tipoVideoStorytelling").checked,
estrutura: document.getElementById("tipoVideoEstrutura").value.trim(),
cortes: document.getElementById("tipoVideoCortes").value.trim(),
broll: document.getElementById("tipoVideoBroll").value.trim(),
texto: document.getElementById("tipoVideoTexto").value.trim(),
som: document.getElementById("tipoVideoSom").value.trim(),
diretriz: document.getElementById("tipoVideoDiretriz").value.trim(),
prioridades: tipoVideoPrioridadesDoFormulario(),
usa_broll: document.getElementById("tipoVideoUsaBroll").checked,
usa_legendas: document.getElementById("tipoVideoUsaLegendas").checked,
usa_textos: document.getElementById("tipoVideoUsaTextos").checked,
usa_graficos: document.getElementById("tipoVideoUsaGraficos").checked,
usa_zoom: document.getElementById("tipoVideoUsaZoom").checked,
usa_musica: document.getElementById("tipoVideoUsaMusica").checked,
intensidade_musica: Number(document.getElementById("tipoVideoIntensidadeMusica").value) || 0,
prioridade_voz: document.getElementById("tipoVideoPrioridadeVoz").value,
restricoes: document.getElementById("tipoVideoRestricoes").value.trim(),
qualidade: document.getElementById("tipoVideoQualidade").value.trim(),
criado_em: base && base.criado_em ? base.criado_em : new Date().toISOString(),
atualizado_em: new Date().toISOString()
};
}
function tipoVideoSalvar() {
try {
var item = tipoVideoDoFormulario();
var lista = tiposVideoLer();
var indice = lista.findIndex(function (tipo) { return tipo.id === item.id; });
if (indice >= 0) lista[indice] = item; else lista.push(item);
tiposVideoSalvarNoCatalogo(lista);
tipoVideoAtualId = item.id;
document.getElementById("tipoVideoEditorStatus").textContent = "Salvo";
document.getElementById("tiposVideoStatus").textContent = "Catálogo salvo localmente · " + lista.length + " tipo(s) cadastrado(s).";
tiposVideoRenderizarLista();
showToast("ok", "Tipo de vídeo salvo no catálogo.");
} catch (erro) { showToast("err", erro.message); }
}
function tipoVideoDuplicar(id) {
var origem = tiposVideoLer().filter(function (item) { return item.id === id; })[0];
if (!origem) return;
var copia = JSON.parse(JSON.stringify(origem));
copia.id = origem.id + "-copia-" + Date.now();
copia.nome = origem.nome + " (cópia)";
copia.ativo = true;
copia.criado_em = new Date().toISOString();
copia.atualizado_em = copia.criado_em;
var lista = tiposVideoLer();
lista.push(copia);
tiposVideoSalvarNoCatalogo(lista);
tipoVideoAtualId = copia.id;
tipoVideoPreencher(copia);
document.getElementById("tipoVideoEditorTitulo").textContent = "Editar tipo de vídeo";
document.getElementById("tipoVideoEditorStatus").textContent = "Cópia criada";
document.getElementById("tipoVideoEditorCard").hidden = false;
document.getElementById("tiposVideoStatus").textContent = "Perfil duplicado. Revise os campos e salve a cópia.";
tiposVideoRenderizarLista();
showToast("ok", "Perfil duplicado. Você pode ajustar a cópia antes de salvar.");
}
function tipoVideoAlternarAtivo(id) {
var lista = tiposVideoLer();
var item = lista.filter(function (perfil) { return perfil.id === id; })[0];
if (!item) return;
item.ativo = item.ativo === false;
item.atualizado_em = new Date().toISOString();
tiposVideoSalvarNoCatalogo(lista);
if (tipoVideoAtualId === id) {
document.getElementById("tipoVideoAtivo").checked = item.ativo;
document.getElementById("tipoVideoEditorStatus").textContent = item.ativo ? "Ativo" : "Inativo";
}
tiposVideoRenderizarLista();
showToast("ok", item.ativo ? "Perfil ativado." : "Perfil inativado.");
}
function tipoVideoCancelar() {
tipoVideoAtualId = null;
document.getElementById("tipoVideoEditorCard").hidden = true;
tiposVideoRenderizarLista();
}
function tipoVideoCopiarJson() {
try {
var json = JSON.stringify({ tipo_de_video: tipoVideoDoFormulario() }, null, 2);
var copia = childProcess.spawn("pbcopy");
copia.stdin.end(json);
showToast("ok", "Configuração copiada em JSON para a IA.");
} catch (erro) { showToast("err", erro.message); }
} }
// ---- Análises --------------------------------------------------------------- // ---- Análises ---------------------------------------------------------------
+41 -4
View File
@@ -114,11 +114,14 @@ h1, h2, h3 { margin: 0; }
top: 53px; top: 53px;
z-index: 25; z-index: 25;
display: flex; display: flex;
flex: 0 0 auto;
min-height: 39px;
gap: 2px; gap: 2px;
margin: 0 -14px 14px; margin: 0 -14px 14px;
padding: 0 14px; padding: 0 14px;
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
background: var(--bg); background: var(--bg);
overflow-x: auto;
} }
.tab-button { .tab-button {
@@ -126,7 +129,8 @@ h1, h2, h3 { margin: 0; }
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 5px; gap: 5px;
flex: 1; flex: 0 0 auto;
min-width: 88px;
min-width: 0; min-width: 0;
padding: 10px 4px; padding: 10px 4px;
border: none; border: none;
@@ -139,6 +143,8 @@ h1, h2, h3 { margin: 0; }
white-space: nowrap; white-space: nowrap;
transition: color .15s, border-color .15s; transition: color .15s, border-color .15s;
} }
.tab-bar::-webkit-scrollbar { height: 3px; }
.tab-bar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.tab-icon { font-size: 11px; opacity: .8; } .tab-icon { font-size: 11px; opacity: .8; }
.tab-button:hover { color: var(--text-secondary); } .tab-button:hover { color: var(--text-secondary); }
.tab-button.active { color: var(--text); border-bottom-color: var(--violet); } .tab-button.active { color: var(--text); border-bottom-color: var(--violet); }
@@ -332,7 +338,7 @@ h1, h2, h3 { margin: 0; }
.field-static { margin: 0; padding: 8px 0; color: var(--text-secondary); font-size: 10.5px; } .field-static { margin: 0; padding: 8px 0; color: var(--text-secondary); font-size: 10.5px; }
.field-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .8fr); gap: 10px; } .field-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .8fr); gap: 10px; }
.select-field, .path-field input, textarea, .file-field input { .select-field, .text-field, .path-field input, textarea, .file-field input {
width: 100%; width: 100%;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 6px; border-radius: 6px;
@@ -342,14 +348,15 @@ h1, h2, h3 { margin: 0; }
transition: border-color .15s, box-shadow .15s; transition: border-color .15s, box-shadow .15s;
} }
.select-field { height: 32px; padding: 0 8px; font-size: 10.5px; } .select-field { height: 32px; padding: 0 8px; font-size: 10.5px; }
.text-field { height: 32px; padding: 0 9px; font-size: 10.5px; outline: none; user-select: text; }
.range-field-row { display: flex; align-items: center; gap: 10px; } .range-field-row { display: flex; align-items: center; gap: 10px; }
.range-field-row input[type="range"] { flex: 1 1 auto; accent-color: var(--violet); height: 20px; } .range-field-row input[type="range"] { flex: 1 1 auto; accent-color: var(--violet); height: 20px; }
.range-field-value { flex: 0 0 auto; min-width: 84px; text-align: right; font: 10.5px var(--font-mono); color: var(--text-secondary); } .range-field-value { flex: 0 0 auto; min-width: 84px; text-align: right; font: 10.5px var(--font-mono); color: var(--text-secondary); }
.path-field input, .file-field input { height: 34px; padding: 0 10px; font: 10px var(--font-mono); color: var(--text-secondary); user-select: text; } .path-field input, .file-field input { height: 34px; padding: 0 10px; font: 10px var(--font-mono); color: var(--text-secondary); user-select: text; }
.path-field > svg + input { padding-left: 32px; } .path-field > svg + input { padding-left: 32px; }
textarea { padding: 8px 10px; font: 10px var(--font-mono); color: var(--text-secondary); resize: vertical; user-select: text; } textarea { padding: 8px 10px; font: 10px var(--font-mono); color: var(--text-secondary); resize: vertical; user-select: text; }
.select-field:hover, .path-field input:hover, textarea:hover, .file-field input:hover { border-color: var(--border-strong); } .select-field:hover, .text-field:hover, .path-field input:hover, textarea:hover, .file-field input:hover { border-color: var(--border-strong); }
.select-field:focus, .path-field input:focus, textarea:focus, .file-field input:focus { border-color: var(--violet); color: var(--text); box-shadow: 0 0 0 2px var(--violet-soft); } .select-field:focus, .text-field:focus, .path-field input:focus, textarea:focus, .file-field input:focus { border-color: var(--violet); color: var(--text); box-shadow: 0 0 0 2px var(--violet-soft); }
.path-field { position: relative; display: flex; align-items: center; } .path-field { position: relative; display: flex; align-items: center; }
.path-field > svg { position: absolute; left: 10px; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.5; color: var(--text-muted); pointer-events: none; } .path-field > svg { position: absolute; left: 10px; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.5; color: var(--text-muted); pointer-events: none; }
@@ -381,6 +388,36 @@ textarea { padding: 8px 10px; font: 10px var(--font-mono); color: var(--text-sec
.button-row { display: flex; gap: 8px; } .button-row { display: flex; gap: 8px; }
.button-row .button { flex: 1; } .button-row .button { flex: 1; }
/* -------------------------- Catálogo editorial ------------------------- */
.video-type-list { display: grid; gap: 6px; }
.video-type-row { display: flex; align-items: center; gap: 9px; padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface-deep); }
.video-type-row.is-selected { border-color: rgba(155, 108, 255, .55); background: var(--violet-soft); }
.video-type-copy { flex: 1; min-width: 0; }
.video-type-copy { cursor: pointer; }
.video-type-copy strong, .video-type-copy span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.video-type-copy strong { color: var(--text); font-size: 10.5px; font-weight: 650; }
.video-type-copy span { margin-top: 3px; color: var(--text-muted); font-size: 9px; }
.video-type-meta { max-width: 32%; overflow: hidden; color: var(--text-muted); font: 8.5px var(--font-mono); text-overflow: ellipsis; white-space: nowrap; }
.video-type-status { flex: 0 0 auto; padding: 3px 7px; border-radius: 12px; font-size: 8.5px; font-weight: 650; }
.video-type-status[data-state="active"] { background: var(--green-soft); color: var(--green); }
.video-type-status[data-state="inactive"] { background: var(--surface-raised); color: var(--text-muted); }
.video-type-actions { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.video-type-row .button { height: 27px; padding: 0 8px; flex: 0 0 auto; font-size: 9px; }
.profile-section { margin-top: 12px; padding: 12px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface-deep); }
.profile-section-head { display: flex; align-items: center; gap: 9px; margin-bottom: 11px; }
.profile-section-head > span { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; flex: 0 0 auto; border-radius: 50%; background: var(--violet-soft); color: var(--violet-hover); font-size: 10px; font-weight: 700; }
.profile-section-head strong, .profile-section-head small { display: block; }
.profile-section-head strong { font-size: 10.5px; font-weight: 650; }
.profile-section-head small { margin-top: 2px; color: var(--text-muted); font-size: 9px; }
.profile-section > * + * { margin-top: 9px; }
.profile-section .checkbox-field { margin-top: 9px; }
.profile-section output { float: right; color: var(--text-muted); font: 9px var(--font-mono); }
.profile-section input[type="range"] { width: 100%; accent-color: var(--violet); }
.priority-list { display: grid; gap: 6px; }
.priority-row { display: flex; align-items: center; gap: 7px; }
.priority-number { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex: 0 0 auto; border-radius: 50%; background: var(--surface-raised); color: var(--text-muted); font: 9px var(--font-mono); }
.priority-input { flex: 1; }
/* ---------------------------- Chave/valor, stats ---------------------------- */ /* ---------------------------- Chave/valor, stats ---------------------------- */
.kv { display: grid; gap: 1px; margin: 0; padding: 0; overflow: hidden; border: 1px solid var(--border); border-radius: 6px; background: var(--border); } .kv { display: grid; gap: 1px; margin: 0; padding: 0; overflow: hidden; border: 1px solid var(--border); border-radius: 6px; background: var(--border); }
.kv[hidden] { display: none; } .kv[hidden] { display: none; }
@@ -0,0 +1,50 @@
---
name: transcript-to-edit-actions
description: Transform transcript-based editorial selections into validated executable Premiere edit plans when the user asks to edit by voice, edit by transcript, summarize an interview, select excerpts, or generate JSON actions.
---
# Transcript to Edit Actions
Converte uma seleção editorial baseada em transcrição em um plano JSON executável pelo editor do projeto.
## Contrato de saída
Devolva um único objeto JSON com esta forma:
```json
{
"source": "nome-do-arquivo.mp4",
"actions": [
{
"kind": "cut",
"start": 0.0,
"end": 10.0,
"reason": "Motivo curto e verificável do corte."
}
]
}
```
`source` deve ser o nome do arquivo de mídia usado pela sequência. Os tempos de `start` e `end` são segundos na mídia original. `actions` usa o contrato externo do editor: `kind: "cut"` remove o intervalo, portanto o plano deve listar as partes que serão excluídas, não as partes que serão mantidas.
## Fluxo
1. Leia a transcrição e as instruções editoriais como evidência. Identifique a tese, o contexto, os argumentos, os contrapontos e o fechamento antes de escolher trechos.
2. Quando o usuário pedir um resumo, selecione primeiro os intervalos a manter. Prefira frases completas, falas compreensíveis sem contexto adicional e uma sequência narrativa curta.
3. Exclua falantes marcados como inativos ou com `include_in_video: false`. Não use nome de falante como prova de identidade quando o JSON só fornece um rótulo.
4. Normalize os intervalos mantidos: ordene por tempo, una sobreposições e descarte intervalos vazios. Respeite a duração máxima solicitada; se não houver limite, preserve o objetivo editorial sem cortar a compreensão.
5. Converta os intervalos mantidos no complemento da mídia: crie uma ação `cut` para cada intervalo entre o início da mídia, os trechos mantidos e o fim da mídia. Preserve pequenos silêncios somente quando necessários para não quebrar uma frase.
6. Valide antes de responder: JSON válido, `source` preenchido, pelo menos uma ação, `start < end`, números finitos, ações dentro da duração da mídia, sem sobreposição e duração mantida dentro do limite.
## Julgamento editorial
- Abra com uma pergunta, afirmação ou trecho que estabeleça imediatamente o conflito.
- Use o mínimo de trechos necessário para explicar contexto, análise e consequência.
- Termine com a conclusão mais forte ou com uma frase que feche a tese.
- Não invente falas, fatos, correções jurídicas ou identificadores de clipes.
- Preserve o áudio original; correções de transcrição servem para `reason` e revisão, não para reescrever a fala.
- Se um nome ou palavra estiver com baixa confiança, registre a necessidade de conferência no áudio em vez de afirmar a correção.
## Resposta
Quando o pedido for para executar no programa, entregue o JSON executável sem campos editoriais extras dentro do objeto raiz. Resumos, observações e dúvidas devem ficar fora do bloco JSON. Se a seleção não puder ser convertida com segurança por falta de duração ou timecodes, peça apenas o dado faltante.
@@ -0,0 +1,4 @@
interface:
display_name: "Transcript to Edit Actions"
short_description: "Convert transcript selections into Premiere JSON actions"
default_prompt: "Use $transcript-to-edit-actions to turn my transcript-based video selections into validated executable JSON actions."
+47
View File
@@ -0,0 +1,47 @@
{
"source": "videoplayback (1).mp4",
"actions": [
{
"kind": "cut",
"start": 0.05,
"end": 188.78,
"reason": "Remover a abertura e todas as falas do falante Barba; manter o primeiro trecho selecionado, de Fabiola."
},
{
"kind": "cut",
"start": 210.80,
"end": 211.75,
"reason": "Remover a pausa entre a pergunta de Fabiola e a resposta selecionada de Marco Teixeira."
},
{
"kind": "cut",
"start": 260.02,
"end": 399.91,
"reason": "Remover o conteúdo intermediário até o trecho selecionado de Marco Teixeira sobre o impacto político."
},
{
"kind": "cut",
"start": 439.90,
"end": 462.14,
"reason": "Remover o intervalo entre a análise sobre impacto político e a conclusão de Marco Teixeira."
},
{
"kind": "cut",
"start": 490.05,
"end": 567.98,
"reason": "Remover o conteúdo entre a conclusão de Marco Teixeira e a introdução da metáfora do jurista."
},
{
"kind": "cut",
"start": 577.26,
"end": 578.11,
"reason": "Remover a pausa entre os dois trechos finais do jurista."
},
{
"kind": "cut",
"start": 607.07,
"end": 778.85,
"reason": "Remover o restante da entrevista após o fechamento selecionado."
}
]
}
+100
View File
@@ -0,0 +1,100 @@
{
"schema_version": "1.0",
"tipo": "plano_de_resumo_jornalistico",
"objetivo": "Resumir a entrevista sobre a crise no STF, seus efeitos institucionais e possíveis impactos eleitorais.",
"duracao_maxima_segundos": 180,
"duracao_estimada_segundos": 176.43,
"fonte": {
"arquivo": "videoplayback (1).mp4",
"caminho": "/Volumes/Merongo/Downloads/videoplayback (1).mp4"
},
"regras": {
"excluir_falantes": ["SPEAKER_01"],
"manter_falantes": ["SPEAKER_00", "SPEAKER_02", "SPEAKER_03"],
"remover_silencios_excessivos": true,
"preservar_sentido_original": true,
"adicionar_legendas": true
},
"estrutura": [
{
"ordem": 1,
"segmento_origem": 9,
"falante": "Fabiola",
"speaker_id": "SPEAKER_00",
"entrada": "00:03:08.780",
"saida": "00:03:30.800",
"duracao_segundos": 22.02,
"funcao": "abertura_e_contexto",
"justificativa": "Apresenta a crise como uma tragédia e introduz a análise do professor Marco Teixeira."
},
{
"ordem": 2,
"segmentos_origem": [10, 11, 12],
"falante": "Marco Teixeira",
"speaker_id": "SPEAKER_02",
"entrada": "00:03:31.750",
"saida": "00:04:20.020",
"duracao_segundos": 48.27,
"funcao": "diagnostico_institucional",
"justificativa": "Explica que a crise mina a confiança no Judiciário, envolve os demais Poderes e foi agravada pela demora na reação."
},
{
"ordem": 3,
"segmento_origem": 18,
"falante": "Marco Teixeira",
"speaker_id": "SPEAKER_02",
"entrada": "00:06:39.910",
"saida": "00:07:19.900",
"duracao_segundos": 39.99,
"funcao": "impacto_politico",
"justificativa": "Mostra que as decisões possuem impacto eleitoral e podem provocar uma crise dentro do STF e da Polícia Federal."
},
{
"ordem": 4,
"segmento_origem": 20,
"falante": "Marco Teixeira",
"speaker_id": "SPEAKER_02",
"entrada": "00:07:42.140",
"saida": "00:08:10.050",
"duracao_segundos": 27.91,
"funcao": "conclusao_do_analista",
"justificativa": "Defende previsibilidade, respeito às instituições e alerta para o risco de enfraquecimento dos Poderes."
},
{
"ordem": 5,
"segmento_origem": 23,
"falante": "Outro",
"speaker_id": "SPEAKER_03",
"entrada": "00:09:27.980",
"saida": "00:09:37.260",
"duracao_segundos": 9.28,
"funcao": "transicao_e_metafora",
"justificativa": "Introduz uma metáfora forte para explicar a escalada do conflito no Supremo."
},
{
"ordem": 6,
"segmento_origem": 25,
"falante": "Outro",
"speaker_id": "SPEAKER_03",
"entrada": "00:09:38.110",
"saida": "00:10:07.070",
"duracao_segundos": 28.96,
"funcao": "fechamento_de_impacto",
"justificativa": "Resume a crise como uma disputa interna grave e reforça o conflito entre decisões individuais e o funcionamento colegiado do STF."
}
],
"orientacoes_de_edicao": {
"ritmo": "informativo, firme e crescente",
"abertura": "Começar diretamente com a pergunta de Fabiola, sem vinheta longa.",
"cortes": "Remover cumprimentos, repetições, hesitações e pausas prolongadas.",
"transicoes": "Usar cortes secos entre os blocos, com transições discretas.",
"legendas": "Aplicar legendas sincronizadas e destacar termos como STF, democracia, eleições e instituições.",
"texto_na_tela": [
"Crise institucional no STF",
"Impactos sobre a democracia e as eleições",
"O risco de enfraquecimento das instituições"
],
"trilha": "Opcional, discreta e de tensão jornalística, sem encobrir as falas.",
"checagem": "Conferir no áudio os nomes Fachin, Andrei Rodrigues e demais termos corrigidos da transcrição."
}
}