feat: add view transcription to video card in edit mode
This commit is contained in:
+47
-1
@@ -4,10 +4,13 @@
|
||||
import { IconButton } from '@cio/ui/custom/icon-button';
|
||||
import { mediaApi } from '$features/media/api';
|
||||
import { JobPoller, jobsApi, type MediaJobEnvelope } from '$features/jobs';
|
||||
import { sidePanel } from '$features/side-panel';
|
||||
import { snackbar } from '$features/ui/snackbar/store';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { onDestroy } from 'svelte';
|
||||
import type { LessonVideo } from './video-card-utils';
|
||||
import { lessonVideoBus } from './lesson-video-bus.svelte';
|
||||
import { TRANSCRIPT_PANEL_ID } from './transcript-panel-definition';
|
||||
|
||||
interface Props {
|
||||
video: LessonVideo;
|
||||
@@ -19,6 +22,8 @@
|
||||
let { video, onRemove, menuPlacement = 'inline' }: Props = $props();
|
||||
|
||||
let isTranscribing = $state(false);
|
||||
let hasTranscript = $state(false);
|
||||
let hasCheckedTranscript = $state(false);
|
||||
let activePoller: JobPoller<MediaJobEnvelope> | null = null;
|
||||
|
||||
const assetId = $derived((video as LessonVideo & { assetId?: string }).assetId ?? null);
|
||||
@@ -29,6 +34,14 @@
|
||||
activePoller?.stop();
|
||||
});
|
||||
|
||||
async function ensureTranscriptChecked() {
|
||||
if (hasCheckedTranscript || !assetId) return;
|
||||
|
||||
hasCheckedTranscript = true;
|
||||
const data = await mediaApi.getAssetTranscript(assetId);
|
||||
hasTranscript = !!data?.segments?.length;
|
||||
}
|
||||
|
||||
async function startTranscriptionPoll(afterAssetId: string) {
|
||||
activePoller?.stop();
|
||||
activePoller = null;
|
||||
@@ -44,6 +57,7 @@
|
||||
|
||||
if (latest.job.status === 'completed') {
|
||||
isTranscribing = false;
|
||||
hasTranscript = true;
|
||||
snackbar.success('snackbar.media_manager.transcription_completed');
|
||||
|
||||
return;
|
||||
@@ -62,6 +76,7 @@
|
||||
activePoller?.stop();
|
||||
activePoller = null;
|
||||
isTranscribing = false;
|
||||
hasTranscript = true;
|
||||
snackbar.success('snackbar.media_manager.transcription_completed');
|
||||
}
|
||||
|
||||
@@ -85,6 +100,22 @@
|
||||
await startTranscriptionPoll(assetId);
|
||||
}
|
||||
|
||||
async function handleViewTranscript() {
|
||||
if (!assetId) return;
|
||||
|
||||
lessonVideoBus.assetId = assetId;
|
||||
lessonVideoBus.transcriptLoading = true;
|
||||
sidePanel.open(TRANSCRIPT_PANEL_ID);
|
||||
|
||||
try {
|
||||
const data = await mediaApi.getAssetTranscript(assetId);
|
||||
lessonVideoBus.transcript = data;
|
||||
hasTranscript = !!data?.segments?.length;
|
||||
} finally {
|
||||
lessonVideoBus.transcriptLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
const generateLabel = $derived(
|
||||
isTranscribing
|
||||
? t.get('course.navItem.lessons.materials.tabs.video.generate_transcript_in_progress')
|
||||
@@ -92,7 +123,13 @@
|
||||
);
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Root
|
||||
onOpenChange={(open) => {
|
||||
if (open && canGenerateTranscript) {
|
||||
void ensureTranscriptChecked();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.Trigger
|
||||
class={menuPlacement === 'corner'
|
||||
? 'ui:data-[state=open]:opacity-100 absolute top-2 right-2 z-40 flex items-center justify-center opacity-0 transition-all delay-150 duration-200 ease-in-out group-hover:opacity-100'
|
||||
@@ -114,6 +151,15 @@
|
||||
>
|
||||
{generateLabel}
|
||||
</DropdownMenu.Item>
|
||||
{#if hasTranscript}
|
||||
<DropdownMenu.Item
|
||||
onclick={() => {
|
||||
void handleViewTranscript();
|
||||
}}
|
||||
>
|
||||
{$t('course.navItem.lessons.materials.tabs.video.view_transcript')}
|
||||
</DropdownMenu.Item>
|
||||
{/if}
|
||||
{/if}
|
||||
<DropdownMenu.Item class="ui:text-red-600" onclick={onRemove}>
|
||||
{$t('course.navItem.lessons.materials.tabs.video.remove_video')}
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Indlejret",
|
||||
"course_fallback": "Kursus",
|
||||
"menu_aria": "Video muligheder"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Se transskription"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Slide",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Hvor dybt skal kurset gå?",
|
||||
"topic": "Emne eller niche",
|
||||
"expertise_level": "Mål ekspertiseniveau",
|
||||
"documentation_url": {
|
||||
"hint": "Vi læser dette websted for at basere kurset på dit rigtige produkt."
|
||||
}
|
||||
"documentation_url": "Dokumentations-URL (valgfrit)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Bliv ekspert på X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Eingebettet",
|
||||
"course_fallback": "Kurs",
|
||||
"menu_aria": "Videooptionen"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Transkription ansehen"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Rutsche",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Wie tief soll der Kurs gehen?",
|
||||
"topic": "Thema oder Nische",
|
||||
"expertise_level": "Zielkompetenzniveau",
|
||||
"documentation_url": {
|
||||
"hint": "Wir werden diese Website lesen, um den Kurs in Ihrem realen Produkt zu verankern."
|
||||
}
|
||||
"documentation_url": "Dokumentations-URL (optional)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Werden Sie Experte für X",
|
||||
|
||||
@@ -2276,6 +2276,7 @@
|
||||
},
|
||||
"generate_transcript": "Generate transcription",
|
||||
"generate_transcript_in_progress": "Transcribing…",
|
||||
"view_transcript": "View transcription",
|
||||
"simple_card": {
|
||||
"kind_youtube": "YouTube",
|
||||
"kind_upload": "Upload",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Incrustado",
|
||||
"course_fallback": "Curso",
|
||||
"menu_aria": "Opciones de vídeo"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Ver transcripción"
|
||||
},
|
||||
"slide": {
|
||||
"title": "diapositiva",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "¿Qué profundidad debe tener el curso?",
|
||||
"topic": "Tema o nicho",
|
||||
"expertise_level": "Nivel de experiencia objetivo",
|
||||
"documentation_url": {
|
||||
"hint": "Leeremos este sitio para basar el curso en su producto real."
|
||||
}
|
||||
"documentation_url": "URL de documentación (opcional)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Conviértete en un experto en X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Intégré",
|
||||
"course_fallback": "Cours",
|
||||
"menu_aria": "Options vidéo"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Voir la transcription"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Diapositive",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Jusqu’où doit aller le cours ?",
|
||||
"topic": "Sujet ou niche",
|
||||
"expertise_level": "Niveau d’expertise cible",
|
||||
"documentation_url": {
|
||||
"hint": "Nous lirons ce site pour ancrer le cours dans votre produit réel."
|
||||
}
|
||||
"documentation_url": "URL de la documentation (facultatif)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Devenez un expert sur X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "एंबेडेड",
|
||||
"course_fallback": "पाठ्यक्रम",
|
||||
"menu_aria": "वीडियो विकल्प"
|
||||
}
|
||||
},
|
||||
"view_transcript": "प्रतिलेखन देखें"
|
||||
},
|
||||
"slide": {
|
||||
"title": "फिसल पट्टी",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "पाठ्यक्रम कितना गहरा होना चाहिए?",
|
||||
"topic": "विषय या आला",
|
||||
"expertise_level": "लक्ष्य विशेषज्ञता स्तर",
|
||||
"documentation_url": {
|
||||
"hint": "हम आपके वास्तविक उत्पाद में पाठ्यक्रम को आधार बनाने के लिए इस साइट को पढ़ेंगे।"
|
||||
}
|
||||
"documentation_url": "दस्तावेज़ीकरण URL (वैकल्पिक)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "एक्स पर विशेषज्ञ बनें",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Wbudowany",
|
||||
"course_fallback": "Kurs",
|
||||
"menu_aria": "Opcje wideo"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Zobacz transkrypcję"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Przesuń",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Jak głęboko powinien sięgać kurs?",
|
||||
"topic": "Temat lub nisza",
|
||||
"expertise_level": "Docelowy poziom wiedzy",
|
||||
"documentation_url": {
|
||||
"hint": "Przeczytamy tę witrynę, aby oprzeć kurs na Twoim prawdziwym produkcie."
|
||||
}
|
||||
"documentation_url": "Adres URL dokumentacji (opcjonalnie)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Zostań ekspertem w dziedzinie X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Incorporado",
|
||||
"course_fallback": "Curso",
|
||||
"menu_aria": "Opções de vídeo"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Ver transcrição"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Deslizar",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Quão profundo o curso deve ir?",
|
||||
"topic": "Tópico ou nicho",
|
||||
"expertise_level": "Nível de especialização alvo",
|
||||
"documentation_url": {
|
||||
"hint": "Leremos este site para fundamentar o curso em seu produto real."
|
||||
}
|
||||
"documentation_url": "URL da documentação (opcional)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Torne-se um especialista em X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Встроенный",
|
||||
"course_fallback": "Курс",
|
||||
"menu_aria": "Параметры видео"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Посмотреть транскрипцию"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Слайд",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Насколько глубоким должен быть курс?",
|
||||
"topic": "Тема или ниша",
|
||||
"expertise_level": "Целевой уровень экспертизы",
|
||||
"documentation_url": {
|
||||
"hint": "Мы прочитаем этот сайт, чтобы закрепить курс на вашем реальном продукте."
|
||||
}
|
||||
"documentation_url": "URL-адрес документации (необязательно)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Станьте экспертом по X",
|
||||
|
||||
@@ -1872,7 +1872,8 @@
|
||||
"kind_generic": "Đã nhúng",
|
||||
"course_fallback": "Khóa học",
|
||||
"menu_aria": "Tùy chọn video"
|
||||
}
|
||||
},
|
||||
"view_transcript": "Xem bản chép lời"
|
||||
},
|
||||
"slide": {
|
||||
"title": "Trượt",
|
||||
@@ -2163,9 +2164,7 @@
|
||||
"depth": "Khóa học nên đi sâu đến mức nào?",
|
||||
"topic": "Chủ đề hoặc niche",
|
||||
"expertise_level": "Mục tiêu trình độ chuyên môn",
|
||||
"documentation_url": {
|
||||
"hint": "Chúng tôi sẽ đọc trang web này để xây dựng khóa học về sản phẩm thực của bạn."
|
||||
}
|
||||
"documentation_url": "URL tài liệu (tùy chọn)"
|
||||
},
|
||||
"expert_on_x": {
|
||||
"title": "Trở thành chuyên gia về X",
|
||||
|
||||
Reference in New Issue
Block a user