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

# Format Hear transcripts

> Use numerals, smart_format, and optional dictation, drop_fillers, and custom vocabulary on Hear finals.

This is Hear's cleanup layer: make a **final** transcript readable
without slowing the live partials. Interim results are never rewritten.
Every step is fail-open: a timeout, exception, or lexical-guard miss returns
the previous text unchanged.

<Info>
  Hear sync/streaming supports the [published language set](/reference/language-support).
  Number formatting and the English lexical cleanup flags are strongest on
  English. Unsupported cleanup operations remain conservative/no-op. Async jobs
  transcribe the same eight languages; the spoken language is auto-detected per
  call.
</Info>

## Flags

| Flag | Default | What it does |
| - | - | - |
| `numerals` omitted | Engine default: **ITN on** | Spoken numbers → digits on finals (phones, currency, dates, ordinals) |
| `numerals=true` | Not applicable | Force digits |
| `numerals=false` | Not applicable | Keep spoken form (`fifty dollars`) |
| `smart_format` | **Off** | Sentence wrapping: capitalize, terminal `.` / `?`, conservative run-on splits, list commas, standalone `I`, tag questions |
| `dictation` | **Off** | Spoken commands → punctuation (`period`, `comma`, `new paragraph`, `question mark`) |
| `drop_fillers` | **Off** | Strip `um`, `uh`, `umm`, `uhh`, `er` |
| `vocabulary` | **Empty** | Request-level terms that bias known vocabulary for one call or job |

`numerals` is independent of the others. `dictation`, `drop_fillers`, and `vocabulary` are **not** implied by `smart_format`.

## `smart_format`

Opt-in. Changes **case and punctuation only**. Word identity is guarded. If wrapping would add or drop a word, Hear returns the unformatted final.

```
how much do i owe
→ How much do I owe?

hello how are you today the meeting is at 3
→ Hello how are you today. The meeting is at 3.

please send it to accounts payable and legal
→ Please send it to accounts payable, and legal.

the order is ready right
→ The order is ready right?
```

List commas keep the spoken `and`. Run-on splits are conservative: they fire only with enough words before a new clause (`the meeting/call/order/…`, `also` / `anyway` / `meanwhile`, `please send/call/…`, or a late standalone `i`). Tag questions use a short closer (`right`, `yeah`, `okay`, `isn't it`, …).

`smart_format` does **not**:

* Invent emails, URLs, or street addresses
* Expand or rewrite words (`threepm` stays `threepm` unless ITN already normalized it)
* Remove fillers (that is `drop_fillers`)
* Honor spoken "period" / "comma" (that is `dictation`)
* Format non-English text

## `dictation`

Separate from `smart_format`. Off by default. On English finals only, these spoken commands become punctuation:

* `period` → `.`
* `comma` → `,`
* `question mark` → `?`
* `new paragraph` → a paragraph break

```
hello period how are you question mark
→ hello. how are you?
```

Turn `smart_format` on as well if you also want sentence capitalization.

## `drop_fillers`

Off by default. Strips filled pauses (`um`, `uh`, `umm`, `uhh`, `er`) on English finals. **Do not enable on legal or compliance audio by default**. Those tokens can be evidence.

## `vocabulary`

<Warning>
  On a curated human evaluation set focused on named entities, vocabulary context
  raised entity recall from **70.9% to 89.3%**. Aggregate word error rate on the
  same set rose from **23.5% to 24.9%**. This is a measured entity-recall tradeoff,
  not evidence of a general accuracy improvement. Use a short list only when you
  know which distinctive terms are likely to appear.
</Warning>

Use vocabulary only when you know distinctive names, brands, products, or
phrases that may appear in the audio. Streaming and async jobs use up to five
effective terms. They trim whitespace, preserve the first spelling and order,
deduplicate without regard to case, and ignore entries that are shorter than 4
characters, longer than 64 characters, longer than five words, or made only of
common words. Vocabulary biases recognition toward your terms; it does not
steer the output script (Hindi decodes render Devanagari regardless of how a
term is spelled in the list).

You can send `vocabulary` for one stream or job. You can also store an
organization list with `GET` and `PUT /v1/hear/vocabulary` using the
`hear:configure` scope. Stored terms remain inactive until `enabled_for`
includes `batch` or `hear_stream`.

When both are active, request terms come first. Stored suggestions fill any
remaining slots up to five. The resulting list is fixed when the job is created
or the stream opens. Changing organization settings does not change work that
is already running.

```
this is nguyen calling   + vocabulary=["Nguyen"]
→ This is Nguyen calling.
```

```bash theme={null}
curl -X PUT https://api.pyai.com/v1/hear/vocabulary \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "terms": ["Nguyen", "SKU-99"],
    "enabled_for": ["batch", "hear_stream"]
  }'
```

<Info>
  Organization Hear vocabulary is not used by Omni. A managed Omni Agent can use
  its own explicit `vocabulary` list. Hear does not automatically import names
  from a CRM, dialer, or callee record.
</Info>

## Phone numbers

NANP grouping lives under **`numerals` / ITN**, not `smart_format`:

```
4155550172   →  415-555-0172
14155550172  →  1-415-555-0172
```

9-digit SSN-shaped spans and 16-digit card-shaped spans are never grouped.

## Surfaces

| Surface | How to send | When it applies |
| - | - | - |
| Sync | multipart fields | On the returned `text` |
| Stream | query params (SDK: `smartFormat`, `dictation`, `dropFillers`, `vocabulary`) | On `speech_final` and `final` only. Stored terms apply only with the `hear_stream` profile. `partial` stays raw. |
| Async jobs | JSON `smart_format` / `dictation` / `drop_fillers` / `vocabulary` | Once on the **stitched** transcript. The fixed effective list applies to each chunk and retry. Stored terms apply only with the `batch` profile. |

## Examples

<CodeGroup>
  ```bash Sync theme={null}
  curl https://api.pyai.com/v1/audio/transcriptions \
    -H "Authorization: Bearer $PYAI_API_KEY" \
    -F file=@audio.wav \
    -F model=pyai-hear \
    -F smart_format=true \
    -F vocabulary=Nguyen,SKU-99
  ```

  ```bash Stream theme={null}
  wss://api.pyai.com/v1/audio/transcriptions/stream\
  ?protocol=pyai-hear-v1&language=en&sample_rate=16000&encoding=pcm16\
  &smart_format=true
  ```

  ```python Python theme={null}
  import os
  from pyai import PyAI

  pyai = PyAI(api_key=os.environ["PYAI_API_KEY"])

  result = pyai.audio.transcriptions.create(
      file=open("audio.wav", "rb"),
      model="pyai-hear",
      smart_format=True,
      vocabulary=["Nguyen", "SKU-99"],
  )

  url = pyai.hear_stream_url(smart_format=True, dictation=True)

  job = pyai.transcription_jobs.create(
      audio_url="https://recordings.example.com/calls/abc123.wav",
      numerals=True,
      smart_format=True,
      drop_fillers=False,
      vocabulary=["Nguyen"],
  )
  ```

  ```ts Node theme={null}
  import PyAI from "@pyai/sdk";

  const pyai = new PyAI({ apiKey: process.env.PYAI_API_KEY! });

  await pyai.hear.vocabulary.set({
    terms: ["Nguyen", "SKU-99"],
    enabledFor: ["batch", "hear_stream"],
  });

  const url = pyai.hearStreamURL({
    smartFormat: true,
    dictation: true,
    vocabulary: ["Nguyen"],
  });

  await pyai.transcriptionJobs.create({
    audio_url: "https://recordings.example.com/calls/abc123.wav",
    numerals: true,
    smart_format: true,
    vocabulary: ["Nguyen"],
  });
  ```
</CodeGroup>

On the stream, render `partial` greyed and only commit `speech_final` / `final`. That is how you get live captions that snap to punctuated text instead of flickering punctuation on every hypothesis. See [Stream speech-to-text](/guides/streaming-stt).

## Failure behavior

Formatting is best-effort and **fail-open**. A timeout, exception, or lexical-guard miss returns the previous final unchanged. `dictation` and `drop_fillers` may change word count. When word timestamps cannot be realigned, the transcript still updates and the `words` array is cleared. Clients should not treat missing punctuation as an API error.

## Next steps

<CardGroup cols={2}>
  <Card title="Stream speech-to-text" href="/guides/streaming-stt">Partials vs finals, commit, and endpointing.</Card>
  <Card title="Timestamped recording jobs" href="/guides/async-transcription-jobs">Word/segment offsets, subtitles, diarization, webhooks, and retention.</Card>
  <Card title="Conversation intelligence" href="/guides/conversation-intelligence">Batch jobs, diarization, and post-call analytics.</Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.