docs: update root, bot, and pm README files for integrated ERP architecture
This commit is contained in:
+55
-105
@@ -1,120 +1,70 @@
|
||||
# procurement_ai_agent — Bale chatbot for the procurement ERP
|
||||
# procurement_ai_agent — ایجنت هوشمند بله برای سامانه ERP
|
||||
|
||||
A **Bale messenger bot** that turns Persian **chat messages and voice notes**
|
||||
into procurement actions in the
|
||||
[procurement ERP](https://git.bennu-api-bahrestan.ir/ali_mohaghegh/ERP) —
|
||||
draft-first: it captures what it understood, tells you **what it did** and
|
||||
**what is still empty**, and **commits only after you approve** with a ✅ button.
|
||||
بات پیامرسان بله (Bale Messenger Bot) که پیامهای صوتی و متنی فارسی کاربران را دریافت کرده و با استفاده از مدلهای هوش مصنوعی (DeepSeek NLU + Whisper STT) آنها را به اقدامات و پیشنویسهای استعلام در سامانه ERP تبدیل میکند.
|
||||
|
||||
```
|
||||
you (Bale, text/voice) ┌─────────────────────────────────┐
|
||||
│ getUpdates (long poll) │ procurement_ai_agent │
|
||||
▼ │ ffmpeg → STT (Persian) │
|
||||
┌──────────────────┐ POST {base}/bot<T> │ LLM → intent + entities │
|
||||
│ tapi.bale.ai │◄───────────────────────►│ fuzzy resolve → draft payload │
|
||||
└──────────────────┘ sendMessage / buttons │ review + «چه چیزهایی خالی مونده»│
|
||||
└───────────────┬─────────────────┘
|
||||
│ HTTP + X-Actor-Id
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ ERP api (/api/v1) │
|
||||
│ quotes · suppliers · materials│
|
||||
└─────────────────────────────────┘
|
||||
---
|
||||
|
||||
## 🏗️ وضعیت استقرار در استک ERP
|
||||
|
||||
این ایجنت **به صورت سرویس بومی (`procurement-bot`) مستقیماً درون `docker-compose.yml` ریشه پروژه** تعریف شده است و نیازی به نصب یا راهاندازی دستی ندارد.
|
||||
|
||||
* **نوع اتصال:** Long-polling از سرور بله (`tapi.bale.ai`) — بدون نیاز به باز کردن پورت خارجی، وبهوک یا TLS.
|
||||
* **ارتباط با بکاند:** به صورت مستقیم و درونشبکهای با سرویس `api` در آدرس `http://api:8000/api/v1`.
|
||||
* **پایگاه داده:** استفاده از جدول `bot_drafts` در پایگاهداده مشترک PostgreSQL.
|
||||
|
||||
```text
|
||||
کاربر (بله: متن یا صوت)
|
||||
│ getUpdates (Long-polling)
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ procurement_ai_agent │
|
||||
│ ffmpeg → STT تبدیل صوت به متن │
|
||||
│ LLM → استخراج نیت و موجودیتها │
|
||||
│ Fuzzy Match → انطباق با ERP │
|
||||
│ ایجاد پیشنویس در bot_drafts │
|
||||
└────────────────┬────────────────┘
|
||||
│
|
||||
├── ثبت نهایی از بله با دکمه تایید
|
||||
└── یا باز کردن مستقیم در ویزارد وب:
|
||||
/wizard?draft=<UUID>
|
||||
```
|
||||
|
||||
## What it can do
|
||||
---
|
||||
|
||||
| Activity | Example (voice or text) | Committed via |
|
||||
## 🌟 قابلیتها و کاربردها
|
||||
|
||||
| فعالیت | نمونه پیام (صوت یا متن) | اقدام نهایی |
|
||||
|---|---|---|
|
||||
| Register a supplier quote | «سازان نو برای پروژه برج آسمان ۵۰۰ کیلو میلگرد A3 سایز ۱۴، هر کیلو ۴۵ تومن، پرداخت ۳ فاز» | `POST /quotes` |
|
||||
| Add a supplier | «تأمینکننده جدید پروفیل بر، دسته لوله و اتصالات، تلفن ۰۹۱۲…» | `POST /suppliers` |
|
||||
| Add a material | «کالای جدید میلگرد A3 سایز ۱۸ با واحد کیلوگرم» | `POST /materials` |
|
||||
| Status queries | «استعلامهای در انتظار؟» / «کدامها بهزودی منقضی میشوند؟» | `GET /quotes?…` |
|
||||
| Accept a quote | «استعلام سازان نو را قبول کن» | `PATCH /quotes/{id}/accept` |
|
||||
| Announce a delivery | «اقلام سازان نو رسید، ۵۰۰ و ۲۰۰» | `PATCH /quotes/{id}/arrive-items` |
|
||||
| **ثبت استعلام جدید** | «سازان نو برای پروژه برج آسمان ۵۰۰ کیلو میلگرد A3 سایز ۱۴، هر کیلو ۴۵ تومن، پرداخت ۳ فاز» | `POST /quotes` |
|
||||
| **تعریف تأمینکننده** | «تأمینکننده جدید پروفیل بر، دسته لوله و اتصالات، تلفن ۰۹۱۲…» | `POST /suppliers` |
|
||||
| **تعریف متریال جدید** | «کالای جدید میلگرد A3 سایز ۱۸ با واحد کیلوگرم» | `POST /materials` |
|
||||
| **استعلام وضعیت** | «استعلامهای در انتظار؟» / «کدامها بهزودی منقضی میشوند؟» | `GET /quotes` |
|
||||
| **پذیرش استعلام** | «استعلام سازان نو را قبول کن» | `PATCH /quotes/{id}/accept` |
|
||||
|
||||
### The draft → approve loop
|
||||
---
|
||||
|
||||
1. Send a message or voice note. Voice → ffmpeg → STT; text/STT text → LLM
|
||||
extracts a typed **intent + entities** (JSON mode, Persian digits
|
||||
normalized).
|
||||
2. Names are fuzzy-matched against the ERP. Several candidates → inline
|
||||
**pick buttons**; no match → listed as missing.
|
||||
3. The bot replies with a **review card**: everything captured + a
|
||||
✅/⚠️/❌ list of what is still empty.
|
||||
4. Keep chatting to refine («قیمت میلگرد ۴۷ شد») — the open draft updates and
|
||||
re-renders. Drafts survive bot restarts (postgres-backed, TTL-swept).
|
||||
5. **Nothing is written to the ERP until you tap ✅.** After commit you get the
|
||||
created quote id and the fields left empty.
|
||||
## 🔗 حلقه پیشنویس و تایید (Draft-First Loop)
|
||||
|
||||
### Team access & attribution
|
||||
1. کاربر پیام صوتی یا متنی میفرستد. صوت به متن تبدیل شده و مدل هوش مصنوعی موجودیتها را استخراج میکند.
|
||||
2. اسامی تامینکننده، متریال، پروژه و واحدها با کاتالوگ ERP تطبیق داده میشوند.
|
||||
3. کارت مرور پیشنویس همراه با فیلدهای مشخصشده و اقلام خالی («چه چیزهایی ناقص است») برای کاربر ارسال میشود.
|
||||
4. **دو روش برای تکمیل و ثبت نهایی وجود دارد:**
|
||||
* **از طریق چت بله:** با ارسال پیامهای اصلاحی و در نهایت لمس دکمه «✅ ثبت نهایی».
|
||||
* **از طریق پنل وب ویزارد:** با کلیک روی لینک مستقیم `/wizard?draft=<UUID>` که اطلاعات به صورت خودکار در فرم ۵ مرحلهای ویزارد بارگذاری میشود و کاربر میتواند فایل فاکتور را نیز ضمیمه کند.
|
||||
|
||||
Each member links their Bale chat once: `/start` → Casdoor username → password
|
||||
(validated via the ERP's real `POST /auth/login`, used once, never stored).
|
||||
Every mutating call carries `X-Actor-Id: <users.id>` so `quote_events.actor`
|
||||
records the **human** who asked.
|
||||
---
|
||||
|
||||
Commands: `/start` · `/help` · `/drafts` · `/cancel` · `/whoami` · `/unlink`
|
||||
## ⚙️ متغیرهای محیطی و پیکربندی
|
||||
|
||||
## Quick start (Docker)
|
||||
تنظیمات بات از طریق فایل `.env` در ریشه پروژه خوانده میشود:
|
||||
|
||||
```bash
|
||||
cp .env.example .env # fill PROCUREMENT_BOT_BOT_TOKEN + AI_API_KEY
|
||||
docker build -t procurement-ai-agent .
|
||||
docker run -d --name procurement-bot --env-file .env \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
procurement-ai-agent
|
||||
docker logs -f procurement-bot
|
||||
```env
|
||||
BALE_BOT_TOKEN=توکن_دریافتی_از_بات_فادر_بله
|
||||
BALE_API_BASE=https://tapi.bale.ai
|
||||
AI_BASE_URL=https://api.deepseek.com
|
||||
AI_API_KEY=کلید_سرویس_هوش_مصنوعی
|
||||
AI_LLM_MODEL=deepseek-flash
|
||||
BALE_ADMIN_CHAT_IDS=شناسه_عددی_مدیران_در_بله
|
||||
```
|
||||
|
||||
Or as part of the ERP stack — see [`integration/`](integration/README.md)
|
||||
(compose service + the one tiny ERP-side patch).
|
||||
|
||||
Full setup, env-var reference, flows and troubleshooting:
|
||||
**[docs/SETUP.md](docs/SETUP.md)**.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
app/
|
||||
├── main.py ensure bot tables → sweeper task → getUpdates long-poll loop
|
||||
├── config.py pydantic-settings, PROCUREMENT_BOT_ prefix
|
||||
├── bale/client.py Telegram-compatible Bale API (poll, send, edit, buttons, files)
|
||||
├── api/client.py ERP /api/v1 client (X-Actor-Id attribution, error envelope)
|
||||
├── stt.py ffmpeg (OGG/Opus → MP3) → OpenAI-compatible /audio/transcriptions
|
||||
├── nlu.py Persian intent+entity extraction (JSON-mode chat completions)
|
||||
├── resolve.py fuzzy name→id matching (difflib over ilike search), TTL caches
|
||||
├── drafts.py draft store · QuoteCreate payload builder · missing-field logic
|
||||
├── keyboards.py inline keyboards (callback_data ≤ 64 B op-codes)
|
||||
├── texts.py Persian message templates
|
||||
├── runtime.py context, link store, in-memory pending flows
|
||||
├── models.py bot_links / bot_drafts / bot_messages / bot_meta (own schema)
|
||||
└── handlers/ dispatch · commands · callbacks · links ·
|
||||
quote · supplier · material · queries · decisions
|
||||
```
|
||||
|
||||
Design notes:
|
||||
|
||||
- **Telegram-compatible Bale API** (`tapi.bale.ai`): getUpdates long polling —
|
||||
no public port, no webhook, resumable offset persisted across restarts.
|
||||
- **Draft-first**: `bot_drafts.payload` holds a talking-friendly JSON that is
|
||||
converted into the exact `POST /quotes` request body (temp_id
|
||||
cross-references) only on approval; the API deliberately tolerates
|
||||
incomplete quotes, so partial commits are explicit, never accidental.
|
||||
- **Accept flow echoes the termsheet's existing `schedule_steps`** back to
|
||||
`PATCH /quotes/{id}/accept` (the API replaces steps with what it receives).
|
||||
- **Persian-aware matching**: Persian/Arabic digit normalization, ZWNJ folding,
|
||||
Arabic ya/ka folding, difflib ranking on top of the API's ilike search.
|
||||
- **Voice notes** arrive as OGG/Opus; ffmpeg converts to mono 16 kHz MP3 before
|
||||
STT. The LLM provider and the STT provider are configured independently
|
||||
(e.g. DeepSeek for NLU + any whisper-compatible endpoint for voice).
|
||||
|
||||
## Testing
|
||||
|
||||
An offline end-to-end harness stubs Bale/ERP/AI and drives the real handler
|
||||
pipeline with fake updates — no token, DB or API key needed:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
python tools/smoke_test.py # → ALL PASSED: 48 passed
|
||||
```
|
||||
راهنمای گامبهگام اتصال و عیبیابی در [docs/SETUP.md](docs/SETUP.md) در دسترس است.
|
||||
|
||||
Reference in New Issue
Block a user