Sindarin Persona enables you to add lifelike conversational speech AI agents to your webapp. It features ultra low latency, industry-leading turn-taking and transcription, and high-fidelity speech synthesis.
Demo: https://sindarin.tech
Install the package with:
npm install @sindarin/persona
# or
yarn add @sindarin/persona
or
var script = document.createElement("script");
script.src = "https://api.prod.centralus.az.sindarin.tech/PersonaClientPublicV2?apikey=<YOUR_CLIENT_KEY>";
script.onload = () => {
var personaClient = new window.PersonaClient.default("<YOUR_CLIENT_KEY>");
// ... initialize, etc
};
document.head.appendChild(script);
The package needs to be configured with your account's secret key, which is available in the Persona Web App / Settings.
import PersonaClient from "@sindarin/persona";
const personaClient = new PersonaClient("<YOUR_CLIENT_KEY>");
const handleStartChatButtonClick = async () => {
// Example config using a persona defined in the Playground; there are many ways to do things!
const config = {
userId: "admin",
personaName: "John",
options: {
debugMode: true,
streamTranscripts: true,
shouldNotSaveConversation: true,
},
};
try {
await personaClient.init(config);
configurePersonaEvents();
} catch (error) {
console.log(error);
}
};
const handlePauseChatButtonClick = async () => {
try {
await personaClient.pause();
} catch (error) {
console.log(error);
}
};
const handleResumeChatButtonClick = async () => {
try {
await personaClient.resume();
} catch (error) {
console.log(error);
}
};
const handleStopChatButtonClick = async () => {
try {
await personaClient.end();
} catch (error) {
console.log(error);
}
};
const handleUpdateState = async (newState) => {
try {
personaClient.updateState(newState);
} catch (error) {
console.log(error);
}
};
const handleReactTo = async (thought) => {
try {
personaClient.reactTo(thought);
} catch (error) {
console.log(error);
}
};
const configurePersonaEvents = () => {
personaClient.on("messages_update", (messages) => {
console.log(messages);
});
personaClient.on("state_updated", (newState) => {
console.log(newState);
})
personaClient.on("action", (action) => {
console.log(action);
})
};
You can initialize a conversation with the following config fields:
const config = {
userId: "admin", // optional
personaName: "John", // optional
personaId: "example_id", // optional; this is found in the Persona Playground
details: { firstName: "John" }, // optional; arbitrary data you can inject into your prompt with {{details.x}}
metadata: { orderId: "1" }, // optional; arbitrary data used for conversation retrieval / filtering later
personaConfig: {
initialMessage: "Hello {{details.firstName}}!",
prompt: "You are a fun and helpful persona.",
actions: { properties: {} },
ttsConfig: {
voiceId: "example_id", // voice IDs can be found and tested in the Playground
},
llmConfig: {
llm: "example_llm_name", // e.g. llama-3-70b, llama-3-8b, gpt-4o, hermes-2-mixtral-8x7B-dpo
temperature: 0.8, // 0 to 1
repetitionPenalty: 1 // -3.5 to 3.5 for non-openai models; -2 to 2 for openai models
},
interjections: { // the ability for the persona to speak spontaneously
enabled: true,
minWait: 7500,
maxWait: 10000,
thought: "Nobody has said anything in a while. I should nudge the conversation along."
},
chargeLimitEnabled: true, // optional; should the conversation be cut off after a certain amount of charges incurred?
chargeLimit: 2, // optional; the charge limit
lifecycleEvents: { // optional; if the webhook endpoint returns { state } or { details } in the response body, they will be injected
onInit: {
webhook: {
url: "http://your-webhook-url/init",
method: "POST",
body: {},
headers: "Bearer xyz"
}
},
onStateChange: { /* ... */ },
onEnd: { /* ... */ }
}
},
options: {
debugMode: true, // emit debug events in messages
streamTranscripts: true, // stream transcripts in realtime
shouldNotSaveConversation: true, // do not save transcripts
},
};
try {
await personaClient.init(config);
} catch (error) {
console.log(error);
}
Option | Default | Description |
---|---|---|
userId |
null |
[Optional] Your unique ID for the current user. |
personaName |
null |
[Optional; this or personaId or personaConfig required] The persona name in the Playground specifying a particular persona config. |
personaId |
null |
[Optional; this or personaName or personaConfig required] The persona ID in the Playground specifying a particular persona config. This takes priority over personaName if both are provided. |
details |
null |
[Optional] An object containing arbitrary information that you can inject into your prompt before the conversation starts using {{details.x}}. |
metadata |
null |
[Optional] An object containing arbitrary information for the developer to retrieve the conversation by. |
personaConfig |
null |
[Optional; this or personaName or personaId required] An ad hoc persona configuration specified entirely in your code. |
options |
- | [Optional] Additional options (below). |
options.debugMode |
false |
Messages array will contain additional debug events (info, warn, error) for debugging purposes during a conversation. |
options.streamTranscripts |
false |
Temporary transcripts will be rendered in the messages array. |
options.shouldNotSaveConversation |
false |
If true, the transcript will not be saved after the conversation ends. |
try {
await personaClient.init(config);
} catch (error) {
console.log(error);
}
personaClient.on("error", (error) => {
console.log(error);
});
personaClient.on("connect_error", (error) => {
console.log(error);
});