حزم SDK

JavaScript وTypeScript

استخدم @humain-voice/sdk 0.18.0 من بيئة Node.js أو Bun على الخادم.

يستهدف هذا الدليل وسم الإصدار الدقيق javascript/v0.18.0. تُصرّف برامجه الستة مقابل ذلك الوسم وتُعرض من ملفات المصدر المختبرة نفسها.

التثبيت والإعداد

ثبّت الإصدار الموثق:

npm install @humain-voice/sdk@0.18.0

تستهدف الحزمة ES2021 وتستخدم fetch وFormData وBlob. لا تعلن حدًا أدنى لإصدار Node.js أو Bun. تُفحص أمثلة الوثائق باستخدام Node.js 24 وBun 1.3.14؛ وهما بيئتا تحقق وليستا وعد دعم من SDK.

اضبط القيم الصادرة لبيئتك:

export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"

يتطلب عملاء Socket.IO الحقلين api_url وapi_key فقط؛ ويستخدم الإصدار 0.18.0 المسار /socket.io افتراضيًا. مرّر api_path فقط عند استخدام نشر بمسار مخصص، أو مع نقطة النهاية القديمة sautech.humain.com التي تتطلب /realtime/socket.io. احتفظ بـAPI_KEY في إعدادات الخادم.

ينتج المثال الناجح نتيجة تطبيق، لا مجرد اتصال: يكتب Batch صيغة WebVTT، ويكتب Fast صيغة SRT، ويكتب Realtime صيغة WebVTT النهائية، ويعيد التمييز المباشر خطًا زمنيًا موفقًا، ويكتب TTS ملف WAV قابلًا للتشغيل.

اختر العميل

المهمةالعميلاختره عندما
نسخ تسجيل مكتملBatchTranscribeClientيكون الملف الكامل موجودًا، خاصة اجتماعًا أو بودكاست أو مكالمة أو مادة أرشيفية أطول
نسخ وحدة صوت مكتملة وقصيرة بزمن وصول أقلFastTranscriptionClientتكون الحمولة المكتملة متاحة بالفعل، مثل دور واحد في محادثة وكيل
نسخ الصوت أثناء وصولهRealtimeClientما زال ميكروفون أو مكالمة أو مصدر مباشر ينتج الصوت
بناء خط زمني مباشر للمتحدثينRealtimeDiarizationClientتحتاج إلى مقاطع متحدثين متغيرة ونهائية
توليد الكلامTTSClientتحتاج إلى خرج PCM متدفق من نص

النسخ السريع ليس مسار المحتوى الطويل. استخدم Batch للاجتماعات والبودكاست والمواد الأرشيفية؛ واستخدم Fast لوحدات صوت قصيرة ومكتملة وحساسة لزمن الوصول.

انسخ تسجيلًا مكتملًا

يفعّل برنامج Batch المختبر تمييز المتحدثين، ويستعلم مع حد لحلقة الاستعلام قدره 300 ثانية، ويطبع النص، ويكتب WebVTT نهائية. قد يمدد الإرسال أو طلب قيد التنفيذ المدة الفعلية.

العقدسلوك الإصدار 0.18.0
المُنشئnew BatchTranscribeClient({ api_url, api_key, api_version="v1", maxRetries? })
الصوت المقبولArrayBuffer أو Uint8Array أو Blob أو File
العملياتsubmit() وgetResult() وtranscribe() وclose()
الخياراتخيارات submit: ‎diarization وasr وitn وredact؛ وgetResult: ‎saveResult؛ وtranscribe: تلك الخيارات مع pollInterval (2 s) وtimeout (300 s) وonProgress وsaveResult
النتيجة والنهائيةيعيد submit() النوع JobResponse؛ ينجح المساعد عند done، ويرفع خطأ عند failed، وتنتهي مهلته إذا بقيت المهمة queued أو processing أو cleared
التنظيف والأخطاءclose() عام ولا ينفذ عملًا حاليًا. maxRetries مهمل ومتجاهل؛ تستخدم إخفاقات Batch هرم الأنواع الموضح في قسم إعادة المحاولة.
batch-transcription.ts
import { readFile, writeFile } from 'node:fs/promises';

import {
  BatchDiarization,
  BatchTranscribeClient,
  BatchTranscriptionModel,
  Language,
  Subtitles,
} from '@humain-voice/sdk';

function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

async function main(): Promise<void> {
  const inputPath = process.argv[2] ?? 'meeting.wav';
  const outputPath = process.argv[3] ?? 'meeting.vtt';
  const client = new BatchTranscribeClient({
    api_url: requiredEnv('API_URL'),
    api_key: requiredEnv('API_KEY'),
    api_version: process.env.API_VERSION ?? 'v1',
  });

  try {
    const result = await client.transcribe(
      await readFile(inputPath),
      Language.ArEn,
      {
        asr: BatchTranscriptionModel.BayanArEn,
        diarization: BatchDiarization.On,
        saveResult: true,
        pollInterval: 2,
        timeout: 300,
        onProgress: ({ status }) => console.info('status:', status),
      },
    );

    console.info(result.results?.transcript ?? '');
    await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
  } finally {
    await client.close();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

استخدم submit(audio, language, options) و getResult(jobId, language, options) عندما يملك عامل أو طابور الاستعلام. يجب أن يتوقف المستعلم المخصص صراحة عند done وfailed وcleared. قد تمسح القيمة الافتراضية saveResult=false نتيجة done أو failed بعد بناء الاستجابة. اضبط saveResult: true قبل الاستعلام عندما يجب أن يتحمل تسليم النتيجة النهائية فقد استجابة؛ ولا يحدد API مدة احتفاظ.

يقرأ Subtitles.fromResponse(result) القيم من result.results.offsets؛ استخدم toSrt() أو toVtt(). تعرض استجابات Batch أيضًا diarization_segments عندما يعيدها مسار النتيجة القديم.

انسخ وحدة صوت مكتملة وقصيرة

يرسل النسخ السريع حمولة الصوت المكتملة مرة واحدة عبر Socket.IO. وهو محسّن لوحدات قصيرة وحساسة لزمن الوصول مثل دور في محادثة وكيل؛ وليس عميل الاجتماعات الطويلة أو البودكاست.

العقدسلوك الإصدار 0.18.0
المُنشئnew FastTranscriptionClient({ api_url, api_key, api_path?, onConnect?, onFileUpload?, onError? })
الصوت المقبولArrayBuffer أو Uint8Array أو Blob تحتوي حمولة الصوت المكتملة
العملياتconnect() وtranscribe() وclose()
الاستدعاءtranscribe(audio, language, model, { onResponse?, onFileUpload?, onError?, diarizationModel?, itnModel?, redactModel? })
النتيجة والنهائيةيستقبل onFileUpload إقرار الرفع؛ ويمكن أن يستقبل onResponse نتائج جزئية قبل FtTranscribeResponse النهائية. يعيد الوعد الاستجابة النهائية أو undefined.
المهلة والتنظيف والأخطاءلا يوجد خيار مهلة في SDK. طبّق مهلة تطبيق وأغلق صراحة. يستدعي خطأ الطلب الموجه onError ثم يرفض بـError عام يحتفظ بالرسالة فقط.
fast-transcription.ts
import { readFile, writeFile } from 'node:fs/promises';

import {
  FastTranscriptionClient,
  FastTranscriptionModel,
  Language,
  Subtitles,
} from '@humain-voice/sdk';

function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

async function withDeadline<T>(operation: Promise<T>, milliseconds: number): Promise<T> {
  let timer: ReturnType<typeof setTimeout> | undefined;
  try {
    return await Promise.race([
      operation,
      new Promise<never>((_, reject) => {
        timer = setTimeout(() => reject(new Error('Fast transcription deadline exceeded')), milliseconds);
      }),
    ]);
  } finally {
    if (timer) clearTimeout(timer);
  }
}

async function main(): Promise<void> {
  const inputPath = process.argv[2] ?? 'short-call.wav';
  const outputPath = process.argv[3] ?? 'short-call.srt';
  const client = new FastTranscriptionClient({
    api_url: requiredEnv('API_URL'),
    api_path: requiredEnv('API_PATH'),
    api_key: requiredEnv('API_KEY'),
  });

  try {
    await client.connect();
    const result = await withDeadline(
      client.transcribe(
        await readFile(inputPath),
        Language.Ar,
        FastTranscriptionModel.BayanAr,
        {
          onFileUpload: (response) => console.info('uploaded:', response?.id),
          onResponse: (response) => {
            console.info(response.is_final ? 'final:' : 'partial:', response.transcription);
          },
          onError: (error) => console.error('server error:', error.code, error.message),
        },
      ),
      60_000,
    );

    if (!result) throw new Error('Fast transcription ended without a final result');
    await writeFile(outputPath, Subtitles.fromResponse(result).toSrt(), 'utf8');
  } finally {
    await client.close();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

يرفض المثال غياب النتيجة النهائية ولا يكتب SRT إلا بعد النهائية. لا تعد الإرسال بلا تمييز بعد مهلة ملتبسة: لا ينشر API عقد idempotency-key. يعرض SDK 0.18.0 القيم diarizationModel وitnModel وredactModel للتوافق مع البروتوكول، لكن خدمة Fast العامة المتحقق منها لا تطبقها. احذفها، واستخدم Batch عندما تحتاج إلى خيارات المعالجة هذه.

انسخ الصوت أثناء وصوله

دخل Realtime هو PCM16 little-endian بتردد 16 kHz وأحادي القناة. يرسل البرنامج المختبر مقاطع حجمها 3,200 بايت، أي 100 ms من الصوت، ويكتب WebVTT نهائية.

العقدسلوك الإصدار 0.18.0
المُنشئnew RealtimeClient({ api_url, api_key, api_path? })؛ ويعرض العميل أيضًا خصائص الاستدعاء
العملياتconnect() وstartStream() وdisconnect()
البدءstartStream(language, { onConnect?, onDisconnect?, onResponse?, onError?, subtitles? })
التدفقsend(audio, isLast=false) وclose(timeoutSeconds=1) وstop()
النتيجة والنهائيةيحمل RtTranscribeResponse الحقول seq وis_final وis_speech_final؛ يحدد is_speech_final نهاية مقطع كلام، ولا ينهي التدفق إلا is_final على مستوى البروتوكول
التنظيف والأخطاءيرسل close() النهاية وينتظر؛ ويزيل stop() التدفق بلا انتظار. قد يزيل خطأ موجه سياق التدفق، لذلك استدعِ دائمًا disconnect() على مستوى العميل داخل finally.
realtime-transcription.ts
import { readFile, writeFile } from 'node:fs/promises';

import {
  type ErrorResponse,
  Language,
  RealtimeClient,
  Subtitles,
  type WordSegment,
} from '@humain-voice/sdk';

const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.

function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

async function pause(milliseconds: number): Promise<void> {
  await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
}

async function main(): Promise<void> {
  const inputPath = process.argv[2] ?? 'speech.pcm';
  const outputPath = process.argv[3] ?? 'speech.vtt';
  const client = new RealtimeClient({
    api_url: requiredEnv('API_URL'),
    api_path: requiredEnv('API_PATH'),
    api_key: requiredEnv('API_KEY'),
  });
  const finalizedWords: WordSegment[] = [];
  let serverError: ErrorResponse | undefined;
  let protocolFinalObserved = false;

  try {
    const stream = await client.startStream(Language.ArEn, {
      onResponse: (response) => {
        const kind = response.is_final
          ? 'final'
          : response.is_speech_final
            ? 'speech-final'
            : 'partial';
        console.info(`${kind}:`, response.transcription);
        if (response.is_final) protocolFinalObserved = true;
        if (response.is_final || response.is_speech_final) {
          // The current public Realtime contract does not guarantee increasing
          // seq values, so collect final words in arrival order instead of
          // asking RealtimeSubtitles to deduplicate by id:seq.
          finalizedWords.push(...response.words);
        }
      },
      // The released SDK can invoke a stream handler more than once for one
      // routed error, so keep this callback idempotent.
      onError: (error) => {
        serverError = error;
      },
    });

    const pcm = await readFile(inputPath);
    for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
      await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
      await pause(100);
    }

    // close() sends the last frame and waits for protocol is_final, a routed
    // error, or this timeout. It resolves rather than throwing on timeout.
    await stream.close(5);
    if (serverError) {
      throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
    }
    if (!protocolFinalObserved) {
      throw new Error('Realtime stream ended before protocol is_final');
    }
    await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
  } finally {
    await client.disconnect();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

استبدل النص المؤقت بترتيب الوصول المرصود حتى تصل إحدى رايتي النهاية. يجمع المثال كلمات الأحداث النهائية بنفسه ويعرضها باستخدام Subtitles؛ ولا يعتمد على seq لأن ترتيبها وتفرّدها ليسا جزءًا من عقد السلك العام الحالي. يزيل RealtimeSubtitles التكرار حسب id:seq وقد يدمج أحداثًا نهائية متميزة بموجب ذلك العقد. ينتظر stream.close(timeoutSeconds) قيمة is_final على مستوى البروتوكول أو خطأ موجهًا أو مهلته. ويعود بدل رفع خطأ عند انتهاء المهلة؛ ولا تنهي is_speech_final ذلك الانتظار.

ابنِ خطًا زمنيًا مباشرًا للمتحدثين

يجمع SDK زيادات المقاطع النهائية ويستبدل الذيل النشط ليعرض خطًا زمنيًا واحدًا موفقًا في update.segments.

العقدسلوك الإصدار 0.18.0
المُنشئnew RealtimeDiarizationClient({ api_url, api_key, api_path? })
العملياتconnect() وstartStream() وdisconnect()
خيارات البدءتكون language افتراضيًا Language.Ar؛ واستدعاءات الاتصال والتحديث والخطأ اختيارية
التدفقيعرض streamId وspeakers وsend() وclose(5) ومكررًا غير متزامن واحدًا
النتيجة والنهائيةيحتوي DiarizationUpdate على segments الموفقة وnewlyFinalized وactiveSegments وisFinal وraw
التنظيف والأخطاءاستهلك التحديثات أثناء إرسال الصوت ثم افصل. أخطاء المكرر هي DiarizationStreamError؛ ويعيد close(5) أفضل خط زمني معروف إذا انتهت مهلة الانتظار النهائي، لكنه لا ينهي مكررًا منتظرًا في مسار المهلة.
realtime-diarization.ts
import { readFile, writeFile } from 'node:fs/promises';

import {
  DIARIZATION_RECOMMENDED_CHUNK_BYTES,
  RealtimeDiarizationClient,
  type SpeakerSegment,
  toRttm,
} from '@humain-voice/sdk';

function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

async function pause(milliseconds: number): Promise<void> {
  await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
}

async function main(): Promise<void> {
  const inputPath = process.argv[2] ?? 'meeting.pcm';
  const outputPath = process.argv[3] ?? 'meeting.rttm';
  const client = new RealtimeDiarizationClient({
    api_url: requiredEnv('API_URL'),
    api_path: requiredEnv('API_PATH'),
    api_key: requiredEnv('API_KEY'),
  });

  try {
    let finalObserved = false;
    const stream = await client.startStream({
      onError: (error) => console.error('server error:', error.code, error.message),
      onUpdate: (update) => {
        finalObserved ||= update.isFinal;
        for (const segment of update.newlyFinalized) {
          console.info(segment.speaker, segment.start_time, segment.end_time);
        }
      },
    });
    const pcm = await readFile(inputPath);

    if (pcm.length === 0 || pcm.length % 2 !== 0) {
      throw new Error('Input must be nonempty PCM16 with an even byte length');
    }
    for (
      let offset = 0;
      offset < pcm.length;
      offset += DIARIZATION_RECOMMENDED_CHUNK_BYTES
    ) {
      await stream.send(
        pcm.subarray(offset, offset + DIARIZATION_RECOMMENDED_CHUNK_BYTES),
      );
      await pause(480);
    }

    // close() returns the best-known reconciled timeline after five seconds,
    // even when no isFinal update arrived. A callback avoids leaving an async
    // iterator waiting forever on that timeout path.
    const timeline: SpeakerSegment[] = await stream.close(5);
    const destination = finalObserved ? outputPath : `${outputPath}.partial`;
    await writeFile(destination, toRttm(timeline, 'meeting'), 'utf8');
    if (!finalObserved) {
      console.warn(`Final result not observed; wrote incomplete output to ${destination}`);
    }
  } finally {
    await client.disconnect();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

قيمة DIARIZATION_RECOMMENDED_CHUNK_BYTES هي 15,360 بايت، أي 480 ms بصيغة الصوت المطلوبة. قد يعلق المسار إذا لم تبدأ الاستهلاك إلا بعد انتهاء التغذية. يستخدم المثال onUpdate كي لا تترك المهلة مكررًا منتظرًا، ويكتب ملف RTTM بلاحقة .partial ما لم يرصد isFinal.

ولّد الكلام واكتب WAV

تعيد listVoices() هويات متعددة اللغات بالشكل { id, label, profile }. يحمل profile بيانات speaker مشتركة وقائمة languages مفتوحة؛ مرر id الخاص بالهوية نفسها في voice_id. تعامل مع قائمة فارغة قبل التوليف. يعيد TTS عبر Socket.IO بايتات PCM16 little-endian خام بتردد 24 kHz وأحادية القناة، لا حاوية WAV.

في هويات العربية/الإنجليزية الحالية، يختار أي حرف من محارف الكتابة العربية في text النسخة العربية؛ وإلا تُختار الإنجليزية. تبقى معرّفات النسخ الفعلية داخلية وتُرفض.

العقدسلوك الإصدار 0.18.0
المُنشئnew TTSClient({ api_url, api_key, api_path?, verbose?, onConnect?, onError? })؛ يُقبل verbose لكن لا سلوك له
العملياتconnect() وlistVoices() وsynthesize() وsynthesizeStream() وclose()
المدخلاتنص يحتوي بعد إزالة الفراغات على حرف Unicode أو رقم واحد على الأقل، وواحد بالضبط من voice_id أو voice_references غير الفارغة؛ أرسل للمسار العام مرجعًا واحدًا { text, audio } يكون audio فيه RIFF/WAVE بترميز base64 القياسي وبيانات PCM16 أحادية غير فارغة
القيم الافتراضيةمهلة قائمة الأصوات 5 s؛ وmodel=TtsModel.Nebula؛ وtimeoutSeconds=30 ثانية من الخمول
الخيارات الأخرىonAudio في الاستدعاء المخزن فقط، وonError، وrequest_id
النتيجة والتنظيف والأخطاءالنوع TtsAudioResponse هو { id, is_last, audio: Uint8Array }. أغلق صراحة. يتلقى onError بيانات منظمة ومطبعة، بينما يكون رفض التوليف Error عامًا يحتفظ بالرسالة فقط.
tts-to-wav.ts
import { writeFile } from 'node:fs/promises';

import {
  TTSClient,
  TtsModel,
  getSampleRate,
} from '@humain-voice/sdk';

function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

function pcm16ToWav(pcm: Uint8Array, sampleRate: number): Buffer {
  const header = Buffer.alloc(44);
  header.write('RIFF', 0);
  header.writeUInt32LE(36 + pcm.byteLength, 4);
  header.write('WAVE', 8);
  header.write('fmt ', 12);
  header.writeUInt32LE(16, 16);
  header.writeUInt16LE(1, 20); // Linear PCM.
  header.writeUInt16LE(1, 22); // Mono.
  header.writeUInt32LE(sampleRate, 24);
  header.writeUInt32LE(sampleRate * 2, 28);
  header.writeUInt16LE(2, 32);
  header.writeUInt16LE(16, 34);
  header.write('data', 36);
  header.writeUInt32LE(pcm.byteLength, 40);

  return Buffer.concat([
    header,
    Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength),
  ]);
}

async function main(): Promise<void> {
  const outputPath = process.argv[2] ?? 'speech.wav';
  const client = new TTSClient({
    api_url: requiredEnv('API_URL'),
    api_path: requiredEnv('API_PATH'),
    api_key: requiredEnv('API_KEY'),
  });

  try {
    const voices = await client.listVoices({ timeoutSeconds: 5 });
    const voice = voices.find((candidate) => candidate.profile) ?? voices[0];
    if (!voice) throw new Error('No TTS voices are available');
    if (voice.profile) {
      console.log(
        'profile:',
        voice.label,
        voice.profile.speaker.dialect,
        voice.profile.languages,
      );
    }

    const model = TtsModel.Nebula;
    const pcm = await client.synthesize('Hello from HUMAIN Voice', {
      voice_id: voice.id,
      model,
      // This is an inactivity timeout applied while awaiting each audio chunk.
      timeoutSeconds: 30,
      onError: (error) => console.error('server error:', error.code, error.message),
    });

    await writeFile(outputPath, pcm16ToWav(pcm, getSampleRate(model)));
  } finally {
    await client.close();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

استخدم synthesizeStream() لمعالجة response.audio عند وصوله. يحتفظ الخطأ المنظم بـcode وretryable؛ وتُطبع الحمولة القديمة غير الكائنية إلى { message }. يحافظ المثال على نطاق بايتات Uint8Array ويضيف ترويسة WAV الصحيحة.

ويفرض الخادم بصورة مستقلة مهلة كلية غير قابلة لإعادة الضبط قدرها 25 ثانية ومراقب خمول قدره 60 ثانية. إذا سبقت المهلة الكلية الإطار النهائي، يكون TTS_DEADLINE_EXCEEDED قابلاً لإعادة المحاولة ويظل الصوت المستلم جزئيًا.

مساعدو TTS العامون هم TtsModel.Nebula وDEFAULT_SAMPLE_RATE و MODEL_SAMPLE_RATES وgetSampleRate() وdecodeTtsAudioFrame().

أعد محاولة قراءة Batch محفوظة

ينفذ SDK 0.18.0 استدعاء HTTP واحدًا لكل عملية Batch. يعيد هذا المثال قراءة نتيجة بتراجع أسي محدود ويمرر saveResult: true قبل جلب الحالة النهائية. من دون هذا الخيار، قد تتبع الاستجابة النهائية المفقودة حالة cleared، لذلك ليست القراءة الافتراضية idempotent في كل الحالات.

الاستثناءالحقول المنشورة
BatchTranscribeErrorstatusCode وpayload وcode وretryable وjobId وdetail وtimestamp وcapacity وrawBody
BatchTranscribeAuthErrorنوع فرعي لإخفاق المصادقة
BatchTranscribeTimeoutErrorيضيف elapsed
BatchTranscribeJobFailedErrorيضيف error وerrorCode
BatchTranscribeRateLimitErrorيضيف retryAfter
batch-error-retry.ts
import {
  BatchTranscribeClient,
  BatchTranscribeError,
  BatchTranscribeRateLimitError,
  Language,
  type TranscriptionResponse,
} from '@humain-voice/sdk';

function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

async function pause(milliseconds: number): Promise<void> {
  await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
}

async function getResultWithRetry(
  client: BatchTranscribeClient,
  jobId: string,
  attempts = 5,
): Promise<TranscriptionResponse> {
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      // saveResult prevents a terminal read from clearing the stored result
      // before a retry. It does not establish a retention duration.
      return await client.getResult(jobId, Language.ArEn, { saveResult: true });
    } catch (error: unknown) {
      if (!(error instanceof BatchTranscribeError)) throw error;

      const rateLimited = error instanceof BatchTranscribeRateLimitError;
      const retryable = rateLimited || error.retryable === true;
      console.error({
        statusCode: error.statusCode,
        code: error.code,
        capacity: error.capacity,
      });
      if (!retryable || attempt === attempts) throw error;

      const serverDelayMs = rateLimited && error.retryAfter !== undefined
        ? error.retryAfter * 1_000
        : 0;
      const exponentialDelayMs = 500 * 2 ** (attempt - 1);
      await pause(Math.max(serverDelayMs, exponentialDelayMs) + Math.random() * 250);
    }
  }

  throw new Error('Retry loop exhausted');
}

async function main(): Promise<void> {
  const jobId = process.argv[2];
  if (!jobId) throw new Error('Pass a batch job ID as the first argument');

  const client = new BatchTranscribeClient({
    api_url: requiredEnv('API_URL'),
    api_key: requiredEnv('API_KEY'),
  });
  try {
    const result = await getResultWithRetry(client, jobId);
    console.info(result.status, result.results?.transcript ?? '');
  } finally {
    await client.close();
  }
}

void main().catch((error: unknown) => {
  console.error(error);
  process.exitCode = 1;
});

maxRetries مهمل ومتجاهل. لا تطبق هذه الحلقة بلا تمييز على إنشاء المهمة: بعد مهلة، قد لا يعرف العميل هل أنشأ الرفع عملًا أم لا.

مرجع الاستجابات والمساعدين في الإصدار

النوع أو المساعدالحقول أو السلوك المنشور
JobResponsejobId وstatus
TranscriptionResponsestatus؛ والحقول الاختيارية results وAPIVersion وversion وmetadata وdiarization_segments وerror وerrorCode. تحتوي النتائج transcript والإزاحات، وتحتوي البيانات الوصفية sautechVersion وjobId وfileDuration.
مساعدو BatchisComplete وisFailed وisPending وgetJobId وgetFileDuration؛ ويصدر BatchDiarization وBatchRedact وثوابت الحالة والنموذج.
FileUploadedResponse / FtTranscribeResponseالرفع: id وmessage اختياري. نتيجة Fast: ‎id وseq وtranscription وwords وis_final.
RtTranscribeResponseحقول Fast مع is_speech_final.
DiarizationUpdateid وsegments الموفقة وnewlyFinalized وactiveSegments وisFinal وraw.
SpeakerContext / VoiceProfile / VoiceInfo{ gender, dialect }؛ و{ speaker, languages }؛ و{ id, label, profile? }. توفر الواجهة الحالية profile دائمًا.
VoiceReference / TtsAudioResponse{ text, audio }؛ و{ id, is_last, audio: Uint8Array }.
ErrorResponseالحقول الاختيارية id وmessage وcode وretryable وtimestamp وretry_after_seconds وdata وreason وretry_scope؛ ويسوي parseErrorResponse() الحمولات القديمة غير الكائنية.

قد يصل خطأ Socket غير القابل للتوجيه إلى الاستدعاء العام فقط. احتفظ بمهلة للتطبيق ونظّف دائمًا. تستدعي أخطاء طلب Fast ‏onError ثم ترفض بـError عام؛ ويشير Realtime إلى استدعائه وانتظاره النهائي؛ وترفع مكررات التمييز DiarizationStreamError؛ وتحتفظ استدعاءات TTS بالبيانات المنظمة بينما تحتفظ وعود التوليف المرفوضة بالرسالة فقط.

صادرات الأحداث والأخطاء منخفضة المستوى

تصدر الحزمة العليا generateUuid() ومشفرات إطار Fast وRealtime وثوابت الأعلام.

ثوابت الأحداثقيم السلك
EVENT_FT_ERROR, EVENT_FT_TRANSCRIBE_FILE, EVENT_FT_TRANSCRIBE_FILE_UPLOAD_SUCCESS, EVENT_FT_TRANSCRIBE_RESULTerror, audio_file, audio_file_upload_success, transcription_result
EVENT_RT_AUDIO_STREAM, EVENT_RT_END_AUDIO_STREAMaudio_stream, end_audio_stream
EVENT_DIARIZATION_STREAM, EVENT_DIARIZATION_RESULTdiarization_stream, diarization_result
EVENT_TTS_REQUEST, EVENT_TTS_AUDIO, EVENT_TTS_ERRORtts, tts_audio, error
EVENT_TTS_VOICE_LIST_REQUEST, EVENT_TTS_VOICE_LIST_RESULTtts_voice_list, tts_voice_list_result
مجموعة رموز الخطأالثوابت
المصادقةAUTH_UNAUTHORIZED, AUTH_KEY_INVALID, AUTH_FORBIDDEN
التحققVALIDATION_INVALID_LANGUAGE, VALIDATION_INVALID_FORMAT, VALIDATION_REQUIRED_FIELD, VALIDATION_FILE_CORRUPT, VALIDATION_INVALID_PARAM, VALIDATION_INVALID_UUID
الحدود والفوترةRATE_LIMIT_EXCEEDED, RATE_LIMIT_SERVICE_BUSY, CONCURRENCY_LIMIT_EXCEEDED, CREDITS_EXHAUSTED, BILLING_AUTHORIZATION_UNAVAILABLE, PAYLOAD_TOO_LARGE, AUDIO_DURATION_EXCEEDED, FILE_COUNT_EXCEEDED, CHARACTER_COUNT_EXCEEDED, VOICE_REFERENCE_COUNT_EXCEEDED ورموز SESSION_* المصدّرة
ASRASR_TRANSCRIPTION_FAILED, ASR_MODEL_NOT_FOUND, ASR_MODEL_UNAVAILABLE, ASR_STREAM_EXPIRED, ASR_UNSUPPORTED_CODEC, ASR_STREAM_NOT_FOUND
TTSTTS_SYNTHESIS_FAILED, TTS_DEADLINE_EXCEEDED, TTS_MODEL_NOT_FOUND, TTS_VOICE_NOT_FOUND, TTS_VOICE_RESOLUTION_FAILED, TTS_VOICE_LIST_FAILED, TTS_INPUT_NOT_ALLOWED, TTS_MODERATION_UNAVAILABLE, TTS_MODEL_UNAVAILABLE, TTS_INVALID_INPUT
المتحدث والتمييزSPEAKER_ID_FAILED, DIARIZATION_FAILED, DIARIZATION_MODEL_NOT_FOUND
الخادم وBatch والتوافقSERVER_INTERNAL, SERVER_DEPENDENCY_FAILURE, METHOD_NOT_ALLOWED, TRANSCRIPTION_JOB_NOT_FOUND, RATE_LIMITED, VALIDATION_FAILED, INTERNAL_ERROR

يوجّه الإصدار 0.18.0 أخطاء حدود العمل والفوترة وسياسة محتوى TTS إلى سياق الطلب النشط، فيُرفض الاستدعاء المعلّق بدل انتظار مهلته. اقرأ data لمعرفة الحد، واحترم retry_after_seconds عند ضغط قابل لإعادة المحاولة، وافتح تدفقًا جديدًا عندما يحمل ASR_STREAM_EXPIRED القيمة retry_scope: "new_stream".

استخدم isAsrCode() وisTtsCode() وisRequestScopedCode() و isRealtimeOwned() وisTtsOwned() وisDiarizationCode() و isDiarizationOwned() لتوجيه أخطاء Socket المنظمة. لا تغني هذه المصنفات عن مهلة سير العمل أو التنظيف عند وصول خطأ غير قابل للتوجيه.

مرجع التسميات التوضيحية

APIالعقد
SubtitlesSubtitleCue وSubtitleOptions وSubtitleRenderOptions وSubtitleError؛ مُنشئ من cues؛ ‎cues؛ ‎fromWords وfromCues وfromResponse؛ ‎toSrt وtoVtt
RealtimeSubtitleswords وcues وaddResponse وsubtitles وtoSrt وtoVtt؛ يتجاهل النتائج المؤقتة ويلغي تكرار استجابات id:seq النهائية
المساعدون العلويونwordsToCues وcuesToSrt وcuesToVtt وsubtitles وtoSrt وtoVtt
قيم التشكيل الافتراضيةmaxDurationSeconds=6 وmaxGapSeconds=0.7 وminDurationSeconds=0.5 وmaxCharsPerLine=42 وmaxLines=2 وsplitOnSpeakerChange=true وstrict=false؛ يبدأ startIndex=1 في SRT

يقبل دخل التسميات إزاحات Batch ذات camel-case وكلمات Realtime ذات snake-case. استخدم الوضع الصارم عندما يجب أن يفشل التوقيت غير الصالح أو غير المرتب بدل تسويته أو تخطيه.

الخطوات التالية

في هذه الصفحة