البدء السريع

ثبّت 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 أو أحدث.
  • 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.

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;
});

شغّل الأمر المطابق للملف الذي حفظته:

  • 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 الخام ترويسة ملف قابلة للتشغيل.

احفظ المثال المحدد باسم الملف المعروض:

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;
});

شغّل الأمر المطابق للملف الذي حفظته:

  • 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 على مستوى البروتوكول، ويفصل العميل أثناء التنظيف. ويبلغ انتهاء المهلة بوصفه عدم اكتمال بدلاً من كتابة ملف تسميات عادي.

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

تابع المسار الذي يطابق منتجك. قبل حركة الإنتاج، أعد تشغيله بمدخلات ممثلة واختبر المهل والحالات النهائية والانقطاعات وإعادة المحاولة والتنظيف مهما كان نمط التسليم.

في هذه الصفحة