feat: adicionada reprodução dos trechos de áudio individuais de ca
- adicionada reprodução dos trechos de áudio individuais de cada falante Resumo: - 2 arquivos alterados - 0 novos - 2 modificados - 0 removidos 2 files changed, 95 insertions(+), 4 deletions(-) Arquivos: - code/cep-plugin/main.js - code/cep-plugin/styles.css
This commit is contained in:
+92
-3
@@ -1326,6 +1326,7 @@ var silenceState = {
|
||||
sequenceId: null,
|
||||
sequenceName: null,
|
||||
mediaPath: null,
|
||||
audioCachePath: null,
|
||||
fileBaseName: null,
|
||||
outputDir: null,
|
||||
transcriptPath: null,
|
||||
@@ -1333,8 +1334,12 @@ var silenceState = {
|
||||
cachedTranscriptPath: null,
|
||||
jsonOutputPath: null,
|
||||
speakers: [],
|
||||
speakerTurns: [],
|
||||
};
|
||||
|
||||
var speakerAudioPlayer = null;
|
||||
var speakerAudioQueue = null;
|
||||
|
||||
// ---- Central transcript cache ----
|
||||
// Evita rodar o Whisper de novo para um vídeo já transcrito antes: indexa
|
||||
// transcrições por caminho absoluto + tamanho + data de modificação do
|
||||
@@ -1572,9 +1577,11 @@ function silenceSelectSequence() {
|
||||
silenceState.mediaPath = result.mediaPath;
|
||||
silenceState.fileBaseName = slugify(result.clipName || result.sequenceName);
|
||||
silenceState.outputDir = path.join(SILENCE_OUTPUT_ROOT, silenceState.fileBaseName);
|
||||
silenceState.audioCachePath = path.join(silenceState.outputDir, path.parse(result.mediaPath).name + ".wav");
|
||||
silenceState.transcriptPath = null;
|
||||
silenceState.jsonOutputPath = null;
|
||||
silenceState.speakers = [];
|
||||
silenceState.speakerTurns = [];
|
||||
var speakerConfig = document.getElementById("silenceSpeakerConfig");
|
||||
if (speakerConfig) speakerConfig.hidden = true;
|
||||
|
||||
@@ -1774,6 +1781,7 @@ function silenceTranscribe() {
|
||||
silenceState.transcriptPath = out;
|
||||
silenceState.transcribeModel = model;
|
||||
silenceState.speakers = [];
|
||||
silenceState.speakerTurns = [];
|
||||
var speakerConfig = document.getElementById("silenceSpeakerConfig");
|
||||
if (speakerConfig) speakerConfig.hidden = true;
|
||||
var resumo = parsed.segments + " trechos · " + Math.round(parsed.duration) + "s de áudio";
|
||||
@@ -1844,7 +1852,10 @@ function silenceDiarizeSpeakers(onFinished) {
|
||||
}
|
||||
var parsed = null;
|
||||
try { parsed = JSON.parse(fs.readFileSync(silenceState.transcriptPath, "utf-8")).diarization; } catch (e) {}
|
||||
if (parsed && Array.isArray(parsed.speakers)) renderSpeakerConfiguration(parsed.speakers);
|
||||
if (parsed && Array.isArray(parsed.speakers)) {
|
||||
silenceState.speakerTurns = Array.isArray(parsed.turns) ? parsed.turns : [];
|
||||
renderSpeakerConfiguration(parsed.speakers, silenceState.speakerTurns);
|
||||
}
|
||||
var msg = parsed
|
||||
? "Foram detectados " + parsed.num_speakers + (parsed.num_speakers === 1 ? " falante" : " falantes") + ": " + parsed.speakers.join(", ") + "."
|
||||
: "Falantes detectados.";
|
||||
@@ -1863,11 +1874,12 @@ function speakerNameDefault(speakerId) {
|
||||
return speakerId;
|
||||
}
|
||||
|
||||
function renderSpeakerConfiguration(speakerIds) {
|
||||
function renderSpeakerConfiguration(speakerIds, speakerTurns) {
|
||||
var config = document.getElementById("silenceSpeakerConfig");
|
||||
var list = document.getElementById("silenceSpeakerList");
|
||||
var count = document.getElementById("silenceSpeakerCount");
|
||||
if (!config || !list || !count) return;
|
||||
silenceState.speakerTurns = Array.isArray(speakerTurns) ? speakerTurns : silenceState.speakerTurns;
|
||||
var previous = {};
|
||||
silenceState.speakers.forEach(function (speaker) { previous[speaker.id] = speaker; });
|
||||
silenceState.speakers = speakerIds.map(function (id) {
|
||||
@@ -1887,6 +1899,13 @@ function renderSpeakerConfiguration(speakerIds) {
|
||||
var label = document.createElement("label");
|
||||
label.className = "field-label";
|
||||
label.textContent = speaker.id;
|
||||
var play = document.createElement("button");
|
||||
play.type = "button";
|
||||
play.className = "button speaker-play-button";
|
||||
play.textContent = "▶";
|
||||
play.title = "Ouvir trechos de " + speaker.id;
|
||||
play.setAttribute("aria-label", "Ouvir trechos de " + speaker.id);
|
||||
play.addEventListener("click", function () { toggleSpeakerAudio(speaker.id, play); });
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.className = "select-field speaker-name-input";
|
||||
@@ -1906,6 +1925,7 @@ function renderSpeakerConfiguration(speakerIds) {
|
||||
activeLabel.appendChild(active);
|
||||
activeLabel.appendChild(activeText);
|
||||
row.appendChild(label);
|
||||
row.appendChild(play);
|
||||
row.appendChild(input);
|
||||
row.appendChild(activeLabel);
|
||||
list.appendChild(row);
|
||||
@@ -1913,12 +1933,81 @@ function renderSpeakerConfiguration(speakerIds) {
|
||||
config.hidden = silenceState.speakers.length === 0;
|
||||
}
|
||||
|
||||
function speakerAudioFileUrl(filePath) {
|
||||
return encodeURI("file://" + String(filePath || ""));
|
||||
}
|
||||
|
||||
function stopSpeakerAudio() {
|
||||
if (speakerAudioPlayer) {
|
||||
speakerAudioPlayer.pause();
|
||||
speakerAudioPlayer.removeAttribute("src");
|
||||
speakerAudioPlayer.load();
|
||||
}
|
||||
speakerAudioPlayer = null;
|
||||
speakerAudioQueue = null;
|
||||
document.querySelectorAll(".speaker-play-button").forEach(function (button) {
|
||||
button.textContent = "▶";
|
||||
button.classList.remove("is-playing");
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSpeakerAudio(speakerId, button) {
|
||||
if (speakerAudioPlayer && speakerAudioQueue && speakerAudioQueue.speakerId === speakerId) {
|
||||
stopSpeakerAudio();
|
||||
return;
|
||||
}
|
||||
stopSpeakerAudio();
|
||||
var ranges = silenceState.speakerTurns.filter(function (turn) {
|
||||
return turn.speaker === speakerId && Number(turn.end) > Number(turn.start);
|
||||
}).sort(function (a, b) { return Number(a.start) - Number(b.start); });
|
||||
if (!ranges.length) {
|
||||
showToast("err", "Não há intervalos de áudio disponíveis para " + speakerId + ".");
|
||||
return;
|
||||
}
|
||||
if (!silenceState.audioCachePath || !fs.existsSync(silenceState.audioCachePath)) {
|
||||
showToast("err", "Arquivo de áudio do cache não encontrado. Reprocesse a transcrição.");
|
||||
return;
|
||||
}
|
||||
speakerAudioQueue = { speakerId: speakerId, ranges: ranges, index: 0, button: button };
|
||||
speakerAudioPlayer = new Audio(speakerAudioFileUrl(silenceState.audioCachePath));
|
||||
button.textContent = "■";
|
||||
button.classList.add("is-playing");
|
||||
speakerAudioPlayer.addEventListener("loadedmetadata", playCurrentSpeakerRange);
|
||||
speakerAudioPlayer.addEventListener("timeupdate", advanceSpeakerAudioRange);
|
||||
speakerAudioPlayer.addEventListener("ended", advanceSpeakerAudioRange);
|
||||
speakerAudioPlayer.addEventListener("error", function () {
|
||||
stopSpeakerAudio();
|
||||
showToast("err", "Não foi possível reproduzir o áudio deste falante.");
|
||||
});
|
||||
}
|
||||
|
||||
function playCurrentSpeakerRange() {
|
||||
if (!speakerAudioPlayer || !speakerAudioQueue) return;
|
||||
var range = speakerAudioQueue.ranges[speakerAudioQueue.index];
|
||||
if (!range) { stopSpeakerAudio(); return; }
|
||||
speakerAudioPlayer.currentTime = Math.max(0, Number(range.start) - 0.15);
|
||||
var playPromise = speakerAudioPlayer.play();
|
||||
if (playPromise && playPromise.catch) playPromise.catch(function () { stopSpeakerAudio(); });
|
||||
}
|
||||
|
||||
function advanceSpeakerAudioRange() {
|
||||
if (!speakerAudioPlayer || !speakerAudioQueue) return;
|
||||
var range = speakerAudioQueue.ranges[speakerAudioQueue.index];
|
||||
if (!range || speakerAudioPlayer.currentTime < Number(range.end)) return;
|
||||
speakerAudioQueue.index += 1;
|
||||
if (speakerAudioQueue.index >= speakerAudioQueue.ranges.length) {
|
||||
stopSpeakerAudio();
|
||||
return;
|
||||
}
|
||||
playCurrentSpeakerRange();
|
||||
}
|
||||
|
||||
function silenceLoadSpeakerConfiguration() {
|
||||
if (!silenceState.transcriptPath) return;
|
||||
try {
|
||||
var transcript = JSON.parse(fs.readFileSync(silenceState.transcriptPath, "utf-8"));
|
||||
var diarization = transcript.diarization;
|
||||
if (diarization && Array.isArray(diarization.speakers)) renderSpeakerConfiguration(diarization.speakers);
|
||||
if (diarization && Array.isArray(diarization.speakers)) renderSpeakerConfiguration(diarization.speakers, diarization.turns);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user