Files
aramesh-backend/chatbot/README.md
T
MMD ce0735d775 feat(stack): full overhaul — hardening, ops tooling, monitoring, analytics, chatbot
Security: deep /api/health (DB+MinIO probes, 503 on failure) + /api/live;
rate-limited public forms with honeypots; real client IP behind Traefik
(--proxy-headers); TipTap URL sanitization on write (nh3); non-root
containers + slim .dockerignore; prod MinIO console bound to 127.0.0.1;
HSTS/nosniff on TLS routers; JWT 8h; no default credentials in code.

Reliability: Alembic migrations (create_all baseline); graceful shutdown
(exec uvicorn); hardened backups (checksums, sanity check, freshness gauge,
optional rclone off-site) + restore.sh + hourly db-backup sidecar (ops
profile); stack.sh ops tooling (deploy/logs/health/backup/restore/monitoring);
.gitattributes LF for shell scripts.

Orchestration: json-file log rotation, pinned images, per-service memory
limits, edge/internal networks, Traefik ping/accesslog/metrics + flood
limiter, conditional minio-setup, pgvector db image, one-shot db-init
(umami + aramesh_chatbot databases).

Chatbot: unified from site-chatbot branch (RAG + pgvector, SSE, ChatWidget).

Monitoring: Prometheus/Alertmanager/Loki/Promtail/Grafana + cAdvisor,
node/postgres/blackbox exporters, provisioned dashboards and 10 alert
rules; alerts delivered to Bale (tapi.bale.ai — Telegram-compatible).

Analytics: Umami on shared Postgres, build-time tracker injection, custom
events (contact/newsletter/phone/chat/lang) via frontend/src/analytics.ts.

Hygiene: CSV export for contact messages and subscribers; upload image
optimization (Pillow); CI script + GitHub-compatible workflow; audit.sh;
gen-env.sh for strong credentials.
2026-09-19 00:24:57 +03:30

8.7 KiB

دستیار هوشمند سایت (چت‌بات)

سرویس گفتگوی محتوای سایت «گروه ساختمانی آرامش» — بازدیدکننده به فارسی سؤال می‌پرسد و دستیار فقط از روی محتوای خود سایت (مقاله‌ها، پروژه‌ها، خدمات، سؤالات متداول، اطلاعات تماس و…) پاسخ می‌دهد؛ اگر پاسخ در محتوا نباشد، به‌جای ساخت جواب، صادقانه اعلام می‌کند.

این سرویس پورت خط لولهٔ پروژهٔ llm-srerver-chatbot (نسخه v13) با چهار تغییر اصلی برای این سایت است:

  1. پایگاه sparse به‌جای SPLADE از BM25 استفاده می‌کند — SPLADE انگلیسی‌محور است و روی فارسی عملاً بی‌فایده؛ BM25 با نرمال‌سازی فارسی (ی/ک عربی، اعراب، ارقام، نیم‌فاصله) جایگزین شده است.
  2. ذخیره‌ساز برداری pgvector است، نه FAISS — بردارها در یک دیتابیس جدا (aramesh_chatbot) روی همان نمونه Postgres نگهداری می‌شوند؛ همگام‌سازی افزایشی است (فقط سطرهای جدید/تغییریافته امبد می‌شوند)، بکاپ‌گیری با خود دیتابیس است و فایل ایندکس جدا وجود ندارد.
  3. تأخیر کمتر — مسیریابی alpha با LLM و گسترش چند‌پرسشی (multi-query) به‌صورت پیش‌فرض خاموش‌اند (با متغیر محیطی قابل فعال‌سازی)؛ بازنویسی پرسش فقط وقتی تاریخچه گفتگو وجود دارد اجرا می‌شود.
  4. استریم واقعی توکن‌به‌توکن با astream_events به‌جای دیف پیام‌های کامل.

خط لوله هر پیام

پرسش کاربر
  │
  ├─[اگر تاریخچه هست] بازنویسی پرسش با LLM (حل ضمیرها و اشاره‌ها: «اون دومی» → موضوع واقعی)
  │
  ├─ بازیابی ترکیبی:  pgvector (معنایی، کسینوسی روی HNSW — MiniLM چندزبانه)
  │                   + BM25 (کلیدواژه، متن نرمال‌شده فارسی)
  │                   نمره‌ها min-max → ترکیب α×معنایی + (1-α)×کلیدواژه
  │
  ├─ برش خوشه‌ای (K-Means K=2 + silhouette ≥ 0.55) — مرز طبیعی کیفیت
  │
  ├─ ری‌رنک با BAAI/bge-reranker-v2-m3  →  نگه‌داشتن ۳ سند برتر
  │
  └─ تولید پاسخ فارسی با LLM (قواعد تکیه بر داده + معرفی صفحه مرتبط + پیام جایگزین مشخص)

ایندکس از محتوای PostgreSQL سایت ساخته می‌شود (articles منتشرشده، projects، services، faqs، brand، offices، investment_models، process_steps، why_us، team، testimonials، timeline، story). متن‌های بلند به قطعات ~۷۰۰ نویسه‌ای هم‌پوشان برش می‌خورند.

  • ایندکس برداری در pgvector: جدول chatbot_chunks در دیتابیس اختصاصی aramesh_chatbot (روی همان نمونه Postgres) با ستون embedding vector(384) و ایندکس HNSW کسینوسی؛ هر قطعه doc_id پایدار و content_hash دارد و همگام‌سازی فقط سطرهای جدید/تغییریافته را امبد می‌کند. دیتابیس و جدول در شروع سرویس خودکار ساخته می‌شوند.
  • بازسازی خودکار: یک حلقهٔ پس‌زمینه هر INDEX_REFRESH_SECONDS ثانیه محتوا را چک می‌کند و اگر ادمین چیزی را در پنل عوض کرده باشد، فقط تغییرات همگام می‌شود (امبد اجباری همه: POST /chat/reindex).
  • ماندگاری گفتگو: در حافظهٔ همان پروسه (MemorySaver لنگ‌گراف) — با ری‌استارت پاک می‌شود.

متغیرهای محیطی (در .env ریشه پروژه)

متغیر پیش‌فرض توضیح
LLM_BASE_URL خالی اجباری — نشانی سرویس LLM سازگار با OpenAI. بدون آن چت‌بات بالا می‌آید ولی پاسخ نمی‌دهد
LLM_API_KEY خالی کلید API (برای سرور داخلی not-needed بگذارید)
LLM_MODEL openai/gpt-oss-120b نام مدل
CHAT_REINDEX_TOKEN خالی توکن POST /chat/reindex — اگر خالی باشد آن مسیر ۴۰۳ می‌دهد
CHATBOT_DB_NAME aramesh_chatbot نام دیتابیس اختصاصی چت‌بات روی همان نمونه Postgres (بردارها اینجا می‌روند)
EMBEDDING_DIM 384 بعد بردار مدل امبدینگ — با تعویض مدل امبدینگ باید هماهنگ شود
RERANKER_ENABLED true روی سرور کم‌رم (زیر ~۴GB) false بگذارید
ALPHA_DENSE 0.5 وزن جست‌وجوی معنایی در ترکیب نمره‌ها (۰ تا ۱)
BEST_OF_K 3 تعداد سند نهایی که به LLM می‌رود
INDEX_REFRESH_SECONDS 600 بازسازی خودکار ایندکس پس از تغییر محتوا (۰ = خاموش)
RATE_LIMIT_MESSAGES / RATE_LIMIT_WINDOW 20 / 300 سقف پیام هر IP در پنجره زمانی (ثانیه)

DATABASE_URL در داکر از docker-compose.yml تزریق می‌شود — دیتابیس سایت فقط خوانده می‌شود و نوشتن (بردارها) فقط در دیتابیس جدا aramesh_chatbot انجام می‌گیرد.

پیش‌نیاز pgvector

سرویس db استک از ایمیج pgvector/pgvector:pg17 استفاده می‌کند (همان postgres:17 + افزونهٔ vector). اگر Postgres سایت روی نمونهٔ دیگری است، باید افزونهٔ pgvector روی آن فعال باشد؛ در غیر این صورت شروع چت‌بات با خطای واضح متوقف می‌شود.

مسیرها

مسیر توضیح
GET /chat/stream?message=…&thread_id=… استریم SSE توکن‌به‌توکن پاسخ ({"content": …} و در پایان {"done": true})
GET /chat/suggestions ۴ پیشنهاد پرسش (کش ۱۰ دقیقه؛ جایگزین: خود سؤالات متداول)
GET /chat/eval?message=… مخصوص ارزیابی RAGAS — پاسخ + اسناد بازیابی‌شده با thread تازه
GET /chat/healthz وضعیت ایندکس/LLM/تعداد اسناد
POST /chat/reindex بازسازی اجباری ایندکس (هدر X-Reindex-Token)

مسیرهای GET /chat/{scope}/stream|eval|suggestions هم برای سازگاری با اسکریپت eval_ragas.py قدیمی موجود است — کافی است --url را به نشانی این سرویس بدهید.

اجرا

با داکر (بخشی از استک اصلی است — docker compose up -d --build):

# در .env ریشه:
LLM_BASE_URL=http://172.16.22.21:4460/v1   # یا هر سرویس سازگار با OpenAI
LLM_API_KEY=not-needed

اولین بوت مدل‌ها را دانلود می‌کند (~۱.۵GB: امبدینگ + ری‌رنکر) و در والیوم chatbot_cache کش می‌شود؛ بوت‌های بعدی چند ثانیه طول می‌کشد.

اجرای محلی بدون داکر:

cd chatbot
python -m venv .venv && source .venv/bin/activate   # ویندوز: .venv\Scripts\activate
pip install -r requirements.txt
export DATABASE_URL="postgresql+psycopg://aramesh:PASS@localhost:5432/arameshplaza"
export LLM_BASE_URL="http://…" LLM_MODEL="openai/gpt-oss-120b"
uvicorn chatbot.app:api --port 8000   # از ریشه پوشه والد

منابع مورد نیاز

  • رم: با ری‌رنکر ~۴GB (مدل ۵۶۸M پارامتری روی CPU)؛ بدون ری‌رنکر ~۲GB
  • CPU: امبدینگ و ری‌رنک روی CPU اجرا می‌شوند؛ GPU لازم نیست
  • شبکه: دسترسی به PostgreSQL و به نشانی LLM_BASE_URL

نکات امنیتی

  • دیتابیس سایت فقط خواندن؛ نوشتن فقط در دیتابیس اختصاصی aramesh_chatbot انجام می‌شود
  • محدودسازی نرخ per-IP فعال است (پیش‌فرض ۲۰ پیام در ۵ دقیقه)
  • CORS باز است ولی کوکی/اعتبارنامه‌ای رد و بدل نمی‌شود؛ در تولید همه‌چیز هم‌مبدأ (پشت Traefik) است