Skip to content

Advice

A tier tells you whether a recording is clean enough. advise() tells the person what to do about it, in one line, from the same numbers.

from voicequal import assess, advise

result = assess("recording.wav")
tip = advise(result)
print(tip.headline)  # "Steady background noise (fan, AC, hum)"
print(tip.actions)  # ("Turn off fans or AC if you can", "Move to a quieter room")
print(tip.severity)  # "warn"

advise() works on a FileAssessment or a LiveAssessment. It is deterministic, dependency-free, and never invents a cause the metrics do not support. Rules are checked in this order; the first match wins.

# Condition Headline Severity
1 clipping_ratio > 1% Recording is clipping bad if > 5%, else warn
2 quality = excellent Clean enough to process ok
3 background_db ≥ 72 and snr_estimate < 13.5 Loud room is drowning the voice bad for poor, warn for fair
4 fair/poor and temporal_variance < 3 Steady background noise (fan, AC, hum) bad for poor, warn for fair
5 fair/poor and temporal_variance ≥ 5 Intermittent noise is cutting into the voice bad for poor, warn for fair
6 quality = good Usable, with mild background noise warn
7 otherwise (fair/poor) Too noisy to process reliably bad for poor, warn for fair

Each rule has at most three short imperative actions. Advice.to_dict() gives a JSON-friendly form; the MCP server includes it in every tool result.

Optional: rephrasing with Claude

advise_with_llm() sends the metrics and the deterministic advice to Claude and asks it to rephrase and prioritise, with a system prompt that forbids inventing causes the numbers do not support and caps the reply at two sentences. The returned Advice keeps the deterministic actions and severity; only the headline comes from the model. Nothing in voicequal calls it unless you do.

pip install 'voicequal[llm]'
export ANTHROPIC_API_KEY=...
from voicequal import assess
from voicequal.advice import advise_with_llm

tip = advise_with_llm(assess("recording.wav"))  # default: claude-sonnet-5
tip = advise_with_llm(result, model="claude-opus-5-5")  # or pick a model

If the model refuses or returns no text, the deterministic headline is kept. Without the anthropic package installed the call raises ImportError with the install hint.