Guide to accessing and managing chat history with the Empathic Voice Interface (EVI) API

The Empathic Voice Interface (EVI) captures detailed histories of conversations, allowing developers to review and analyze past interactions. This guide provides an overview of Chats and Chat Groups, instructions for retrieving chat transcripts and expression measurements, and steps to access reconstructed audio.

If data retention is disabled, Chat history will not be recorded, and previous Chat data and audio reconstruction will not be retrievable.

Chats vs Chat Groups

EVI organizes conversation history into Chats and Chat Groups.

  • Chats: Represents a single session from the moment a WebSocket connection is established until it disconnects. Each Chat contains messages and events recorded during that specific session.
  • Chat Groups: Links related chats to provide continuity across interactions. A group can contain one or more chats, allowing ongoing conversations to be tracked even when users reconnect to continue from a previous interaction.

When a new Chat session begins, it creates a new Chat Group by default. However, if the Chat resumes a previous session, it is added to the existing Chat Group, ensuring the conversation’s history and context are preserved across multiple Chats.

Fetching Chats and Chat Groups

Each Chat has a unique ID and a chat_group_id field that links it to its associated Chat Group. Similarly, each Chat Group has its own unique ID, enabling the retrieval of individual sessions or entire groups of related sessions.

  • Chat ID: To obtain a Chat ID, use the list Chats endpoint. This ID allows you to retrieve details of individual sessions or resume a previous Chat. See sample code for fetching Chats below:

    1curl -G https://api.hume.ai/v0/evi/chats \
    2 -H "X-Hume-Api-Key: <YOUR_API_KEY>" \
    3 -d page_number=0 \
    4 -d page_size=10 \
    5 -d ascending_order=false
  • Chat Group ID: Each Chat includes a chat_group_id field, which identifies the Chat Group it belongs to. To obtain a Chat Group ID directly, use the list Chat Groups endpoint. This ID is useful for accessing all Chats linked to a single conversation that spans multiple sessions. See sample code for fetching Chats below:

    1curl -G https://api.hume.ai/v0/evi/chat_groups \
    2 -H "X-Hume-Api-Key: <YOUR_API_KEY>" \
    3 -d page_number=0 \
    4 -d page_size=1 \
    5 -d ascending_order=false

While you can retrieve these IDs using the API, the Chat and Chat Group IDs are also included at the start of every Chat session in a chat_metadata message. This is particularly useful if your integration needs to associate data or actions with Chats as they are initiated.

chat_metadata
1{
2 "type": "chat_metadata",
3 "chat_group_id": "369846cf-6ad5-404d-905e-a8acb5cdfc78",
4 "chat_id": "470a49f6-1dec-4afe-8b61-035d3b2d63b0",
5 "request_id": "73c75efd-afa2-4e24-a862-91096b0961362258039"
6}

Viewing Chats in the Platform UI

You can also view chat history and obtain Chat IDs through the Platform UI:

  1. Go to the Chat history page for a paginated list of past Chats, each displaying key details like the Chat ID, datetime, event count, and duration.

    Platform UI chat history page
  2. Click “Open” on any Chat to view its details. The details page includes information such as status, start and end timestamps, duration, the Chat ID, Chat Group ID, associated Config ID (if any), and a paginated list of Chat Events.

    Platform UI chat details page

Chat Events

During each Chat session, EVI records events that detail interactions between the user and the system. These events provide a complete record of user input, assistant responses, tool usage, and system commands, enabling developers to review transcripts, analyze activity, and extract expression measurements. Below is the complete list of WebSocket messages recorded as Chat Events:

These events cannot be modified and represent an immutable record of the conversation for transcription and analysis purposes.

Fetching Chat Events

The Chat Events API provides endpoints to fetch events for a specific Chat or a Chat Group, allowing developers to retrieve detailed session data. Below are examples of how to use these endpoints:

Fetching chat events for a specific Chat

Use the /chats/{chat_id}/events endpoint to fetch events for a single Chat:

1curl -G https://api.hume.ai/v0/evi/chats/<YOUR_CHAT_ID> \
2 -H "X-Hume-Api-Key: <YOUR_API_KEY>" \
3 -d page_number=0 \
4 -d page_size=10 \
5 -d ascending_order=false

Fetching events for a specific Chat Group

Use the /chat_groups/{chat_group_id}/events endpoint to fetch events from all Chats within a specific Chat Group:

1curl -G https://api.hume.ai/v0/evi/chats/<YOUR_CHAT_GROUP_ID> \
2 -H "X-Hume-Api-Key: <YOUR_API_KEY>" \
3 -d page_number=0 \
4 -d page_size=10 \
5 -d ascending_order=false

Parsing Chat Events

Chat Events provide a detailed record of interactions during a Chat session, capturing both transcriptions and expression measurement predictions. This section demonstrates how to process these events to generate readable transcripts and analyze emotional trends.

For sample code demonstrating how to fetch and parse Chat Events, explore our example projects in TypeScript and Python.

Transcription

Transcriptions of a conversation are stored in user_message and assistant_message events. These events include the speaker’s role and the corresponding text, allowing you to reconstruct the dialogue into a readable format.

For instance, you may need to create a transcript of a conversation for documentation or analysis. Transcripts can help review user intent, evaluate system responses, or provide written records for compliance or training purposes.

The following example demonstrates how to extract the Chat transcription from a list of Chat Events and save it as a text file named transcription_<CHAT_ID>.txt:

1import fs from "fs";
2import { ReturnChatEvent } from "hume/api/resources/empathicVoice";
3
4function generateTranscript(chatEvents: ReturnChatEvent[]): void {
5 // Filter events for user and assistant messages
6 const relevantChatEvents = chatEvents.filter(
7 (chatEvent) => chatEvent.type === "USER_MESSAGE" || chatEvent.type === "AGENT_MESSAGE"
8 );
9
10 // Map each relevant event to a formatted line
11 const transcriptLines = relevantChatEvents.map((chatEvent) => {
12 const role = chatEvent.role === "USER" ? "User" : "Assistant";
13 const timestamp = new Date(chatEvent.timestamp).toLocaleString(); // Human-readable date/time
14 return `[${timestamp}] ${role}: ${chatEvent.messageText}`;
15 });
16
17 // Join all lines into a single transcript string
18 const transcript = transcriptLines.join("\n");
19 // Define the transcript file name
20 const transcriptFileName = `transcript_${CHAT_ID}.txt`;
21 // Write the transcript to a text file
22 try {
23 fs.writeFileSync(transcriptFileName, transcript, "utf8");
24 console.log(`Transcript saved to ${transcriptFileName}`);
25 } catch (fileError) {
26 console.error(`Error writing to file ${transcriptFileName}:`, fileError);
27 }
28}

Expression measurement

Expression measurement predictions are stored in the user_message events under the models.prosody.scores property. These predictions provide confidence levels for various emotions detected in the user’s speech.

For example, you might want to gauge the emotional tone of a conversation to better understand user sentiment. This information can guide customer support strategies or highlight trends in the expression measurement predictions over time.

The following example calculates the top 3 emotions from the user_messages by averaging their emotion scores across the Chat session:

1import { ReturnChatEvent, EmotionScores } from "hume/api/resources/empathicVoice";
2
3function getTopEmotions(chatEvents: ReturnChatEvent[]): Partial<EmotionScores> {
4 // Extract user messages that have emotion features
5 const userMessages = chatEvents.filter(
6 (event) => event.type === "USER_MESSAGE" && event.emotionFeatures
7 );
8
9 const totalMessages = userMessages.length;
10
11 // Infer emotion keys from the first user message
12 const firstMessageEmotions = JSON.parse(userMessages[0].emotionFeatures!) as EmotionScores;
13 const emotionKeys = Object.keys(firstMessageEmotions) as (keyof EmotionScores)[];
14
15 // Initialize sums for all emotions to 0 (no extra type assertions needed)
16 const emotionSums: Record<keyof EmotionScores, number> = Object.fromEntries(
17 emotionKeys.map((key) => [key, 0])
18 ) as Record<keyof EmotionScores, number>;
19
20 // Accumulate emotion scores from each user message
21 for (const event of userMessages) {
22 const emotions = JSON.parse(event.emotionFeatures!) as EmotionScores;
23 for (const key of emotionKeys) {
24 emotionSums[key] += emotions[key];
25 }
26 }
27
28 // Compute average scores for each emotion
29 const averageEmotions = emotionKeys.map((key) => ({
30 emotion: key,
31 score: emotionSums[key] / totalMessages,
32 }));
33
34 // Sort by average score (descending) and pick the top 3
35 averageEmotions.sort((a, b) => b.score - a.score);
36 const top3 = averageEmotions.slice(0, 3);
37
38 // Build a Partial<EmotionScores> with only the top 3 emotions
39 const result: Partial<EmotionScores> = {};
40 for (const { emotion, score } of top3) {
41 result[emotion] = score;
42 }
43
44 return result;
45}

Chat audio reconstruction

The audio reconstruction feature allows you to listen to past conversations by stitching together all audio snippets from a Chat—including both user inputs and EVI’s responses—into a single audio file. This can be useful for reviewing interactions, quality assurance, or integrating playback functionality into your application.

How audio reconstruction works

The audio reconstruction process combines individual audio clips into a continuous file. Here are some important considerations:

  • Storage duration: Reconstructed audio files are stored indefinitely.
  • Signed URL expiration: The signed_audio_url expires after 60 minutes. If it expires before you download the file, you can generate a new URL by making another API request.
  • No merging of Chats: The API does not support combining multiple Chats within a Chat Group into a single audio file.
  • Asynchronous process: Audio reconstruction is performed in the background. The time required depends on the conversation’s length and system load.

Audio reconstruction statuses

The status of an audio reconstruction request will indicate its progress:

  • QUEUED: The reconstruction job is waiting to be processed.
  • IN_PROGRESS: The reconstruction is currently being processed.
  • COMPLETE: The audio reconstruction is finished and ready for download.
  • ERROR: An error occurred during the reconstruction process.
  • CANCELED: The reconstruction job has been canceled.

Fetching reconstructed audio for a Chat

To fetch the reconstructed audio for a specific Chat, use the following endpoint: /chats/{chat_id}/audio.

$# Replace {chat_id} with your Chat ID
># Ensure your API key is set in the HUME_API_KEY environment variable
>curl -X GET "https://api.hume.ai/v0/evi/chats/{chat_id}/audio" \
> -H "X-Hume-Api-Key: $HUME_API_KEY" \
> -H "Accept: application/json"

Example response (audio reconstruction initiated):

1// Sample response (audio reconstruction initiated)
2{
3 "id": "470a49f6-1dec-4afe-8b61-035d3b2d63b0",
4 "user_id": "e6235940-cfda-3988-9147-ff531627cf42",
5 "status": "QUEUED",
6 "filename": null,
7 "modified_at": 1729875432555,
8 "signed_audio_url": null,
9 "signed_url_expiration_timestamp_millis": null
10}

If audio reconstruction for a Chat or Chat Group hasn’t already occurred, calling the respective endpoint will automatically add the audio reconstruction process to our job queue.

Fetching reconstructed audio for a Chat Group

To fetch a paginated list of reconstructed audio for Chats within a Chat Group, use the following endpoint: /chat_groups/{chat_group_id}/audio.

$# Replace {chat_group_id} with your Chat Group ID
># Include pagination parameters as needed
># Ensure your API key is set in the HUME_API_KEY environment variable
>curl -X GET "https://api.hume.ai/v0/evi/chat_groups/{chat_group_id}/audio?page_number=1&page_size=10&ascending_order=false" \
> -H "X-Hume-Api-Key: $HUME_API_KEY" \
> -H "Accept: application/json"
1// Sample response (audio reconstruction initiated)
2{
3 "id": "369846cf-6ad5-404d-905e-a8acb5cdfc78",
4 "user_id": "e6235940-cfda-3988-9147-ff531627cf42",
5 "num_chats": 1,
6 "page_number": 0,
7 "page_size": 10,
8 "total_pages": 1,
9 "pagination_direction": "DESC",
10 "audio_reconstructions_page": [
11 {
12 "id": "470a49f6-1dec-4afe-8b61-035d3b2d63b0",
13 "user_id": "e6235940-cfda-3988-9147-ff531627cf42",
14 "status": "QUEUED",
15 "filename": null,
16 "modified_at": 1729875432555,
17 "signed_audio_url": null,
18 "signed_url_expiration_timestamp_millis": null
19 }
20 ]
21}

Polling for completion

Since the reconstruction process is asynchronous, you can poll the endpoint to check the status field until it changes to COMPLETE. Once the status is COMPLETE, the signed_audio_url and signed_url_expiration fields will be populated.

1// Sample response (reconstruction complete)
2{
3 "id": "470a49f6-1dec-4afe-8b61-035d3b2d63b0",
4 "user_id": "e6235940-cfda-3988-9147-ff531627cf42",
5 "status": "COMPLETE",
6 "filename": "e6235940-cfda-3988-9147-ff531627cf42/470a49f6-1dec-4afe-8b61-035d3b2d63b0/reconstructed_audio.mp4",
7 "modified_at": 1729875432555,
8 "signed_audio_url": "https://storage.googleapis.com/...etc.",
9 "signed_url_expiration_timestamp_millis": 1730232816964
10}

Downloading the audio file

After the reconstruction is complete, you can download the audio file using the signed_audio_url. The following cURL command saves the audio file using the original filename provided by the server:

$# Replace {signed_audio_url} with the URL from the API response
>curl -O "{signed_audio_url}"