Public document and services¶
Canonical JSON uses named objects. A minimal document is:
{
"schema_version": 1,
"time_unit": "ms",
"language": "en",
"media_duration_ms": 3000,
"utterances": [
{
"text": "Hello, 世界!\n",
"separator_after": "\n",
"start_ms": 0,
"end_ms": 1000,
"speaker_key": "generation-uuid:A",
"raw_speaker_label": "Speaker A",
"words": [
{
"key": "generation-uuid:token-1",
"text": "Hello",
"start_ms": 0,
"end_ms": 400,
"char_start": 0,
"char_end": 5,
"confidence": 0.98765,
"alignment": "measured"
}
]
}
]
}
Optional utterance speaker is { "entity_type": "node", "id": "42" }; speaker_override preserves individual assignments during cluster remaps. Keys identify tokens across corrections and must be unique within the whole document. Generation-scoped speaker cluster keys prevent collisions between provider runs. Missing times/spans are paired null, never an invented zero. Text and separators are UTF-8; separators contain whitespace only. All present times are integer milliseconds in the original media. Mapped text must match its Unicode code-point span exactly.
Optional provenance.speaker_suggestions lists names an engine returned for speaker clusters: each has a speaker_key present in the document, its raw_speaker_label, a plain-text name, source: "automatic" and an optional entity of entity_type and id. Imports store them on the transcription revision and exports include them, leaving out an entity the viewer cannot see. Suggestions never assign a speaker.
TranscriptionResult::fromArray() validates named input and derives actual timing coverage and warning strings. Timing order/containment anomalies are retained for review. Imports replace the entire owned utterance graph; they do not reconstruct text by joining words. Configured additional fields are edited through ordinary entity form displays and are outside this version-one exchange schema. An exporter decorator can add a site's namespaced metadata.
Imports resolve language against Drupal's available languages. Regional codes match case-insensitively with either _ or -: an available exact regional language wins, otherwise its available base language is used (en_us becomes en on an English site). An unavailable language aborts the save and must first be configured in Drupal. und preserves the parent's current language. Raw provider language codes remain in the protected provider artifact; canonical exports use the resolved Drupal language.
Inject transcribe.editor (TranscriptEditorInterface) to save:
$result = TranscriptionResult::fromArray($namedDocument);
$parent = $editor->import($newTranscription, $result);
$parent = $editor->edit($parent, (int) $parent->getRevisionId(), [
['type' => 'correct', 'uuid' => $utteranceUuid, 'text' => $exactText],
]);
For an existing parent, import() also requires its expected latest revision ID as the third argument. edit() always requires it. The selected parent can be historical when restoring; the expected revision still describes the latest committed revision. Each operation acquires a persistent lock, validates the graph, and saves child and parent revisions inside one SQL transaction. RevisionConflictException requires a reload and deliberate reconciliation. Database rollback cannot undo external side effects performed by a subscriber.
Both methods take an optional final $newRevision argument. NULL uses the transcription type's Create new revision setting (default on). FALSE saves the latest revision in place, rewriting only new or changed utterances; it refuses a historical parent. A new parent revision gives every utterance a new Paragraph revision, including its word data, so pass FALSE for follow-up machine edits such as naming speakers right after an import:
$parent = $editor->import($newTranscription, $result);
$parent = $editor->edit($parent, (int) $parent->getRevisionId(), $remaps, FALSE);
| Operation | Additional properties |
|---|---|
correct |
uuid, exact text; optional separator_after, paired start_ms/end_ms |
append |
exact text, optional separator_after (defaults to newline); creates untimed tokens |
split |
uuid, Unicode code-point offset between mapped tokens; cannot split inside a token or through unmapped evidence |
merge |
uuid; joins the following utterance with the same speaker reference and cluster, preserving the intervening separator |
remove |
uuid; older parent revisions keep their references |
speaker |
uuid, speaker_type, string speaker_id; empty ID clears; records an individual override |
remap |
speaker_key, speaker_type, string speaker_id; preserves individual overrides |
align |
uuid, tokens keyed by existing token ID with paired times and alignment; cannot change text, spans or identities |
reorder |
uuids, an exact permutation of all current child UUIDs |
Automatic corrections preserve unaffected identities and times. A one-token replacement may keep the old identity and interval as stale evidence; only explicit confirmation makes it retained. Added/replaced phrases become untimed. Estimated intervals do not drive measured word highlighting.
transcribe.exporter->export($parent, $format) supports json, txt, srt, vtt. JSON includes named words, explicit separators, source identity and provenance. TXT is exact full_text. Captions use real utterance ranges, skip unknown ranges, escape caption markup and normalize blank cue separators; they are presentation and do not change canonical text. Export routes enforce an export permission and graph/source access, and return uncached attachments. Historical revision exports validate the nested parent identity.
transcribe.query->find($filters, $offset, $limit) returns items, access-filtered count and CacheableMetadata under cache. Filters include source_media, langcode, transcription, revision, speaker_type plus string speaker_id, case-insensitive text, overlapping start_ms/end_ms, and scalar ordinary fields. It applies visibility before counting and paging, returns revision IDs and a seek URL, and searches utterance text. Always bubble returned cache metadata into rendered consumers.
transcribe.text_assembler returns a TextProjection with exact full text and utterance offset maps. transcribe.diagnostics derives timing coverage and warnings using the site's tolerance. transcribe.preferred_resolver chooses an accessible published transcript by media/language and the configured created/changed policy, with ID as a deterministic tie breaker.