One processor, two frame tags.
Pipecat pipelines are a list of frame processors, which makes the split straightforward: the processor emits each audio frame twice, tagged raw and enhanced, and downstream services declare which tag they want.
pip install anecho-pipecatimport os
from pipecat.pipeline.pipeline import Pipeline
from anecho_pipecat import AnechoProcessor
anecho = AnechoProcessor(
api_key=os.environ["ANECHO_API_KEY"],
model="clearline-s",
sample_rate=8000, # the call is narrowband; keep it that way
echo_suppression=True,
split_pipeline=True,
)
pipeline = Pipeline([
transport.input(),
anecho, # emits raw + enhanced, sample-aligned
stt, # consumes tag="raw"
context_aggregator.user(),
llm,
tts,
transport.output(),
])Point your VAD analyser at the enhanced tag. This is the half of the split our own measurements support most strongly: voice-activity F1 barely moves, but the false-alarm rate drops by twenty to thirty points in babble and competing-speaker conditions — which is exactly the failure where someone else in the room stops your agent mid-sentence.
from pipecat.audio.vad.silero import SileroVADAnalyzer
from anecho_pipecat import AnechoVADSource
transport = DailyTransport(
...,
params=DailyParams(
audio_in_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
# take VAD input from the enhanced tag rather than the wire
vad_audio_source=AnechoVADSource(anecho, channel="enhanced"),
),
)Nyquist runs alongside and emits a frame you can log or act on. The useful pattern is not a dashboard — it is a runtime decision: when the score drops below your threshold, stop trusting the transcript and ask the caller to repeat, before the language model acts on a hallucinated account number.
@anecho.event_handler("on_quality_frame")
async def on_quality(processor, frame):
if frame.score < 0.35:
await task.queue_frame(
TTSSpeakFrame("Sorry — the line is breaking up. Could you repeat that?")
)