> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gradium.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Keyword Boosting

> Recognize names, brands, and jargon by biasing STT toward a custom dictionary

Speech-to-Text is excellent on everyday language. Keyword boosting extends
that strength to the vocabulary that is specific to *your* product: player
names, brands, products, and channel names. Terms like `Mbappé` or
`Vinícius` come out exactly the way you expect.

You pass a dictionary of the terms you care about in `json_config`, and the
model gives them priority while decoding, in real time, with no retraining.

## The idea

Add a `keywords` object with the terms and a `boost` weight:

```python theme={null}
json_config = {
    "language": "en",
    "keywords": {
        "words": ["Mbappé", "Haaland", "Vinícius", "Bellingham", "Lewandowski"],
        "boost": 3,
    },
}
```

`boost` is applied in log-probability space, so its effect is exponential: a
small value already shifts decoding noticeably. Use the range `-6` to `6`,
with `3` as a strong default. See
[Transcription Settings](/guides/transcription-settings#keyword-boosting) for
the full parameter reference.

## Build a good dictionary

Keywords are matched one token at a time, which means two things.

1. **Use single tokens, with no spaces.** Split multi-word names, so
   `"Ferran Torres"` becomes `"Ferran"` and `"Torres"`.
2. **Match case and accents.** `"Mbappé"` and `"Mbappe"` are different keys,
   so include the variants you expect.

A small helper that does both:

```python theme={null}
import unicodedata


def build_keywords(terms):
    strip = lambda s: "".join(
        c for c in unicodedata.normalize("NFKD", s) if not unicodedata.combining(c)
    )
    out = []
    for term in terms:
        for token in term.split():                       # split phrases into tokens
            for variant in (token, token.lower(), strip(token), strip(token).lower()):
                if variant not in out:
                    out.append(variant)
    return out


build_keywords(["Ferran Torres", "Mbappé"])
# ['Ferran', 'ferran', 'Torres', 'torres', 'Mbappé', 'mbappé', 'Mbappe', 'mbappe']
```

## Full example

```python theme={null}
import asyncio
import gradium

TERMS = ["Kylian Mbappé", "Erling Haaland", "Vinícius Júnior", "Jude Bellingham"]


async def transcribe(audio_source):
    client = gradium.client.GradiumClient(api_key="your-api-key")

    async with client.stt_realtime(
        model_name="default",
        input_format="pcm",
        json_config={
            "language": "en",
            "delay_in_frames": 16,
            "keywords": {"words": build_keywords(TERMS), "boost": 3},
        },
    ) as stt:
        transcript = []

        async def producer():
            async for chunk in audio_source:
                await stt.send_audio(chunk)
            await stt.send_eos()

        async def consumer():
            async for msg in stt:
                if msg["type"] == "text":
                    transcript.append(msg["text"])
                elif msg["type"] == "end_of_stream":
                    return

        await asyncio.gather(producer(), consumer())
        return " ".join(transcript).strip()
```

## Tuning

| Boost    | Behaviour                                                                 | Use it when                                           |
| -------- | ------------------------------------------------------------------------- | ----------------------------------------------------- |
| `1`-`2`  | Gentle nudge, no risk                                                     | Fairly common vocabulary, where a tiebreak is enough. |
| `3`      | Recommended default; recovers most rare names                             | Most cases.                                           |
| `4`      | Stronger recovery                                                         | Dense or foreign proper nouns.                        |
| `5`-`6`  | Diminishing returns, and the decoder may start to loop (repeat a keyword) | Rarely, and watch the output.                         |
| negative | De-boosts a term                                                          | Only to remove a specific word you never want.        |

Boosting is fully compatible with streaming, and it earns its keep most at low
`delay_in_frames`, where the model has less look-ahead and leans more on the
dictionary.

## Related

<CardGroup cols={2}>
  <Card title="Transcription Settings" icon="sliders" href="/guides/transcription-settings#keyword-boosting">
    The `keywords` parameter reference and the rest of `json_config`.
  </Card>

  <Card title="Speech-to-Text WebSocket" icon="microphone" href="/guides/speech-to-text">
    STT message types, VAD details, and flushing.
  </Card>
</CardGroup>
