در تشخیص گفتار زنده، متن موقت ممکن است با رسیدن صوت بیشتر تغییر کند. اگر هر بار همان قطعه را به انتهای متن اضافه کنید، یک جمله چندبار دیده میشود. مسیر درست به قرارداد همان سرویس وابسته است: نتیجه موقت را به جایگاه خودش وصل کنید و فقط پس از رویداد مناسب، آن قطعه را نهایی بدانید.
مثال: شنبه تبدیل به سهشنبه میشود
فرض کنید سه رویداد آموزشی برای یک قطعه دریافت میکنیم: «برای شنبه»، «برای سهشنبه» و در پایان «برای سهشنبه میخواهم». نمایش زنده باید بتواند حدس اول را اصلاح کند؛ چسباندن سه پیام، متن «برای شنبه برای سهشنبه برای سهشنبه میخواهم» میسازد که اصلاً گفته گوینده نیست.
این رویدادها ساختگیاند. در مستند Google Cloud، isFinal برای یک بخش نتیجه و stability برای برآورد احتمال ثابتماندن حدس موقت تعریف شده است. ثبات متن با درستبودن آن یکی نیست؛ نهاییشدن هم تضمین درستی روز یا عدد نیست. ممکن است چند بخش نهایی در یک جریان داشته باشید؛ یک بخش نهایی الزاماً پایان کل جلسه نیست.
یک قرارداد آموزشی برای کلاینت
دریافت نمونه مدیریت نسخه قطعه. این کد API واقعی را صدا نمیزند. برای آموزش، چهار فیلد segment_id، revision، text و is_final تعریف کردهایم؛ این نامها را قرارداد آماده همه سرویسها یا اپرا فرض نکنید.
{"segment_id":"s1", "revision":2,
"text":"برای سهشنبه", "is_final":false}
تا پیش از نهاییشدن، revision بالاتر همان شناسه جای نسخه موقت قبلی را میگیرد. رویداد معتبر با revision پایینتر از رکورد فعلی، حتی اگر بعد از نهاییشدن برسد، نادیده گرفته میشود. تکرار دقیق همان رویداد با revision برابر، چه موقت و چه نهایی، اثری ندارد؛ اما revision برابر با متن، وضعیت یا داده متفاوت خطاست و رکورد را تغییر نمیدهد. پس از نهاییشدن، هر revision بالاتر نیز خطاست، حتی اگر متنش یکسان باشد. این سیاست قرارداد آموزشی همین نمونه است، نه تضمین رفتار یک API واقعی.
ترتیب همین کنترلها در کد مهم است؛ بررسی قدیمیبودن revision پیش از قفل نهایی انجام میشود:
old = self.parts.get(key)
if old:
if revision < old["revision"]:
return # Stale valid event: ignore even after finalization.
if revision == old["revision"]:
if event != old:
raise ValueError("Same-revision event conflict")
return # Exact duplicate: idempotent before or after final.
if old["is_final"]:
raise ValueError("Higher revision after final")
self.parts[key] = dict(event)
نمونه برای جریان تککاناله با ترتیب معرفی قطعههاست؛ مرتبسازی چند کانال، اتصال دوباره و قرارداد تأیید سرور در آن پیاده نشده است. مدیریت چند بازپخش در یک فرایند، بازیابی وضعیت پس از قطع اتصال را تضمین نمیکند.
قبل از اتصال واقعی چه چیزهایی روشن شود؟
- شناسه قطعه یا روش تعیین جایگزینی را از قرارداد سرویس بخوانید؛ اگر revision وجود ندارد، آن را در پاسخ واقعی اختراع نکنید.
- دامنه نهاییشدن را مشخص کنید: کلمه، قطعه یا کل جلسه؟
- رفتار تکرار، قطع اتصال و بازگشت پیام را آزمایش کنید؛ نمایش دوباره متن را با گفتار تکراری اشتباه نگیرید.
- در رابط، موقتبودن را فقط با رنگ منتقل نکنید؛ عنوان یا وضعیت قابل خواندن هم داشته باشد.
- ثبت سفارش یا اقدام حساس را به متن موقت وابسته نکنید؛ حتی متن نهایی به قواعد تأیید نیاز دارد.
آزمون نمونه چه چیزی را نشان داد؟
آزمون محلی، تکرار دقیق نسخه موقت و نهایی، بازپخش نسخه قدیمی پیش و پس از نهاییشدن، تعارض همان revision قبل و بعد از نهاییشدن و revision بالاتر پس از نهاییشدن را بررسی کرد. در رویدادهای ردشده، رکورد قبلی ثابت ماند و در پایان فقط یک قطعه نهایی وجود داشت. دادهها ساختگیاند؛ هیچ میکروفن، تشخیص گفتار واقعی یا سامانه اپرا اجرا نشده است. در اتصال واقعی، خطاهای شبکه و ترتیب پیام هم باید با همان پروتکل سنجیده شوند.
برای جای این مرحله در مکالمه، معماری هوش مصنوعی صوتی را ببینید؛ برای اینکه زمان نهاییشدن را با زمان شروع پاسخ یکی نگیرید، بودجه تأخیر مفید است. اگر نیازتان پیادهسازی زنده است، آن را هنگام درخواست از اپرانگار مشخص کنید؛ این نوشته وجود API استریم اپرانگار را تأیید نمیکند.
منبع تعریف نتیجه: StreamingRecognitionResult در مستند Google Cloud. قرارداد نسخه و نمونه فارسی، ساخته مستقل این مقالهاند.