Skip to content

Elevenlabs

ElevenLabsSTTAdapter

Bases: BaseSTTAdapter

ElevenLabs Scribe (/v1/speech-to-text) with word-level speaker ids.

Source code in dynamiq/components/audio/stt/elevenlabs.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class ElevenLabsSTTAdapter(BaseSTTAdapter):
    """ElevenLabs Scribe (``/v1/speech-to-text``) with word-level speaker ids."""

    provider = "ElevenLabs"
    capabilities = STTCapabilities(diarization=True, speaker_hints=True, word_timestamps=True)
    default_model = "scribe_v2"

    def build_fields(self, request: TranscriptionRequest) -> dict[str, Any]:
        fields: dict[str, Any] = {"model_id": request.model}
        if request.language:
            fields["language_code"] = request.language
        if request.diarize:
            fields["diarize"] = True
            hints = request.speakers
            speakers = (hints.expected or hints.max) if hints else None
            if speakers:
                fields["num_speakers"] = speakers
        if request.timestamps != TimestampGranularity.NONE:
            fields["timestamps_granularity"] = "word"
        fields.update(request.provider_options)
        fields.update(self.connection.data or {})
        return {key: format_param_value(value) for key, value in fields.items() if value is not None}

    def transcribe(self, request: TranscriptionRequest) -> Transcript:
        http = resolve_http_client(self.client)
        audio = request.audio
        response = http.post(
            f"{elevenlabs_api_base(self.connection.url)}/speech-to-text",
            headers=self.connection.headers,
            data=self.build_fields(request),
            files={"file": (audio.name, audio, getattr(audio, "content_type", None))},
        )
        raise_for_status(response, self.provider)
        return self.normalize(response.json(), request)

    @staticmethod
    def normalize(data: dict[str, Any], request: TranscriptionRequest) -> Transcript:
        words: list[TranscriptWord] = []
        for word in data.get("words") or []:
            kind = word.get("type") or "word"
            if kind == "spacing":
                continue
            words.append(
                TranscriptWord(
                    word=word.get("text") or "",
                    start=word.get("start"),
                    end=word.get("end"),
                    speaker=optional_str(word.get("speaker_id")),
                    type="audio_event" if kind == "audio_event" else "word",
                )
            )
        return build_transcript(
            content=data.get("text") or "",
            words=words,
            language=data.get("language_code") or request.language,
            raw=data,
        )

elevenlabs_api_base(url)

Base API URL from a connection URL that may point at a specific endpoint (legacy configs).

Source code in dynamiq/components/audio/stt/elevenlabs.py
 9
10
11
12
13
14
def elevenlabs_api_base(url: str) -> str:
    """Base API URL from a connection URL that may point at a specific endpoint (legacy configs)."""
    marker = "/v1"
    if marker in url:
        return url[: url.index(marker) + len(marker)]
    return url.rstrip("/")