بناء وكيل صوتي ذكي ينضم إلى مكالمات Google Meet (ElevenLabs + Selenium + PulseAudio)

Noqta Team
بواسطة Noqta Team ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

ما الذي ستبنيه

تخيّل وكيلاً ذكياً يمكنه الانضمام إلى مكالمات Google Meet، الاستماع إلى المشاركين، والرد بصوت بشري طبيعي — كل ذلك يعمل بشكل مستقل على خادم سحابي. هذا بالضبط ما سنبنيه في هذا الدليل.

في النهاية، ستحصل على:

  • بوت مبني على Selenium ينضم إلى Google Meet كمشارك ضيف
  • توجيه صوت افتراضي PulseAudio ينقل صوت Meet إلى الذكاء الاصطناعي والعكس
  • جسر ElevenLabs Conversational AI يستمع ويفكر ويتحدث
  • نشر على خادم سحابي GPU على Vast.ai مع سكريبت إعداد بأمر واحد

هكذا يتدفق الصوت:

المشاركون في Meet يتحدثون
    ← Chrome يلتقط الصوت ← sink meet_capture
        ← ElevenLabs ConvAI (STT ← LLM ← TTS)
            ← sink atlas_out ← مصدر افتراضي atlas_mic
                ← مدخل ميكروفون Chrome ← Meet يسمع رد الذكاء الاصطناعي

هذا نفس الإعداد الذي اختبرناه داخلياً في نقطة — وهو يعمل.


المتطلبات المسبقة

قبل البدء، تأكد من أن لديك:

  1. حساب ElevenLabs مع إمكانية الوصول إلى Conversational AI
  2. حساب Vast.ai (أو أي خادم Linux مع صلاحيات root)
  3. معرفة أساسية بـ Python وسطر أوامر Linux
  4. رابط Google Meet للاختبار

نظرة عامة على البنية

يتكون النظام من ثلاثة مكونات رئيسية تعمل معاً:

المكونالدورالأداة
Meet Joinerيفتح Chrome، يتنقل إلى Meet، ينضم كضيفSelenium + Xvfb
موجّه الصوتينشئ أجهزة صوت افتراضية، يوجه الصوت بين Meet والذكاء الاصطناعيPulseAudio
جسر الذكاء الاصطناعييلتقط صوت Meet، يرسله إلى ElevenLabs، يشغّل الردSDK ElevenLabs ConvAI

الثلاثة يعملون على نفس الجهاز. الفكرة الأساسية هي استخدام null sinks ومصادر افتراضية PulseAudio لإنشاء جسر صوتي ثنائي الاتجاه بين Chrome وواجهة برمجة ElevenLabs — لا حاجة لميكروفون أو مكبر صوت فعلي.


الخطوة 1: توفير خادم سحابي

تحتاج إلى خادم Linux مع بيئة سطح مكتب (لـ Chrome). استخدمنا Vast.ai لأنه رخيص وسريع التشغيل ويمنحك صلاحيات root.

على Vast.ai

  1. سجّل في Vast.ai
  2. ابحث عن قالب مع Ubuntu 22.04 و4 جيجابايت RAM على الأقل
  3. لا تحتاج بالضرورة إلى GPU لهذا المشروع — مثيلات CPU تعمل بشكل جيد
  4. اتصل بـ SSH بمثيلك بمجرد تشغيله

تبعيات النظام

بمجرد الاتصال، قم بتثبيت كل شيء:

#!/bin/bash
set -e
 
echo "=== إعداد الوكيل الصوتي ==="
 
# حزم النظام الأساسية
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
 
# تثبيت 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
 
# تثبيت ChromeDriver (يتوافق مع إصدار 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
 
# تبعيات Python
pip install -q \
    selenium \
    websockets \
    elevenlabs
 
echo "=== اكتمل الإعداد ==="

احفظ هذا كـ setup.sh وشغّله:

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

الخطوة 2: إعداد العرض الافتراضي والصوت

بما أنه لا يوجد شاشة فعلية أو بطاقة صوت على الخادم السحابي، نستخدم Xvfb (مخزن إطارات افتراضي) للعرض وPulseAudio لأجهزة الصوت الافتراضية.

تشغيل Xvfb وPulseAudio

# تشغيل العرض الافتراضي
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99
 
# تشغيل PulseAudio في وضع النظام
pulseaudio --start --exit-idle-time=-1

إنشاء أجهزة الصوت الافتراضية

هذا هو الجزء الحاسم. نحتاج إلى جهازي صوت افتراضيين:

# 1. meet_capture — خرج صوت Chrome يذهب هنا
#    سنقرأ من meet_capture.monitor لسماع ما يقوله المشاركون
pactl load-module module-null-sink \
    sink_name=meet_capture \
    sink_properties=device.description=MeetCapture
 
# 2. atlas_out — ردود الذكاء الاصطناعي تُشغَّل هنا
#    atlas_mic يقرأ من atlas_out.monitor ويعمل كمدخل ميكروفون Chrome
pactl load-module module-null-sink \
    sink_name=atlas_out \
    sink_properties=device.description=AtlasOutput
 
# 3. atlas_mic — مصدر ميكروفون افتراضي يتغذى من atlas_out
pactl load-module module-virtual-source \
    source_name=atlas_mic \
    master=atlas_out.monitor \
    source_properties=device.description=AtlasMic
 
# تعيين الافتراضيات ليستخدمها Chrome
pactl set-default-source atlas_mic    # ميكروفون Chrome = خرج الذكاء الاصطناعي
pactl set-default-sink meet_capture   # مكبرات صوت Chrome = نقطة الالتقاط

التحقق من الإعداد

# التحقق من sinks (يجب أن ترى meet_capture وatlas_out)
pactl list short sinks
 
# التحقق من المصادر (يجب أن ترى atlas_mic وmeet_capture.monitor)
pactl list short sources

يجب أن ترى مخرجاً مثل:

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

الخطوة 3: بناء بوت Meet Joiner

يستخدم البوت Selenium لفتح Chrome، التنقل إلى Google Meet، إدخال اسم، والنقر على "طلب الانضمام":

#!/usr/bin/env python3
"""meet_bot.py — ينضم إلى مكالمة Google Meet كضيف عبر 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")   # السماح تلقائياً بالميكروفون/الكاميرا
    # مهم: لا تستخدم --use-fake-device-for-media-stream
    # نريد أن يستخدم Chrome أجهزة 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):
    """يجرب عدة محددات XPath، يعيد أول تطابق مرئي."""
    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"فتح {url}")
    driver.get(url)
    time.sleep(4)
 
    # الخطوة 1: اختيار وضع الضيف (بدون حساب 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("  تم اختيار وضع الضيف")
        time.sleep(3)
 
    # الخطوة 2: إدخال اسم البوت
    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"  تم إدخال الاسم: {BOT_NAME}")
        time.sleep(1)
 
    # الخطوة 3: النقر على الانضمام
    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("  تم إرسال طلب الانضمام — في انتظار القبول...")
    else:
        print("  خطأ: لم يتم العثور على زر الانضمام")
        driver.save_screenshot("/tmp/meet_debug.png")
        return False
 
    # الخطوة 4: انتظار القبول (حتى 5 دقائق)
    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"  في المكالمة!")
            return True
        time.sleep(5)
 
    print("  انتهت مهلة انتظار القبول")
    return False
 
 
if __name__ == "__main__":
    driver = make_driver()
    try:
        if join_meet(driver, MEET_URL):
            print("\nالبوت في المكالمة. اضغط Ctrl+C للمغادرة.")
            while True:
                time.sleep(10)
    except KeyboardInterrupt:
        print("\nمغادرة المكالمة...")
    finally:
        driver.quit()

شرح أعلام Chrome المهمة

العلملماذا
--use-fake-ui-for-media-streamيقبل تلقائياً نوافذ أذونات الميكروفون/الكاميرا
--no-sandboxمطلوب للتشغيل كـ root على الخوادم السحابية
--disable-blink-features=AutomationControlledيمنع Meet من اكتشاف Selenium
عدم استخدام --use-fake-device-for-media-streamيضمن أن Chrome يستخدم PulseAudio (أجهزة صوت حقيقية)

مهم: بعد بدء Chrome، قد تحتاج إلى نقل تدفق الصوت يدوياً إلى sink meet_capture. سنقوم بأتمتة هذا في الجسر.


الخطوة 4: بناء جسر ElevenLabs ConvAI

هذا هو المكون الأساسي. يلتقط الصوت من meet_capture.monitor (ما يقوله المشاركون)، يرسله إلى ElevenLabs Conversational AI، ويشغّل رد الذكاء الاصطناعي في atlas_out (الذي يغذي ميكروفون Chrome).

#!/usr/bin/env python3
"""
meet_elevenlabs_bridge.py — جسر ElevenLabs ConvAI <-> Google Meet عبر PulseAudio.
 
تدفق الصوت:
  خرج صوت Meet -> meet_capture.monitor -> وكيل ElevenLabs
  وكيل ElevenLabs -> atlas_out -> atlas_out.monitor -> atlas_mic -> ميكروفون 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,
)
 
# ── الإعدادات ─────────────────────────────────────────────────────
API_KEY = "مفتاح_api_elevenlabs_الخاص_بك"
 
INPUT_SOURCE  = "meet_capture.monitor"   # ما يشغله Meet
OUTPUT_SINK   = "atlas_out"              # يغذي atlas_mic -> ميكروفون Meet
 
SAMPLE_RATE   = 16000
CHANNELS      = 1
FORMAT        = "s16le"          # PCM 16-بت موقّع little-endian
CHUNK_SAMPLES = 4000             # أجزاء 250 مللي ثانية (موصى بها من SDK)
CHUNK_BYTES   = CHUNK_SAMPLES * CHANNELS * 2
 
 
# ── واجهة صوت PulseAudio مخصصة ──────────────────────────────────
class PulseAudioInterface(AudioInterface):
    """يوجه الصوت عبر PulseAudio باستخدام عمليات فرعية 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()
 
        # الالتقاط من خرج صوت 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,
        )
 
        # تشغيل ردود الذكاء الاصطناعي في atlas_out -> ميكروفون 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"[صوت] الالتقاط من {INPUT_SOURCE}")
        print(f"[صوت] التشغيل إلى {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):
        # تفريغ قائمة الانتظار عند مقاطعة المستخدم للذكاء الاصطناعي
        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
 
 
# ── الرئيسي ───────────────────────────────────────────────────────
def run_bridge(client: ElevenLabs, agent_id: str):
    print(f"\n[جسر] بدء جسر ElevenLabs ConvAI")
    print(f"[جسر] الوكيل: {agent_id}")
    print(f"[جسر] اضغط Ctrl+C للإيقاف\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("[جسر] بدء جلسة جديدة...")
        try:
            conversation = Conversation(
                client=client,
                agent_id=agent_id,
                requires_auth=False,
                audio_interface=PulseAudioInterface(),
                callback_agent_response=lambda t: print(f"[وكيل] {t}"),
                callback_user_transcript=lambda t: print(f"[مستخدم] {t}"),
                callback_latency_measurement=lambda ms: print(
                    f"[زمن الاستجابة] {ms}ms"
                ),
            )
            conversation.start_session()
            conversation.wait_for_session_end()
        except Exception as e:
            print(f"[جسر] خطأ في الجلسة: {e}")
 
        if not quit_event.is_set():
            print("[جسر] انتهت الجلسة، إعادة التشغيل خلال 2 ثانية...")
            time.sleep(2)
 
    print("[جسر] تم.")
 
 
def main():
    parser = argparse.ArgumentParser(
        description="جسر ElevenLabs ConvAI <-> Google Meet"
    )
    parser.add_argument("--agent-id", required=True, help="معرّف وكيل ElevenLabs")
    parser.add_argument(
        "--api-key",
        default=API_KEY,
        help="مفتاح API ElevenLabs",
    )
    args = parser.parse_args()
 
    client = ElevenLabs(api_key=args.api_key)
    run_bridge(client, args.agent_id)
 
 
if __name__ == "__main__":
    main()

كيف يعمل PulseAudioInterface

يتوقع SDK ElevenLabs واجهة AudioInterface بأربع طرق:

الطريقةماذا تفعل
start(callback)تشغّل عمليات فرعية parec (التقاط) وpacat (تشغيل)
output(audio)تضع بايتات الصوت المُنتجة بالذكاء الاصطناعي في قائمة الانتظار للتشغيل
interrupt()تفرّغ قائمة الانتظار عندما يبدأ المستخدم بالتحدث (مقاطعة)
stop()تنهي العمليات الفرعية للصوت

استخدام parec وpacat مباشرة (بدلاً من PyAudio أو sounddevice) هو النهج الأكثر موثوقية على خوادم Linux بدون واجهة — لا تعارضات ALSA/JACK، لا مشاكل في تعداد الأجهزة.


الخطوة 5: ربط كل شيء معاً

الآن لنشغّل المكونات الثلاثة. افتح ثلاث جلسات طرفية (أو استخدم tmux):

الطرفية 1: تشغيل العرض والصوت

# تشغيل Xvfb
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99
 
# تشغيل PulseAudio
pulseaudio --start --exit-idle-time=-1
 
# إنشاء أجهزة الصوت الافتراضية
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

الطرفية 2: الانضمام إلى Meet

export DISPLAY=:99
python3 meet_bot.py "https://meet.google.com/رمز-اجتماعك"

انتظر حتى يطلب البوت الانضمام. اقبل البوت من نافذة Meet لمشارك آخر.

الطرفية 3: تشغيل جسر الذكاء الاصطناعي

python3 meet_elevenlabs_bridge.py --agent-id معرّف_الوكيل --api-key مفتاح_API

نقل صوت Chrome (مهم!)

بعد انضمام Chrome إلى المكالمة، انقل خرج الصوت إلى sink الالتقاط:

# عرض تدفقات صوت Chrome
pactl list short sink-inputs
 
# نقل كل تدفق إلى meet_capture (استبدل INDEX بالرقم الفعلي)
pactl move-sink-input INDEX meet_capture

يمكنك أتمتة هذا بدالة مساعدة:

def move_chrome_audio():
    """نقل جميع تدفقات صوت Chrome إلى sink meet_capture."""
    import time
    time.sleep(6)  # انتظار بدء Chrome بتشغيل الصوت
    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"تم نقل تدفق الصوت {parts[0]} إلى meet_capture")

الخطوة 6: إنشاء وكيل ElevenLabs

قبل تشغيل الجسر، تحتاج إلى وكيل Conversational AI على ElevenLabs:

  1. اذهب إلى لوحة تحكم ElevenLabs > Conversational AI
  2. انقر على إنشاء وكيل
  3. قم بتكوين وكيلك:
    • الاسم: اسم البوت (مثلاً "Atlas")
    • الصوت: اختر أي صوت من المكتبة
    • موجه النظام: حدد شخصية الوكيل ومعرفته
    • اللغة: اضبط على لغتك المفضلة
  4. انسخ معرّف الوكيل من صفحة إعدادات الوكيل

مثال على موجه النظام

أنت Atlas، مساعد ذكاء اصطناعي مفيد يشارك في مكالمة Google Meet.
تستمع إلى ما يقوله المشاركون وترد بشكل طبيعي.
اجعل ردودك موجزة — هذه محادثة مباشرة، وليست دردشة نصية.
إذا لم تكن متأكداً من شيء، اطلب التوضيح.

الخطوة 7: النشر كسكريبت واحد

للاستخدام في الإنتاج، ادمج كل شيء في سكريبت واحد:

#!/usr/bin/env python3
"""voice_meet_bot.py — وكيل صوتي ذكي كامل لـ Google Meet."""
 
import os
import subprocess
import sys
import threading
import time
 
# ... (دمج meet_bot.py + meet_elevenlabs_bridge.py)
# انظر السكريبت المدمج الكامل في مستودع المشروع
 
def main():
    # 1. إعداد أجهزة الصوت
    setup_audio()
 
    # 2. تشغيل Chrome والانضمام إلى Meet
    driver = make_driver()
    join_thread = threading.Thread(target=join_meet, args=(driver, MEET_URL))
    join_thread.start()
 
    # 3. نقل صوت Chrome بعد الانضمام
    time.sleep(10)
    move_chrome_audio()
 
    # 4. تشغيل جسر ElevenLabs
    client = ElevenLabs(api_key=API_KEY)
    run_bridge(client, AGENT_ID)

استكشاف الأخطاء وإصلاحها

"لا يوجد صوت من مشاركي Meet"

  • قد لا يكون صوت Chrome موجهاً إلى meet_capture. شغّل:
    pactl list short sink-inputs
    إذا رأيت تدفق Chrome على sink مختلف، انقله:
    pactl move-sink-input <INDEX> meet_capture

"الذكاء الاصطناعي يرد لكن مشاركي Meet لا يسمعونه"

  • تحقق أن atlas_mic هو مصدر إدخال Chrome:
    pactl list short source-outputs
    انقل مدخل مصدر Chrome إذا لزم الأمر:
    pactl move-source-output <INDEX> atlas_mic

"Chrome لا يبدأ"

  • تأكد أن Xvfb يعمل: export DISPLAY=:99
  • تحقق أن إصدار ChromeDriver يتطابق مع Chrome: google-chrome --version

"جلسة ElevenLabs تستمر في إعادة التشغيل"

  • تحقق أن مفتاح API صالح
  • تأكد أن هناك صوتاً فعلياً يدخل (الصمت قد يسبب انتهاء مهلة الجلسة)
  • جرّب زيادة CHUNK_SAMPLES إلى 8000 (أجزاء 500 مللي ثانية)

"Meet يكتشف البوت كآلي"

  • علم --disable-blink-features=AutomationControlled يساعد
  • تجاوز خاصية webdriver في make_driver() يساعد أيضاً
  • تجنب الانضمام إلى مكالمات كثيرة بشكل متتابع سريع

تفصيل التكاليف

الخدمةالتكلفةملاحظات
ElevenLabsمجاني: 10 دقائق/شهر، Pro: ~5$/ساعة محادثةتسعير Conversational AI
Vast.ai~0.10-0.30$/ساعةمثيل CPU يكفي
Google Meetمجانييعمل مع الوصول كضيف

للاختبار والتطوير، يمكنك تشغيل كامل النظام بأقل من 1$/يوم.


ما التالي

بمجرد أن يعمل الإعداد الأساسي، إليك بعض الأفكار لتوسيعه:

  • إضافة قواعد معرفة لوكيل ElevenLabs لمحادثات متخصصة بمجال معين
  • تسجيل النصوص باستخدام دوال الاستدعاء لملاحظات اجتماعات آلية
  • دعم متعدد اللغات من خلال تكوين إعدادات لغة الوكيل
  • أدوات مخصصة — وكلاء ElevenLabs يدعمون استدعاء الدوال، لذا يمكن لبوتك الاستعلام من قواعد البيانات، استدعاء APIs، أو تنفيذ إجراءات أثناء المحادثة
  • عدة بوتات في نفس المكالمة — كل واحد بدور مختلف (مدوّن ملاحظات، مترجم، خبير متخصص)

الخلاصة

بناء وكيل صوتي ذكي لـ Google Meet أمر ممكن بشكل مدهش مع الإعداد الصحيح لتوجيه الصوت. الجمع بين Selenium لأتمتة المتصفح، PulseAudio لأجهزة الصوت الافتراضية، وElevenLabs للذكاء الاصطناعي التحادثي ينشئ خط أنابيب قوي يعمل بشكل موثوق على الخوادم السحابية بدون واجهة.

الجزء الأصعب ليس الذكاء الاصطناعي — إنه توصيلات الصوت. بمجرد فهم تدفق meet_capture -> ElevenLabs -> atlas_out -> atlas_mic، يصبح الباقي بسيطاً.

شغّل مثيل Vast.ai، اتبع الخطوات، واجعل ذكاءك الاصطناعي ينضم إلى المكالمات في أقل من ساعة. أخبرنا بما تبنيه!


بُني واختُبر بواسطة فريق هندسة نقطة. أسئلة؟ تواصل معنا على noqta.tn.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على أفضل ممارسات البرمجة التوليدية: تقنيات متقدمة للتطوير بمساعدة الذكاء الاصطناعي.

ناقش مشروعك معنا

نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة

البدء مع ALLaM-7B-Instruct-preview

تعلم كيفية استخدام نموذج ALLaM-7B-Instruct-preview مع Python، وكيفية التفاعل معه من JavaScript عبر واجهة برمجة مستضافة (مثل Hugging Face Spaces).

8 د قراءة·