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

# AIC Tyto Observer

> AICTytoObserver scores the quality of the user's audio with the ai-coustics Tyto model and summarizes the scores at the end of a call.

## Overview

`AICTytoObserver` scores the quality of the user's audio with the ai-coustics Tyto model. It analyzes the latest 5-second window in a background thread after every 5 seconds of received audio, and emits each result through `on_analysis_result`. When the call ends, it emits a summary through `on_call_summary`.

> **[AIC Tyto Observer API Reference](https://reference-server.pipecat.ai/en/latest/api/pipecat.observers.aic_tyto_observer.html)**
>
> Pipecat's API methods for the Tyto observer

> **[Example Implementation](https://github.com/pipecat-ai/pipecat/blob/main/examples/voice/voice-aicoustics-tyto.py)**
>
> Complete example with AICFilter and AICTytoObserver

> **[ai-coustics Documentation](https://docs.ai-coustics.com/tutorials/pipecat-quickstart)**
>
> ai-coustics Pipecat quickstart and model guides

> **[ai-coustics Models](https://artifacts.ai-coustics.io/)**
>
> Browse available Tyto and Quail models

## Installation

```bash theme={null}
uv add "pipecat-ai[aic]"
```

## Prerequisites

You need an ai-coustics license key. Get one at [developers.ai-coustics.io](https://developers.ai-coustics.io).

### Required Environment Variables

* `AIC_SDK_LICENSE`: Your ai-coustics SDK license key

## Configuration

```python theme={null}
from pipecat.observers.aic_tyto_observer import AICTytoObserver
```

**license\_key** `str` *required*

ai-coustics SDK license key.

**model\_id** `str | None` (default: "tyto-1.1-l-16khz")

Tyto model identifier. Ignored if `model_path` is set. See
[artifacts.ai-coustics.io](https://artifacts.ai-coustics.io/) for available
models.

**model\_path** `Path | None` (default: None)

Path to a local `.aicmodel` file.

**model\_download\_dir** `Path | None` (default: None)

Directory for downloaded models. Defaults to `~/.cache/pipecat/aic-models`.

**degraded\_threshold** `float` (default: 0.3)

`risk_score` value at or above which the summary counts a window as degraded.
Must be between `0.0` and `1.0`. Calibrate it against the failures you see in
your application.

**audio\_filter** `AICFilter | None` (default: None)

The transport's
[`AICFilter`](https://docs.pipecat.ai/api-reference/server/services/audio-filters/aic-filter). When
set, the filter feeds the analysis with the audio before enhancement. When
`None`, the observer analyzes the `InputAudioRawFrame` audio that the input
transport pushes.

Raises `ValueError` when neither `model_id` nor `model_path` is set, or when `degraded_threshold` is outside `0.0` to `1.0`.

## Usage

### Scoring Audio Before Enhancement

Tyto must score the audio before enhancement. When `AICFilter` is the transport's `audio_in_filter`, pass the same filter as `audio_filter`:

```python theme={null}
import os

from loguru import logger

from pipecat.audio.filters.aic_filter import AICFilter
from pipecat.observers.aic_tyto_observer import AICTytoObserver
from pipecat.pipeline.worker import PipelineWorker
from pipecat.transports.daily.transport import DailyParams, DailyTransport

aic_filter = AICFilter(
    license_key=os.environ["AIC_SDK_LICENSE"],
    model_id="quail-vf-2.2-l-16khz",
)

transport = DailyTransport(
    room_url,
    token,
    "Bot",
    DailyParams(
        audio_in_enabled=True,
        audio_out_enabled=True,
        audio_in_filter=aic_filter,
    ),
)

tyto = AICTytoObserver(
    license_key=os.environ["AIC_SDK_LICENSE"],
    audio_filter=aic_filter,
)

@tyto.event_handler("on_analysis_result")
async def on_analysis_result(observer, scores, audio_secs):
    logger.info(f"Risk score {scores.risk_score:.2f} at {audio_secs:.0f}s")

@tyto.event_handler("on_call_summary")
async def on_call_summary(observer, summary):
    logger.info(f"Mean risk score: {summary.mean.risk_score}")

worker = PipelineWorker(pipeline, observers=[tyto])
```

Without an `AICFilter` on the transport, leave out `audio_filter` and the observer analyzes the input audio frames directly.

## Notes

* **One filter per session**: The observer attaches itself to `audio_filter` and the filter holds one attachment at a time, so create a new `AICFilter` and observer for each session rather than sharing a filter between sessions.
* **First result**: The first analysis waits for a full 5-second window, so calls with less than 5 seconds of user audio emit no results.
* **Model load failure**: If the model fails to load, the observer logs an error and the call continues without analysis.
* **Analysis failure**: If an analysis fails, the observer logs an error and stops analyzing for the rest of the call.
* **Filter initialization**: When `audio_filter` is set and the filter fails to initialize, it passes audio through unenhanced and the observer analyzes nothing.

## Event Handlers

| Event | Description |
| - | - |
| `on_analysis_result` | A window was analyzed. Receives `scores` (`AICAudioQualityScores`) and `audio_secs` (`float`), the seconds of user audio received so far. |
| `on_call_summary` | The call ended. Receives `summary` (`AICAudioQualitySummary`). Not emitted when no window was analyzed. |

### AICAudioQualityScores

All scores are in the range `0.0` to `1.0`. A higher value means more problematic audio.

| Field | Type | Description |
| - | - | - |
| `risk_score` | `float` | Likelihood that downstream models (STT, VAD, turn-taking, speech-to-speech) fail on this audio. |
| `noise` | `float` | Ambient or environmental noise. |
| `speaker_reverb` | `float` | Speaker distance and reverberation. |
| `speaker_loudness` | `float` | Level of the main speaker. A neutral level, not a degradation. |
| `interfering_speech` | `float` | Speech from other speakers, live or from a device. |
| `packet_loss` | `float` | Dropouts or discontinuities in the stream. |
| `codec_degradation` | `float` | Artifacts from lossy speech codecs. |

### AICAudioQualitySummary

| Field | Type | Description |
| - | - | - |
| `windows` | `int` | Number of analyzed windows. |
| `mean` | `AICAudioQualityScores` | Mean of each score over all windows. |
| `p95` | `AICAudioQualityScores` | 95th percentile of each score over all windows. |
| `max` | `AICAudioQualityScores` | Maximum of each score over all windows. |
| `degraded_threshold` | `float` | `risk_score` value at or above which a window counts as degraded. |
| `degraded_fraction` | `float` | Fraction of windows that are degraded. |
| `dominant_dimension` | `str` | Name of the score with the highest mean, excluding `risk_score` and `speaker_loudness`. It shows the largest degradation, not the cause of the risk score. |


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