البدء السريع
ثبّت SDK 0.18.0، وأكمل أول نسخ دفعي، ثم اختر التسليم السريع أو الفوري.
أقصر مسار إلى أول نتيجة هو النسخ الدفعي لملف صوت مكتمل. فهو يقبل حاوية صوت مدعومة ولا يتطلب تحضير مقاطع PCM فورية. أكمل هذا المسار أولًا، ثم اختر التسليم السريع أو الفوري إذا احتاجه منتجك.
قبل أن تبدأ
جهّز ما يلي قبل تشغيل أي أمر:
- مفتاح API ومسار Socket.IO تحصل عليهما عبر مسار الوصول في مؤسستك. تعرض الصفحة عنوان الخدمة المهيأ لبيئتها.
- ملف صوت مكتمل ومدعوم. تستخدم الأمثلة أدناه
meeting.wavوتكتب التسميات التوضيحية فيmeeting.vtt. - إحدى بيئات تشغيل SDK المدعومة:
- JavaScript / TypeScript: بيئة Node.js أو Bun على الخادم تدعم ES2021 و
fetchوFormDataوBlob. لا ينشر SDK حدًا أدنى لإصدار Node.js أو Bun. تُفحص الأمثلة باستخدام Node.js 24 وBun 1.3.14؛ وتفترض أوامرnodeالمباشرة أدناه بيئة التحقق Node.js 24 تلك. - Python 3.10 أو أحدث.
- JavaScript / TypeScript: بيئة Node.js أو Bun على الخادم تدعم ES2021 و
ffmpegفقط إذا كنت ستجرب مسار البث الفوري الاختياري.
احتفظ بمفتاح API في إعدادات الخادم. لا تضعه في شيفرة المتصفح أو الجوال.
1. ثبّت SDK 0.18.0
اختر لغة واحدة. تستخدم الصفحة تسميات تبويبي JavaScript وPython نفسها في كل بديل.
npm install @humain-voice/sdk@0.18.0النتيجة المتوقعة: يكمل مدير الحزم بنجاح ويسجل إصدار SDK الدقيق
0.18.0.
2. اضبط البيئة
شغّل أوامر التصدير هذه في الصدفة نفسها التي ستشغّل المثال. استبدل المفتاح بالقيمة المهيأة لمؤسستك.
export API_URL="https://api.voice.humain.com"
export API_PATH="/socket.io"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
test -n "$API_URL" && test -n "$API_PATH" && test -n "$API_KEY" && echo "HUMAIN Voice environment ready"النتيجة المتوقعة: يطبع الأمر الأخير HUMAIN Voice environment ready.
تنشر هذه البيئة Socket.IO على المسار /socket.io. يستخدم كل عميل Socket.IO
في الإصدار 0.18.0 المسار /socket.io افتراضيًا.
اضبط API_PATH فقط عندما يحتاج النشر إلى مسار مخصص. تتطلب نقطة النهاية
القديمة sautech.humain.com المسار /realtime/socket.io. يستخدم عميل Batch
القيم API_URL وAPI_KEY وAPI_VERSION فقط.
3. نفّذ نسخًا دفعيًا
استخدم زر نسخ كتلة الشيفرة واحفظ المثال المحدد باسم الملف المعروض. يرسل
meeting.wav، ويستعلم بمهلة خمس دقائق، ويفعّل تمييز المتحدثين، ويطبع النص
المعاد، ويكتب تسميات WebVTT.
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;
});
شغّل الأمر المطابق للملف الذي حفظته:
- JavaScript / TypeScript:
node batch-transcription.ts meeting.wav meeting.vtt - Python:
python batch_transcription.py meeting.wav meeting.vtt
النتيجة المتوقعة: في العمل الناجح، تطبع الطرفية تحديثًا واحدًا أو أكثر
يبدأ بـstatus: ثم النص المعاد، ويُنشأ meeting.vtt. قد ينتج الصوت الذي لا
يحتوي كلامًا متعرفًا عليه نصًا فارغًا.
يكتمل أول طلب HUMAIN Voice عندما تصل المهمة إلى done ويُكتب ملف التسميات.
بعد النتيجة الأولى
- يستعلم المثال كل ثانيتين مع حد لحلقة الاستعلام قدره 300 ثانية. قد يمدد الإرسال أو طلب قيد التنفيذ المدة الفعلية. اختر مهلًا تناسب حملك؛ فمهلة الطلب ليست مهلة سير العمل الإجمالية.
- يعيد SDK
0.18.0النتيجة عندdoneويرفع خطأ عندfailedأو انتهاء المهلة. لا يتوقف مساعدtranscribe()بشكل خاص عندcleared، فتصل المهمة الممسوح إلى المهلة المضبوطة. يجب أن يتوقف المستعلم المباشر صراحة عندdoneوfailedوcleared. - يغلق المثال العميل حتى عند إخفاق الإرسال أو الاستعلام. حافظ على نمط التنظيف هذا في الإنتاج.
توسّع وصفة نسخ تسجيل أنماط الاستعلام، وتسميات المتحدثين، والتسميات التوضيحية.
اختر نمط التسليم التالي
| النمط | استخدمه عندما | تسليم الصوت | تدفق النتيجة |
|---|---|---|---|
| النسخ الدفعي | لديك تسجيل مكتمل، بما في ذلك الاجتماعات أو المكالمات أو حلقات البودكاست الأطول | ارفع مرة واحدة | استعلم عن المهمة حتى done أو failed أو cleared |
| النسخ السريع | تحتاج حمولة صوت مكتملة وقصيرة إلى زمن وصول أقل، مثل دور واحد في محادثة وكيل | أرسل الحمولة المكتملة مرة واحدة عبر Socket.IO | استقبل أحداث الرفع والنسخ حتى النتيجة النهائية |
| النسخ الفوري | ما زال الصوت يصل من ميكروفون أو مكالمة أو مصدر مباشر | أرسل مقاطع PCM16 little-endian بتردد 16 kHz وأحادية القناة | استبدل النص المؤقت حتى تصل استجابة نهائية أو نهاية كلام |
النسخ السريع ليس مسار الصوت الطويل أو البودكاست. استخدم Batch لهذه التسجيلات المكتملة؛ واستخدم النسخ السريع عندما تكون الحمولة المكتملة قصيرة ويهم زمن الوصول.
اختياري: نفّذ نسخًا فوريًا
يجب أن يكون دخل Realtime مسبقًا بصيغة PCM16 little-endian خام، بتردد 16 kHz، وأحادي القناة. حوّل تسجيلًا لهذا المثال:
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ar 16000 -ac 1 speech.pcmالنتيجة المتوقعة: ينتهي ffmpeg بنجاح وينشئ speech.pcm. لا يملك PCM
الخام ترويسة ملف قابلة للتشغيل.
احفظ المثال المحدد باسم الملف المعروض:
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;
});
شغّل الأمر المطابق للملف الذي حفظته:
- JavaScript / TypeScript:
node realtime-transcription.ts speech.pcm speech.vtt - Python:
python realtime_transcription.py speech.pcm speech.vtt
النتيجة المتوقعة: تصف الطرفية الاستجابات بـpartial: أو final: أو
speech-final:، ويكتب التدفق الناجح التسميات النهائية في speech.vtt.
بعد النجاح، أبقِ نص واجهة المستخدم المؤقت منفصلًا واستبدله عند وصول أحداث
النتائج. يجمع المثال الكلمات من الأحداث النهائية أو أحداث نهاية الكلام فقط، ثم
يستخدم Subtitles لعرضها؛ ولا يعتمد على seq لأن ترتيبها ليس جزءًا من عقد
Realtime السلكي الحالي. يغلق المثال التدفق، وينتظر حتى خمس ثوانٍ لوصول
is_final على مستوى البروتوكول، ويفصل العميل أثناء التنظيف. ويبلغ انتهاء
المهلة بوصفه عدم اكتمال بدلاً من كتابة ملف تسميات عادي.
الخطوات التالية
تابع المسار الذي يطابق منتجك. قبل حركة الإنتاج، أعد تشغيله بمدخلات ممثلة واختبر المهل والحالات النهائية والانقطاعات وإعادة المحاولة والتنظيف مهما كان نمط التسليم.