File size: 2,915 Bytes
ffee326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""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))