Skip to content

Commit 41fa171

Browse files
author
Sylvain Girod
committed
rfc: add ttaas transcription rfc proposal
1 parent aecab49 commit 41fa171

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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

Comments
 (0)