Reference

Conversation

Transcript state, voice frames, trajectories, and deltas

Conversation is the shared state model for recorded and live analysis. Transcription.conversation exposes it directly; LiveSession maintains one as events arrive.

class Conversation {
  static fromAnalysis(result: AnalysisResult): Conversation;

  apply(event: ProsodyEvent | Record<string, unknown>): this;

  getTranscript(): string;
  getTurns(): ConversationTurn[];
  getTurn(index: number): ConversationTurn | null;
  getSpeakers(): DiarizedSpeaker[];
  getVad(): AffectVad | null;

  getFrames(speakerId?: string): VoiceFrame[];
  getFrame(index: number): VoiceFrame | null;
  getProsody(turnIndex?: number): Prosody | null;
  getMeasurementSeries(
    path: MeasurementPath,
    speakerId?: string,
  ): MeasurementPoint[];
  getChanges(speakerId?: string): ChangePoint[];
  getMoments(speakerId?: string): Moment[];
  getTopMoments(limit?: number, speakerId?: string): Moment[];
}

Event application

apply() accepts the realtime event stream:

  • directive
  • transcript_update
  • speaker_update
  • speaker_profiles
  • session_end

Speaker updates fill committed attribution for analyzed intervals. getTurns() returns the current attribution.

const conversation = new Conversation();

for await (const event of events) {
  conversation.apply(event);
  render(conversation.getTurns());
}

LiveSession and ProsodySession call apply() automatically when supplied a conversation.

VoiceFrame

One measured interval in the conversation: who spoke, when, how they sounded, how they moved, and the affect when the checkpoint publishes it.

class VoiceFrame {
  readonly speakerId: string;
  readonly startMs: number;
  readonly endMs: number;
  readonly timestampMs: number;
  readonly state: ProsodyState | null;
  readonly change: ProsodyChange | null;
  readonly vad: AffectVad | null;

  getProsody(): Prosody | null;
  getChange(): ProsodyDelta | null;
}

Trajectories

const pitch = conversation.getMeasurementSeries('intonation.pitch', speaker.id);
const changes = conversation.getChanges(speaker.id);

MeasurementPoint and ChangePoint carry speakerId, the frame bounds, and the measured value. MeasurementPath is the typed key union, mirroring the state families: intonation.pitch, intonation.range, intonation.slope, stress.loudness, stress.peak, rhythm.voiced, rhythm.pause, rhythm.onset, tilt, clipping. Unavailable measurements are excluded from series.

frame.getProsody() returns the full measurement bundle: state, how the frame sounded, and change, the signed movement against the speaker's own baseline. frame.getChange() returns the movement as a ProsodyDelta: the reference frame and the signed change values.

Moments

A moment is a span the model committed as having moved the speaker's state. magnitude is the model's own readout of how far the state travelled, so it is published rather than derived: only the model carrying the person's state can measure it.

interface Moment {
  frameMs: number;      // where the evidence began, on the 80ms frame clock
  commitMs: number;     // where the decision landed
  durationMs: number;   // how long the movement ran
  magnitude: number;    // how far the speaker's state moved
  resolved: boolean;    // true when the state returned to its prior trajectory
  speakerId: string | null;
}

getMoments() returns them in commit order. getTopMoments() ranks them by magnitude, largest first, and defaults to ten. Transcription.moments is that ranked shortlist.

for (const moment of result.moments) {
  console.log(moment.frameMs, moment.magnitude, moment.speakerId);
}

const callerMoments = conversation.getTopMoments(5, speaker.id);

frameMs is retrodictive: it points at where the evidence began, while commitMs is where the model committed. Seek to frameMs to hear the moment.

Moments come from the batch report's committed events. A live conversation carries none, because the live wire publishes measurement and attribution as they land.

On this page