"""Tag the turns of a voice-agent call with Pipecat Tone. pip install -r requirements.txt python example.py # full precision: model.opt.onnx python example.py --fp16 # the 16-bit file: model_fp16.onnx, half the size The model files are read from this folder. Without them, as in a git checkout, they are downloaded once from Hugging Face (pipecat-ai/tone, release rc1). With --fp16, only model_fp16.onnx, tokenizer.json and config.json are needed. """ import pathlib import sys HERE = pathlib.Path(__file__).resolve().parent sys.path.insert(0, str(HERE / "runtime")) from tonetext.runtime.classifier import ToneTextClassifier # noqa: E402 PRECISION = "fp16" if "--fp16" in sys.argv[1:] else "fp32" MODEL_FILES = (["model_fp16.onnx", "tokenizer.json", "config.json"] if PRECISION == "fp16" else ["model.opt.onnx", "model.onnx", "tokenizer.json", "config.json"]) model_dir = HERE if not all((HERE / f).exists() for f in MODEL_FILES): from huggingface_hub import snapshot_download model_dir = snapshot_download("pipecat-ai/tone", revision="rc1", allow_patterns=MODEL_FILES) tone = ToneTextClassifier(model_dir, threads=4, precision=PRECISION) # A support call, the agent and the caller in turn. Each turn is read with the turn before it, as plain text: who said # either is not needed. CALL = [ "Thanks for calling Northwind Broadband, this is Ava. How can I help today?", "hi um yeah my internet's been down since this morning", "I'm sorry to hear that. Which plan are you on?", "I think my husband set it up, I'm not sure", "No problem. Can I take the account holder's date of birth?", "Why do you need that?", "It's only to confirm the account. The next engineer visit is in about forty minutes, I'm afraid.", "Oh great, a forty minute wait. Love that.", "Let me try a reset from my side first. The light on your router should turn green.", "mm-hm", "Do you know which router model you have?", "No idea, sorry.", "That's fine. Can you try loading a page now?", "That's brilliant, it's working, thank you so much!", "Is there anything else I can help with?", "thanks, that's all i needed", ] for previous, text in zip(CALL, CALL[1:]): tags = tone.tag(text, previous) sarcasm = f" · sarcastic ({tags.sarcasm.probability:.2f})" if tags.sarcasm.sarcastic else "" backchannel = " · backchannel" if tags.backchannel.is_backchannel else "" print(f"{text!r}") print(f" emotion {tags.emotion.label} ({tags.emotion.intensity}) · move {tags.move.label} ({tags.move.confidence:.2f})" f"{sarcasm}{backchannel}") # The full output for one turn, as JSON print(tone.tag("Oh great, a forty minute wait. Love that.", previous="It's only to confirm the account. The next engineer visit is in about forty minutes, I'm afraid.") .model_dump_json(indent=1))