From 1bfb791e0539df54d1d007683719dcb883870e1d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 13 Jun 2024 09:23:12 +0200 Subject: [PATCH] Integrate transcription in PeerTube --- .github/workflows/test.yml | 14 ++ .gitignore | 3 + .../src/server/process/process.ts | 43 ++++-- .../src/server/process/shared/common.ts | 4 +- .../src/server/process/shared/index.ts | 2 +- .../process/shared/process-transcription.ts | 79 ++++++++++ .../process/shared/transcoding-logger.ts | 19 --- .../server/process/shared/winston-logger.ts | 19 +++ .../src/server/shared/supported-job.ts | 8 +- .../src/shared/config-manager.ts | 18 +++ .../edit-basic-configuration.component.html | 31 +++- .../edit-basic-configuration.component.ts | 12 ++ .../edit-custom-config.component.ts | 6 + .../overview/videos/video-list.component.ts | 31 +++- .../app/+admin/system/jobs/jobs.component.ts | 1 + ...ount-notification-preferences.component.ts | 6 +- .../shared/video-edit.component.html | 15 +- .../shared/video-edit.component.scss | 5 - .../shared/video-edit.component.ts | 27 +++- .../video-go-live.component.html | 2 +- .../video-import-torrent.component.html | 3 +- .../video-import-url.component.html | 3 +- .../video-upload.component.html | 2 +- .../+video-edit/video-update.component.html | 1 + .../instance-features-table.component.html | 7 + .../buttons/action-dropdown.component.scss | 4 + .../users/user-notification.model.ts | 13 ++ .../video-caption/video-caption.service.ts | 15 +- .../shared/shared-main/video/video.model.ts | 4 + .../video-actions-dropdown.component.ts | 28 +++- .../user-notifications.component.html | 8 + config/default.yaml | 28 ++++ config/production.yaml.example | 28 ++++ config/test.yaml | 3 + packages/ffmpeg/src/ffmpeg-command-wrapper.ts | 19 ++- packages/jiwer/README.md | 37 ----- packages/jiwer/requirements.txt | 1 - packages/jiwer/src/index.ts | 1 - packages/models/src/common/index.ts | 1 + .../models/src/common/simple-logger.model.ts | 6 + .../src/runners/runner-job-payload.model.ts | 9 +- .../runner-job-private-payload.model.ts | 9 +- .../runners/runner-job-success-body.model.ts | 13 +- .../src/runners/runner-job-type.type.ts | 3 +- .../models/src/server/custom-config.model.ts | 8 + packages/models/src/server/job.model.ts | 12 ++ .../models/src/server/server-config.model.ts | 4 + .../src/server/server-error-code.enum.ts | 47 +++--- .../users/user-notification-setting.model.ts | 2 + .../src/users/user-notification.model.ts | 11 +- packages/models/src/videos/caption/index.ts | 3 +- .../caption/video-caption-generate.model.ts | 3 + .../import/video-import-create.model.ts | 3 + .../models/src/videos/video-create.model.ts | 3 + .../src/runners/runner-jobs-command.ts | 16 +- .../src/server/config-command.ts | 23 +++ .../src/shared/abstract-command.ts | 10 +- .../src/videos/captions-command.ts | 18 +++ .../src/videos/video-imports-command.ts | 17 +- ...muniquer-lors-dune-classe-transplantee.mp4 | Bin 11443901 -> 1711524 bytes .../transcription/videos/derive_sectaire.mp4 | Bin 5859113 -> 1705515 bytes packages/tests/package.json | 3 +- packages/tests/requirements.txt | 2 + packages/tests/src/api/check-params/index.ts | 1 + .../api/check-params/user-notifications.ts | 1 + .../api/check-params/video-transcription.ts | 106 +++++++++++++ .../notifications/caption-notifications.ts | 81 ++++++++++ packages/tests/src/api/notifications/index.ts | 1 + packages/tests/src/api/runners/index.ts | 1 + .../src/api/runners/runner-transcription.ts | 109 +++++++++++++ packages/tests/src/api/server/config.ts | 9 ++ packages/tests/src/api/videos/index.ts | 13 +- .../src/api/videos/video-transcription.ts | 145 ++++++++++++++++++ packages/tests/src/jiwer/jiwer-cli.spec.ts | 2 +- packages/tests/src/peertube-runner/index.ts | 1 + .../src/peertube-runner/live-transcoding.ts | 2 +- .../src/peertube-runner/studio-transcoding.ts | 2 +- .../peertube-runner/video-transcription.ts | 89 +++++++++++ .../src/peertube-runner/vod-transcoding.ts | 2 +- packages/tests/src/shared/directories.ts | 6 +- packages/tests/src/shared/fixture-urls.ts | 1 + packages/tests/src/shared/notifications.ts | 38 ++++- packages/tests/src/shared/transcription.ts | 81 ++++++++++ .../levenshtein-distance.spec.ts | 2 +- .../transcription/transcriber-factory.spec.ts | 17 +- .../transcript-file-evaluator.spec.ts | 13 +- .../transcript/transcript-file.spec.ts | 16 +- .../transcription/transcription-run.spec.ts | 1 - .../tests/src/transcription/utils.spec.ts | 21 +-- .../openai-transcriber.spec.ts | 75 +++++---- .../timestamped-transcriber.spec.ts | 133 ---------------- .../whisper-ctranslate2.spec.ts | 132 ++++++++++------ packages/tests/tsconfig.json | 4 +- packages/transcription-devtools/README.md | 63 ++++++++ .../package.json | 6 +- .../transcription-devtools/requirements.txt | 1 + .../src/benchmark.ts | 53 ++++--- packages/transcription-devtools/src/index.ts | 5 + .../src/jiwer-cli.ts | 0 .../src/levenshtein.ts | 0 .../transcript-file-evaluator-interface.ts | 0 .../src}/transcript-file-evaluator.ts | 10 +- .../src/utils.ts | 0 .../tsconfig.json | 7 +- packages/transcription/README.md | 71 ++++----- packages/transcription/package.json | 4 +- packages/transcription/requirements.txt | 3 - .../transcription/src/abstract-transcriber.ts | 60 +++++--- packages/transcription/src/index.ts | 5 +- .../transcription/src/transcriber-factory.ts | 42 +++-- .../src/{transcript => }/transcript-file.ts | 30 +--- .../transcription/src/transcript/index.ts | 3 - .../transcript/transcript-file-interface.ts | 3 - .../transcription/src/transcription-engine.ts | 21 +-- .../transcription/src/transcription-run.ts | 11 +- packages/transcription/src/whisper/README.md | 0 packages/transcription/src/whisper/engines.ts | 39 +---- .../transcriber/ctranslate2-transcriber.ts | 38 +++-- .../src/whisper/transcriber/index.ts | 1 - .../whisper/transcriber/openai-transcriber.ts | 61 +++++--- .../transcriber/timestamped-transcriber.ts | 55 ------- packages/transcription/tsconfig.json | 1 - scripts/ci.sh | 9 +- server/core/controllers/api/config.ts | 24 +-- server/core/controllers/api/runners/jobs.ts | 61 ++++---- .../controllers/api/users/my-notifications.ts | 1 + .../core/controllers/api/videos/captions.ts | 41 ++++- server/core/controllers/api/videos/import.ts | 3 +- .../helpers/custom-validators/runners/jobs.ts | 67 ++++---- server/core/initializers/config.ts | 11 ++ server/core/initializers/constants.ts | 18 ++- .../migrations/0855-transcription.ts | 67 ++++++++ .../lib/job-queue/handlers/video-import.ts | 25 ++- .../job-queue/handlers/video-live-ending.ts | 28 ++-- .../job-queue/handlers/video-transcription.ts | 21 +++ server/core/lib/job-queue/job-queue.ts | 48 +++--- server/core/lib/local-video-creator.ts | 9 +- server/core/lib/notifier/notifier.ts | 17 +- .../core/lib/notifier/shared/caption/index.ts | 1 + ...video-transcription-generated-for-owner.ts | 63 ++++++++ server/core/lib/notifier/shared/index.ts | 1 + .../job-handlers/abstract-job-handler.ts | 7 + .../abstract-vod-transcoding-job-handler.ts | 6 +- server/core/lib/runners/job-handlers/index.ts | 1 + .../job-handlers/runner-job-handlers.ts | 6 +- .../lib/runners/job-handlers/shared/index.ts | 1 - .../shared/{vod-helpers.ts => utils.ts} | 4 +- .../job-handlers/transcription-job-handler.ts | 101 ++++++++++++ .../video-studio-transcoding-job-handler.ts | 6 +- ...vod-audio-merge-transcoding-job-handler.ts | 14 +- .../vod-hls-transcoding-job-handler.ts | 20 +-- .../vod-web-video-transcoding-job-handler.ts | 14 +- server/core/lib/server-config-manager.ts | 3 + .../importers/user-settings-importer.ts | 3 +- server/core/lib/user.ts | 3 +- server/core/lib/video-captions.ts | 139 ++++++++++++++++- server/core/lib/video-file.ts | 2 +- server/core/lib/video-jobs.ts | 10 +- server/core/lib/video-pre-import.ts | 1 + .../validators/videos/video-captions.ts | 86 +++++++++-- .../user-notitication-list-query-builder.ts | 14 +- .../models/user/user-notification-setting.ts | 10 ++ server/core/models/user/user-notification.ts | 32 ++++ server/core/models/video/video-caption.ts | 49 +++--- server/core/models/video/video-job-info.ts | 12 +- .../types/models/user/user-notification.ts | 10 +- .../core/types/models/video/video-caption.ts | 2 +- server/tsconfig.types.json | 3 +- support/doc/api/openapi.yaml | 43 +++++- support/doc/dependencies.md | 20 +-- support/doc/development/tests.md | 6 + tsconfig.eslint.json | 2 +- 172 files changed, 2674 insertions(+), 945 deletions(-) create mode 100644 apps/peertube-runner/src/server/process/shared/process-transcription.ts delete mode 100644 apps/peertube-runner/src/server/process/shared/transcoding-logger.ts create mode 100644 apps/peertube-runner/src/server/process/shared/winston-logger.ts delete mode 100644 packages/jiwer/README.md delete mode 100644 packages/jiwer/requirements.txt delete mode 100644 packages/jiwer/src/index.ts create mode 100644 packages/models/src/common/simple-logger.model.ts create mode 100644 packages/models/src/videos/caption/video-caption-generate.model.ts create mode 100644 packages/tests/requirements.txt create mode 100644 packages/tests/src/api/check-params/video-transcription.ts create mode 100644 packages/tests/src/api/notifications/caption-notifications.ts create mode 100644 packages/tests/src/api/runners/runner-transcription.ts create mode 100644 packages/tests/src/api/videos/video-transcription.ts create mode 100644 packages/tests/src/peertube-runner/video-transcription.ts create mode 100644 packages/tests/src/shared/transcription.ts delete mode 100644 packages/tests/src/transcription/transcription-run.spec.ts rename packages/tests/src/transcription/whisper/{transcriber => }/openai-transcriber.spec.ts (70%) delete mode 100644 packages/tests/src/transcription/whisper/transcriber/timestamped-transcriber.spec.ts rename packages/tests/src/transcription/whisper/{transcriber => }/whisper-ctranslate2.spec.ts (61%) create mode 100644 packages/transcription-devtools/README.md rename packages/{jiwer => transcription-devtools}/package.json (65%) create mode 100644 packages/transcription-devtools/requirements.txt rename packages/{transcription => transcription-devtools}/src/benchmark.ts (82%) create mode 100644 packages/transcription-devtools/src/index.ts rename packages/{jiwer => transcription-devtools}/src/jiwer-cli.ts (100%) rename packages/{transcription => transcription-devtools}/src/levenshtein.ts (100%) rename packages/{transcription/src/transcript => transcription-devtools/src}/transcript-file-evaluator-interface.ts (100%) rename packages/{transcription/src/transcript => transcription-devtools/src}/transcript-file-evaluator.ts (75%) rename packages/{transcription => transcription-devtools}/src/utils.ts (100%) rename packages/{jiwer => transcription-devtools}/tsconfig.json (51%) delete mode 100644 packages/transcription/requirements.txt rename packages/transcription/src/{transcript => }/transcript-file.ts (69%) delete mode 100644 packages/transcription/src/transcript/index.ts delete mode 100644 packages/transcription/src/transcript/transcript-file-interface.ts delete mode 100644 packages/transcription/src/whisper/README.md delete mode 100644 packages/transcription/src/whisper/transcriber/timestamped-transcriber.ts create mode 100644 server/core/initializers/migrations/0855-transcription.ts create mode 100644 server/core/lib/job-queue/handlers/video-transcription.ts create mode 100644 server/core/lib/notifier/shared/caption/index.ts create mode 100644 server/core/lib/notifier/shared/caption/video-transcription-generated-for-owner.ts delete mode 100644 server/core/lib/runners/job-handlers/shared/index.ts rename server/core/lib/runners/job-handlers/shared/{vod-helpers.ts => utils.ts} (87%) create mode 100644 server/core/lib/runners/job-handlers/transcription-job-handler.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04bff26aa..1fa7704df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,6 +71,20 @@ jobs: ${{ runner.OS }}-fixtures- ${{ runner.OS }}- + - name: Cache PeerTube pip directory + uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + key: ${{ runner.OS }}-${{ matrix.test_suite }}-pip-v1 + + - name: Cache Hugging Face models + uses: actions/cache@v4 + with: + path: | + ~/.cache/huggingface + key: ${{ runner.OS }}-${{ matrix.test_suite }}-hugging-face-v1 + - name: Set env test variable (schedule) if: github.event_name != 'schedule' run: | diff --git a/.gitignore b/.gitignore index 6865442eb..cf3b25a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,11 @@ yarn-error.log /test4/ /test5/ /test6/ + +# Big fixtures generated/downloaded on-demand /packages/tests/fixtures/video_high_bitrate_1080p.mp4 /packages/tests/fixtures/video_59fps.mp4 +/packages/tests/fixtures/transcription/models-v1/ # Production /storage diff --git a/apps/peertube-runner/src/server/process/process.ts b/apps/peertube-runner/src/server/process/process.ts index e8a1d7c28..b20c2297d 100644 --- a/apps/peertube-runner/src/server/process/process.ts +++ b/apps/peertube-runner/src/server/process/process.ts @@ -1,6 +1,7 @@ import { RunnerJobLiveRTMPHLSTranscodingPayload, RunnerJobStudioTranscodingPayload, + RunnerJobTranscriptionPayload, RunnerJobVODAudioMergeTranscodingPayload, RunnerJobVODHLSTranscodingPayload, RunnerJobVODWebVideoTranscodingPayload @@ -9,25 +10,41 @@ import { logger } from '../../shared/index.js' import { processAudioMergeTranscoding, processHLSTranscoding, ProcessOptions, processWebVideoTranscoding } from './shared/index.js' import { ProcessLiveRTMPHLSTranscoding } from './shared/process-live.js' import { processStudioTranscoding } from './shared/process-studio.js' +import { processVideoTranscription } from './shared/process-transcription.js' export async function processJob (options: ProcessOptions) { const { server, job } = options logger.info(`[${server.url}] Processing job of type ${job.type}: ${job.uuid}`, { payload: job.payload }) - if (job.type === 'vod-audio-merge-transcoding') { - await processAudioMergeTranscoding(options as ProcessOptions) - } else if (job.type === 'vod-web-video-transcoding') { - await processWebVideoTranscoding(options as ProcessOptions) - } else if (job.type === 'vod-hls-transcoding') { - await processHLSTranscoding(options as ProcessOptions) - } else if (job.type === 'live-rtmp-hls-transcoding') { - await new ProcessLiveRTMPHLSTranscoding(options as ProcessOptions).process() - } else if (job.type === 'video-studio-transcoding') { - await processStudioTranscoding(options as ProcessOptions) - } else { - logger.error(`Unknown job ${job.type} to process`) - return + switch (job.type) { + case 'vod-audio-merge-transcoding': + await processAudioMergeTranscoding(options as ProcessOptions) + break + + case 'vod-web-video-transcoding': + await processWebVideoTranscoding(options as ProcessOptions) + break + + case 'vod-hls-transcoding': + await processHLSTranscoding(options as ProcessOptions) + break + + case 'live-rtmp-hls-transcoding': + await new ProcessLiveRTMPHLSTranscoding(options as ProcessOptions).process() + break + + case 'video-studio-transcoding': + await processStudioTranscoding(options as ProcessOptions) + break + + case 'video-transcription': + await processVideoTranscription(options as ProcessOptions) + break + + default: + logger.error(`Unknown job ${job.type} to process`) + return } logger.info(`[${server.url}] Finished processing job of type ${job.type}: ${job.uuid}`) diff --git a/apps/peertube-runner/src/server/process/shared/common.ts b/apps/peertube-runner/src/server/process/shared/common.ts index 09241d93b..cf7682991 100644 --- a/apps/peertube-runner/src/server/process/shared/common.ts +++ b/apps/peertube-runner/src/server/process/shared/common.ts @@ -5,7 +5,7 @@ import { RunnerJob, RunnerJobPayload } from '@peertube/peertube-models' import { buildUUID } from '@peertube/peertube-node-utils' import { PeerTubeServer } from '@peertube/peertube-server-commands' import { ConfigManager, downloadFile, logger } from '../../../shared/index.js' -import { getTranscodingLogger } from './transcoding-logger.js' +import { getWinstonLogger } from './winston-logger.js' export type JobWithToken = RunnerJob & { jobToken: string } @@ -101,6 +101,6 @@ function getCommonFFmpegOptions () { available: getDefaultAvailableEncoders(), encodersToTry: getDefaultEncodersToTry() }, - logger: getTranscodingLogger() + logger: getWinstonLogger() } } diff --git a/apps/peertube-runner/src/server/process/shared/index.ts b/apps/peertube-runner/src/server/process/shared/index.ts index 638bf127f..67d556f91 100644 --- a/apps/peertube-runner/src/server/process/shared/index.ts +++ b/apps/peertube-runner/src/server/process/shared/index.ts @@ -1,3 +1,3 @@ export * from './common.js' export * from './process-vod.js' -export * from './transcoding-logger.js' +export * from './winston-logger.js' diff --git a/apps/peertube-runner/src/server/process/shared/process-transcription.ts b/apps/peertube-runner/src/server/process/shared/process-transcription.ts new file mode 100644 index 000000000..715433f09 --- /dev/null +++ b/apps/peertube-runner/src/server/process/shared/process-transcription.ts @@ -0,0 +1,79 @@ +import { hasAudioStream } from '@peertube/peertube-ffmpeg' +import { RunnerJobTranscriptionPayload, TranscriptionSuccess } from '@peertube/peertube-models' +import { buildSUUID } from '@peertube/peertube-node-utils' +import { TranscriptionModel, WhisperBuiltinModel, transcriberFactory } from '@peertube/peertube-transcription' +import { remove } from 'fs-extra/esm' +import { join } from 'path' +import { ConfigManager } from '../../../shared/config-manager.js' +import { logger } from '../../../shared/index.js' +import { ProcessOptions, downloadInputFile, scheduleTranscodingProgress } from './common.js' +import { getWinstonLogger } from './winston-logger.js' + +export async function processVideoTranscription (options: ProcessOptions) { + const { server, job, runnerToken } = options + + const config = ConfigManager.Instance.getConfig().transcription + + const payload = job.payload + + let inputPath: string + + const updateProgressInterval = scheduleTranscodingProgress({ + job, + server, + runnerToken, + progressGetter: () => undefined + }) + + const outputPath = join(ConfigManager.Instance.getTranscriptionDirectory(), buildSUUID()) + + const transcriber = transcriberFactory.createFromEngineName({ + engineName: config.engine, + enginePath: config.enginePath, + logger: getWinstonLogger() + }) + + try { + logger.info(`Downloading input file ${payload.input.videoFileUrl} for transcription job ${job.jobToken}`) + + inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job }) + + logger.info(`Downloaded input file ${payload.input.videoFileUrl} for job ${job.jobToken}. Running transcription.`) + + if (await hasAudioStream(inputPath) !== true) { + await server.runnerJobs.error({ + jobToken: job.jobToken, + jobUUID: job.uuid, + runnerToken, + message: 'This input file does not contain audio' + }) + + return + } + + const transcriptFile = await transcriber.transcribe({ + mediaFilePath: inputPath, + model: config.modelPath + ? await TranscriptionModel.fromPath(config.modelPath) + : new WhisperBuiltinModel(config.model), + format: 'vtt', + transcriptDirectory: outputPath + }) + + const successBody: TranscriptionSuccess = { + inputLanguage: transcriptFile.language, + vttFile: transcriptFile.path + } + + await server.runnerJobs.success({ + jobToken: job.jobToken, + jobUUID: job.uuid, + runnerToken, + payload: successBody + }) + } finally { + if (inputPath) await remove(inputPath) + if (outputPath) await remove(outputPath) + if (updateProgressInterval) clearInterval(updateProgressInterval) + } +} diff --git a/apps/peertube-runner/src/server/process/shared/transcoding-logger.ts b/apps/peertube-runner/src/server/process/shared/transcoding-logger.ts deleted file mode 100644 index d0775e13b..000000000 --- a/apps/peertube-runner/src/server/process/shared/transcoding-logger.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { LogFn } from 'pino' -import { logger } from '../../../shared/index.js' - -export function getTranscodingLogger () { - return { - info: buildWinstonLogger(logger.info.bind(logger)), - debug: buildWinstonLogger(logger.debug.bind(logger)), - warn: buildWinstonLogger(logger.warn.bind(logger)), - error: buildWinstonLogger(logger.error.bind(logger)) - } -} - -function buildWinstonLogger (log: LogFn) { - return (arg1: string, arg2?: object) => { - if (arg2) return log(arg2, arg1) - - return log(arg1) - } -} diff --git a/apps/peertube-runner/src/server/process/shared/winston-logger.ts b/apps/peertube-runner/src/server/process/shared/winston-logger.ts new file mode 100644 index 000000000..d2958ea6a --- /dev/null +++ b/apps/peertube-runner/src/server/process/shared/winston-logger.ts @@ -0,0 +1,19 @@ +import { LogFn } from 'pino' +import { logger } from '../../../shared/index.js' + +export function getWinstonLogger () { + return { + info: buildLogLevelFn(logger.info.bind(logger)), + debug: buildLogLevelFn(logger.debug.bind(logger)), + warn: buildLogLevelFn(logger.warn.bind(logger)), + error: buildLogLevelFn(logger.error.bind(logger)) + } +} + +function buildLogLevelFn (log: LogFn) { + return (arg1: string, arg2?: object) => { + if (arg2) return log(arg2, arg1) + + return log(arg1) + } +} diff --git a/apps/peertube-runner/src/server/shared/supported-job.ts b/apps/peertube-runner/src/server/shared/supported-job.ts index d905b5de2..38cd28140 100644 --- a/apps/peertube-runner/src/server/shared/supported-job.ts +++ b/apps/peertube-runner/src/server/shared/supported-job.ts @@ -1,15 +1,16 @@ import { RunnerJobLiveRTMPHLSTranscodingPayload, RunnerJobPayload, - RunnerJobType, RunnerJobStudioTranscodingPayload, + RunnerJobTranscriptionPayload, + RunnerJobType, RunnerJobVODAudioMergeTranscodingPayload, RunnerJobVODHLSTranscodingPayload, RunnerJobVODWebVideoTranscodingPayload, VideoStudioTaskPayload } from '@peertube/peertube-models' -const supportedMatrix = { +const supportedMatrix: { [ id in RunnerJobType ]: (payload: RunnerJobPayload) => boolean } = { 'vod-web-video-transcoding': (_payload: RunnerJobVODWebVideoTranscodingPayload) => { return true }, @@ -29,6 +30,9 @@ const supportedMatrix = { if (!Array.isArray(tasks)) return false return tasks.every(t => t && supported.has(t.name)) + }, + 'video-transcription': (_payload: RunnerJobTranscriptionPayload) => { + return true } } diff --git a/apps/peertube-runner/src/shared/config-manager.ts b/apps/peertube-runner/src/shared/config-manager.ts index 84a326a16..97a70204a 100644 --- a/apps/peertube-runner/src/shared/config-manager.ts +++ b/apps/peertube-runner/src/shared/config-manager.ts @@ -1,4 +1,5 @@ import { parse, stringify } from '@iarna/toml' +import { TranscriptionEngineName, WhisperBuiltinModelName } from '@peertube/peertube-transcription' import envPaths from 'env-paths' import { ensureDir, pathExists, remove } from 'fs-extra/esm' import { readFile, writeFile } from 'fs/promises' @@ -24,6 +25,13 @@ type Config = { runnerName: string runnerDescription?: string }[] + + transcription: { + engine: TranscriptionEngineName + enginePath: string | null + model: WhisperBuiltinModelName + modelPath: string | null + } } export class ConfigManager { @@ -37,6 +45,12 @@ export class ConfigManager { threads: 2, nice: 20 }, + transcription: { + engine: 'whisper-ctranslate2', + enginePath: null, + model: 'small', + modelPath: null + }, registeredInstances: [] } @@ -98,6 +112,10 @@ export class ConfigManager { return join(paths.cache, this.id, 'transcoding') } + getTranscriptionDirectory () { + return join(paths.cache, this.id, 'transcription') + } + getSocketDirectory () { return join(paths.data, this.id) } diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html index 3de40666f..ea8094d5f 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html @@ -318,7 +318,7 @@ > - ⛔ You need to allow import with HTTP URL to be able to activate this feature. + ⛔ You need to allow import with HTTP URL to be able to activate this feature. @@ -359,7 +359,6 @@ -
+
+ +
+ + + Automatically create a subtitle file of uploaded/imported VOD videos + + + +
+ + + + Use remote runners to process transcription tasks. + Remote runners has to register on your instance first. + + + +
+
+
+
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts index 9f1cbc758..98510c7c3 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts @@ -137,6 +137,18 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges { return { 'disabled-checkbox-extra': !this.isSearchIndexEnabled() } } + // --------------------------------------------------------------------------- + + isTranscriptionEnabled () { + return this.form.value['videoTranscription']['enabled'] === true + } + + getTranscriptionRunnerDisabledClass () { + return { 'disabled-checkbox-extra': !this.isTranscriptionEnabled() } + } + + // --------------------------------------------------------------------------- + isAutoFollowIndexEnabled () { return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true } diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index 6c14b5c55..a85b17165 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts @@ -267,6 +267,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { enabled: null } }, + videoTranscription: { + enabled: null, + remoteRunners: { + enabled: null + } + }, videoFile: { update: { enabled: null diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index 3eb932322..f7d88b752 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts @@ -1,7 +1,7 @@ import { DatePipe, NgClass, NgFor, NgIf } from '@angular/common' import { Component, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Router, RouterLink } from '@angular/router' -import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' +import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' import { formatICU, getAbsoluteAPIUrl } from '@app/helpers' import { VideoDetails } from '@app/shared/shared-main/video/video-details.model' import { VideoFileTokenService } from '@app/shared/shared-main/video/video-file-token.service' @@ -30,6 +30,7 @@ import { VideoActionsDropdownComponent } from '../../../shared/shared-video-miniature/video-actions-dropdown.component' import { VideoAdminService } from './video-admin.service' +import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service' @Component({ selector: 'my-video-list', @@ -84,7 +85,8 @@ export class VideoListComponent extends RestTable