Convai Integration
Convai Integration - PlayCanvas Plugin Guide for seamless integration.
Convai Initialization Script
var ConvaiNpc = pc.createScript('convaiNpc');
/** Loading convai-sdk cdn */
var convaiClient = null;
var userTextStream = ""; // Stores the user's text input
var npcTextStream = ""; // Stores the NPC's text response
var keyPressed = false; // Keeps track of whether the "T" key is pressed
var isTalking = false; // Indicates if the NPC is currently talking
var conversationActive = false; // Indicates if a conversation is currently active
var visemeData = []; // Stores viseme data for lip sync animation
var visemeDataActive = false; // Indicates if viseme data is available
var formLoaded = false; // Indicates if the form has been loaded
let timeoutId;
/**
* Initializes the ConvaiClient with an API key, a character ID, and flags for enabling the audio recorder and player. Call this first from Start()
* Sets up several callbacks for handling different types of responses from the Convai Client.
* @param {string} apiKey - The API key for the Convai service.
* @param {string} characterId - The ID of the character to use in the Convai service.
* @param {boolean} enableAudioRecorder - Flag to enable the audio recorder.
* @param {boolean} enableAudioPlayer - Flag to enable the audio player.
* @param {number} faceModal - The face modal to use for the character.
* @param {boolean} enableFacialData - Flag to enable facial data.
*/
function initializeConvaiClient () {
console.log("Convai client initiated.");
convaiClient = new ConvaiClient({
apiKey: "", // Replace with your API key
characterId: "", // Replace with your character ID
enableAudio: true,
faceModal: 3,
enableFacialData: true,
});
// Error callback
convaiClient.setErrorCallback(function(type, statusMessage) {
console.log("Error Callback", type, statusMessage);
});
// Response callback
convaiClient.setResponseCallback(function(response) {
// Handle user query
if (response.hasUserQuery) {
var transcript = response.getUserQuery();
if (transcript) {
var isFinal = transcript?.getIsFinal();
var transcriptText = transcript.getTextData();
if (isFinal) {
userTextStream += " " + transcriptText;
}
userTextStream = transcriptText;
}
}
// Handle audio response
if (response.hasAudioResponse()) {
var audioResponse = response.getAudioResponse();
npcTextStream += " " + audioResponse.getTextData();
// Handle viseme data for lip sync animation
if (audioResponse.hasVisemesData()) {
let lipsyncData = audioResponse.getVisemesData().array[0];
if (lipsyncData[0] !== -2) {
visemeData.push(lipsyncData);
visemeDataActive = true;
}
} else {
visemeDataActive = false;
}
}
});
}
// Handle key down event for starting audio input
function handleKeyDown(e) {
const convaiFormEl = document.getElementById("convai-input");
if (convaiClient && e.keyCode === 84 && !keyPressed && !(document.activeElement === convaiFormEl)) {
e.stopPropagation();
e.preventDefault();
keyPressed = true;
userTextStream = "";
npcTextStream = "";
convaiClient.startAudioChunk();
conversationActive = true;
}
}
// Handle key up event for stopping audio input
function handleKeyUp(e) {
const convaiFormEl = document.getElementById("convai-input");
if (convaiClient && e.keyCode === 84 && keyPressed && !(document.activeElement === convaiFormEl)) {
e.preventDefault();
keyPressed = false;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
convaiClient.endAudioChunk();
}, 500);
}
}
// Add event listeners for key down and key up
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
// Initialize code called once per entity
ConvaiNpc.prototype.initialize = function() {
initializeConvaiClient();
// Set callbacks for audio playback
convaiClient.onAudioPlay(() => {
isTalking = true;
});
convaiClient.onAudioStop(() => {
isTalking = false;
conversationActive = false;
});
};
// Handle animation based on the talking state
ConvaiNpc.prototype.handleAnimation = function() {
this.entity.anim.setBoolean("Talking", isTalking);
};
// Update code called every frame
ConvaiNpc.prototype.update = function(dt) {
this.handleAnimation();
// Check if the form is loaded and add event listener
if (!formLoaded && document.getElementById("convai-form")) {
this.formListener();
formLoaded = true;
}
};
// Add event listener for form submission
ConvaiNpc.prototype.formListener = function() {
document.getElementById("convai-form").addEventListener("submit", (e) => {
e.preventDefault();
var inputValue = document.getElementById("convai-input").value;
window.convaiClient.sendTextChunk(inputValue);
userTextStream = inputValue;
document.getElementById("convai-form").reset();
conversationActive = true;
npcTextStream = "";
});
}PlayerAnimationHandler Script
Lipsync Script
HeadTracking Script

Last updated
Was this helpful?