تحويل الكلام إلى نص في الوقت الحقيقي
تحويل البث الصوتي المباشر إلى نص في الوقت الحقيقي باستخدام WebSockets
بث الصوت الخام إلى خوادمنا واستلام نسخ نصي ثنائي الاتجاه في الوقت الحقيقي. يستجيب الخادم بنتائج جزئية (نص مباشر أثناء حديث المستخدم) ونتائج نهائية (جمل مكتملة مع طوابع زمنية على مستوى الكلمة).
نظرًا لأن البث مباشر وغير متوقع، نستخدم عدادًا مسبق الدفع. عند الاتصال، نحجز فورًا 83 نقطة (دفعًا للثانية الستين الأولى). عند قطع الاتصال، نحسب استخدامك الفعلي بدقة إلى الثانية ونعيد تلقائيًا الاعتمادات غير المستخدمة إلى حسابك!بما أن البث مباشر وغير متوقع، فإننا نستخدم عداداً مسبق الدفع. عند الاتصال، نقوم فوراً بحجز 83 نقطة (ثمن أول 60 ثانية). عند قطع الاتصال، نحسب استخدامك الفعلي بالثانية ونعيد النقاط غير المستخدمة تلقائياً إلى حسابك!
المصادقة والاتصال
يجب عليك مصادقة اتصال WebSocket الخاص بك. تعتمد الطريقة على بيئة العميل لديك:
- متصفحات الواجهة الأمامية (Frontend): لا تدعم WebSockets القياسية في المتصفحات ترويسات HTTP المخصصة. يجب عليك تضمين مفتاح API كمعلمة استعلام (?api_key=YOUR_KEY).
- الخلفية (Backend) / بايثون / Node.js: يمكنك استخدام ترويسة HTTP القياسية Authorization: Bearer YOUR_API_KEY.
| معلمة الاستعلام | إجراء مطلوب | النوع | الوصف |
|---|---|---|---|
| api_key | مشروط | نص (string) | مفتاح API الخاص بمكنه. (مطلوب هنا إذا لم يتم تمريره عبر ترويسة Authorization). |
| language | اختياري | نص (string) | كود اللغة المراد نسخها. القيمة الافتراضية ar-JO. الأكواد المدعومة تشمل ar-SA، ar-EG، en-US، إلخ. |
مواصفات الصوت
لا ترسل ملفات صوتية مضغوطة (مثل .mp3، .m4a) أو ملفات .wav قياسية مع ترويسات عبر WebSocket. سيقوم الذكاء الاصطناعي بإخراج ضجيج عشوائي أو نصوص فارغة. يقبل WebSocket حصرياً إطارات Raw Binary PCM.
قبل إرسال الإطارات الثنائية عبر المقبس، تأكد من مطابقة بث الصوت تماماً للمواصفات التالية:
- معدل العينة (Sample Rate): 16,000 هرتز (16 كيلو هرتز)
- عمق البت (Bit Depth): عدد صحيح 16 بت (Int16)
- القنوات: 1 (مونو)
- حجم المقطع (Chunk Size): أرسل في مقاطع صغيرة (مثلاً: 100 مللي ثانية / 3200 بايت). سيتم رفض المقاطع التي تزيد عن 256 كيلو بايت.
استجابات الخادم (أحداث JSON)
بينما تقوم ببث الصوت الثنائي إلى الخادم، سيرد الخادم بشكل غير متزامن بإطارات نصية بتنسيق JSON.
| نوع الحدث | مثال للبيانات |
|---|---|
|
نجاح الاتصال يتم إرسالها فور نجاح المصادقة. |
{"status": "connected", "message": "جاهز لبث الصوت..."} |
|
نتيجة جزئية يتم إرسالها باستمرار. تُستخدم لعرض ترجمة فورية حية أثناء الكتابة. |
{"type": "partial", "text": "مرحبا بك في منصة"} |
|
نتيجة نهائية يتم إرسالها عند اكتمال الجملة. تتضمن طوابع زمنية. |
{
"type": "final",
"text": "مرحبا بك في منصة مكنة.",
"words": [
{"word": "مرحبا", "start_time_ms": 150, "duration_ms": 300},
{"word": "بك", "start_time_ms": 460, "duration_ms": 200}
]
}
|
إنهاء البث: When the user stops speaking, send a JSON text frame: {"command": "stop"} to safely close the connection and calculate the final refund.
مثال للتكامل
# pip install websockets pyaudio
import asyncio
import websockets
import json
import pyaudio
import sys
API_KEY = "YOUR_API_KEY"
URL = "wss://moknah.io/api/v1/stt/ws/?language=ar-SA"
# 16kHz, 16-bit, Mono (100ms chunks)
CHUNK = 1600
async def stream_live_microphone(ws):
audio = pyaudio.PyAudio()
stream = audio.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=CHUNK)
print("🎤 Microphone is LIVE. Start speaking!")
loop = asyncio.get_running_loop()
try:
while True:
data = await loop.run_in_executor(None, stream.read, CHUNK, False)
await ws.send(data)
await asyncio.sleep(0.001)
except asyncio.CancelledError:
await ws.send(json.dumps({"command": "stop"}))
finally:
stream.stop_stream()
stream.close()
audio.terminate()
async def receive_transcriptions(ws):
async for message in ws:
data = json.loads(message)
if data.get('type') == 'partial':
sys.stdout.write(f"\r⏳ {data['text']}")
sys.stdout.flush()
elif data.get('type') == 'final':
sys.stdout.write(f"\r✅ {data['text']}\n")
sys.stdout.flush()
async def main():
headers = {"Authorization": f"Bearer {API_KEY}"}
async with websockets.connect(URL, additional_headers=headers) as ws:
await asyncio.gather(
asyncio.create_task(stream_live_microphone(ws)),
asyncio.create_task(receive_transcriptions(ws))
)
asyncio.run(main())
// 1. Connect to WebSocket
const ws = new WebSocket('wss://moknah.io/api/v1/stt/ws/?api_key=YOUR_API_KEY&language=ar-SA');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'partial') {
console.log("Live:", data.text);
} else if (data.type === 'final') {
console.log("Final:", data.text);
}
};
// 2. Capture Microphone Audio on Connection
ws.onopen = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
// Force 16kHz sample rate for the AudioContext
const audioCtx = new AudioContext({ sampleRate: 16000 });
const source = audioCtx.createMediaStreamSource(stream);
const processor = audioCtx.createScriptProcessor(4096, 1, 1);
processor.onaudioprocess = (e) => {
if (ws.readyState === WebSocket.OPEN) {
const float32Data = e.inputBuffer.getChannelData(0);
// Convert Browser Float32 to Int16 PCM (Required by Server)
const pcm16 = new Int16Array(float32Data.length);
for (let i = 0; i < float32Data.length; i++) {
pcm16[i] = Math.max(-1, Math.min(1, float32Data[i])) * 0x7FFF;
}
// Send binary PCM audio chunk to server
ws.send(pcm16.buffer);
}
};
source.connect(processor);
processor.connect(audioCtx.destination);
};
// 3. Handle graceful shutdown
function stopRecording() {
ws.send(JSON.stringify({ command: "stop" }));
}
أكواد قطع الاتصال والخطأ
إذا تم رفض الاتصال أو انقطع، سيتم إغلاق WebSocket بأحد هذه الأكواد المحددة:
| كود الإغلاق | الاسم | الوصف |
|---|---|---|
| 1000 | NORMAL_CLOSURE |
انتهى البث بنجاح. تم تسجيل الاستخدام ورد النقاط بشكل مناسب. |
| 4001 | MISSING_API_KEY |
لم يتم توفير معلمة ?api_key= أو أنها غير صالحة. |
| 4002 | UNAUTHORIZED |
مفتاح API غير صالح، IP مقيد، أو رصيد غير كافٍ لبدء/مواصلة البث. |
| 4009 | PAYLOAD_TOO_LARGE |
لقد أرسلت جزءًا صوتيًا أكبر من 256 كيلوبايت. قم بالبث في مخازن مؤقتة أصغر.لقد أرسلت مقطعاً صوتياً أكبر من 256 كيلو بايت. قم بالبث في مخازن مؤقتة أصغر. |
| 4290 | CONCURRENT_LIMIT |
توجد اتصالات WebSocket نشطة كثيرة جداً لحسابك. الحد هو بث نشط واحد. |
للأسئلة أو المشكلات المتعلقة بواجهة برمجة التطبيقات، اتصل بنا على api@moknah.io.