逐字稿
All checks were successful
Deploy to Server / deploy (push) Successful in 18s

This commit is contained in:
jeremygan2021
2026-03-17 21:43:33 +08:00
parent 3d94a1f0de
commit 7695ac3edf
2 changed files with 65 additions and 3 deletions

View File

@@ -314,7 +314,8 @@ def project_detail_api(request, project_id):
ai_data = { ai_data = {
'transcription': latest_task.transcription, 'transcription': latest_task.transcription,
'summary': latest_task.summary, 'summary': latest_task.summary,
'auto_chapters_data': latest_task.auto_chapters_data 'auto_chapters_data': latest_task.auto_chapters_data,
'transcription_data': latest_task.transcription_data
} }
latest_task_any = TranscriptionTask.objects.filter(project=project).order_by('-created_at').first() latest_task_any = TranscriptionTask.objects.filter(project=project).order_by('-created_at').first()

View File

@@ -108,9 +108,12 @@
<div> <div>
<h4 class="text-lg font-semibold text-gray-900 mb-3 flex items-center"><i class="fas fa-headphones mr-2 text-blue-500"></i>项目录音</h4> <h4 class="text-lg font-semibold text-gray-900 mb-3 flex items-center"><i class="fas fa-headphones mr-2 text-blue-500"></i>项目录音</h4>
<div id="modalAudioSection" class="bg-gray-50 p-4 rounded-lg border border-gray-100 flex items-center justify-center min-h-[80px]"> <div id="modalAudioSection" class="bg-gray-50 p-4 rounded-t-lg border border-gray-100 flex items-center justify-center min-h-[80px]">
<!-- Audio player or "No audio" message will be injected here --> <!-- Audio player or "No audio" message will be injected here -->
</div> </div>
<div id="subtitleContainer" class="bg-black text-white p-3 rounded-b-lg text-center min-h-[48px] flex items-center justify-center text-lg font-medium" style="display: none;">
<span id="subtitleText"></span>
</div>
</div> </div>
<div id="aiResultSection" style="display:none;" class="border border-indigo-100 rounded-xl overflow-hidden"> <div id="aiResultSection" style="display:none;" class="border border-indigo-100 rounded-xl overflow-hidden">
@@ -379,9 +382,17 @@ async function viewProject(id) {
// Render Audio Player // Render Audio Player
const audioSection = document.getElementById('modalAudioSection'); const audioSection = document.getElementById('modalAudioSection');
const subtitleContainer = document.getElementById('subtitleContainer');
const subtitleText = document.getElementById('subtitleText');
if (subtitleContainer && subtitleText) {
subtitleText.innerText = '';
subtitleContainer.style.display = 'none';
}
if (data.audio_url) { if (data.audio_url) {
audioSection.innerHTML = ` audioSection.innerHTML = `
<audio controls class="w-full"> <audio id="projectAudio" controls class="w-full">
<source src="${data.audio_url}" type="audio/mpeg"> <source src="${data.audio_url}" type="audio/mpeg">
<source src="${data.audio_url}" type="audio/mp4"> <source src="${data.audio_url}" type="audio/mp4">
您的浏览器不支持音频播放。 您的浏览器不支持音频播放。
@@ -403,6 +414,56 @@ async function viewProject(id) {
if (data.ai_result) { if (data.ai_result) {
aiSection.style.display = 'block'; aiSection.style.display = 'block';
// Subtitle integration
if (data.audio_url && data.ai_result.transcription_data && subtitleContainer && subtitleText) {
let transData = data.ai_result.transcription_data;
if (typeof transData === 'string') {
try { transData = JSON.parse(transData); } catch(e) { console.error('Error parsing transcription_data', e); }
}
if (transData && transData.Transcription && transData.Transcription.Paragraphs) {
subtitleContainer.style.display = 'flex';
const sentences = [];
transData.Transcription.Paragraphs.forEach(p => {
if (p.Words && p.Words.length > 0) {
let currentSentenceId = null;
let currentSentence = { text: '', start: 0, end: 0 };
p.Words.forEach(w => {
if (w.SentenceId !== currentSentenceId) {
if (currentSentenceId !== null) {
sentences.push({...currentSentence});
}
currentSentenceId = w.SentenceId;
currentSentence = { text: w.Text, start: w.Start, end: w.End };
} else {
currentSentence.text += w.Text;
currentSentence.end = w.End;
}
});
if (currentSentenceId !== null) {
sentences.push({...currentSentence});
}
}
});
const audio = document.getElementById('projectAudio');
if (audio) {
audio.addEventListener('timeupdate', () => {
const currentTimeMs = audio.currentTime * 1000;
// Add a small buffer (e.g. 200ms) to make subtitle display smoother
const activeSentence = sentences.find(s => currentTimeMs >= (s.start - 200) && currentTimeMs <= (s.end + 200));
if (activeSentence) {
subtitleText.innerText = activeSentence.text;
} else {
subtitleText.innerText = '';
}
});
}
}
}
const summaryDiv = document.getElementById('modalAiSummary'); const summaryDiv = document.getElementById('modalAiSummary');
const toggleBtn = document.getElementById('toggleAiSummaryBtn'); const toggleBtn = document.getElementById('toggleAiSummaryBtn');
const toggleText = document.getElementById('toggleAiSummaryText'); const toggleText = document.getElementById('toggleAiSummaryText');