Créer un agent vocal IA qui rejoint les appels Google Meet (ElevenLabs + Selenium + PulseAudio)

Noqta Team
Par Noqta Team ·

Chargement du lecteur de synthèse vocale...

Ce que vous allez construire

Imaginez un agent IA capable de rejoindre vos appels Google Meet, écouter les participants et répondre avec une voix humaine naturelle — le tout de manière autonome sur un serveur cloud. C'est exactement ce que nous allons construire dans ce tutoriel.

À la fin, vous aurez :

  • Un bot basé sur Selenium qui rejoint Google Meet en tant que participant invité
  • Un routage audio virtuel PulseAudio qui achemine l'audio de Meet vers une IA et inversement
  • Un pont ElevenLabs Conversational AI qui écoute, réfléchit et parle
  • Un déploiement sur serveur cloud GPU sur Vast.ai avec un script de configuration en une commande

Voici comment l'audio circule :

Les participants Meet parlent
    → Chrome capture l'audio → sink meet_capture
        → ElevenLabs ConvAI (STT → LLM → TTS)
            → sink atlas_out → source virtuelle atlas_mic
                → Entrée micro de Chrome → Meet entend l'IA répondre

C'est la même configuration que nous avons testée en interne chez Noqta — et ça fonctionne.


Prérequis

Avant de commencer, assurez-vous d'avoir :

  1. Un compte ElevenLabs avec accès à Conversational AI
  2. Un compte Vast.ai (ou tout serveur Linux avec accès root)
  3. Des connaissances de base en Python et en ligne de commande Linux
  4. Un lien Google Meet pour tester

Vue d'ensemble de l'architecture

Le système comporte trois composants principaux qui fonctionnent ensemble :

ComposantRôleOutil
Meet JoinerOuvre Chrome, navigue vers Meet, rejoint en tant qu'invitéSelenium + Xvfb
Routeur audioCrée des périphériques audio virtuels, route l'audio entre Meet et l'IAPulseAudio
Pont IACapture l'audio de Meet, l'envoie à ElevenLabs, joue la réponse en retourSDK ElevenLabs ConvAI

Les trois s'exécutent sur la même machine. L'idée clé est d'utiliser des null sinks et des sources virtuelles PulseAudio pour créer un pont audio bidirectionnel entre Chrome et l'API ElevenLabs — aucun microphone physique ou haut-parleur nécessaire.


Étape 1 : Provisionner un serveur cloud

Vous avez besoin d'un serveur Linux avec un environnement de bureau (pour Chrome). Nous avons utilisé Vast.ai car c'est bon marché, rapide à démarrer et donne un accès root.

Sur Vast.ai

  1. Inscrivez-vous sur Vast.ai
  2. Recherchez un template avec Ubuntu 22.04 et au moins 4 Go de RAM
  3. Vous n'avez pas strictement besoin d'un GPU pour ce projet — les instances CPU fonctionnent très bien
  4. Connectez-vous en SSH à votre instance une fois qu'elle est en marche

Dépendances système

Une fois connecté, installez tout :

#!/bin/bash
set -e
 
echo "=== Installation de l'agent vocal ==="
 
# Paquets système principaux
apt-get update -q
apt-get install -y -q \
    wget curl unzip \
    xvfb pulseaudio \
    libsndfile1 libportaudio2 ffmpeg portaudio19-dev \
    fonts-liberation libappindicator3-1 libasound2 \
    libatk-bridge2.0-0 libatk1.0-0 libcups2 libdbus-1-3 \
    libgdk-pixbuf2.0-0 libnspr4 libnss3 libx11-xcb1 \
    libxcomposite1 libxdamage1 libxrandr2 xdg-utils
 
# Installer Google Chrome
wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
dpkg -i google-chrome-stable_current_amd64.deb || apt-get -f install -y
rm google-chrome-stable_current_amd64.deb
 
# Installer ChromeDriver (correspondant à votre version de Chrome)
CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+')
DRIVER_URL="https://storage.googleapis.com/chrome-for-testing-public/${CHROME_VERSION}.0/linux64/chromedriver-linux64.zip"
wget -q "$DRIVER_URL" -O /tmp/chromedriver.zip
unzip -o /tmp/chromedriver.zip -d /tmp/
mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin/
chmod +x /usr/local/bin/chromedriver
 
# Dépendances Python
pip install -q \
    selenium \
    websockets \
    elevenlabs
 
echo "=== Installation terminée ==="

Enregistrez ceci sous setup.sh et exécutez-le :

chmod +x setup.sh && ./setup.sh

Étape 2 : Configurer l'affichage virtuel et l'audio

Comme il n'y a pas de moniteur physique ni de carte son sur un serveur cloud, nous utilisons Xvfb (framebuffer virtuel) pour l'affichage et PulseAudio pour les périphériques audio virtuels.

Démarrer Xvfb et PulseAudio

# Démarrer l'affichage virtuel
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99
 
# Démarrer PulseAudio en mode système
pulseaudio --start --exit-idle-time=-1

Créer les périphériques audio virtuels

C'est la partie cruciale. Nous avons besoin de deux périphériques audio virtuels :

# 1. meet_capture — La sortie audio de Chrome va ici
#    Nous lirons depuis meet_capture.monitor pour entendre ce que disent les participants
pactl load-module module-null-sink \
    sink_name=meet_capture \
    sink_properties=device.description=MeetCapture
 
# 2. atlas_out — Les réponses de l'IA sont jouées ici
#    atlas_mic lit depuis atlas_out.monitor et agit comme entrée micro de Chrome
pactl load-module module-null-sink \
    sink_name=atlas_out \
    sink_properties=device.description=AtlasOutput
 
# 3. atlas_mic — Source microphone virtuelle alimentée par atlas_out
pactl load-module module-virtual-source \
    source_name=atlas_mic \
    master=atlas_out.monitor \
    source_properties=device.description=AtlasMic
 
# Définir les valeurs par défaut pour que Chrome les utilise
pactl set-default-source atlas_mic    # Micro de Chrome = sortie IA
pactl set-default-sink meet_capture   # Haut-parleurs de Chrome = notre point de capture

Vérifier la configuration

# Vérifier les sinks (devrait afficher meet_capture et atlas_out)
pactl list short sinks
 
# Vérifier les sources (devrait afficher atlas_mic et meet_capture.monitor)
pactl list short sources

Vous devriez voir une sortie comme :

1  meet_capture   module-null-sink.c   s16le 1ch 44100Hz   IDLE
2  atlas_out      module-null-sink.c   s16le 1ch 44100Hz   IDLE

Étape 3 : Construire le bot Meet Joiner

Le bot utilise Selenium pour ouvrir Chrome, naviguer vers Google Meet, entrer un nom et cliquer sur « Demander à rejoindre » :

#!/usr/bin/env python3
"""meet_bot.py — Rejoint un appel Google Meet en tant qu'invité via Selenium."""
 
import os
import sys
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
 
MEET_URL = sys.argv[1] if len(sys.argv) > 1 else "https://meet.google.com/abc-defg-hij"
DISPLAY = os.environ.get("DISPLAY", ":99")
BOT_NAME = "Atlas"
 
 
def make_driver():
    opts = Options()
    opts.binary_location = "/usr/bin/google-chrome"
    opts.add_argument("--no-sandbox")
    opts.add_argument("--disable-dev-shm-usage")
    opts.add_argument("--disable-gpu")
    opts.add_argument("--use-fake-ui-for-media-stream")   # auto-allow mic/cam
    # Important : NE PAS utiliser --use-fake-device-for-media-stream
    # Nous voulons que Chrome utilise les vrais périphériques PulseAudio
    opts.add_argument("--disable-blink-features=AutomationControlled")
    opts.add_argument("--window-size=1280,720")
    opts.add_argument("--autoplay-policy=no-user-gesture-required")
    opts.add_experimental_option("excludeSwitches", ["enable-automation"])
 
    svc = Service("/usr/local/bin/chromedriver")
    driver = webdriver.Chrome(service=svc, options=opts)
    driver.execute_script(
        "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
    )
    return driver
 
 
def find_any(driver, xpaths, timeout=10):
    """Essaie plusieurs sélecteurs XPath, retourne la première correspondance visible."""
    deadline = time.time() + timeout
    while time.time() < deadline:
        for xpath in xpaths:
            try:
                el = driver.find_element(By.XPATH, xpath)
                if el.is_displayed():
                    return el
            except NoSuchElementException:
                pass
        time.sleep(0.5)
    return None
 
 
def join_meet(driver, url):
    print(f"Ouverture de {url}")
    driver.get(url)
    time.sleep(4)
 
    # Étape 1 : Choisir le mode invité (sans compte Google)
    guest = find_any(driver, [
        "//span[contains(text(),'Use without an account')]",
        "//button[contains(text(),'Use without')]",
        "//span[contains(text(),'Continue without')]",
    ], timeout=8)
    if guest:
        guest.click()
        print("  Mode invité sélectionné")
        time.sleep(3)
 
    # Étape 2 : Entrer le nom du bot
    name_el = find_any(driver, [
        "//input[contains(@aria-label,'name') or contains(@aria-label,'Name')]",
        "//input[@placeholder='Your name']",
        "//input[@type='text']",
    ], timeout=8)
    if name_el:
        name_el.clear()
        name_el.send_keys(BOT_NAME)
        print(f"  Nom saisi : {BOT_NAME}")
        time.sleep(1)
 
    # Étape 3 : Cliquer sur rejoindre
    join_btn = find_any(driver, [
        "//span[contains(text(),'Ask to join')]",
        "//span[contains(text(),'Join now')]",
        "//button[contains(text(),'Ask to join')]",
        "//button[contains(text(),'Join now')]",
    ], timeout=15)
    if join_btn:
        join_btn.click()
        print("  Demande de participation envoyée — en attente d'admission...")
    else:
        print("  ERREUR : Bouton de participation non trouvé")
        driver.save_screenshot("/tmp/meet_debug.png")
        return False
 
    # Étape 4 : Attendre l'admission (jusqu'à 5 minutes)
    for i in range(60):
        mute_btns = driver.find_elements(By.XPATH,
            "//button[contains(@aria-label,'microphone') or contains(@aria-label,'mic')]"
        )
        if mute_btns:
            print(f"  DANS L'APPEL !")
            return True
        time.sleep(5)
 
    print("  Délai d'attente dépassé pour l'admission")
    return False
 
 
if __name__ == "__main__":
    driver = make_driver()
    try:
        if join_meet(driver, MEET_URL):
            print("\nLe bot est dans l'appel. Appuyez sur Ctrl+C pour quitter.")
            while True:
                time.sleep(10)
    except KeyboardInterrupt:
        print("\nDéconnexion de l'appel...")
    finally:
        driver.quit()

Explication des flags Chrome importants

FlagPourquoi
--use-fake-ui-for-media-streamAccepte automatiquement les popups de permission micro/caméra
--no-sandboxRequis pour l'exécution en root sur les serveurs cloud
--disable-blink-features=AutomationControlledEmpêche Meet de détecter Selenium
Pas de --use-fake-device-for-media-streamGarantit que Chrome utilise PulseAudio (vrais périphériques audio)

Important : Après le démarrage de Chrome, vous devrez peut-être déplacer manuellement son flux audio vers le sink meet_capture. Nous automatiserons cela dans le pont.


Étape 4 : Construire le pont ElevenLabs ConvAI

C'est le composant principal. Il capture l'audio depuis meet_capture.monitor (ce que disent les participants), l'envoie à ElevenLabs Conversational AI et joue la réponse de l'IA dans atlas_out (qui alimente le micro de Chrome).

#!/usr/bin/env python3
"""
meet_elevenlabs_bridge.py — Pont ElevenLabs ConvAI <-> Google Meet via PulseAudio.
 
Flux audio :
  Audio sortant Meet -> meet_capture.monitor -> Agent ElevenLabs
  Agent ElevenLabs -> atlas_out -> atlas_out.monitor -> atlas_mic -> Micro Meet
"""
 
import argparse
import queue
import subprocess
import sys
import threading
import signal
import time
from typing import Callable
 
from elevenlabs.client import ElevenLabs
from elevenlabs.conversational_ai.conversation import (
    AudioInterface,
    Conversation,
)
 
# ── Configuration ─────────────────────────────────────────────────
API_KEY = "votre_clé_api_elevenlabs_ici"
 
INPUT_SOURCE  = "meet_capture.monitor"   # ce que Meet joue
OUTPUT_SINK   = "atlas_out"              # alimente atlas_mic -> micro Meet
 
SAMPLE_RATE   = 16000
CHANNELS      = 1
FORMAT        = "s16le"          # PCM 16-bit signé little-endian
CHUNK_SAMPLES = 4000             # chunks de 250ms (recommandé par le SDK)
CHUNK_BYTES   = CHUNK_SAMPLES * CHANNELS * 2
 
 
# ── Interface audio PulseAudio personnalisée ─────────────────────
class PulseAudioInterface(AudioInterface):
    """Route l'audio via PulseAudio en utilisant des sous-processus parec/pacat."""
 
    def start(self, input_callback: Callable[[bytes], None]):
        self.input_callback = input_callback
        self.output_queue: queue.Queue[bytes] = queue.Queue()
        self.should_stop = threading.Event()
 
        # Capture depuis la sortie audio de Meet
        self._rec_proc = subprocess.Popen(
            [
                "parec",
                f"--device={INPUT_SOURCE}",
                f"--format={FORMAT}",
                f"--rate={SAMPLE_RATE}",
                f"--channels={CHANNELS}",
                "--latency-msec=50",
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
        )
 
        # Jouer les réponses de l'IA dans atlas_out -> micro de Meet
        self._play_proc = subprocess.Popen(
            [
                "pacat",
                "--playback",
                f"--device={OUTPUT_SINK}",
                f"--format={FORMAT}",
                f"--rate={SAMPLE_RATE}",
                f"--channels={CHANNELS}",
                "--latency-msec=50",
            ],
            stdin=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
        )
 
        self._input_thread = threading.Thread(
            target=self._read_input, daemon=True
        )
        self._output_thread = threading.Thread(
            target=self._write_output, daemon=True
        )
        self._input_thread.start()
        self._output_thread.start()
 
        print(f"[audio] capture depuis {INPUT_SOURCE}")
        print(f"[audio] lecture vers {OUTPUT_SINK}")
 
    def stop(self):
        self.should_stop.set()
        if self._rec_proc:
            self._rec_proc.terminate()
        if self._play_proc:
            try:
                self._play_proc.stdin.close()
            except Exception:
                pass
            self._play_proc.terminate()
 
    def output(self, audio: bytes):
        self.output_queue.put(audio)
 
    def interrupt(self):
        # Vider la file d'attente quand l'utilisateur interrompt l'IA
        try:
            while True:
                self.output_queue.get_nowait()
        except queue.Empty:
            pass
 
    def _read_input(self):
        while not self.should_stop.is_set():
            chunk = self._rec_proc.stdout.read(CHUNK_BYTES)
            if not chunk:
                break
            self.input_callback(chunk)
 
    def _write_output(self):
        while not self.should_stop.is_set():
            try:
                audio = self.output_queue.get(timeout=0.25)
                self._play_proc.stdin.write(audio)
                self._play_proc.stdin.flush()
            except queue.Empty:
                pass
            except BrokenPipeError:
                break
 
 
# ── Principal ─────────────────────────────────────────────────────
def run_bridge(client: ElevenLabs, agent_id: str):
    print(f"\n[pont] Démarrage du pont ElevenLabs ConvAI")
    print(f"[pont] Agent : {agent_id}")
    print(f"[pont] Appuyez sur Ctrl+C pour arrêter\n")
 
    quit_event = threading.Event()
    signal.signal(signal.SIGTERM, lambda s, f: quit_event.set())
    signal.signal(signal.SIGINT, lambda s, f: quit_event.set())
 
    while not quit_event.is_set():
        print("[pont] Démarrage d'une nouvelle session...")
        try:
            conversation = Conversation(
                client=client,
                agent_id=agent_id,
                requires_auth=False,
                audio_interface=PulseAudioInterface(),
                callback_agent_response=lambda t: print(f"[agent] {t}"),
                callback_user_transcript=lambda t: print(f"[user]  {t}"),
                callback_latency_measurement=lambda ms: print(
                    f"[latence] {ms}ms"
                ),
            )
            conversation.start_session()
            conversation.wait_for_session_end()
        except Exception as e:
            print(f"[pont] Erreur de session : {e}")
 
        if not quit_event.is_set():
            print("[pont] Session terminée, redémarrage dans 2s...")
            time.sleep(2)
 
    print("[pont] Terminé.")
 
 
def main():
    parser = argparse.ArgumentParser(
        description="Pont ElevenLabs ConvAI <-> Google Meet"
    )
    parser.add_argument("--agent-id", required=True, help="ID de l'agent ElevenLabs")
    parser.add_argument(
        "--api-key",
        default=API_KEY,
        help="Clé API ElevenLabs",
    )
    args = parser.parse_args()
 
    client = ElevenLabs(api_key=args.api_key)
    run_bridge(client, args.agent_id)
 
 
if __name__ == "__main__":
    main()

Comment fonctionne le PulseAudioInterface

Le SDK ElevenLabs attend un AudioInterface avec quatre méthodes :

MéthodeCe qu'elle fait
start(callback)Lance les sous-processus parec (capture) et pacat (lecture)
output(audio)Met en file d'attente les octets audio générés par l'IA pour la lecture
interrupt()Vide la file quand l'utilisateur commence à parler (interruption)
stop()Termine les sous-processus audio

Utiliser parec et pacat directement (au lieu de PyAudio ou sounddevice) est l'approche la plus fiable sur les serveurs Linux headless — pas de conflits ALSA/JACK, pas de problèmes d'énumération de périphériques.


Étape 5 : Tout connecter ensemble

Maintenant, exécutons les trois composants. Ouvrez trois sessions de terminal (ou utilisez tmux) :

Terminal 1 : Démarrer l'affichage et l'audio

# Démarrer Xvfb
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99
 
# Démarrer PulseAudio
pulseaudio --start --exit-idle-time=-1
 
# Créer les périphériques audio virtuels
pactl load-module module-null-sink sink_name=meet_capture \
    sink_properties=device.description=MeetCapture
pactl load-module module-null-sink sink_name=atlas_out \
    sink_properties=device.description=AtlasOutput
pactl load-module module-virtual-source source_name=atlas_mic \
    master=atlas_out.monitor \
    source_properties=device.description=AtlasMic
pactl set-default-source atlas_mic
pactl set-default-sink meet_capture

Terminal 2 : Rejoindre le Meet

export DISPLAY=:99
python3 meet_bot.py "https://meet.google.com/votre-code-reunion"

Attendez que le bot demande à rejoindre. Acceptez le bot depuis la fenêtre Meet d'un autre participant.

Terminal 3 : Démarrer le pont IA

python3 meet_elevenlabs_bridge.py --agent-id VOTRE_ID_AGENT --api-key VOTRE_CLE_API

Déplacer l'audio de Chrome (Important !)

Après que Chrome a rejoint l'appel, déplacez sa sortie audio vers le sink de capture :

# Lister les flux audio de Chrome
pactl list short sink-inputs
 
# Déplacer chaque flux vers meet_capture (remplacez INDEX par le numéro réel)
pactl move-sink-input INDEX meet_capture

Vous pouvez automatiser cela avec une fonction d'aide :

def move_chrome_audio():
    """Déplace tous les flux audio Chrome vers le sink meet_capture."""
    import time
    time.sleep(6)  # attendre que Chrome commence à jouer de l'audio
    result = subprocess.run(
        ["pactl", "list", "short", "sink-inputs"],
        capture_output=True, text=True,
    )
    for line in result.stdout.strip().splitlines():
        parts = line.split()
        if parts:
            subprocess.run(
                ["pactl", "move-sink-input", parts[0], "meet_capture"],
                capture_output=True,
            )
            print(f"Flux audio {parts[0]} déplacé vers meet_capture")

Étape 6 : Créer votre agent ElevenLabs

Avant de lancer le pont, vous avez besoin d'un agent Conversational AI sur ElevenLabs :

  1. Allez dans Tableau de bord ElevenLabs > Conversational AI
  2. Cliquez sur Créer un agent
  3. Configurez votre agent :
    • Nom : Le nom de votre bot (ex. « Atlas »)
    • Voix : Choisissez une voix dans la bibliothèque
    • Prompt système : Définissez la personnalité et les connaissances de l'agent
    • Langue : Réglez sur votre langue préférée
  4. Copiez l'ID de l'agent depuis la page de paramètres de l'agent

Exemple de prompt système

Tu es Atlas, un assistant IA serviable qui participe à un appel Google Meet.
Tu écoutes ce que disent les participants et tu réponds naturellement.
Garde tes réponses concises — c'est une conversation en direct, pas un chat textuel.
Si tu n'es pas sûr de quelque chose, demande des précisions.

Étape 7 : Déployer en un seul script

Pour une utilisation en production, combinez tout en un seul script :

#!/usr/bin/env python3
"""voice_meet_bot.py — Agent vocal IA complet pour Google Meet."""
 
import os
import subprocess
import sys
import threading
import time
 
# ... (combiner meet_bot.py + meet_elevenlabs_bridge.py)
# Voir le script combiné complet dans le dépôt du projet
 
def main():
    # 1. Configurer les périphériques audio
    setup_audio()
 
    # 2. Démarrer Chrome et rejoindre Meet
    driver = make_driver()
    join_thread = threading.Thread(target=join_meet, args=(driver, MEET_URL))
    join_thread.start()
 
    # 3. Déplacer l'audio de Chrome après qu'il a rejoint
    time.sleep(10)
    move_chrome_audio()
 
    # 4. Démarrer le pont ElevenLabs
    client = ElevenLabs(api_key=API_KEY)
    run_bridge(client, AGENT_ID)

Dépannage

« Pas d'audio des participants Meet »

  • L'audio de Chrome n'est peut-être pas routé vers meet_capture. Exécutez :
    pactl list short sink-inputs
    Si vous voyez le flux Chrome sur un autre sink, déplacez-le :
    pactl move-sink-input <INDEX> meet_capture

« L'IA répond mais les participants Meet ne l'entendent pas »

  • Vérifiez que atlas_mic est la source d'entrée de Chrome :
    pactl list short source-outputs
    Déplacez l'entrée source de Chrome si nécessaire :
    pactl move-source-output <INDEX> atlas_mic

« Chrome ne démarre pas »

  • Assurez-vous que Xvfb est en cours d'exécution : export DISPLAY=:99
  • Vérifiez que la version de ChromeDriver correspond à Chrome : google-chrome --version

« La session ElevenLabs redémarre sans cesse »

  • Vérifiez que votre clé API est valide
  • Assurez-vous qu'il y a bien de l'audio entrant (le silence peut causer des timeouts de session)
  • Essayez d'augmenter CHUNK_SAMPLES à 8000 (chunks de 500ms)

« Meet détecte le bot comme automatisé »

  • Le flag --disable-blink-features=AutomationControlled aide
  • La surcharge de la propriété webdriver dans make_driver() aide aussi
  • Évitez de rejoindre trop d'appels en succession rapide

Détail des coûts

ServiceCoûtNotes
ElevenLabsGratuit : 10 min/mois, Pro : ~5$/h de conversationTarification Conversational AI
Vast.ai~0,10-0,30$/hUne instance CPU suffit
Google MeetGratuitFonctionne avec l'accès invité

Pour les tests et le développement, vous pouvez faire tourner l'ensemble pour moins de 1$/jour.


Et ensuite

Une fois la configuration de base fonctionnelle, voici quelques idées pour l'étendre :

  • Ajouter des bases de connaissances à votre agent ElevenLabs pour des conversations spécifiques à un domaine
  • Enregistrer les transcriptions en utilisant les fonctions de rappel pour des notes de réunion automatisées
  • Support multilingue en configurant les paramètres de langue de l'agent
  • Outils personnalisés — Les agents ElevenLabs supportent l'appel de fonctions, votre bot peut donc interroger des bases de données, appeler des API ou déclencher des actions en pleine conversation
  • Plusieurs bots dans le même appel — chacun avec un rôle différent (secrétaire, traducteur, expert métier)

Conclusion

Construire un agent vocal IA pour Google Meet est étonnamment réalisable avec la bonne configuration de routage audio. La combinaison de Selenium pour l'automatisation du navigateur, PulseAudio pour les périphériques audio virtuels et ElevenLabs pour l'IA conversationnelle crée un pipeline robuste qui fonctionne de manière fiable sur les serveurs cloud headless.

La partie la plus difficile n'est pas l'IA — c'est la plomberie audio. Une fois que vous comprenez le flux meet_capture -> ElevenLabs -> atlas_out -> atlas_mic, le reste est simple.

Lancez une instance Vast.ai, suivez les étapes et faites rejoindre votre IA à des appels en moins d'une heure. Dites-nous ce que vous construisez avec !


Construit et testé par l'équipe d'ingénierie Noqta. Des questions ? Contactez-nous sur noqta.tn.


Vous voulez lire plus de tutoriels? Découvrez notre dernier tutoriel sur Fine-tuning de Gemma pour l'arabe.

Discutez de votre projet avec nous

Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.

Trouvons les meilleures solutions pour vos besoins.

Articles connexes

Demarrer avec ALLaM-7B-Instruct-preview

Apprenez a utiliser le modele ALLaM-7B-Instruct-preview avec Python, et comment interagir avec lui depuis JavaScript via une API hebergee (ex: sur Hugging Face Spaces).

8 min read·