Zum Hauptinhalt springen

Wie du das vollständige Transkript einer Aufnahme abrufst

Das Transkript ist die Grundlage, aus der Sally die Zusammenfassung erstellt: wer wann was gesagt hat. Diese Anleitung zeigt, wie du prüfst, ob ein Transkript existiert, was die Antwort enthält, wie du sie klein hältst, wie du es als fertige Datei oder als Untertitel herunterlädst, und endet mit einem Skript, das aus einer Aufnahme eine lesbare Textdatei macht.

Jedes Beispiel funktioniert so, wie es dasteht, sobald SALLY_TOKEN, DIRECTORY_ID und RECORDING_ID gesetzt sind, siehe Schnellstart. Wähl deine Sprache einmal, alle Beispiele im API-Bereich folgen ihr.

Schnellnavigation

  1. Vorher den Status prüfen
  2. Transkript abrufen
  3. Die Antwort klein halten
  4. Als Datei herunterladen
  5. Vollständiges Skript: Transkript als Text exportieren
  6. Endpunkte im Überblick

1. Vorher den Status prüfen​

Ein beendeter Transkriptionslauf ist nicht dasselbe wie ein vorhandenes Transkript. Sieh dir zuerst die Aufnahme an. Mit der Feldauswahl beschränkst du die Antwort auf die drei Statusfelder:

curl "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID?fields=isTranscriptionCompleted,isTranscriptionSucceeded,transcriptionCompletionReason" \
-H "Authorization: Bearer $SALLY_TOKEN"
200 OK
{
"isTranscriptionCompleted": true,
"isTranscriptionSucceeded": true,
"transcriptionCompletionReason": "succeeded"
}
FeldTypBedeutung
isTranscriptionCompletedbooleanDer Lauf ist vorbei, wie auch immer er ausging.
isTranscriptionSucceededbooleanEs gibt ein brauchbares Transkript. Dieses Feld solltest du prüfen.
transcriptionCompletionReasonstringWarum der Lauf endete, siehe die nächste Tabelle.
transcriptionCompletionReasonBedeutung
succeededEs gibt ein brauchbares Transkript.
noSpokenAudioIn der Aufnahme hat niemand gesprochen.
fileEmptyDie Datei war leer.
languageNotDetectedDie Sprache konnte nicht erkannt werden.
quotaExceededDas Transkriptionskontingent war aufgebraucht.
errorDer Lauf ist fehlgeschlagen. Der eigentliche Fehlertext wird bewusst nicht herausgegeben.
unknownDer Lauf ist noch nicht beendet.
Das heißt

Ein Meeting, in dem niemand gesprochen hat, ergibt einen beendeten Lauf ohne Transkript. Das ist kein Fehler und braucht keinen zweiten Versuch, noSpokenAudio sagt es deutlich.

2. Transkript abrufen​

Sobald isTranscriptionSucceeded gleich true ist, rufst du das Transkript ab:

curl "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID/transcription" \
-H "Authorization: Bearer $SALLY_TOKEN"
200 OK
{
"recordingId": "53e2e041-4b34-41c7-a285-634d80b3675d",
"speakers": [
{
"speakerId": "b16c2c6f-d9f5-4709-a27e-41a319410893",
"speakerNumber": 1,
"name": "Anna Berger",
"emailAddress": "anna.berger@example.com"
},
{
"speakerId": "4f0e1c52-7a3b-4d8e-9c61-2b5d8e7f3a10",
"speakerNumber": 2,
"name": null,
"emailAddress": null
}
],
"segments": [
{
"speakerId": "b16c2c6f-d9f5-4709-a27e-41a319410893",
"startTime": 12.4,
"endTime": 17.9,
"text": "Wir haben uns auf den Rollout-Plan für Oktober geeinigt."
},
{
"speakerId": "4f0e1c52-7a3b-4d8e-9c61-2b5d8e7f3a10",
"startTime": 18.2,
"endTime": 21.0,
"text": "Dann passe ich den Zeitplan heute noch an."
}
]
}

Die Antwort enthält zwei Listen, die zusammengehören:

  • speakers enthält je Stimme einen Eintrag mit speakerId, speakerNumber und, wo Sally es auflösen konnte, name und emailAddress.
  • segments enthält die zeitcodierten Sprachabschnitte mit startTime und endTime in Sekunden, dem text und einer speakerId aus der Liste speakers. Für den Sprecher eines Segments brauchst du also keinen zweiten Aufruf.
FeldTypBeschreibung
recordingIdstringId der Aufnahme.
speakers[].speakerIdstringId des Sprechers, auf die jedes Segment verweist.
speakers[].speakerNumbernumberNummer des Sprechers.
speakers[].namestring | nullName des Sprechers.
speakers[].emailAddressstring | nullE-Mail des Sprechers.
segments[].speakerIdstringSprecher des Segments, verweist auf die Liste speakers.
segments[].startTimenumberBeginn in Sekunden.
segments[].endTimenumberEnde in Sekunden.
segments[].textstring | nullTranskribierter Text des Segments.

3. Die Antwort klein halten​

Wichtig

Transkripte sind die größten Antworten dieser API, und fast alles davon steckt in segments. Wenn du nur wissen willst, wer teilgenommen hat, frag ?fields=speakers ab. Die Segmente werden dann gar nicht erst gesendet. Die Regeln erklärt Feldauswahl.

curl "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID/transcription?fields=speakers" \
-H "Authorization: Bearer $SALLY_TOKEN"
200 OK
{
"speakers": [
{
"speakerId": "b16c2c6f-d9f5-4709-a27e-41a319410893",
"speakerNumber": 1,
"name": "Anna Berger",
"emailAddress": "anna.berger@example.com"
}
]
}

Auswählbar sind an diesem Endpunkt recordingId, speakers und segments. Eine verschachtelte Liste kommt ganz oder gar nicht, speakers.name wird nicht unterstützt.

4. Als Datei herunterladen​

Wenn du das Transkript als Dokument statt als Daten brauchst, liefert GET …/recordings/{recordingId}/transcription/document genau die Datei, die ein Nutzer in der Sally-Weboberfläche herunterlädt: mit Branding, Logos, Kopf- und Fußzeile, Sprechern, Zeitstempeln und demselben Dateinamen. Die Datei wird bei der Anfrage erzeugt und kommt direkt in der Antwort zurück, es gibt keinen Auftrag, den du abfragen musst. Die Formate vtt und srt sind Untertiteldateien ohne Kopfbereich, direkt bereit für einen Videoplayer.

ParameterTypPflichtBeschreibung
formatstringjapdf, docx, xlsx, txt, md, vtt oder srt.
languageCodestringneinde-DE, en-US, es-ES, fr-FR, it-IT, nl-NL oder pl-PL. Ohne Angabe gilt die Sprache des Token-Inhabers, wie in der Weboberfläche.
# -OJ speichert die Datei unter dem Namen aus Content-Disposition
curl -fOJ "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID/transcription/document?format=docx&languageCode=de-DE" \
-H "Authorization: Bearer $SALLY_TOKEN"
Hinweis

languageCode ändert nur die Beschriftungen und das Datumsformat im Dokument, nicht den transkribierten Text. Die Schrift richtet sich immer nach der Sprache der Aufnahme, chinesische Schriftzeichen bleiben also auch mit en-US-Beschriftungen lesbar. ?fields= wird bei diesem Endpunkt nicht unterstützt.

Die Antwort ist 200 mit der Datei selbst, kein JSON. Der Header Content-Disposition enthält den Dateinamen, den die Weboberfläche für denselben Download verwendet, in ASCII in filename und in UTF-8 in filename*. Der Content-Type richtet sich nach dem Format:

formatContent-Type
pdfapplication/pdf
docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
txttext/plain; charset=utf-8
mdtext/markdown; charset=utf-8
vtttext/vtt; charset=utf-8
srtapplication/x-subrip; charset=utf-8

Neben den üblichen Fehlern antwortet dieser Endpunkt mit:

StatuscodeBedeutung
400UNKNOWN_DOCUMENT_FORMAT oder UNKNOWN_LANGUAGE_CODEformat fehlt oder ist unbekannt, oder languageCode ist unbekannt. Der Body nennt die erlaubten Werte.
403TRANSCRIPT_DOWNLOAD_PREVENTEDDas Unternehmenskonto hat diesen Download für seine Mitglieder gesperrt.
404Die Aufnahme gibt es nicht, sie gehört zu einem anderen Unternehmenskonto, oder du hast keinen Zugriff darauf.
409TRANSCRIPT_NOT_AVAILABLEDie Aufnahme hat noch kein Transkript. Prüf vorher den Status.

Unter Fehler siehst du, wie du diese Codes an einer Stelle behandelst.

5. Vollständiges Skript: Transkript als Text exportieren​

Dieses Skript wartet, bis der Transkriptionslauf einer Aufnahme beendet ist, hört sauber auf, wenn es kein Transkript gibt, und schreibt sonst eine lesbare Textdatei mit einer Zeile je Segment: Zeitstempel, Sprecher, Text. Sprecher ohne aufgelösten Namen erscheinen als Speaker 1, Speaker 2 und so weiter. Das Abfrageintervall von 30 Sekunden hat das Skript gewählt, es ist kein Wert der API.

#!/usr/bin/env bash
# Braucht curl und jq. curl --retry wiederholt eine Anfrage nach einem 429 mit wachsenden Pausen.
set -euo pipefail
BASE="https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID"
CURL=(curl -sf --retry 5 -H "Authorization: Bearer $SALLY_TOKEN")

# 1. Warten, bis der Lauf beendet ist
while : ; do
status=$("${CURL[@]}" "$BASE?fields=isTranscriptionCompleted,isTranscriptionSucceeded,transcriptionCompletionReason")
[ "$(echo "$status" | jq '.isTranscriptionCompleted')" = "true" ] && break
sleep 30
done

# 2. Aufhören, wenn es kein Transkript gibt
if [ "$(echo "$status" | jq '.isTranscriptionSucceeded')" != "true" ]; then
echo "Kein Transkript: $(echo "$status" | jq -r '.transcriptionCompletionReason')"
exit 0
fi

# 3. Abrufen und eine Zeile je Segment schreiben
"${CURL[@]}" "$BASE/transcription" | jq -r '
(.speakers | map({key: .speakerId, value: (.name // "Speaker \(.speakerNumber)")}) | from_entries) as $names
| .segments[]
| (.startTime | floor) as $s
| "[\($s / 60 | floor):\($s % 60 | tostring | ("0" + .)[-2:])] \($names[.speakerId]): \(.text // "")"
' > "transcript-$RECORDING_ID.txt"

Das Ergebnis sieht so aus:

transcript-53e2e041-4b34-41c7-a285-634d80b3675d.txt
[0:12] Anna Berger: Wir haben uns auf den Rollout-Plan für Oktober geeinigt.
[0:18] Speaker 2: Dann passe ich den Zeitplan heute noch an.

6. Endpunkte im Überblick​

Jeder Eintrag führt in die Referenz, wo du die Anfrage mit deinem eigenen Token abschicken kannst.