Focus

Flag the moments you care about

Focus flags the moments you care about. You list the labels you want to watch, e.g. angry or low_confidence, and the API adds a focus result to every utterance or segment where that label is likely but is not the finalLabel, so check finalLabel too. high_stress, low_confidence and negative_tone are combined labels: they are flagged whenever their score is high enough.

Focus is available for the Behavioral API, in batch and streaming.

Labels

LabelWhat it flags
angry, happyMoments with likely anger or happiness (emotion)
negative, positiveMoments with likely negative or positive sentiment (positivity)
slow, fastMoments with likely slow or fast speech (speaking_rate)
high_stressMoments with signs of stress, combined from several behavioral signals
low_confidenceMoments with signs of low confidence, combined from several behavioral signals
negative_toneMoments with a negative tone, combined from several behavioral signals (negative uses only positivity)

Sensitivity

sensitivity sets how easily a moment is flagged:

  • low: flags fewer moments, only the clearer ones
  • default: the default, if you leave it empty
  • high: flags more moments, including the subtler ones

🌐 cURL Example (batch)

Submit your audio as usual. When processing is complete, add the focus and, optionally, the sensitivity query params to the results request:

curl --request GET \
     --url 'https://api.behavioralsignals.com/v5/clients/your-client-id/processes/pid/results?focus=angry,low_confidence&sensitivity=high' \
     --header 'X-Auth-Token: your-api-token' \
     --header 'accept: application/json'

Focus is computed when you read the results, so you can read the same process again with other labels or another sensitivity, without uploading the audio again.

🐍 Python SDK Example

Batch:

from behavioralsignals import Client

client = Client()

process = client.behavioral.upload_audio(file_path="audio.wav")
result = client.behavioral.wait_for_result(
    pid=process.pid,
    focus=["angry", "low_confidence"],
    sensitivity="high",
)

for r in result.results:
    if r.task == "focus":
        print(r.st, r.et, r.finalLabel)

Streaming:

from behavioralsignals import Client, StreamingOptions
from behavioralsignals.utils import make_audio_stream

client = Client()
audio_stream, sample_rate = make_audio_stream("audio.wav", chunk_size=0.25)

options = StreamingOptions(
    sample_rate=sample_rate,
    encoding="LINEAR_PCM",
    focus=["angry", "low_confidence"],
    sensitivity="high",
)

for response in client.behavioral.stream_audio(audio_stream=audio_stream, options=options):
    for r in response.results:
        if r.task == "focus":
            print(r.st, r.et, r.finalLabel)

Streaming with gRPC

Add a focus field to the AudioConfig of the first message (see the proto file):

config = pb.AudioConfig(
    encoding=pb.AudioEncoding.LINEAR_PCM,
    sample_rate_hertz=16000,
    focus=pb.FocusConfig(labels=["angry", "low_confidence"], sensitivity="high"),
)

Response

Each flagged moment is one extra result with task set to focus and finalLabel set to suspected_<label>. It has the same id, startTime, endTime and level as the utterance or segment it flags:

{
  "id": "3",
  "startTime": "12.48",
  "endTime": "16.02",
  "task": "focus",
  "prediction": [
    {
      "label": "low_confidence",
      "posterior": "0.6124"
    }
  ],
  "finalLabel": "suspected_low_confidence",
  "level": "utterance"
}

The posterior is the likelihood of the label. For high_stress, low_confidence and negative_tone it is a combined score. In batch results, each focus result comes right after the other results of its utterance.

📘

Notes

  • A process that never used focus returns the same results as before.
  • An unknown or empty label list, an unknown sensitivity, or sensitivity without focus is rejected: with 400 in batch and INVALID_ARGUMENT in streaming.
  • In streaming, send focus in the first message: once it is set, later values are ignored. Focus is not available for deepfake detection streams.
  • In batch, focus results are not stored: they are added to the response each time you ask for them. A stream's focus results are stored with its results, and asking for focus again replaces them.


Did this page help you?