Files
ERP/bale stt report/bale_stt_final_report.md
T

20 KiB
Raw Blame History

گزارش جامع: اعتبارسنجی گزارش‌ها و راهکار کرال موتور STT بله

تاریخ: ۱۵ مهر ۱۴۰۵
موضوع: افزودن متن تولیدشده توسط قابلیت «تبدیل ویس به متن» پیام‌رسان بله به‌عنوان یک کاندید در خط‌لوله چندمدله STT بات تدارکات
ورودی‌ها: سه سند ارائه‌شده (تحلیل جامع، پلی‌بوک اجرایی، تحلیل مقایسه‌ای) + راستی‌آزمایی مستقل وب
محدودیت: integration_report شماره ۱ و ۲ در دسترس من نبود و فقط از روی نقل‌قول‌های همین اسناد قضاوت شده‌اند. دستورهای کشف (بخش ۴) در محیط من اجرا نشده‌اند، چون شبکه sandbox بسته بود.


۱. خلاصه مدیریتی

  1. Bot API رسمی بله STT ندارد. همه اسناد در این مورد درست می‌گویند.
  2. تناقض اصلی (مهندسی معکوس «غیرعملی است» در برابر «ساده است») هیچ‌کدام کاملاً درست نیست. مسیر شدنی است، ولی «افزودن یک متد» نیست و نیاز به یک فاز کشف دارد.
  3. دو فرض اثبات‌نشده کل مسیر را تحت تأثیر قرار می‌دهد:
    • دکمه «تبدیل به متن» روی وب بله وجود دارد (هر سه سند فرض کرده‌اند، هیچ منبعی تأیید نکرده).
    • پکیج aiobale-py نسخه 0.3.9 فعال است (پیدا نشد؛ به بخش ۲ مراجعه کنید).
  4. کشف جدید: پکیج bale-sdk با ۶۰۷ RPC تایپ‌شده و پروتوهای بازیابی‌شده. احتمال وجود RPC ترنسکریپشن در آن بالاست. ولی مجوز آن اختصاصی است.
  5. بزرگ‌ترین صرفه‌جویی: آزمون دقت را قبل از ساخت و به‌صورت دستی روی ۳۰ ویس واقعی انجام دهید. اگر بله از خط‌لوله فعلی بهتر نبود، پروژه لازم نیست.
  6. ریسک حقوقی/ToS (استفاده خودکار از حساب کاربری) تصمیم مدیریتی است و باید قبل از استقرار روشن شود.

۲. اعتبارسنجی گزارش‌ها

۲.۱ جدول ادعاها

ادعا نتیجه توضیح
Bot API رسمی STT ندارد ✅ تأیید پروب‌ها همگی ۴۰۴ داده‌اند و تایپ‌های SDKها برای Voice فقط شناسه فایل و مدت‌زمان دارند. تذکر: ۴۰۴ برای نام‌های حدسی چیزی درباره فیلد مخفی در payload نمی‌گوید؛ تست T1 (ویس به یک بات تستی و خواندن JSON کامل) هنوز لازم است (۳۰ دقیقه).
بله قابلیت تبدیل ویس به متن دارد ✅ با شرط نسخه جدید بله این قابلیت را برای اندروید و iOS منتشر کرده. وجود دکمه در وب تأییدنشده است و ریسک اصلی مسیر Playwright همین است.
مهندسی معکوس «غیرعملی» است (گزارش ۲) ⚠️ بدبینانه کلاینت‌های متن‌باز مهندسی‌معکوس‌شده وجود دارند. اما استدلال «Protobuf خودتوصیف است» نادرست است: wire format بدون .proto فقط تا حدی (شماره فیلد و نوع خام، بدون نام و معنا) دیکود می‌شود.
مهندسی معکوس «در حد افزودن یک متد» است (پلی‌بوک) ⚠️ خوش‌بینانه کشف RPC، نگاشت فیلدها و پایداری نشست کار واقعی است. تخمین «نیم‌روز» برای T2 ریسکی است.
aiobale-py v0.3.9 فعال است و نام aiobale را پکیج خالی گرفته ❌ تأییدنشده / احتمالاً غلط aiobale-py را پیدا نکردم. aiobale یک کتابخانه واقعی است (MIT، مستندات docs.aiobale.ir، نسخه‌های 0.1.x). فورک‌هایی مثل Autobale می‌گویند نسخه اصلی نگهداری نمی‌شود و باگ دارد. قبل از وابستگی به هر نام، pip index versions را اجرا کنید.
bale-sdk (کشف جدید) 🔎 مهم از کلاینت وب بله مهندسی معکوس شده؛ ۶۰۷ RPC در ۵۲ سرویس، پروتوهای بازیابی‌شده، احراز با JWT یا OTP؛ نسخه 0.1.1 (ژوئن ۲۰۲۶). مجوز اختصاصی و «همه حقوق محفوظ».
تأخیر «زیر ۱ ثانیه» ❌ رد همه موافقند. اعداد ۱–۴ ثانیه (R2) و ۴–۸ ثانیه (Playwright) هم اندازه‌گیری نشده‌اند؛ فقط T5 عدد واقعی می‌دهد.
AI Chat بله ویس را «پیاده» می‌کند (R3) ⚠️ تأییدنشده و نامطلوب حتی اگر درست باشد، خروجی «متن + تفسیر مدل» است و برای consensus مناسب نیست. با کنار گذاشتن موافقم.
RAM ‏۳۵۰–۵۰۰ مگابایت برای Playwright ✅ معقول برای بات تک‌کاربره قابل‌تحمل است.
Playwright در ۱–۲ روز ⚠️ خوش‌بینانه وابسته به وجود دکمه وب، چالش‌های ورود و پایداری سلکتورها.
ساختار Gate / State-machine پلی‌بوک ✅ قوی بهترین بخش اسناد. ایراد: دروازه دقت (T7) بعد از ساخت آمده، در حالی که دستی و قبل از ساخت شدنی است.
ریسک بن، ToS و حریم خصوصی ✅ درست و حیاتی فقط پلی‌بوک به آن پرداخته است.
ترجیح WebSocket به POST gRPC (پلی‌بوک) ✅ منطقی کلاینت رسمی بله POST gRPC را عمدتاً برای چند متد احراز هویت استفاده می‌کند؛ استفاده زیاد از آن غیرعادی به نظر می‌رسد.
«Playwright اول» (سند مقایسه‌ای) در برابر «R2 اول» (پلی‌بوک) ⚠️ هر دو مشروط بدون نتیجه کشف روز اول قابل تصمیم نیست.

۲.۲ ایرادهای کد adapter در سند اول

  • کلید پیش‌فرض ضعیف (bale_secure_token) و مقایسه کلید با != به‌جای مقایسه ثابت‌زمان.
  • بلعیدن همه استثناها بدون لاگ.
  • بازگرداندن ۲۰۰ با متن خالی: ممکن است بات آن را یک کاندید معتبر (خالی) در consensus بشمارد. باید در bot/app/stt.py بررسی شود که پاسخ ۵xx و متن خالی چطور مدیریت می‌شوند. توصیه: در خطا ۵۰۳ برگردد.
  • نبود قفل ترتیبی، سقف روزانه و تأخیر تصادفی در خود adapter.

۲.۳ نکات فنی اصلاح‌شده

  • فریم gRPC-Web پیشوند ۵ بایتی دارد (۱ بایت فلگ + ۴ بایت طول). این برای POST gRPC-Web درست است؛ اینکه فریم‌های WebSocket بله هم همان قالب را دارند فرض اثبات‌نشده‌ای است و باید در T2 دیده شود.
  • هاست‌ها و نام ماژول‌هایی مثل maviz-ws.bale.ai و SpeechTranscript از تحلیل باندل آمده‌اند و در وب ایندکس نشده‌اند. باید با چشم در کپچر تأیید شوند.

۳. راهکارها

راهکار توضیح رم خلوص متن ریسک حکم
A. مسیر رسمی درخواست API یا همکاری از بله — — — هزینه صفر؛ قبل از هر کار غیررسمی یک ایمیل بزنید
B. RPC مستقیم کلاینت کاربری روی WebSocket با bale-sdk یا aiobale + RPC ترنسکریپت ≈ ۲۰ MB خالص متوسط (تغییر پروتکل، بن) بهترین نتیجه فنی، مشروط به کشف RPC
C. Playwright Chromium headless روی web.bale.ai با پروفایل پایدار ۳۵۰–۵۰۰ MB خالص کم–متوسط مقاوم، فقط اگر دکمه وب موجود باشد
D. AI Chat ویس به چت هوش مصنوعی بله و استخراج از پاسخ ≈ ۲۰ MB ❌ متن + تفسیر بالا کنار گذاشته شود
E. سرویس ثالث پروکسی‌های STT با ادعای بله — نامشخص حریم خصوصی/پایداری کنار گذاشته شود
F. اندروید امولاتور اپ بله + uiautomator زیاد خالص بالا (شکننده) آخرین چاره اگر B و C ممکن نشد

۴. مسیر دقیق اجرا

گام ۰: آزمون دقت دستی (نیم‌روز، بدون کد)

۳۰ ویس واقعی تدارکاتی (با رضایت فرستندگان؛ صداها را بلندمدت نگه ندارید) را در اپ بله دستی به متن تبدیل کنید و سه حالت را مقایسه کنید:

  1. خروجی فعلی بات (whisper/سایرین + consensus)
  2. فقط متن بله
  3. consensus با اضافه‌شدن بله

سه معیار: WER متن، دقت استخراج اقلام (نام کالا، برند، تعداد، واحد) و تعداد موارد سخت لهجه‌ای که با بله درست شده‌اند.

معیار پیشنهادی: کاهش نسبی خطای استخراج حدود ۱۵٪ یا بیشتر، یا حل حداقل ۲ مورد سخت. در غیر این صورت STOP.

گام ۱: کشف سریع (حدود ۳۰ دقیقه)

python -m venv .v && . .v/bin/activate
pip index versions aiobale-py   # وجود یا عدم وجود را بررسی کنید
pip download bale-sdk --no-deps --no-binary :all: && tar xzf bale_sdk-*.tar.gz
grep -rniE "transcri|speech|asr|stt" bale_sdk-*/proto bale_sdk-*/docs | head -50

همچنین در پایتون from bale import ALL_RPCS را با همان کلیدواژه‌ها فیلتر کنید.

همزمان T1: یک بات تستی مستقل بسازید، یک ویس بفرستید و JSON کامل آپدیت را بخوانید. اگر فیلد ترنسکریپشن وجود داشت، پروژه کرالر لازم نیست.

گام ۲: وب و کپچر (نیم‌روز تا یک روز)

  1. با یک حساب اختصاصی شرکت روی web.bale.ai وارد شوید و بررسی کنید دکمه «تبدیل به متن» روی ویس هست یا نه (روی ویس دریافتی و ارسالی).
  2. DevTools تب Network را با Preserve log و فیلتر WS و Fetch/XHR ضبط کنید و هنگام کلیک روی دکمه ذخیره کنید:
    • URL کامل و ترابری (unary یا WS)
    • هدر احراز
    • req.bin و resp.bin
    • زمان پاسخ (همان تأخیر واقعی ASR)
  3. ۵ تا ۱۰ ویس متنوع (کوتاه، بلند، لهجه‌دار) را تکرار کنید و در findings.md خلاصه کنید.
  4. دیکود آفلاین: پیشوند ۵ بایتی را بردارید، سپس protoc --decode_raw یا protoscope.

گام ۳: انتخاب مسیر

وضعیت مسیر
RPC در bale-sdk یا کپچر پیدا شد B
RPC پیدا نشد ولی دکمه وب هست C
هیچ‌کدام F یا توقف
ترنسکرایب نیاز به امضا یا اثر انگشت مرورگر دارد C

الگوی پیشنهادی برای B: بات خودتان با sendVoice(file_id) ویس را برای حساب کرالر بفرستد (کرالر یک‌بار بات را /start کرده). این‌طور نیازی به دانلود و آپلود مجدد نیست و message_id بومی در اختیار کرالر است. پس از دریافت متن، پیام حذف شود. اگر RPC به message_id نیاز نداشت، مستقیم فایل یا بایت داده شود.

مجوز: aiobale مجوز MIT دارد ولی نگهداری نمی‌شود (فورک‌ها: Autobale و BaleClient). bale-sdk مجوز اختصاصی دارد؛ برای استفاده تجاری از نویسنده اجازه بگیرید.

گام ۴: ساخت adapter سخت‌شده

قرارداد OpenAI-compatible (همان POST /v1/audio/transcriptions که بات انتظار دارد) و موتور قابل‌سوییچ با BALE_STT_ENGINE=grpc|playwright. پیشنهاد کد:

import os, secrets, asyncio, logging
from fastapi import FastAPI, File, Form, Header, HTTPException, UploadFile

log = logging.getLogger("bale-stt")
app = FastAPI()
KEY = os.environ["BALE_STT_INTERNAL_KEY"]          # بدون مقدار پیش‌فرض
DAILY_CAP = int(os.environ.get("BALE_STT_DAILY_CAP", "100"))
lock = asyncio.Lock()                               # اجرای ترتیبی
count_today = 0                                     # در عمل با ریست روزانه

@app.get("/healthz")
def healthz():
    return {"status": "ok"}

@app.post("/v1/audio/transcriptions")
async def transcribe(file: UploadFile = File(...), model: str = Form("bale-stt"),
                     language: str = Form("fa"), authorization: str = Header("")):
    if not secrets.compare_digest(authorization, f"Bearer {KEY}"):
        raise HTTPException(401)
    if count_today >= DAILY_CAP:
        raise HTTPException(429)
    async with lock:
        try:
            text = await run_engine(await file.read())  # + تأخیر تصادفی ۱ تا ۳ ثانیه
        except Exception:
            log.exception("bale stt failed")
            raise HTTPException(503)    # تا بات فقط همین کاندید را حذف کند
    if not text:
        raise HTTPException(503)
    return {"text": text}

اتصال به بات (بدون تغییر کد):

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 پر باشند.

گام ۵: عملیات و ایمنی

  • فقط شماره اختصاصی شرکت؛ هرگز شماره شخصی.
  • session_file یا پروفایل مرورگر روی ولوم داکر و هرگز در گیت.
  • OTP تنها گام انسانی است. در ابطال نشست: هشدار به ادمین و هدایت ترافیک به سایر پرووایدرها.
  • اجرای ترتیبی، فاصله تصادفی ۱ تا ۳ ثانیه، سقف روزانه، و ترجیح WebSocket به POST gRPC.
  • حذف فوری پیام اسکرچ پس از استخراج و عدم نگهداری فایل صوتی روی دیسک.
  • پایش: نرخ موفقیت، p50 و p95 تأخیر، انواع خطا، وضعیت نشست. هشدار اگر نرخ خطا در ۳۰ دقیقه بیش از ۲۰٪ شد.
  • Rollback: خالی کردن STT_PROVIDER_3_* در env بات و توقف کانتینر. بات فوراً به وضعیت قبل برمی‌گردد.
  • سکرت‌هایی که در docker-compose.yml کامیت شده‌اند (توکن بات، کلید DeepSeek) باید rotate شوند و DRAFT_TOKEN_SECRET پیش‌فرض ضعیف را عوض کنید.
  • روی برنچ‌های دیگران (prod-v7 و غیره) دخالت نکنید و بدون تأیید مالک چیزی پوش نشود.

گام ۶: اندازه‌گیری و سواک

  • T5: ۵۰ تا ۱۰۰ ویس ترتیبی با فاصله انسانی؛ پذیرش پیشنهادی: موفقیت ≥ ۹۵٪ و p95 ≤ ۸ ثانیه.
  • سواک یک‌هفته‌ای با حجم کم (حدود ۱۰۰ ترنسکرایب در روز): ثبت تعداد ورود مجدد، چالش‌های امنیتی و عمر واقعی توکن.

۵. دروازه‌های تصمیم (خلاصه)

دروازه شرط عبور در صورت شکست
G0 دقت دستی بهبود ≈ ۱۵٪ یا ۲ مورد سخت STOP
G1 (T1) فیلد ترنسکریپشن نبود اگر بود: پایان، مستقیم وصل شود
G2 کشف RPC یا دکمه وب پیدا شد F یا توقف
G3 پروتوتایپ درخواست ساخته و پاسخ خوانده شد سوییچ به C
G4 نرخ و پایداری ≥ ۹۵٪ موفقیت، p95 ≤ ۸ ثانیه کاهش نرخ و backoff؛ در صورت بن: توقف
G6 ToS تصمیم مکتوب مدیریت STOP یا حجم بسیار محدود
G7 سواک نشست سالم یک هفته rollback و بازگشت به G4

۶. زمان‌بندی واقع‌بینانه

مرحله زمان
گام ۰ و ۱ (دقت دستی + کشف سریع) نیم‌روز
گام ۲ (وب و کپچر) ۱ روز
ساخت B یا C ۲ تا ۴ روز
T5 و سواک ۱ هفته

۷. رجیستر ریسک

ریسک احتمال اثر مقابله
بن یا rate-limit حساب متوسط توقف مسیر حجم کم، WS-first، سقف روزانه، حساب اختصاصی قابل‌تعویض
تغییر پروتکل یا UI بله متوسط قطع سرویس هشدار خطا، فالبک، سوییچ موتور با env، rollback با env
انقضای نشست و نیاز به OTP بالا (دوره‌ای) توقف موقت ولوم نشست + هشدار + runbook ورود انسانی
دکمه وب وجود ندارد نامعلوم ناممکن‌شدن C بررسی در گام ۲ قبل از ساخت
دقت ناکافی نسبت به هزینه نامعلوم هزینه بی‌فایده G0 قبل از ساخت
ToS / مسائل حقوقی نامعلوم توقف اجباری تصمیم مکتوب مدیریت (G6)؛ ایمیل به بله (A)
مجوز اختصاصی bale-sdk بالا ممنوعیت استفاده اجازه از نویسنده یا استفاده از aiobale (MIT)
حریم خصوصی صدا کم اعتباری حذف فوری پیام‌ها، عدم نگهداری فایل
وابستگی به یک فرد نگهدارنده متوسط رکود مستندسازی و مالک رسمی

۸. دروازه‌های انسانی

  1. OTP ورود حساب (بار اول و هر انقضا).
  2. تصمیم ToS / حقوقی.
  3. جمع‌آوری نمونه ویس واقعی با رضایت.
  4. تأیید نهایی استقرار و مرج توسط مهندس ارشد.

۹. توصیه نهایی

  1. همین هفته: گام ۰ (دقت دستی) + ایمیل به بله + گام ۱ (کشف سریع و T1).
  2. اگر دقت توجیه داشت: گام ۲ و انتخاب B یا C بر اساس شواهد.
  3. معماری: adapter با قرارداد OpenAI و موتور قابل‌سوییچ؛ بات دست‌نخورده می‌ماند.
  4. تصمیم مدیریتی درباره ToS قبل از استقرار.
  5. اگر هر کدام از G0 یا G6 شکست خورد، توقف و ادامه با پرووایدرهای فعلی.

منابع