|
| 1 | +- Start Date: 2026-06-25 |
| 2 | +- RFC PR: [#XXXX](https://github.com/CERNDocumentServer/cds-videos/pull/XXXX) |
| 3 | +- Authors: Sylvain Girod |
| 4 | + |
| 5 | +# TTaaS Integration: Automatic Transcription and Translation |
| 6 | + |
| 7 | +## Summary |
| 8 | + |
| 9 | +Integrate the CERN Transcription and Translation Service (TTaaS, Weblecture Service) into the CDS Videos processing flow. On an opt-in basis, CDS Videos submits a video's master file to TTaaS, retrieves the generated WebVTT (original transcription plus EN/FR machine translation), and stores the results as subtitle files on the record. No player changes are required: the output reuses the existing subtitle storage and serialization path. |
| 10 | + |
| 11 | +## Motivation |
| 12 | + |
| 13 | +CDS Videos has no automated transcription. Subtitles are user-uploaded or migrated, and the flow chain (download, metadata extraction, frame extraction, transcode) produces no captions. TTaaS exposes a public REST API and is already the Weblecture team's transcription backend, so it is the natural building block rather than a new in-house ASR pipeline. |
| 14 | + |
| 15 | +- As a viewer, I want captions and translated subtitles for accessibility and search. |
| 16 | +- As a repository manager, I want transcription available on demand without a manual workflow. |
| 17 | +- As an administrator, I want transcription status and failures observable, and isolated from the rest of video processing. |
| 18 | + |
| 19 | +## Detailed design |
| 20 | + |
| 21 | +### TTaaS API |
| 22 | + |
| 23 | +From the QA instance (`https://ttaas-qa.web.cern.ch/api/public/v1/`, Swagger at `/swagger.json`): |
| 24 | + |
| 25 | +- **Auth:** Bearer token in `Authorization`. `/test/ping/` is the only unauthenticated route (connectivity probe). |
| 26 | +- **Ingest:** `POST /uploads/ingest/`, `multipart/form-data`. Required: `mediaFile`, `title`, `language` (`EN`/`FR`), `username`, `notificationMethod` (`NONE`/`EMAIL`/`CALLBACK`). Optional: `notificationUrl`, `referenceUrl`, `comments`, CERN Search fields. 2 GB max. Returns a `PreUpload` (`id`, `mediaId`, `state`). |
| 27 | +- **Deduplication:** ingest is keyed on the file MD5. A re-ingest of the same bytes returns the existing media (`ALREADY_EXISTS`, `existingMediaId`); `GET /media-files/checksum/{checksum}/` probes this ahead of upload. |
| 28 | +- **Status:** `GET /uploads/{media_id}/`. Pipeline runs `CREATED` → `SUBMITTED` → transcription/translation states → `COMPLETED` | `ERROR_*`. |
| 29 | +- **Results:** `GET /media-files/{media_id}/languages/` enumerates available languages; `GET /media-files/{media_id}/languages/{lang}/` returns the WebVTT; `GET /media-files/{media_id}/` returns media metadata. |
| 30 | +- **Translation:** `PATCH /uploads/translation/{media_id}/` requests a translation for an existing upload. |
| 31 | +- **Status retrieval:** this integration ingests with `notificationMethod: NONE` and tracks progress by polling `GET /uploads/{media_id}/`. Callback/email notifications are not used. |
| 32 | + |
| 33 | +### Current state in CDS Videos |
| 34 | + |
| 35 | +The flow is a Celery chain in `cds/modules/flows/api.py` (`_build_chain`): |
| 36 | + |
| 37 | +``` |
| 38 | +DownloadTask -> ExtractMetadataTask -> ExtractFramesTask -> TranscodeVideoTask |
| 39 | +``` |
| 40 | + |
| 41 | +Subtitles are bucket files tagged `context_type=subtitle` with a `language` tag, exposed via `get_video_subtitles` (`cds/modules/records/api.py`) and consumed by the player and VTT serializer. Nothing produces subtitles automatically. |
| 42 | + |
| 43 | +### Proposed integration |
| 44 | + |
| 45 | +Add a `TranscriptionTask` branching off the flow. It is decoupled from the transcode result and must not gate publication: |
| 46 | + |
| 47 | +```mermaid |
| 48 | +flowchart TD |
| 49 | + A["DownloadTask"] |
| 50 | + B["ExtractMetadataTask"] |
| 51 | + C["ExtractFramesTask"] |
| 52 | + D["TranscodeVideoTask"] |
| 53 | + E["TranscriptionTask (TTaaS ingest)"] |
| 54 | + F["TTaaS processing (async)"] |
| 55 | + G["Poll GET /uploads/{media_id}/ until COMPLETED"] |
| 56 | + H["Fetch WebVTT per language"] |
| 57 | + I["Store as subtitle ObjectVersions (lang tag)"] |
| 58 | + A --> B --> C --> D |
| 59 | + B --> E |
| 60 | + E --> F --> G --> H --> I |
| 61 | +``` |
| 62 | + |
| 63 | +0. **Gate.** Run only if the per-video opt-in is set and no subtitles exist; otherwise no-op. |
| 64 | +1. **Ingest.** `POST /uploads/ingest/` with `language`, `title`, `notificationMethod: NONE`, streaming the master via `requests_toolbelt.MultipartEncoder`. Persist the returned `mediaId` on the flow/record to correlate status checks. |
| 65 | +2. **Poll.** Drive `GET /uploads/{media_id}/` to a terminal state via a recurrent task with backoff and a hard timeout (no blocking worker loop). |
| 66 | +3. **Fetch.** On `COMPLETED`, `GET .../languages/` then `GET .../languages/{lang}/` per language. |
| 67 | +4. **Store.** Write each WebVTT as a `context_type=subtitle` bucket file with the `language` tag, plus a provenance tag (below). |
| 68 | + |
| 69 | +### Opt-in (per video) |
| 70 | + |
| 71 | +TTaaS is opt-in, disabled by default. Since users may supply their own subtitles, transcription must never run implicitly or contend with a user-provided transcript. |
| 72 | + |
| 73 | +- No video is submitted to TTaaS by default. |
| 74 | +- For a video without subtitles, the user enables TTaaS per video via an explicit control on the deposit form, surfaced only when no user subtitles exist. |
| 75 | +- Backed by a per-video field (`ttaas_enabled`, default `false`). `TranscriptionTask` gates on it. |
| 76 | +- `TTAAS_ENABLED` is an orthogonal platform kill switch. |
| 77 | + |
| 78 | +User-uploaded subtitles take precedence: when present, the option is hidden and TTaaS output never overwrites them. |
| 79 | + |
| 80 | +### Subtitle provenance |
| 81 | + |
| 82 | +TTaaS output is machine-generated and must be distinguishable from user-provided files so a re-run never clobbers a corrected transcript. Tag stored files with e.g. `generated_by=ttaas`. TTaaS also exposes an editor (`GET /editor/{media_id}/` → `editUrl`/`viewUrl`); edits made there can be re-fetched on a later poll or manual refresh if we choose to surface that. |
| 83 | + |
| 84 | +### API workflow summary |
| 85 | + |
| 86 | +| Method | Step | |
| 87 | +| ------ | ---- | |
| 88 | +| GET | (optional) Connectivity via `/test/ping/` | |
| 89 | +| GET | (optional) Checksum probe via `/media-files/checksum/{checksum}/` | |
| 90 | +| POST | Ingest via `/uploads/ingest/` (`notificationMethod: NONE`) | |
| 91 | +| GET | Poll `/uploads/{media_id}/` until `COMPLETED` | |
| 92 | +| GET | List languages via `/media-files/{media_id}/languages/` | |
| 93 | +| GET | Download WebVTT via `/media-files/{media_id}/languages/{lang}/` | |
| 94 | + |
| 95 | +### Configuration |
| 96 | + |
| 97 | +Indicative settings: |
| 98 | + |
| 99 | +- `TTAAS_API_URL` (per-environment, QA vs prod) |
| 100 | +- `TTAAS_API_TOKEN` (secret; not committed) |
| 101 | +- `TTAAS_ENABLED` (platform kill switch) |
| 102 | +- `TTAAS_POLL_INTERVAL` / `TTAAS_POLL_MAX_DURATION` |
| 103 | +- `TTAAS_LANGUAGES` (translation target policy) |
| 104 | + |
| 105 | +### Error handling |
| 106 | + |
| 107 | +TTaaS surfaces explicit failures (`ERROR_SUBMITTING`, `ERROR_UPLOADING`, `ERROR_RUNNING_TRANSCRIPTIONS`, `ERROR_RUNNING_TRANSLATIONS`). The transcription branch is non-blocking: a failure or poll timeout marks the transcription sub-state failed and retriable, never failing the parent flow or blocking publication. The flow status UI represents it as a distinct, optional task. Retry and partial-failure semantics are left open (see Unresolved questions). |
| 108 | + |
| 109 | +## Example |
| 110 | + |
| 111 | +An English talk is uploaded with TTaaS enabled. After metadata extraction, `TranscriptionTask` ingests the master with `language=EN`; TTaaS produces EN and FR subtitles. CDS Videos polls to `COMPLETED`, fetches both WebVTT files, and stores them as `context_type=subtitle` (`en`, `fr`, `generated_by=ttaas`). The player offers EN and FR captions with no further action. |
| 112 | + |
| 113 | +## Unresolved questions |
| 114 | + |
| 115 | +### Polling strategy |
| 116 | + |
| 117 | +Poll interval, backoff, and hard timeout; scheduling that survives worker restarts without pinning a worker (recurrent self-re-enqueuing task vs blocking loop). |
| 118 | + |
| 119 | +### Error handling and retries |
| 120 | + |
| 121 | +- **Retry policy:** automatic vs user-triggered (consistent with opt-in); attempts and backoff. |
| 122 | +- **Partial failures:** transcription succeeds, translation fails. Store partial and retry only the missing language (`PATCH /uploads/translation/{media_id}/`), or fail the task. |
| 123 | +- **Quota:** ingest can return `500 "Volume quota exceeded"`; this should alert an administrator, not loop. |
| 124 | +- **Visibility:** failure surfacing to the uploader and any re-trigger control. |
| 125 | + |
| 126 | +### Token and account model |
| 127 | + |
| 128 | +Single Bearer token tied to a service account. One shared account for all transcriptions vs per-context; provisioning, rotation, storage. Confirm quota limits. |
| 129 | + |
| 130 | +### Reprocessing and editing ownership |
| 131 | + |
| 132 | +Checksum dedup means re-ingesting the same master returns the existing TTaaS media. Define the re-run policy and ownership once a transcript can also be edited in the TTaaS editor; guarantee user-edited subtitles are never overwritten. |
| 133 | + |
| 134 | +### Weblectures multi-video records |
| 135 | + |
| 136 | +Presenter vs presentation track: which is transcribed, and how it maps when videos are stored as additional files. |
| 137 | + |
| 138 | +### QA pipeline stability |
| 139 | + |
| 140 | +On QA, fresh uploads stalled in a pre-submission state and upload IDs were non-unique. Likely environment issues rather than API contract, but validate against a healthy instance before rollout. |
| 141 | + |
| 142 | +## Resources/Timeline |
| 143 | + |
| 144 | +> Which resources are available to implement this RFC and what is the overall timeline? |
| 145 | +
|
| 146 | +To be defined. Suggested phasing: (1) TTaaS client and feature-flagged `TranscriptionTask` with polling; (2) per-video opt-in UI and subtitle storage with provenance; (3) error/retry semantics and flow status UI; (4) weblectures enablement. |
0 commit comments