چتبات تلفنی فارسی (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
-
لتنسی: اگه سرعت پاسخ کند بود:
- مدل whisper رو از
mediumبهsmallتغییر بده (دقت کمتر، سرعت بیشتر) - اگه GPU داری،
WHISPER_DEVICE=cudaرو در docker-compose ست کن - مدل Ollama رو سبکتر انتخاب کن (مثلاً یک مدل 7B به جای 70B)
- مدل whisper رو از
-
Barge-in (قطع صحبت بات): نسخهی فعلی ساده است (نوبتی: بات حرف میزنه، بعد کاربر). برای barge-in واقعی باید از AMI events مثل
TALK_DETECTاستفاده کنی که پیچیدهتره - در صورت نیاز میتونم اضافهاش کنم. -
مدیریت چند تماس همزمان: چون AGI برای هر تماس یک پراسس جداست، همزمانی بهصورت خودکار پشتیبانی میشه؛ فقط مطمئن شو سرویسهای STT/TTS/Ollama منابع کافی (CPU/RAM/GPU) برای بار همزمان دارن.
-
امنیت SIP Trunk: حتماً
type=identifyرو با IP دقیق مرکز تماس محدود کن و فایروال روی پورت 5060 و رنج RTP بذار. -
لاگ و مانیتورینگ:
agi.verbose()در اسکریپت لاگها رو تو کنسول Asterisk میریزه (asterisk -rvvvبرای دیدن زنده).
گام بعدی (اختیاری)
اگه بخوای میتونم اینها رو هم اضافه کنم:
- پشتیبانی از AMI برای barge-in و real-time monitoring
- ذخیرهی تاریخچهی مکالمات در دیتابیس (برای گزارشگیری)
- health-check و auto-restart برای سرویسها
- صف تماس (queue) قبل از رسیدن به بات