34 KiB
پلیبوک اجرایی: افزودن موتور STT بله به خط لوله چندمدلهی بات تدارکات
نسخه: ۱.۰ مخاطب: ایجنت هوش مصنوعی مجری + تیم فنی + مدیر محصول ماهیت سند: سند تصمیممحور — هر تست به یک «دروازهی تصمیم (Gate)» میرسد و هر دروازه، جدول «وضعیت مشاهدهشده ← اقدام» دارد. ایجنت باید فقط بر اساس وضعیتهای واقعیِ مشاهدهشده در همان لحظه، شاخهی درست را انتخاب کند. هدف نهایی: افزودن ترنسکریپشن موتور بله (STT سمت سرور بله) بهعنوان یکی از کاندیداهای خط لولهی Multi-Provider STT فعلیِ بات، بدون هیچ تغییر ساختاری در بات.
۰. قواعد الزامآور اجرا (برای ایجنت — قبل از هر اقدام بخوانید)
- مبنای گیت فقط
productionاست. سایر برنچها (از جملهprod-v7که کد بات روی آن است) متعلق به جریان کاری خودشاناند و نباید توسط ایجنت دستکاری، مرج یا پوش شوند. تنها مهندس ارشد شرکت مرج میکند. هیچ پوشی بدون تأیید صریح مالک انجام نشود. - درخواستهای شبکه به بله باید کمحجم و انساننما باشند. هشدار جدی: سازندگان کتابخانههای مهندسیمعکوس بله تأکید کردهاند که «استفادهی زیاد از POST gRPCِ غیر-احراز (پیام/مدیا/حضور) میتواند فلگ، rate-limit یا بن موقت ایجاد کند». پس: ترجیح کانال WebSocket، ترتیبی نه موازی، تأخیر انسانی، سقف روزانه.
- حسابها: فقط شمارهی اختصاصی شرکت (Bale ئرنر) — هرگز شمارهی شخصی. حساب فقط برای این کار باشد.
- حریم خصوصی: صدای کاربران تدارکات روی سرورهای بله پردازش میشود (همین حالا هم ویس از بله میآید)؛ اما اگر ایجنت صدا را مجدداً به یک چت آپلود میکند (مسیر R2/R3)، باید بلافاصله پس از ترنسکرایب پیام را حذف کند و آدرسی از صدا نگه ندارد.
- هیچ سکرتی (توکن بات، توکن کاربر، session_file، کلید LLM) نباید در گیت کامیت شود. سکرتهای موجود در
docker-compose.yml(توکن بات و کلید DeepSeek بهعنوان پیشفرض) باید در فرصت مناسب rotate و به${VAR:?…}تبدیل شوند. - معیار موفقیت، سرعت نیست — دقت است. بدون عبور از دروازهی دقت (G5) هیچ ساخت/استقراری مجاز نیست.
۱. واقعیتهای تأییدشده (پایهی همهی تصمیمها)
۱.۱ — سیستم فعلی: بات و خط لولهی STT
| مؤلفه | مسیر | توضیح |
|---|---|---|
| خط لوله STT | bot/app/stt.py |
transcribe_multi() صدای MP3 (خروجی ffmpeg: mono 16kHz) را به موازات به همهی پرووایدرها میفرستد؛ هر پرووایدر یک POST {base_url}/audio/transcriptions (multipart، فیلد file، بههمراه model و language=fa) است و خروجی {"text": "..."} انتظار دارد. fail-soft: خطای هر پرووایدر فقط آن را حذف میکند (return None)؛ بقیه ادامه میدهند. |
| پیکربندی پرووایدرها | bot/app/config.py |
STT_PROVIDER_1..3_NAME/BASE_URL/API_KEY/MODEL/LANGUAGE + STT_PROVIDERS_JSON + fallback قدیمی STT_*. نکته: یک پرووایدر فقط وقتی فعال میشود که هم BASE_URL و هم API_KEY پر باشند. |
| مصرف خروجیها | bot/app/nlu.py |
همهی ترنسکریپتهای کاندید به DeepSeek میروند و خروجی نهایی consensus_text + intent + patch (اقلام استعلام) است. یعنی افزودن بله = یک کاندید بیشتر در ورودی consensus. |
| مسیر ویس در بات | bot/app/handlers/__init__.py |
ویس → دانلود (getFile) → transcribe_multi → متن بهعنوان ورودی NLU. |
نتیجهی معماری (کلیدی): افزودن هر مسیر STT = ساخت یک سرویس adapter با قرارداد OpenAI-compatible + پر کردن STT_PROVIDER_3_*. صفر تغییر در کد بات. (این نقطهی اتصال رسمی و پایدار است.)
۱.۲ — شواهد تجربی Bot API (تستشده — تکرارپذیر)
روی توکن بات فعلی (procurement_assistant_bot)، متدهای مشکوک STT تست شدند:
POST https://tapi.bale.ai/bot<TOKEN>/transcribeVoice → {"ok":false,"error_code":404,"description":"Bad Request: handler not found"}
POST .../getTranscription → (همان 404)
POST .../transcribe → (همان 404)
POST .../speechToText → (همان 404)
POST .../voiceToText → (همان 404)
POST .../getMe (کنترل) → {"ok":true,"result":{"username":"procurement_assistant_bot",...}}
مستندات رسمی (docs.bale.ai) هم هیچ متد یا فیلد ترنسکریپشن برای آبجکت Voice/Audio ندارند.
نتیجه: Bot API بله قطعاً STT ندارد. مسیر «فیلد مخفی» فقط با تست T1 (بخش ۳) قابل رد شدن نهایی است.
۱.۳ — یافتههای گزارشهای ایجنت شرکت (خلاصهی راستیآزماییشده)
| یافته | وضعیت راستیآزمایی |
|---|---|
کلاینت وب بله روی gRPC-Web + Protocol Buffers (@bufbuild/protobuf) است |
منطقی و همراستا: کتابخانههای مستقل مهندسیمعکوس بله هم همین را تأیید میکنند؛ باید در T2 مجدداً مشاهده شود. |
گیتویها: https://maviz-ws.bale.ai و wss://maviz-ws.bale.ai/ws/?uid={user_id} (+ بتا/نکست) |
در وب ایندکس نشده (طبیعی) — باید در T2 با چشم مشاهده شود. |
ماژولهای SpeechTranscript و AIChat در باندل |
سرنخ معتبر — باید در T2/T3 تأیید و دیکود شود. |
| «روش دوم غیرعملی است چون باید کل .protoها بازسازی شوند» | نادرست/بیشبرآورد: با دیکود جنریک Protobuf و استخراج توصیفگر از خود باندل (T3) یا با استفاده از aiobale-py (T4)، این کار در حد «افزودن یک متد» کوچک میشود. |
| ماتریس تأخیر («روش دوم زیر ۱ ثانیه») | گمراهکننده: گلوگاه، استنتاج ASR روی سرور بله است؛ عدد واقعی فقط از T2/T5 میآید. |
۱.۴ — اکوسیستم مهندسی معکوس موجود (مهم — دارایی راهبردی)
aiobale-py(v0.3.9، فعال): فریمورک async برای بله روی WebSocket + Protobuf، الهامگرفته از aiogram؛ ~۸۰ متد RPC (پیام، فایل، گروه، مخاطبین…)، ورود تلفنی با OTP،session_file، توکن JWT، rate-limiter داخلی، docs و مخزن عمومی:- PyPI:
pip install aiobale-py(ایمپورت:aiobale) - GitHub:
github.com/aminmadaniofficial/aiobale— مستندات:aminmadaniofficial.github.io/aiobale/ - متد ترنسکرایب ندارد → باید همان RPC کشفشده در T2 به آن افزوده شود (زیرساخت لاگین/WS/کدک آماده است).
- PyPI:
- نسخهی اولیهی
Enalite/aiobale(GitHub الان 404؛ نام PyPI توسط یک پکیج خالی اشغال شده) → فقط به فورک فعالaiobale-pyاتکا کنید. - پروژهی جانبی مرتبط:
bale-mcp-server(MCP برای بله با aiobale-py) — برای الگوگیری نحوهی استفاده. - سرویس ثالث STT: majidapi.ir (
/ai/stt?url=...&token=...) — مسیر جایگزین R7 (بخش ۵).
۱.۵ — وضعیت برنچها (قواعد همکاری)
| برنچ | وضعیت | مجاز برای ایجنت؟ |
|---|---|---|
production (253c922) |
مبنای رسمی کار | ✅ فقط خواندن/مبنا |
prod-v7 (کد بات/ایجنت، 638076d) |
کار مالک این سند؛ منتظر تست نهایی و مرج توسط مهندس ارشد | ⛔ دستکاری/پوش ممنوع |
prod-v8/9/10، pm، pm_2 و بقیه |
برنچهای سایر اعضا؛ در حال تست | ⛔ هیچ دخالتی |
۲. نقشهی وضعیتها (State Machine) — نمای کلی مسیر
S0 (شروع)
│
├─T1─> G1 ──(فیلد ترنسکریپشن پیدا شد)───────────────► R1: پایان! (بدون کرالر) ✅
│ └─(پیدا نشد)──► T2
│
├─T2─> G2 ──(RPC ساده/دیکودپذیر)──► T3+T4 ─> G3 ──(موفق)──► T5+ G4 ─► T7 ─> G5
│ ├─(فقط روی WS)──────────► همان T3+T4 (aiobale مسیر WS است) ▲
│ ├─(رمزنگاری/امضای خاص)──► R4 (Playwright) یا R3 ─► T5/T7
│ └─(نیاز به اثر انگشت مرورگر)─► R4 ─► T5/T7
│
├─(T5/T7)─> G5 ──(بهبود دقت کافی)──► G6 (ToS) ──(سبز)──► BUILD (R2/R3/R4) ─► G7 (سواک) ─► استقرار کامل
│ └─(بهبود ناکافی)──► STOP: همان پرووایدرهای فعلی ⛔
│ └─(قرمز)──► STOP یا فقط R4 در حد محدود ⛔
۳. فاز A — تستهای کشف (T1…T9)
برای هر تست: هدف، پیشنیاز، مراحل، خروجی، معیار قبولی، و حالتهای ممکن. ایجنت بعد از هر تست حتماً به جدول دروازهی مربوطه (بخش ۴) مراجعه کند.
T1 — تست payload خام ویس (۳۰ دقیقه)
هدف: رد یا تأیید نهایی وجود فیلد ترنسکریپشن مخفی در پیامهای Bot API. پیشنیاز: یک ربات تستی مستقل (از BotFather بله بسازید؛ از ربات فعلی استفاده نکنید چون در حال long-poll است و مصرفکنندهی دوم تعارض ایجاد میکند). یک حساب بله برای فرستادن ویس. مراحل:
- اسکریپت مینیمال پایتون:
getUpdatesبدون offset + چاپ JSON کامل هر آپدیت در فایل. - یک ویس فارسی واقعی (۵–۱۰ ثانیه) به ربات تستی بفرستید.
- JSON کامل ویس را ذخیره کنید؛ کلیدهای آبجکت
voice/audio/messageرا لیست کنید. getFileرا هم صدا بزنید و فیلدهای پاسخ را ضبط کنید. معیار قبولی/حالتها:
- حالت A: هر فیلدی مثل
transcription/transcript/speech/textروی ویس وجود دارد → پایان پروژهی کرالر (R1)؛ فقط به بات وصل کنید. - حالت B: خبری نیست (قویترین احتمال طبق مستندات) → برو به T2.
T2 — کپچر ترافیک کلاینت وب (نیمروز) — قاطعترین تست
هدف: کشف «دقیق» مکانیزم ترنسکرایب: نام RPC، ترابری (unary/WS)، قالب فریم، هدر احراز، و زمان واقعی ASR.
پیشنیاز: حساب سوختهی اختصاصی (سیمکارت شرکت)، مرورگر Chromium، ابزار دیکود Protobuf: protoscope یا blackboxprotobuf (نصب با pip/go)، و اختیاری mitmproxy.
مراحل:
- ورود به
web.bale.ai؛ DevTools → Network با گزینهی Preserve log؛ فیلترWSوFetch/XHRرا فعال نگه دارید. - یک ویس در یک چت باز کنید و دکمهی «تبدیل به متن / متن پیاده» را بزنید.
- همهی درخواستهای همان لحظه را ضبط کنید:
- اگر
POSTروی هاستی مثلmaviz-ws.bale.aiباcontent-type: application/grpc-web+proto(یاgrpc-web-text) ظاهر شد → همین RPC است. - اگر قاب باینری روی WebSocket
wss://…/ws/?uid=…رفت → RPC روی WS است.
- اگر
- برای هر نمونه ذخیره کنید:
req.bin،resp.bin، هدرهای مهم (نام هدر توکن:authorization/x-auth/…)، URL کامل، و زمان پاسخ از تب Timing (همین = تأخیر واقعی ASR بله). - ۵ تا ۱۰ ویس متنوع (کوتاه/بلند/با لهجه) تکرار کنید تا پایداری اسکیما معلوم شود؛ در
samples/ذخیره و درfindings.mdخلاصه کنید. - دیکود آفلاین: به یاد داشته باشید پیامهای gRPC-Web یک پیشوند ۵ بایتی دارند (۱ بایت فلگ + ۴ بایت طول) و سپس Protobuf میآید → ابتدا پیشوند را بردارید، سپس:
protoc --decode_raw < resp_payload.binیاprotoscope resp_payload.bin - اگر آرایهی WS دیده شد: فریمها را از DevTools کپی و با protoscope دیکود کنید؛ به دنبال پیام معادل
SpeechTranscriptبگردید. خروجی:capture/findings.mdشامل: نام دقیق RPC، ترابری، framing، هدر احراز، تأخیر واقعی، و نقشهی مقدماتی فیلدها (کدام فیلد = message_id؟ file_id؟ متن؟).
T3 — استخراج اسکیما (۱–۲ روز)
هدف: تبدیل کپچرها به یک اسکیمای قابل استفاده (و ترجیحاً .proto).
روشها (به ترتیب):
- از خود باندل: باندل وب بله (
/static/js/index.*.jsو در صورت وجود.js.map) را از قبل دارید؛ پروژههای ساختهشده با@bufbuild/protobufمعمولاًFileDescriptorProtoباینری را داخل JS جاسازی میکنند. روش عملی: جستوجوی بایتهای توصیفگر، استخراج و سپس:protoc --decode=google.protobuf.FileDescriptorProto google/protobuf/descriptor.proto < desc.bin(یا دیکود همان بایتها با پایتون +grpcio-tools). اگر sourcemap موجود بود، مستقیمتر است. - از نمونهها: با چند نمونهی req/resp دیکودشده با
protoc --decode_raw، همبستگی فیلدها را استخراج کنید (فیلد شمارهی متن جواب، message_id درخواست و…). - مسیر موازی (اپ اندروید): APK رسمی بله (از سایت رسمی) +
jadx؛ جستوجوی"SpeechTranscript"؛ در اندروید معمولاً شمارهی فیلدها واضحترند. معیار قبولی: توان ساخت درخواست معتبر و خواندن پاسخ — حتی بهصورت «فیلد ۱ = message_id، فیلد ۲ = متن». داشتن.protoکامل لازم نیست.
T4 — اسپایک aiobale-py (۱ روز)
هدف: اثبات امکان اجرای ترنسکرایب با یک اکانت کاربری، بدون مرورگر. پیشنیاز: venv ایزوله (نه محیط بات)، حساب سوخته، اسکیمای T3. مراحل:
pip install aiobale-py→ ورود:Client(session_file="bale.session", phone_number="…")و عبور از OTP (دروازهی انسانی).- کاوش لایهی کدک: در
site-packages/aiobale/…ببینید متدها چطور تعریف میشوند (احتمالاً مپینگ متد→پیام Protobuf). یک متد سفارشی برای RPC ترنسکریپت کشفشده اضافه کنید. - کشف مکانیزم دقیق: آیا RPC ترنسکرایب
message_idمیخواهد (یعنی صدا باید از قبل «پیامی در بله» باشد) یاfile_id/بایت خام قبول میکند؟ هر سه فرض را تست کنید:- (الف) آپلود ویس به یک چت اسکرچ (چت با خود یا گروه خصوصی اختصاصی) → گرفتن
message_id→ ترنسکرایب → حذف پیام. - (ب)
upload_file(در aiobale موجود است) → ترنسکرایب با فایل. - (ج) اگر RPC ورودی بایت میگیرد → سادهترین (بدون پیام واسط).
- (الف) آپلود ویس به یک چت اسکرچ (چت با خود یا گروه خصوصی اختصاصی) → گرفتن
- تست صحت: متن برگشتی را با متنی که وب بله برای همان ویس نشان میدهد مقایسه کنید (باید یکسان/نزدیک باشد).
- تست پایداری نشست: ریاستارت پروسه و استفادهی مجدد از session file؛ ثبت زمان انقضای توکن. حالتها:
- موفق کامل → مسیر R2 برای ساخت adapter انتخاب میشود.
- نیمهموفق (login/WS میشود ولی RPC دیکود نمیشود) → T3 را عمیقتر + کپچر بیشتر؛ در غیر این صورت R3/R4.
- ناموفق (چالش احراز، بن، نبود قابلیت افزودن متد) → R3 و R4.
T-extra — تست «AI Chat بهعنوان اوراکل» (نیمروز، موازی با T2/T4)
هدف: اگر چت هوش مصنوعی بله ویس را با متن پیادهشده پاسخ میدهد، حتی نیازی به RPC جدید نیست: با متدهای پیامرسانیِ موجودِ aiobale، ویس را به چت AI بفرستید و متن را از پاسخ استخراج کنید. مراحل: با اکانت سوخته در وب بله، یک ویس به چت AI بفرستید؛ دقیقاً ببینید آیا متن پیادهشده در پاسخ میآید و با چه قالبی. سپس همان را با aiobale بازسازی کنید. معیار: اگر متن پیاده با قالب قابلاعتماد (ثابت) برگردد → مسیر R3 فعال میشود (ارزانتر از R2).
T5 — اندازهگیری تأخیر/پایداری واقعی (۱–۲ روز)
هدف: جایگزینی اعداد ساختگی گزارش با اعداد واقعی. مراحل: ۵۰–۱۰۰ ویس واقعی از مسیر انتخابی (ترتیبی، با فاصلهی انسانی ۱–۳ ثانیه)؛ ثبت p50/p95، نرخ خطا، انواع خطا، و هر نشانهی rate-limit. معیار پذیرش پیشنهادی: نرخ موفقیت ≥ ۹۵٪ و p95 ≤ ۸ ثانیه (برای UX بات). در غیر این صورت G4 قرمز میشود.
T7 — بنچمارک دقت (۱ روز) — دروازهی کسبوکاری، قبل از هر ساخت
هدف: آیا افزودن بله واقعاً خروجی نهایی را بهتر میکند؟ مراحل:
- ۲۰–۳۰ ویس واقعی تدارکاتی جمع کنید (با اطلاع فرستندگان؛ صداها را بلندمدت نگه ندارید).
- برای هر ویس سه خروجی بگیرید: (الف) وضعیت فعلی (whisper/سایر + consensus فعلی)، (ب) فقط متن بله، (ج) consensus با اضافهشدن کاندید بله.
- سه معیار بسنجید: WER متن، دقت استخراج موجودیتها (نام کالا/برند/تعداد/واحد در JSON نهایی)، و تعداد «موارد سخت» که با بله درست شدهاند. معیار پیشنهادی: اگر کاهش خطای استخراج ≥ ~۱۵٪ نسبی یا حل ≥ ۲ مورد سختِ لهجهای → پروژه توجیه دارد؛ در غیر اینصورت STOP (همان خط لولهی فعلی کافی است).
T6 + T9 — سواک بن و ماندگاری نشست (۱–۲ هفته، پسیو)
استفادهی کمحجم روزانه (مثلاً ≤ ۱۰۰ ترنسکرایب در روز) از IP شرکت؛ ثبت: تعداد ورود مجدد لازم، چالشهای امنیتی، هشدارها، عمر واقعی توکن. خروجی: سقف عملیاتی + runbook ورود مجدد.
T8 — بازبینی حقوقی/ToS (موازی — دروازهی انسانی)
ایجنت فقط شواهد را جمع میکند؛ تصمیم Go/No-Go توسط مدیریت مستند میشود. معیار: سند تصمیم مکتوب.
۴. دروازههای تصمیم (جدولهای وضعیت ← اقدام)
G1 (بعد از T1)
| وضعیت مشاهدهشده | اقدام |
|---|---|
| فیلد ترنسکریپشن روی ویس هست | پایان: R1 — مستقیم به بات وصل کن (بدون هیچ کرالری) |
| نیست | برو T2 |
G2 (بعد از T2) — مهمترین دروازهی فنی
| وضعیت مشاهدهشده | معنا | اقدام |
|---|---|---|
| RPC از نوع unary POST gRPC-Web با پروتوباف دیکودپذیر | بهترین حالت | برو T3+T4 → R2 |
| RPC فقط روی WebSocket | حالت مطلوب دوم (aiobale دقیقاً WS است) | برو T3+T4 → R2 (از کانال WS؛ POST gRPC زیاد نزن) |
| درخواست رمزنگاری/امضای اختصاصی دارد (فراتر از پروتوباف) | هزینهی نگهداری بالا | R4 (Playwright) یا R3 بهعنوان مسیر اصلی؛ R2 فقط اگر … شکست |
| ترنسکرایب نیازمند اثر انگشت/رفتار مرورگر است | R2 غیرممکن | R4 |
| ترنسکرایب message_id روی پیامی موجود میخواهد | نیازمند «آپلود به چت اسکرچ» | R2 با فلوی «آپلود→ترنسکرایب→حذف» (بخش ۵.۲) |
G3 (بعد از T3/T4)
| وضعیت | اقدام |
|---|---|
| ساخت درخواست + خواندن پاسخ ممکن شد | برو T5 → T7 |
| فقط یکی از دو جهت ممکن است | کپچر بیشتری بگیر (T2)؛ اگر نشد → R3/R4 |
| شکست کامل | R3 (اگر T-extra موفق بود) وگرنه R4؛ اگر هر دو هم نشد → STOP |
G4 (بعد از T5)
| وضعیت | اقدام |
|---|---|
| نرخ موفقیت ≥ ۹۵٪ و p95 ≤ ۸s | ادامه |
| rate-limit مشاهده شد | کاهش نرخ + backoff نمایی + سقف روزانه؛ مجدداً بسنج |
| بن/چالش امنیتی | توقف فوری؛ رفتن به R4 با اکانت جدید، یا STOP |
G5 (بعد از T7) — دروازهی کسبوکار
| وضعیت | اقدام |
|---|---|
| بهبود دقت مطابق آستانه | ادامه به G6 |
| بهبود ناکافی | STOP — همان پرووایدرها؛ یافتهها را مستند کن |
G6 (ToS) / G7 (سواک)
| وضعیت | اقدام |
|---|---|
| ToS سبز + سواک سالم | استقرار کامل (بخش ۶) |
| ToS قرمز | STOP یا فقط R4 با حجم محدود (طبق تصمیم مدیریت) |
| سواک ناسالم | rollback به پرووایدرهای قبلی (حذف envها) و بازگشت به G4 |
۵. فاز B — پیادهسازی (فقط پس از عبور از دروازهها)
۵.۱ — قرارداد مشترک adapter (برای همهی مسیرها یکسان)
سرویس bale-stt (کانتینر داخلی، بدون پورت عمومی):
POST /v1/audio/transcriptions— multipart، فیلدfile(فایل MP3)،model،language=fa→ پاسخ{"text": "..."}(دقیقاً قرارداد OpenAI که بات انتظار دارد).- هدر
Authorization: Bearer <INTERNAL_KEY>را بپذیرد (فقط کلید داخلی، نه توکن بله). GET /healthzبرای سلامت.- موتور داخلی قابلسوییچ با env:
BALE_STT_ENGINE=grpc|aichat|playwright→ همهی مسیرها همزیستی دارند و تعویض موتور بدون تغییر بات.
۵.۲ — R2: مهندسی معکوس (مسیر پیشنهادی اصلی)
معماری: bot → adapter → aiobale-py (اکانت سوخته) → WS/gRPC بله → متن
نکات پیادهسازی:
- اکانت:
session_fileروی یک داکر ولوم؛ هرگز در گیت.BALE_PHONEو سکرتها در env. - اگر RPC به message_id نیاز دارد: فلوی «آپلود ویس به چت اسکرچ → ترنسکرایب → حذف پیام» — با
send_voiceوdelete_messageموجود در aiobale. - ترتیبی اجرا کنید (قفل asyncio)، فاصلهی ۱–۳ ثانیه، سقف روزانه قابلتنظیم (
BALE_STT_DAILY_CAP). - مدیریت انقضای توکن: تشخیص خطای احراز → علامتگذاری «نیازمند OTP» + هشدار به ادمین (دروازهی انسانی).
- fail-soft مضاعف: adapter در هر خطا
{"text": ""}(یا 5xx کنترلشده) برگرداند تا بات فقط این کاندید را حذف کند.
۵.۳ — R3: اوراکل AI Chat
همان adapter، اما داخلش: ارسال ویس به چت AI (با aiobale) → استخراج متن از قالب پاسخ → بازگرداندن. سبکترین پیادهسازی؛ وابسته به پایداری قالب پاسخ.
۵.۴ — R4: Playwright (فالبک)
کانتینر جدا با Chromium headless + پروفایل پایدار (userDataDir روی ولوم)، یک worker تکنمونه با صف؛ مراحل: ورود یکباره (OTP انسانی) → برای هر درخواست: آپلود ویس به یک چت اسکرچ → کلیک «تبدیل به متن» → انتظار روی سلکتور متن → استخراج → حذف پیام. RAM/زمان بیشتر؛ مقاومتر به تغییر پروتکل.
۵.۵ — ادغام با بات (بدون تغییر کد)
در docker-compose.yml (نسخهی تیم/سرور، نه برنچ دیگران) سرویس bale-stt اضافه و در سرویس bot این envها ست شود:
PROCUREMENT_BOT_STT_PROVIDER_3_NAME=bale
PROCUREMENT_BOT_STT_PROVIDER_3_BASE_URL=http://bale-stt:8080/v1
PROCUREMENT_BOT_STT_PROVIDER_3_API_KEY=<INTERNAL_KEY>
PROCUREMENT_BOT_STT_PROVIDER_3_MODEL=bale-stt
PROCUREMENT_BOT_STT_PROVIDER_3_LANGUAGE=fa
(یادآوری از کد: پرووایدر فقط با پر بودن همزمان BASE_URL و API_KEY فعال میشود.)
۵.۶ — سکرتها و امنیت
| سکرت | محل | نکته |
|---|---|---|
| توکن بات بله | env سرور | موجود در compose کامیتشده → rotate |
| کلید DeepSeek | env سرور | همینطور rotate |
session_file اکانت سوخته |
داکر ولوم | هرگز گیت؛ مالک مشخص |
INTERNAL_KEY adapter |
env | فقط بین bot و adapter |
DRAFT_TOKEN_SECRET بات |
env | پیشفرض فعلی در کد ضعیف است → ست شود |
۵.۷ — مقیاس
فاز اول: تکنمونه، ترتیبی، سقف روزانه. توسعه فقط بعد از G7 و فقط با شواهد پایداری.
۶. پذیرش، استقرار، پایش، بازگشت
تستهای پذیرش (اجباری):
curl -F "file=@voice.mp3" -F model=bale-stt http://localhost:8080/v1/audio/transcriptions→{"text": "<متن فارسی درست>"}.- بات: ارسال ویس واقعی → پاسخ استخراجشدهی صحیح.
- fail-soft: توقف کانتینر
bale-stt→ بات همچنان ویس را (با پرووایدرهای دیگر) پردازش کند ✓. - حریم خصوصی: بررسی کنید هیچ فایل صوتی روی adapter باقی نمیماند و پیامهای اسکرچ حذف شدهاند.
استقرار فازبندیشده: dev → سرور با حجم کم (۱ هفته) → کامل.
پایش: شمارش درخواست، نرخ موفقیت، هیستوگرام تأخیر، انواع خطا، وضعیت نشست. هشدار اگر نرخ خطا در ۳۰ دقیقه > ۲۰٪.
بازگشت (Rollback): حذف STT_PROVIDER_3_* از env بات + توقف کانتینر adapter — بات فوراً به وضعیت قبل برمیگردد (بدون deploy مجدد).
۷. رجیستر ریسک
| ریسک | احتمال | اثر | مقابله |
|---|---|---|---|
| بن/rate-limit اکانت | متوسط | توقف مسیر | حجم کم، WS-first، backoff، اکانت اختصاصی قابلتعویض، G4 |
| تغییر پروتکل بله | متوسط | قطع سرویس | pایش نسخهی باندل (hash)، آلرت خطا، فالبک R4، سوییچ موتور با env |
| انقضای نشست/نیاز OTP | بالا (دورهای) | توقف موقت | ولوم session + آلرت + runbook ورود (انسانی) |
| دقت ناکافی نسبت به هزینه | نامعلوم | هزینهی بیفایده | G5 قبل از ساخت |
| ریسک حقوقی/ToS | نامعلوم | توقف اجباری | T8/G6 — تصمیم مدیریت |
| حریم خصوصی صدا | کم | اعتباری | حذف فوری پیامها/فایلها؛ عدم نگهداری |
| وابستگی به فرد نگهدارنده | متوسط | رکود | مستندسازی در همین پلیبوک + مالک رسمی |
۸. دروازههای انسانی (فقط انسان میتواند)
- OTP ورود اکانت (بار اول و هر بار انقضا).
- تصمیم ToS/حقوقی (G6).
- جمعآوری نمونههای واقعی ویس برای T7 (با رضایت).
- تأیید نهایی استقرار و تأیید مرج برنچ توسط مهندس ارشد.
ضمیمه A — دستورات probe (تکرارپذیر)
TOKEN="<BOT_TOKEN>"
for M in transcribeVoice getTranscription transcribe speechToText voiceToText; do
curl -s -X POST "https://tapi.bale.ai/bot$TOKEN/$M" -H "Content-Type: application/json" -d '{}'; echo
done
curl -s -X POST "https://tapi.bale.ai/bot$TOKEN/getMe" -H "Content-Type: application/json" -d '{}'
خروجی مورد انتظار: پنج 404 «handler not found» و یک getMe سالم. (همین تست را قبل از هر تصمیم مجدداً اجرا کنید — شاید بله متد اضافه کرده باشد.)
ضمیمه B — اسکلت adapter (قابل استفاده برای هر سه موتور)
# bale_stt/adapter.py — قرارداد OpenAI-compatible برای بات
import os
from fastapi import FastAPI, File, Form, Header, HTTPException, UploadFile
app = FastAPI()
INTERNAL_KEY = os.environ["BALE_STT_INTERNAL_KEY"]
ENGINE = os.environ.get("BALE_STT_ENGINE", "grpc") # grpc | aichat | playwright
@app.get("/healthz")
def healthz():
return {"status": "ok", "engine": ENGINE}
@app.post("/v1/audio/transcriptions")
async def transcribe(file: UploadFile = File(...), model: str = Form("bale-stt"),
language: str = Form("fa"), authorization: str = Header("")):
if authorization != f"Bearer {INTERNAL_KEY}":
raise HTTPException(status_code=401)
audio = await file.read()
if ENGINE == "grpc":
text = await grpc_transcribe(audio) # ← aiobale-py + RPC کشفشده
elif ENGINE == "aichat":
text = await aichat_transcribe(audio) # ← ارسال به چت AI و استخراج متن
else:
text = await playwright_transcribe(audio)
return {"text": text or ""}
# نکته: هرگز استثنا را بیرون نده؛ در خطا {"text": ""} برگردان تا بات fail-soft بماند.
ضمیمه C — منابع
- aiobale-py: PyPI · GitHub · مستندات
- مستندات رسمی بات بله: docs.bale.ai
- سرویس ثالث STT: majidapi.ir
- گزارشهای ایجنت شرکت:
bale_stt_integration_report.mdوbale_stt_integration_report_2.md(کنار همین فایل)
ضمیمه D — چکلیست سریع ایجنت (TL;DR)
- قواعد بخش ۰ را خواندم.
- T1 (payload ویس) → G1.
- T2 (کپچر) → G2 → مسیر (R2 / R3 / R4) انتخاب شد.
- T3+T4 (اسکیما + اسپایک) → G3.
- T-extra (اوراکل AI Chat) اگر مسیر R3 مدنظر است.
- T5 (تأخیر واقعی) → G4.
- T7 (دقت) → G5 — بدون این، ساخت ممنوع.
- T8 (ToS — انسانی) → G6.
- ساخت adapter (۵.۱) + ادغام env (۵.۵) + تستهای پذیرش (بخش ۶).
- سواک (T6/T9) → G7 → استقرار کامل. هر شکست ⇒ جدول همان دروازه ⇒ اقدام جایگزین یا STOP.