2026-07-18 01:24:53 +03:30
2026-07-18 01:24:53 +03:30

چت‌بات تلفنی فارسی (Asterisk + STT + Ollama + TTS)

ساختار پروژه

voicebot/
├── docker-compose.yml
├── .env.example               # قالب فایل تنظیمات - کپی کن به .env و پرش کن
├── asterisk/
│   ├── Dockerfile
│   ├── entrypoint.sh          # کانفیگ‌ها رو موقع استارت از .env می‌سازه
│   ├── templates/             # قالب‌های کانفیگ (دستی ادیت نکن)
│   │   ├── pjsip-base.conf.template
│   │   ├── pjsip-trunk.conf.template
│   │   ├── extensions.conf.template
│   │   ├── agi.conf
│   │   └── modules.conf
│   └── config/                # اینجا خالیه - خروجی خودکار ساخته می‌شه
├── agi-scripts/
│   └── voicebot.py           # orchestrator اصلی (STT -> Ollama -> TTS)
├── stt/                      # سرویس گفتار-به-متن (faster-whisper)
├── tts/                      # سرویس متن-به-گفتار (Piper)
└── models/
    ├── whisper/               # مدل‌ whisper اینجا کش می‌شه (خودکار دانلود می‌شه)
    └── piper/                 # باید مدل صدای فارسی رو دستی بذاری

همه‌ی تنظیمات فقط در یک فایل: .env

دیگه لازم نیست تو چند فایل کانفیگ Asterisk بگردی. کافیه .env.example رو کپی کنی و مقادیر رو پر کنی:

cp .env.example .env
nano .env   # یا هر ادیتوری که دوست داری

محتوای فایل:

# ---------- Ollama ----------
OLLAMA_URL=http://OLLAMA_HOST:11434/api/generate
OLLAMA_MODEL=llama3

# ---------- STT (faster-whisper) ----------
WHISPER_MODEL=medium
WHISPER_DEVICE=cpu

# ---------- TTS (Piper) ----------
PIPER_VOICE=/models/piper/fa_IR-model.onnx

# ---------- ترانک مرکز تماس شماره ۱ ----------
TRUNK1_NAME=callcenter1
TRUNK1_HOST=CALLCENTER1_IP
TRUNK1_USERNAME=USERNAME
TRUNK1_PASSWORD=CALLCENTER1_PASS

# ---------- ترانک مرکز تماس شماره ۲ (اختیاری) ----------
TRUNK2_NAME=
TRUNK2_HOST=
TRUNK2_USERNAME=
TRUNK2_PASSWORD=

# ---------- SIP User داخلی (تست) ----------
TEST_USER_EXTEN=1000
TEST_USER_PASSWORD=CHANGE_ME_STRONG_PASSWORD

با هر بار اجرای docker compose up -d --build، اسکریپت entrypoint.sh داخل کانتینر Asterisk خودکار فایل‌های pjsip.conf و extensions.conf رو از روی همین .env می‌سازه. یعنی:

  • اگه TRUNK2_HOST رو خالی بذاری، ترانک دوم اصلاً ساخته نمی‌شه.
  • اگه پرش کنی، ترانک دوم هم خودکار به pjsip.conf اضافه می‌شه (بدون این‌که چیزی رو دستی بنویسی).
  • تغییر شماره‌ی تست (TEST_USER_EXTEN) هم فقط با عوض کردن همین متغیر انجام می‌شه.

⚠️ فایل .env رو در .gitignore نگه دار (چون رمزها توشه) - فقط .env.example رو commit کن.

💡 بعد از هر تغییر در .env، کافیه docker compose up -d بزنی (نیازی به --build نیست، چون کانفیگ موقع استارت کانتینر ساخته می‌شه، نه موقع build). فقط اگه خود Dockerfile یا کد رو عوض کردی --build لازمه.

مرحله ۱: دانلود مدل صدای فارسی Piper

Piper به یک مدل ONNX فارسی نیاز دارد. مدل‌های آماده را از مخزن رسمی دانلود کن:

mkdir -p models/piper
cd models/piper
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/fa/fa_IR/gyro/medium/fa_IR-gyro-medium.onnx -O fa_IR-model.onnx
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/fa/fa_IR/gyro/medium/fa_IR-gyro-medium.onnx.json -O fa_IR-model.onnx.json
cd ../..

اگر لینک بالا در دسترس نبود، در صفحه‌ی huggingface.co/rhasspy/piper-voices دنبال پوشه‌ی fa/fa_IR بگرد و آخرین نسخه رو بردار.

مرحله ۲: تنظیم اطلاعات ترانک SIP و Ollama

همه‌ی این‌ها الان در همون فایل .env هست (بخش بالا رو ببین) - نیازی به دست زدن به فایل‌های داخل asterisk/ نیست.

مرحله ۳: بالا آوردن سرویس‌ها

docker compose up -d --build
docker compose logs -f asterisk

بار اول که stt-service بالا میاد، مدل whisper (چند صد مگابایت) دانلود می‌شه - صبر کن کامل بشه.

مرحله ۴: تست

با هر سافت‌فون (مثل Zoiper یا Linphone) به extension داخلی که در .env تحت TEST_USER_EXTEN تعریف کردی (پیش‌فرض 1000) با یوزر test-user و پسورد TEST_USER_PASSWORD وصل شو و تماس بگیر. باید صدای خوش‌آمدگویی رو بشنوی، بعد صحبت کن و منتظر پاسخ بات باش.

برای اتصال واقعی مرکز تماس، تماس روی ترانک PJSIP وارد context به نام from-trunk می‌شه که در extensions.conf تعریف شده.

نکات مهم برای Production

  1. لتنسی: اگه سرعت پاسخ کند بود:

    • مدل whisper رو از medium به small تغییر بده (دقت کمتر، سرعت بیشتر)
    • اگه GPU داری، WHISPER_DEVICE=cuda رو در docker-compose ست کن
    • مدل Ollama رو سبک‌تر انتخاب کن (مثلاً یک مدل 7B به جای 70B)
  2. Barge-in (قطع صحبت بات): نسخه‌ی فعلی ساده است (نوبتی: بات حرف می‌زنه، بعد کاربر). برای barge-in واقعی باید از AMI events مثل TALK_DETECT استفاده کنی که پیچیده‌تره - در صورت نیاز می‌تونم اضافه‌اش کنم.

  3. مدیریت چند تماس همزمان: چون AGI برای هر تماس یک پراسس جداست، همزمانی به‌صورت خودکار پشتیبانی می‌شه؛ فقط مطمئن شو سرویس‌های STT/TTS/Ollama منابع کافی (CPU/RAM/GPU) برای بار همزمان دارن.

  4. امنیت SIP Trunk: حتماً type=identify رو با IP دقیق مرکز تماس محدود کن و فایروال روی پورت 5060 و رنج RTP بذار.

  5. لاگ و مانیتورینگ: agi.verbose() در اسکریپت لاگ‌ها رو تو کنسول Asterisk می‌ریزه (asterisk -rvvv برای دیدن زنده).

گام بعدی (اختیاری)

اگه بخوای می‌تونم این‌ها رو هم اضافه کنم:

  • پشتیبانی از AMI برای barge-in و real-time monitoring
  • ذخیره‌ی تاریخچه‌ی مکالمات در دیتابیس (برای گزارش‌گیری)
  • health-check و auto-restart برای سرویس‌ها
  • صف تماس (queue) قبل از رسیدن به بات
Description
No description provided
Readme 1.4 GiB
Languages
Python 77.5%
Shell 11.9%
Dockerfile 10.6%