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 هرم الأنواع الموضح في قسم إعادة المحاولة. |
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 عام يحتفظ بالرسالة فقط. |
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. |
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) أفضل خط زمني معروف إذا انتهت مهلة الانتظار النهائي، لكنه لا ينهي مكررًا منتظرًا في مسار المهلة. |
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 عامًا يحتفظ بالرسالة فقط. |
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 في كل الحالات.
| الاستثناء | الحقول المنشورة |
|---|---|
BatchTranscribeError | statusCode وpayload وcode وretryable وjobId وdetail وtimestamp وcapacity وrawBody |
BatchTranscribeAuthError | نوع فرعي لإخفاق المصادقة |
BatchTranscribeTimeoutError | يضيف elapsed |
BatchTranscribeJobFailedError | يضيف error وerrorCode |
BatchTranscribeRateLimitError | يضيف retryAfter |
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 مهمل ومتجاهل. لا تطبق هذه الحلقة بلا تمييز على إنشاء المهمة: بعد
مهلة، قد لا يعرف العميل هل أنشأ الرفع عملًا أم لا.
مرجع الاستجابات والمساعدين في الإصدار
| النوع أو المساعد | الحقول أو السلوك المنشور |
|---|---|
JobResponse | jobId وstatus |
TranscriptionResponse | status؛ والحقول الاختيارية results وAPIVersion وversion وmetadata وdiarization_segments وerror وerrorCode. تحتوي النتائج transcript والإزاحات، وتحتوي البيانات الوصفية sautechVersion وjobId وfileDuration. |
| مساعدو Batch | isComplete وisFailed وisPending وgetJobId وgetFileDuration؛ ويصدر BatchDiarization وBatchRedact وثوابت الحالة والنموذج. |
FileUploadedResponse / FtTranscribeResponse | الرفع: id وmessage اختياري. نتيجة Fast: id وseq وtranscription وwords وis_final. |
RtTranscribeResponse | حقول Fast مع is_speech_final. |
DiarizationUpdate | id و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_RESULT | error, audio_file, audio_file_upload_success, transcription_result |
EVENT_RT_AUDIO_STREAM, EVENT_RT_END_AUDIO_STREAM | audio_stream, end_audio_stream |
EVENT_DIARIZATION_STREAM, EVENT_DIARIZATION_RESULT | diarization_stream, diarization_result |
EVENT_TTS_REQUEST, EVENT_TTS_AUDIO, EVENT_TTS_ERROR | tts, tts_audio, error |
EVENT_TTS_VOICE_LIST_REQUEST, EVENT_TTS_VOICE_LIST_RESULT | tts_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_* المصدّرة |
| ASR | ASR_TRANSCRIPTION_FAILED, ASR_MODEL_NOT_FOUND, ASR_MODEL_UNAVAILABLE, ASR_STREAM_EXPIRED, ASR_UNSUPPORTED_CODEC, ASR_STREAM_NOT_FOUND |
| TTS | TTS_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 | العقد |
|---|---|
Subtitles | SubtitleCue وSubtitleOptions وSubtitleRenderOptions وSubtitleError؛ مُنشئ من cues؛ cues؛ fromWords وfromCues وfromResponse؛ toSrt وtoVtt |
RealtimeSubtitles | words و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. استخدم الوضع الصارم عندما يجب أن يفشل التوقيت غير الصالح أو غير المرتب بدل تسويته أو تخطيه.