31 KiB
ارتقای چت صوتی ایجنت — STT، TTS، کاتالوگ مدیریت، ارائهدهندگان ابری
تاریخ بررسی: ۱۴۰۵/۰۵/۲۸ (۱۸ اوت ۲۰۲۶)
وضعیت: فازهای ۰–۵ و ۷ پیاده شدهاند (cascade). فاز ۶ Realtime عمداً انجام نشده.
هدف سند: نقشهٔ پیادهسازی تدریجی تا سطح ایجنت صوتی حرفهای (مرجع: ChatGPT Advanced Voice / OpenAI Realtime)
مراجع موجود: AI_VOICE_CHAT_IMPLEMENTATION.md (وضعیت فعلی)، AI_AGENT_SYSTEM_AUDIT.md (VOI-01، VOI-02، GAP-06)
این سند را بعد از هر فاز با وضعیت ✓ و یک سطر تاریخچه بهروز کنید.
| فاز | وضعیت |
|---|---|
| ۰ قرارداد + fallback env | ✓ |
| ۱ کاتالوگ ادمین + catalog کاربر | ✓ |
| ۲ ابر OpenAI + سیاست fail-closed | ✓ |
| ۳ دیکته + بلندخوانی + chip STT/TTS | ✓ |
| ۴ تماس = همان ایجنت (session/model/mode/approval) | ✓ |
| ۵ متریک، سقف جلسه، Whisper اشتراکی | ✓ (نمونهٔ WER طلایی باقی است) |
| ۶ Realtime speech-to-speech | عمداً انجام نشده |
| ۷ لاگ مصرف صوت | ✓ جزئی (بدون سهمیهٔ دقیقهٔ جدا در پلن) |
۱. جمعبندی سریع
| قابلیت | در سیستم امروز | کجا | شکاف با سطح ChatGPT |
|---|---|---|---|
| گفتوگوی صوتی دوطرفه | هست (آبشار محلی) | WS /ws/ai/voice |
latency بالا؛ کیفیت فارسی پایینتر از ابر؛ بدون speech-to-speech |
| صدا → متن (STT) | فقط داخل همان جلسهٔ صوت | faster-whisper روی سرور، مدل small از env |
دیکته در باکس متن نیست؛ partial transcript نیست؛ ابر نیست |
| متن → صدا (TTS) | فقط داخل همان جلسهٔ صوت | Piper / Coqui / پیشفرض dummy (سکوت) |
خواندن پیام متنی نیست؛ انتخاب صدا نیست؛ ابر نیست |
| مدیریت ادمین مثل مدل متنی | نیست | مدل متن: جدول ai_models + صفحهٔ ادمین + credential |
صوت فقط ENV (VOICE_*)؛ کاربر مدل/صدا انتخاب نمیکند |
| ارائهدهندهٔ API (OpenAI و …) | فقط برای LLM متن | ai_provider_credentials |
هیچ adapter برای Whisper/TTS/Realtime ابری |
| ایجنت حین صوت (ابزار، تأیید نوشتن، مدل انتخابی) | ناقص | voice_ws حلقه را بدون session_id / execution_mode / request_model صدا میزند |
نوشتن بیتأیید یا بیکارت؛ trace متنی دیده نمیشود |
| سوییچ متن ↔ صوت در یک جلسه | قفل | composer هنگام صوت enabled: false |
ChatGPT در همان thread هم تایپ میکند هم حرف میزند |
نتیجه: زیرساخت صوت وجود دارد و پخته است (VAD، WS، فشردهسازی وب، barge-in پروتکلی، بازخورد کیفیت). آنچه کم است محصول است نه اسکلت: سه حالت استفاده (تماس / دیکته / بلندخوانی)، کاتالوگ قابل مدیریت، کیفیت ابری اختیاری، و همترازی حلقهٔ ایجنت با چت متنی.
۲. آنچه در کد هست (واقعیت امروز)
۲.۱ معماری فعلی — آبشار (cascade)، نه Realtime
میکروفون کلاینت (PCM16 16kHz یا WebM/Opus)
→ WebSocket /ws/ai/voice (auth در اولین فریم JSON)
→ VAD محلی (webrtcvad) + endpointing سکوت
→ STT محلی faster-whisper (کل utterance یکجا؛ بدون streaming)
→ همان LLM ایجنت: AIService.chat_completion_stream
→ TextChunker جمله/۱۴۰ کاراکتر
→ TTS محلی Piper (یا dummy/coqui) → فریم PCM به کلاینت
→ پیام user/assistant در همان جلسهٔ چت ذخیره میشود
این همان «Standard Voice» قدیمی ChatGPT است (صدا→متن→مدل→صدا)، نه Advanced Voice / Realtime که مدل مستقیماً روی صوت فکر میکند.
فایلهای اصلی:
| لایه | مسیر |
|---|---|
| WS و ارکستراسیون | hesabixAPI/adapters/api/v1/ai/voice_ws.py |
| STT | hesabixAPI/app/services/voice/stt.py (WhisperSTT) |
| TTS | hesabixAPI/app/services/voice/tts.py (TTSFactory: piper / coqui / dummy) |
| VAD | hesabixAPI/app/services/voice/vad.py |
| تنظیمات | hesabixAPI/app/core/settings.py فیلدهای voice_* |
| بازخورد | POST /api/v1/ai/voice/interactions/{id}/feedback + جدول ai_voice_interactions |
| کلاینت | VoiceChatController (io/web) + AIChatVoiceSessionController + composer میکروفون |
۲.۲ سه حالت محصول — امروز فقط یکی هست
کاربر و محصول به هر دو STT و TTS نیاز دارند، ولی نه لزوماً همیشه با هم:
| حالت | معنی برای کاربر | امروز |
|---|---|---|
| A — تماس صوتی | مثل تماس ChatGPT: حرف میزند، ایجنت جواب میدهد با صدا | هست (آبشار محلی) |
| B — دیکته (STT alone) | دکمهٔ میکروفون متن را داخل composer میگذارد؛ کاربر ویرایش و ارسال میکند | نیست؛ میکروفون مستقیم تماس را شروع میکند |
| C — بلندخوانی (TTS alone) | روی پیام دستیار «بخوان»؛ بدون میکروفون | نیست |
هدف ارتقا: هر سه حالت روی یک کاتالوگ STT/TTS سوار شوند. تماس صوتی هر دو را با هم مصرف میکند؛ دیکته و بلندخوانی جداگانهاند.
۲.۳ مدیریت ادمین: الگوی مدل متنی هست؛ صوت از آن جدا مانده
مدلهای متنی (الگوی درست برای کپی):
- جدول
ai_models:code,display_name,provider,model_id,tier, قیمت مرجع،is_active,sort_order - API ادمین
/admin/ai/models(CRUD + seed از config) - صفحهٔ
AIModelsAdminPageبا provider: openai / anthropic / local / custom - اعتبارنامه جدا:
ai_provider_credentials(یک کلید per provider، تست اتصال) - BYOK کسبوکار:
business_ai_provider_configs - کاربر در composer با
AIChatModelChipمدل فعال را برمیدارد - پلنها مدلهای مجاز را محدود میکنند
صوت امروز:
- فقط متغیر محیطی:
VOICE_ENABLED,VOICE_STT_*,VOICE_TTS_ENGINE, مسیر Piper، … - پیشفرض TTS در کد:
voice_tts_engine = "dummy"→ در تولید اگر env ست نشده باشد کاربر سکوت میشنود (هشدار UI هست) - هیچ ردیف کاتالوگ، هیچ صفحهٔ ادمین، هیچ انتخاب کاربر، هیچ قیمت جدا برای دقیقهٔ صوت
- credentialهای OpenAI موجود فقط chat completion را تست میکنند؛ Whisper/TTS ابری صدا زده نمیشوند
- منوی تنظیمات سیستم دستهٔ «هوش مصنوعی» آیتم صوت ندارد
۲.۴ حلقهٔ ایجنت در مسیر صوت با چت متنی یکی نیست
چت متنی به chat_completion_stream میدهد: session_id, request_model, execution_mode, approve_writes, user_query, ادامهٔ run، رویدادهای SSE (trace، approval، citation).
مسیر صوت امروز تقریباً فقط این را صدا میزند:
ai_service.chat_completion_stream(
messages=messages,
use_function_calling=True,
session_business_id=business_id,
)
پیامدها:
- مدل انتخابی کاربر در chip اعمال نمیشود (مدل پیشفرض config/پلن).
execution_mode(تحلیلگر / با تأیید / خودکار) از UI صوت نمیآید.approve_writesپیشفرضFalseاست؛ ابزار نوشتن در صوت یا متوقف میشود یا رویدادawaiting_approvalبه کلاینت صوت forward نمیشود (_forward_agent_chunkفقطstatusوtool_startرا میفهمد).session_idنیست → persist run، حافظهٔ جلسه، plan، continuation مثل متن کامل نیست.- تایملاین تفکر متنی و صوت دو کانال جدا هستند (
VOI-01). - شارژ فقط توکن LLM است؛ دقیقهٔ STT/TTS و هزینهٔ ابر ثبت نمیشود.
۲.۵ UX و امنیت صوت (جزئیات مفید برای فازها)
آنچه خوب است:
- Auth WS در query نیست؛ اولین فریم
{"type":"auth","api_key"}با timeout ۱۵ ثانیه (ws_api_key_handshake.py) — بخش بزرگی ازVOI-02انجام شده. - Barge-in: اگر کاربر وسط TTS حرف بزند
cancel_eventست میشود؛ کلاینت هم هنگامstartRecordingدستورbarge_inمیفرستد. - ذخیرهٔ PCM فقط با opt-in و
voice_data_collection_enabled. - سهمیه قبل از
startو قبل از هر utterance چک میشود. - وب: AudioWorklet PCM یا MediaRecorder WebM/Opus.
- تست واحد تفسیر رویداد:
ai_chat_voice_session_test.dart. تست بکاند مسیر صوت تقریباً نیست (ARC-06).
آنچه نیست / ضعیف است:
- Rate limit per user روی WS (
VOI-02باقیمانده). - Transcript زنده (partial) هنگام حرف زدن کاربر.
- سوییچ به تایپ وسط تماس بدون قطع جلسه.
- انتخاب صدا / زبان / کیفیت در UI.
- محدودیت نرخ و سقف همزمانی اتصال صوت (هر اتصال مدل Whisper را lazy-load میکند؛ روی CPU سنگین است).
- متریک WER / latency perceived.
۳. رفتار مطلوب (سطح ChatGPT / ایجنت حرفهای)
مرجع محصول: ChatGPT (حالت استاندارد + Advanced Voice)، Claude (فعلاً ضعیفتر در صوت)، Google Gemini Live.
۳.۱ تجربهٔ کاربر داخل همان جلسهٔ چت
- دیکته: نگه داشتن یا یک ضربه روی میکروفون → متن در composer ظاهر میشود (قابل ویرایش) → ارسال معمولی با همهٔ قابلیت ایجنت (ابزار، تأیید نوشتن، مدل).
- بلندخوانی: روی پیام دستیار «بخوان»؛ قطع با ضربه؛ انتخاب صدا از تنظیمات.
- تماس صوتی: دکمهٔ جدا (مثل گوشی ChatGPT) جلسه را به حالت صوت میبرد ولی تاریخچه همان thread است. کاربر میتواند وسط تماس تایپ کند. Transcript زنده در حبابها دیده میشود. وقتی ایجنت ابزار میزند («دارم موجودی را میخوانم») همان وضعیت در نوار صوت و در تایملاین متنی میآید.
- تأیید نوشتن صوتی: ایجنت بلند میگوید «فاکتور فروش برای علی به مبلغ X بسازم؟ بگو تأیید یا رد» و همان کارت تأیید در UI ظاهر میشود؛ تا تأیید، write اجرا نشود.
- قطع و barge-in: حرف زدن کاربر TTS را فوری قطع کند؛ دکمهٔ پایان تماس قرمز بماند.
- انتخاب: مدل زبانی (همان chip موجود) + موتور STT + صدای TTS، محدود به پلن.
Latency هدف تماس آبشاری خوب: شروع شنیدن پاسخ < ۱.۵s برای عبارت کوتاه فارسی (VOI-01). Realtime ابری میتواند زیر ۵۰۰ms باشد ولی ابزار و فارسی را سختتر میکند.
۳.۲ تجربهٔ مدیر سیستم (مثل مدلهای متنی)
مدیر در تنظیمات سیستم بتواند:
- STT محلی (Whisper size/path) یا STT ابری (کلید، مدل، زبان) را ردیف کاتالوگ کند.
- TTS محلی (Piper voice id) یا TTS ابری (صدا، سرعت، زبان) را ردیف کند.
- هر ردیف را فعال/غیرفعال، مرتب، قیمتگذاری مرجع، و محدود به پلن کند.
- اتصال را با یک نمونهٔ کوتاه فارسی تست کند (مثل test-connection مدل متنی).
- پیشفرض سراسری و پیشفرض پلن تعیین کند.
- تصمیم بگیرد دادهٔ صوت به ابر برود یا فقط محلی بماند (سیاست حریم خصوصی per business).
کاربر نهایی فقط از کاتالوگ فعال و مجاز پلن انتخاب میکند؛ کلید API را نمیبیند (مگر BYOK کسبوکار در فاز بعدی).
۳.۳ دو مسیر فنی که نباید قاطی شوند
| مسیر | شرح | ابزار ایجنت | کیفیت مکالمه | هزینه / حریم |
|---|---|---|---|---|
| Cascade (توصیهٔ پایه) | STT → همان حلقهٔ متن → TTS | کامل؛ همان ۱۰۰+ ابزار | وابسته به کیفیت STT/TTS و latency آبشار | قابل کنترل؛ محلی ممکن است |
| Realtime / speech-to-speech | مدل چندرسانهای مستقیم روی صوت (OpenAI Realtime، Gemini Live) | باید tool را به جلسهٔ realtime وصل کرد؛ پیچیدهتر | طبیعیتر، قطع صحبت نرمتر | داده به ابر؛ فارسی متغیر؛ هزینهٔ دقیقه |
برای حسابیکس (ERP با write guard و ابزار دامنه) Cascade باید مسیر اصلی بماند. Realtime فقط فاز اختیاری برای مکالمهٔ کوتاه بدون نوشتن سنگین است، نه جایگزینی حلقهٔ ایجنت.
۴. پیشنهاد معماری (تکمیل اسکلت فعلی، نه بازنویسی)
۴.۱ لایهٔ Provider جدا از WS
امروز voice_ws.py مستقیماً WhisperSTT و TTSFactory.create میسازد. باید پشت یک قرارداد ثابت برود:
STTProvider.transcribe(pcm16, sample_rate, language) -> Transcript
+ اختیاری: transcribe_stream(...) -> partial + final
TTSProvider.synthesize_stream(text, voice_id, cancel) -> PCM frames
VoiceRuntime.resolve(business_id, user_id, session) -> (stt, tts, policy)
پیادهسازیهای اول:
| kind | پیادهسازی | منبع تنظیم |
|---|---|---|
local_whisper |
کد فعلی WhisperSTT |
کاتالوگ + fallback env |
local_piper |
کد فعلی PiperTTSEngine |
کاتالوگ + fallback env |
dummy |
سکوت / تست | فقط غیرتولید |
openai_transcription |
POST /v1/audio/transcriptions (whisper-1 / gpt-4o-transcribe / gpt-4o-mini-transcribe) |
credential openai موجود |
openai_tts |
POST /v1/audio/speech (tts-1 / tts-1-hd / gpt-4o-mini-tts) |
همان credential |
| بعداً | Groq Whisper، Azure Speech، Google Chirp/TTS، ElevenLabs | credential جدا در همان جدول با provider جدید |
api_base_url فعلی برای gateway سازگار با OpenAI میتواند همان transcription/speech را هم پروکسی کند اگر ارائهدهنده پشتیبانی کند — در تست اتصال باید جداگانه چک شود.
۴.۲ کاتالوگ داده — پیشنهاد schema
جدول جدید بهتر از شلوغ کردن ai_models است، چون فیلدها فرق دارند (sample rate، voice id، زبان، قیمت per minute / per 1k chars). الگوی نامگذاری مثل متن:
ai_voice_models
| فیلد | نقش |
|---|---|
code |
شناسه پایدار مثلاً stt-local-whisper-small |
kind |
stt | tts | realtime |
display_name |
نام فارسی/انگلیسی برای UI |
provider |
local | openai | azure | google | groq | elevenlabs | custom |
model_id |
شناسهٔ API یا فایل محلی (مثلاً whisper-1, fa_IR-ganji-medium) |
language |
پیشفرض fa |
voice_id |
فقط TTS (alloy، ganji، …) |
tier |
basic/pro مثل مدل متن |
is_active, sort_order |
|
reference_cost_* |
مثلاً per_minute یا per_1k_chars |
extra_json |
device/compute_type برای محلی، format خروجی، و … |
سیاست انتخاب (ترتیب resolve):
- انتخاب صریح کاربر در جلسه (اگر پلن اجازه دهد)
- پیشفرض پلن
- پیشفرض فعال سراسری ادمین
- fallback ENV فعلی (سازگاری با نصبهای موجود)
Credential: همان ai_provider_credentials گسترش داده شود (providerهای جدید + فلگ supports_stt / supports_tts / supports_chat) یا در فاز اول از کلید OpenAI موجود برای STT/TTS ابری استفاده شود تا ادمین دو بار کلید نگذارد.
۴.۳ API محصول (علاوه بر WS تماس)
| Endpoint پیشنهادی | حالت |
|---|---|
POST /ai/voice/stt (multipart یا PCM) |
دیکته؛ پاسخ {text, language} |
POST /ai/voice/tts یا SSE/WS کوتاه |
بلندخوانی یک متن؛ اختیاری stream |
GET /ai/voice/catalog |
لیست STT/TTS مجاز کاربر |
WS /ws/ai/voice |
تماس؛ بعد از فاز ۱ از VoiceRuntime.resolve تغذیه شود نه مستقیماً از env |
احراز هویت، سهمیه، و عدم ذخیرهٔ صوت مگر opt-in برای هر سه یکی باشد.
۴.۴ همترازی حلقهٔ تماس با چت متنی
حداقل قرارداد start روی WS:
{
"type": "start",
"session_id": 123,
"execution_mode": "supervised",
"model_code": "gpt-4o-mini",
"stt_code": "stt-local-whisper-small",
"tts_code": "tts-piper-ganji",
"input_codec": "pcm"
}
و chat_completion_stream(..., session_id=..., request_model=..., execution_mode=..., user_query=transcript).
رویدادهای جدید به کلاینت صوت: approval_required، trace_step (خلاصهٔ کوتاه قابل گفتن)، transcript_partial.
۵. فازهای اجرا
ترتیب طوری است که هر فاز بهتنهایی قابل عرضه باشد و فاز بعد روی آن سوار شود. معیار پذیرش را قبل از بستن فاز روی جلسهٔ واقعی فارسی حسابداری اجرا کنید.
فاز ۰ — قرارداد و جداسازی (بدون ابر)
| کار | معیار پذیرش | ریسک |
|---|---|---|
Interface STTProvider / TTSProvider و انتقال Whisper/Piper فعلی پشت آن |
voice_ws دیگر مستقیماً کلاس بتن نسازد؛ تست واحد dummy STT/TTS |
رگرسیون تماس فعلی |
| سند ENV: fallback اگر کاتالوگ خالی است | نصبهای موجود بدون migration همچنان کار کنند |
فاز ۱ — کاتالوگ ادمین (مثل مدل متنی)
| کار | معیار پذیرش | ریسک |
|---|---|---|
جدول ai_voice_models + CRUD ادمین + صفحه در دستهٔ AI تنظیمات |
مدیر ردیف STT محلی و TTS Piper بسازد، فعال/غیرفعال کند، تست کوتاه بزند | کلید در لاگ |
GET /ai/voice/catalog برای کاربر |
chip یا تنظیمات چت لیست غیرخالی برمیگرداند | شلوغی composer |
| Seed از env فعلی (whisper-small + piper ganji + dummy) | یک کلیک seed مثل مدل متنی |
فاز ۲ — ارائهدهندهٔ API (حداقل OpenAI، قابل تعمیم)
| کار | معیار پذیرش | ریسک |
|---|---|---|
| Adapter transcription + speech با credential موجود OpenAI | ادمین ردیف openai بسازد، تست فارسی بزند، تماس از آن استفاده کند |
ارسال صوت مشتری به ابر |
فلگ سیاست allow_cloud_audio per business (پیشفرض بسته برای کسبوکار حساس) |
بدون فلگ، resolve به local برگردد | |
| Timeout، حجم سقف utterance، retry مثل STT فعلی | فایل ۳۰ ثانیهای بیش از سقف رد شود | هزینهٔ غافلگیرکننده |
لاگ usage با context.type=voice_stt / voice_tts |
در گزارش مصرف دیده شود حتی اگر هنوز پول جدا نباشد |
ارائهدهندگان بعدی (فاز ۲+، هر کدام یک adapter): Groq (Whisper سریع و ارزان)، Azure Neural (fa-IR TTS قوی)، Google، ElevenLabs. اول OpenAI چون کلید و الگوی credential از قبل در پنل هست.
فاز ۳ — STT و TTS مستقل در چت متنی
| کار | معیار پذیرش | ریسک |
|---|---|---|
| دیکته: میکروفون کوتاه → متن در composer؛ ارسال جدا | کاربر میتواند «فروش امروز» را دیکته کند، ویرایش کند، بفرستد؛ حلقهٔ کامل ایجنت اجرا شود | تداخل با دکمهٔ تماس |
| جدا کردن UX: میکروفون دیکته vs دکمهٔ تماس | دو کنترل واضح در composer | شلوغی موبایل |
| بلندخوانی پیام دستیار | پخش PCM/صوت؛ Stop؛ عدم قفل شدن composer | همپوشانی با تماس |
این فاز بیشترین ارزش محصول را برای «هم صدا به متن و هم متن به صدا» میدهد بدون اینکه تماس Realtime لازم باشد.
فاز ۴ — تماس صوت = همان ایجنت متنی
| کار | معیار پذیرش | ریسک |
|---|---|---|
| پاس دادن session_id / model / execution_mode | مدل chip در تماس رعایت شود | |
| Forward رویداد approval + کارت در UI؛ تا تأیید، TTS سؤال بپرسد نه اینکه write اجرا شود | ساخت فاکتور از روی صوت بدون تأیید ممکن نباشد | دور زدن SEC |
| قفل نبودن composer | وسط تماس بتوان تایپ کرد؛ متن و صوت یک تاریخچه | race دو utterance |
transcript_partial اگر موتور STT streaming دارد؛ وگرنه حداقل transcript_final فوری در thread |
حباب کاربر قبل از «thinking» دیده شود |
فاز ۵ — کیفیت مکالمه (بدون تغییر ارائهدهنده)
| کار | معیار پذیرش | ریسک |
|---|---|---|
| متریک latency: vad_end → first_audio_out | عبارت کوتاه فارسی < ۱.۵s روی ابر؛ محلی جدا گزارش شود | |
Rate limit اتصال صوت per user (VOI-02) |
اتصال بدون auth بعد از ۱۵s (موجود) + سقف اتصال همزمان | |
| صف/یک مدل Whisper اشتراکی در فرایند به جای load per connection | حافظهٔ سرور پایدار | پیچیدگی lifecycle |
| نمونهٔ ارزیابی فارسی حسابداری (اعداد، نام کالا، «بدهکار») | WER روی ۱۰ فایل طلایی ثبت شود |
فاز ۶ — اختیاری: Realtime speech-to-speech
فقط بعد از فاز ۲–۴. جلسهٔ OpenAI Realtime (یا معادل) با:
- ابزار فقط read در نسخهٔ اول
- fallback به cascade اگر مدل realtime در دسترس نبود
- سیاست ابری اجباری
- عدم جایگزینی write guard
معیار پذیرش: مکالمهٔ کوتاه «سلام، فروش امروز چقدر بود؟» با حس طبیعیتر؛ موجودی از ابزار read بیاید؛ ساخت فاکتور همچنان به cascade+approval برگردد.
فاز ۷ — صورتحساب و پلن
| کار | معیار پذیرش |
|---|---|
| سهمیه دقیقه STT/TTS یا هزینهٔ جدا در پلن | پلن basic فقط local؛ pro ابر |
| BYOK صوت برای کسبوکار (مثل متن) | کلید روی business_ai_provider_configs برای transcription/speech |
| نمایش در UI سهمیه | کاربر بفهمد دیکته از سهمیه صوت کم میکند |
۶. ارائهدهندگان — راهنمای انتخاب (فارسی حسابداری)
کیفیت فارسی باید با فایل واقعی فاکتور/اعداد آزمایش شود؛ ادعاهای بازاریابی کافی نیست.
| نقش | محلی (حریم خصوصی) | ابری پیشنهادی اول | جایگزین |
|---|---|---|---|
| STT | faster-whisper small فعلی؛ برای کیفیت large-v3 روی GPU |
OpenAI gpt-4o-mini-transcribe یا whisper-1 |
Groq Whisper (ارزان/سریع)، Azure fa-IR |
| TTS | Piper fa_IR-ganji-medium (و amir/gyro) |
OpenAI TTS چندزبانه؛ کیفیت فارسی را A/B کنید | Azure Neural fa-IR، Google fa-IR، ElevenLabs multilingual |
| Realtime | نیست | OpenAI Realtime | Gemini Live |
توصیهٔ محصول:
- پیشفرض نصب self-host: STT whisper + TTS piper (تمایز حریم خصوصی که در ممیزی آمده حفظ شود).
- پیشفرض ابر اگر مدیر کلید OpenAI دارد و سیاست اجازه دهد: STT ابری + TTS ابری برای کیفیت؛ LLM همان کاتالوگ متن.
- هرگز ابر را بدون فلگ کسبوکار اجباری نکنید.
۷. آنچه نباید کرد
- حذف پایپلاین محلی به نفع فقط ابر (مشتریان self-host و دادهٔ مالی).
- فرستادن صوت به ابر وقتی
allow_cloud_audioخاموش است. - چسباندن STT/TTS به جدول
ai_modelsمتنی بدونkind— فیلدها و قیمتگذاری فرق دارند. - جایگزینی حلقهٔ ایجنت با Realtime برای عملیات نوشتنی (فاکتور، سند).
- ذخیرهٔ PCM پیشفرض برای «بهبود مدل» بدون opt-in.
- یک دکمهٔ میکروفون که هم دیکته است هم تماس — دو نیت جدا.
- TTS
dummyدر تولید بدون هشدار ادمین در کاتالوگ (الان فقط snackbar کلاینت است).
۸. سناریوهای پذیرش دستی (بعد از پیادهسازی فاز مربوط)
دیکته (فاز ۳)
۱. در چت متنی میکروفون دیکته → «موجودی کالای X را بگو».
۲. متن در باکس ظاهر شود، یک کلمه را دستی درست کند، ارسال.
۳. ایجنت ابزار موجودی بزند و پاسخ متنی بدهد. صدا پخش نشود مگر بلندخوانی.
بلندخوانی (فاز ۳)
۱. روی همان پاسخ «بخوان».
۲. صدا پخش شود؛ Stop قطع کند؛ بتوان همزمان پیام بعدی را تایپ کرد.
تماس + ابزار (فاز ۴)
۱. تماس صوتی: «گزارش فروش این ماه را خلاصه بگو».
۲. نوار وضعیت thinking/tool/speaking؛ متن در thread؛ صدا.
۳. وسط پاسخ حرف بزند (barge-in) و سوال را عوض کند.
تأیید نوشتن (فاز ۴)
۱. «برای علی فاکتور فروش ۱۰ عدد کالا بساز».
۲. کارت تأیید + پرسش صوتی؛ بدون تأیید سند ساخته نشود.
ادمین (فاز ۱–۲)
۱. ردیف Piper محلی و ردیف OpenAI STT/TTS.
۲. تست اتصال فارسی.
۳. غیرفعال کردن ابر → کاربر فقط محلی ببیند.
۴. کسبوکار بدون فلگ ابر حتی اگر کاتالوگ ابری فعال سراسری باشد، محلی بماند.
رگرسیون نصب فعلی
پس از فاز ۰–۱، بدون ردیف کاتالوگ، همان env VOICE_* تماس قبلی را حفظ کند.
۹. نگاشت به ممیزی و ترتیب پیشنهادی نسبت به کارهای دیگر
| آیتم ممیزی | این سند |
|---|---|
VOI-01 کیفیت و همترازی متن |
فاز ۲ (کیفیت) + فاز ۳–۴ (همترازی UX و ایجنت) |
VOI-02 auth/rate limit |
timeout auth موجود است؛ rate limit = فاز ۵ |
GAP-06 همتراز GPT-4o Realtime |
عمداً فاز ۶ و اختیاری؛ Cascade حرفهای هدف اصلی است |
SEC تأیید نوشتن |
فاز ۴ روی صوت |
BIL سهمیه |
فاز ۷ |
ARC-06 تست صوت |
از فاز ۰ تست واحد provider؛ از فاز ۲ تست HTTP mock ابر |
ترتیب پیشنهادی نسبت به صف چت متنی (AI_CHAT_PRODUCT_ISSUES.md): دیکته/بلندخوانی (فاز ۳) را میتوان موازی با باگهای UI متن پیش برد. تماس Realtime را پشت پایداری approval و God Widget نگذارید جلو بیفتد.
پیشنهاد صف اجرا وقتی مالک شروع کرد:
- فاز ۰ (جداسازی)
- فاز ۱ (ادمین/کاتالوگ)
- فاز ۳ (دیکته + بلندخوانی) — ارزش کاربر سریع
- فاز ۲ (ابر) — کیفیت
- فاز ۴ (ایجنت در تماس)
- فاز ۵ (سخت شدن تولید)
- فاز ۷ (پول)
- فاز ۶ (Realtime) فقط اگر محصول خواست
۱۰. چکلیست PR وقتی یک فاز پیاده شد
- Adapter جدید: قرارداد STT/TTS + تست واحد مسیر اصلی و شکست (timeout، کلید خالی، زبان)
- اگر ابر: صوت بدون
allow_cloud_audioهرگز از سرور خارج نشود؛ تست fail-closed - کاتالوگ: CRUD ادمین + catalog کاربر + seed/fallback env
- l10n کلیدهای UI جدید (fa/en)
- اگر تماس:
session_id/ approval / model در مسیر WS - متریک
AI_METRICبرایvoice_stt_ms/voice_tts_ms/voice_ttfa_ms(time-to-first-audio) - بهروز کردن وضعیت فاز در همین سند + یک سطر تاریخچه
- بستن یا یادداشت روی
VOI-01/VOI-02/GAP-06در ممیزی فقط اگر معیار همان آیتم واقعاً تمام شد
۱۱. تاریخچهٔ بهروزرسانی
| تاریخ | نسخه | رخداد |
|---|---|---|
| ۱۴۰۵/۰۵/۲۸ | 0.1 | بررسی کد بدون تغییر؛ ثبت شکاف کاتالوگ، سه حالت محصول، cascade در برابر Realtime، و فازهای اجرا |
| ۱۴۰۵/۰۵/۲۸ | 1.0 | پیادهسازی cascade: کاتالوگ STT/TTS، دیکته، بلندخوانی، تماس با مدل/حالت/تأیید نوشتن، سیاست ابر fail-closed |