Créer une Conversation Autonome entre Deux Chatbots avec l'API OpenAI

Découvrez comment simuler une conversation autonome entre deux chatbots à l'aide de l'API OpenAI. Un prédicateur de rue et Bruce Wayne qui discutent en temps réel.

Créer une Conversation Autonome entre Deux Chatbots avec l'API OpenAI

Suite à mes deux précédents tutoriels, voici un exemple concret de code qui permet de créer une conversation autonome entre deux chatbots. Cette expérience illustre comment exploiter les capacités de l'API OpenAI pour donner vie à des personnages virtuels qui interagissent en temps réel. Le projet se base sur deux assistants virtuels que j'ai créés dans le dashboard d'OpenAI, incarnant chacun un rôle bien distinct.

Les Personnages

Pour cette expérimentation, j'ai choisi de créer deux personnages uniques avec des personnalités fortes, mais opposées.

Assistant 1 : Le Prédicateur de Rue
  • Nom : Prédicateur de rue
  • Instruction : Tu es un prédicateur de rue passionné et agressif, cherchant à convertir les passants à ta foi. Ton objectif est de convaincre les autres de suivre tes croyances en utilisant un ton persuasif, intense et déterminé. Reste toujours dans ce rôle, prêche avec force, et n'accepte aucun compromis dans ta mission. Varie la taille de tes réponses, mais ne fais jamais de réponse de plus de 500 caractères. Finis toujours tes réponses par une question avec une intention et un sujet précis. N’hésite pas à aller dans des détails personnels pour renforcer ta rhétorique.
Assistant 2 : Bruce Wayne
  • Nom : Bruce Wayne
  • Instruction : Tu es Bruce Wayne, l’homme derrière Batman, et tu portes un lourd secret. Ne sors jamais de ce rôle et adopte un ton agressif. Varie la taille de tes réponses, mais ne dépasse jamais les 500 caractères.
0:00
/2:21

Comment fonctionne le projet ?

Le cœur du projet réside dans l'utilisation de l'API OpenAI pour générer des dialogues en temps réel grâce à la fonctionnalité de streaming. À chaque étape de la conversation, l'un des assistants reçoit un message de l'autre, et ses réponses sont progressivement générées et affichées sur une interface web. Cette dynamique crée une interaction continue entre les deux chatbots, sans intervention humaine.

À la fin de ce post, vous trouverez un lien vers le dépôt GitHub contenant le code complet du projet. Mais avant cela, voici une version commentée du code pour vous permettre de mieux comprendre chaque étape de son fonctionnement.

import './style.css';

import OpenAI from 'openai';

// Initialisation de l'objet OpenAI avec la clé API. Cette clé permet d'accéder à l'API OpenAI.
const openai = new OpenAI({
    apiKey: "votre_clé_API", // Remplacez par votre clé API générée
    dangerouslyAllowBrowser: true // Permet d'utiliser OpenAI dans le navigateur (attention à la sécurité)
});	

// Variables pour stocker les assistants virtuels et les threads de conversation
let assistant1, assistant2;
let thread1, thread2;

// Appel des fonctions pour initialiser les deux assistants virtuels
await initializeAssistant1();
await initializeAssistant2();

// Fonction pour initialiser le premier assistant virtuel
async function initializeAssistant1(){
    // Récupère l'assistant en fonction de son ID et crée un thread (conversation)
	assistant1 = await retrieveAssistantById("asst_BuRO7M2bf1ZR1w2SYX8WiLUN");
	thread1 = await openai.beta.threads.create(); // Crée un nouveau thread (une nouvelle conversation)
}

// Fonction pour initialiser le deuxième assistant virtuel
async function initializeAssistant2(){
    // Récupère le deuxième assistant et crée un thread pour lui aussi
	assistant2 = await retrieveAssistantById("asst_qDeoz8mDExrj4oFtrl1YUipT");
	thread2 = await openai.beta.threads.create();
}
  
console.log("Assistants initialisés"); // Affiche un message dans la console pour confirmer l'initialisation des assistants

// Démarre la conversation avec le premier assistant en lui envoyant un message initial
startConversationWithCharacter1("Demande moi qui je suis.");

// Fonction pour récupérer les détails d'un assistant par son ID
async function retrieveAssistantById(assistantId) {
	const assistant = await openai.beta.assistants.retrieve(assistantId); // Appel à l'API OpenAI pour récupérer l'assistant
	return assistant; // Renvoie l'assistant récupéré
}  

// Fonction pour démarrer la conversation avec le premier assistant
async function startConversationWithCharacter1(message){
	// Crée un nouveau message dans le thread du premier assistant avec le rôle "utilisateur" et le contenu du message
	let userMessage = await openai.beta.threads.messages.create(thread1.id, {
		role: "user", // Rôle utilisateur (personne qui parle)
		content: message // Le contenu du message envoyé
	});

	let speechBubble; // Variable pour stocker la bulle de dialogue dans le HTML
	let responseToCharacter2 = ""; // Stocke la réponse pour le deuxième personnage

	// Crée un stream (flux) pour recevoir la réponse du premier assistant en temps réel
	let runStream = openai.beta.threads.runs.stream(thread1.id, {
		assistant_id: assistant1.id // ID de l'assistant qui répond
	})
	.on('textCreated', () => {
		// Quand du texte est créé par l'assistant, on crée une bulle de dialogue dans le HTML
		speechBubble = createSpeechBubble(1); // Affiche la bulle pour le personnage 1
	})
	.on('textDelta', (textDelta) => {
		// A chaque nouveau morceau de texte reçu, on met à jour la bulle de dialogue
		let formattedText = formatTextWithLineBreaks(textDelta.value); // Formate le texte avec des retours à la ligne
		speechBubble.querySelector(".speech-bubble").innerHTML += formattedText; // Ajoute le texte à la bulle
		responseToCharacter2 += formattedText; // Ajoute le texte à la réponse pour le deuxième personnage
	})
	.on('end', () => {
		// Quand la réponse est terminée, on lance la conversation avec le deuxième assistant après un délai
		setTimeout(() => {
			startConversationWithCharacter2(responseToCharacter2); // Envoie la réponse au personnage 2
		}, 3000); // Délai de 3 secondes avant d'envoyer la réponse
	});
}

// Fonction pour démarrer la conversation avec le deuxième assistant
async function startConversationWithCharacter2(message){
	// Crée un nouveau message dans le thread du deuxième assistant avec le message reçu
	let userMessage = await openai.beta.threads.messages.create(thread2.id, {
		role: "user", // Rôle utilisateur (personne qui parle)
		content: message // Le contenu du message envoyé au deuxième personnage
	});

	let speechBubble; // Variable pour stocker la bulle de dialogue dans le HTML
	let responseToCharacter1 = ""; // Stocke la réponse pour le premier personnage

	// Crée un stream (flux) pour recevoir la réponse du deuxième assistant en temps réel
	let runStream = openai.beta.threads.runs.stream(thread2.id, {
		assistant_id: assistant2.id // ID de l'assistant qui répond
	})
	.on('textCreated', () => {
		// Quand du texte est créé par l'assistant, on crée une bulle de dialogue dans le HTML
		speechBubble = createSpeechBubble(2); // Affiche la bulle pour le personnage 2
	})
	.on('textDelta', (textDelta) => {
		// A chaque nouveau morceau de texte reçu, on met à jour la bulle de dialogue
		let formattedText = formatTextWithLineBreaks(textDelta.value); // Formate le texte avec des retours à la ligne
		speechBubble.querySelector(".speech-bubble").innerHTML += formattedText; // Ajoute le texte à la bulle
		responseToCharacter1 += formattedText; // Ajoute le texte à la réponse pour le premier personnage
	})
	.on('end', () => {
		// Quand la réponse est terminée, on lance la conversation avec le premier assistant après un délai
		setTimeout(() => {
			startConversationWithCharacter1(responseToCharacter1); // Envoie la réponse au personnage 1
		}, 3000); // Délai de 3 secondes avant d'envoyer la réponse
	});
}

// Fonction pour créer une bulle de dialogue dans le HTML pour afficher le texte
function createSpeechBubble(characterNumber){
	let textContainer = document.querySelector(".character-" + characterNumber + " .text-container"); // Sélectionne le conteneur de texte du personnage
	let newTextMessage = document.createElement("div"); // Crée un nouveau div pour le message
	newTextMessage.classList.add("message"); // Ajoute une classe CSS pour styliser le message
	newTextMessage.innerHTML = `
		<div class="speech-bubble"></div> <!-- Contient le texte -->
		<div class="arrow"></div>`; <!-- Ajoute une flèche pour indiquer le dialogue -->

	textContainer.appendChild(newTextMessage); // Ajoute le message au conteneur
	textContainer.scrollTop = textContainer.scrollHeight; // Scrolle automatiquement vers le bas pour voir le nouveau message
	return newTextMessage; // Retourne l'élément de la bulle de dialogue
}

// Fonction pour formater le texte en remplaçant les retours à la ligne par des balises HTML <br>
function formatTextWithLineBreaks(text) {
	return text.replace(/\n/g, "<br>"); // Remplace les "\n" par des balises <br> pour gérer les sauts de ligne dans HTML
}

Comment faire vos propres expérimentations ?

Pour réaliser vos propres expérimentations avec ce projet, voici les étapes à suivre :

  1. Téléchargez ou clonez le dépôt GitHub : Rendez-vous sur le dépôt GitHub du projet et récupérez le code.
  2. Suivez les instructions d’installation : Assurez-vous de bien suivre les étapes pour installer toutes les dépendances nécessaires.
  3. Ajoutez votre clé API OpenAI : Insérez votre clé API dans le fichier .env pour permettre au projet d'accéder à l'API OpenAI.
  4. Ajoutez les IDs de vos assistants précréés : Récupérez les IDs des assistants que vous avez créés sur le dashboard d'OpenAI et ajoutez-les également dans le fichier .env.

Pour une meilleure compréhension du fonctionnement global du projet, je vous recommande vivement de suivre mes deux tutoriels précédents. Ils détaillent chaque étape de la création et vous permettront de personnaliser les interactions selon vos besoins.

Amusez vous bien !

La bise, Tchouss !

o(*^@^*)o