الرابط الأساسي https://api.echonova.ai

المطورون

أمثلة الكود

برنامجان كاملان لكل لغة، الأول لمهمة تحويل نص إلى كلام غير متزامنة من الطلب حتى ملف صوتي محفوظ، والثاني لمهمة تحويل كلام إلى نص غير متزامنة من الرفع حتى النص المفرّغ، مع الغلاف الاستجابي الذي تقرؤه كلها.

يعمل كل برنامج في هذه الصفحة من الأعلى إلى الأسفل، مع تعديل واحد: مفتاح API الخاص بك. الأول يحوّل جملة إلى ملف صوتي محفوظ عبر مهمة تحويل نص إلى كلام غير متزامنة. الثاني يرفع ملفًا صوتيًا، وينتظر مهمة تحويل الكلام إلى نص غير المتزامنة، ثم يطبع النص المفرّغ. تشرح دلائل البدء كل استدعاء على حدة، وهذه الصفحة تجمعها معًا. وبرنامج ثالث قصير ينقّي تسجيلًا.

ما تحتاج إليه

  • مفتاح API له وصول إلى الخدمات الثلاث معًا، أو بلا تقييد للخدمات. راجع الحصول على مفتاح API.
  • الرابط الأساسي. يعرض التنبيه في أعلى هذه الصفحة المضيف الذي تستدعيه هذه الأمثلة. راجع الرابط الأساسي.
  • رصيد على مساحة العمل. تُخصم كل مهمة قبل أن تعمل. راجع الرصيد.
  • cURL مع jq، أو Python 3 مع requests، أو Node 18 أو أحدث.
  • للبرنامج الثاني، ملف صوتي اسمه audio.mp3 بمدة تصل إلى 10 دقائق وحجم يصل إلى 150 MB. لملفات WAV أو OGG، غيّر CONTENT_TYPE إلى audio/wav أو audio/ogg.

الخطوات

الخطوة 1: اقرأ الغلاف مرة واحدة

كل استجابة، نجاحًا أو خطأً، كائن JSON واحد يحمل الحقول الأربعة نفسها. يُعيد الاستدعاء الناجح الرمز HTTP 200، بما فيه استدعاءات POST، وتكون النتيجة في data:

{
  "success": true,
  "statusCode": 200,
  "errorMessage": null,
  "data": {}
}

عند الخطأ، تكون قيمة success هي false، وdata هي null، وstatusCode يطابق رمز HTTP، وerrorMessage يحمل نصًا واحدًا:

{
  "data": null,
  "statusCode": 402,
  "success": false,
  "errorMessage": "Insufficient subscription balance"
}

يغلّف كل برنامج أدناه استدعاءاته في دالة مساعدة واحدة تتحقق من success وتعيد data، فيقرأ باقي الكود النتيجة وحدها. يتوقف البرنامج عند أول خطأ. يعرض إعادة الطلبات بأمان النسخة التي تتراجع وتعيد المحاولة.

الخطوة 2: تحويل النص إلى كلام، من الطلب إلى ملف صوتي

يعرض البرنامج الأصوات، ويختار أول صوت قيمة language فيه ar، ثم يبدأ مهمة غير متزامنة، ويستعلم عنها كل 3 ثوانٍ حتى تصبح completed أو failed، ثم ينزّل audioUrl إلى speech.wav. الرابط موقّع، لذلك لا يرسل التنزيل header Authorization.

set -eo pipefail
BASE_URL="https://api.echonova.ai"
AUTH="Authorization: Bearer YOUR_API_KEY"
TEXT="مرحبا بكم في إيكونوڤا"

# api METHOD PATH [curl options]: prints .data, or exits on an error envelope
api() {
  local method=$1 path=$2 body
  shift 2
  body=$(curl -s -X "$method" "$BASE_URL$path" -H "$AUTH" "$@")
  if [ "$(echo "$body" | jq -r '.success')" != "true" ]; then
    echo "error $(echo "$body" | jq -r '.statusCode'): $(echo "$body" | jq -r '.errorMessage')" >&2
    exit 1
  fi
  echo "$body" | jq '.data'
}

# 1. Pick an Arabic voice
VOICE_ID=$(api GET /v1/text-to-speech/voices \
  | jq -r '[.items[] | select(.language == "ar")][0].id')

# 2. Start the job
JOB_ID=$(api POST /v1/text-to-speech -H "Content-Type: application/json" \
  -d "$(jq -n --arg text "$TEXT" --arg voiceId "$VOICE_ID" '{text: $text, voiceId: $voiceId}')" \
  | jq -r '.jobId')
echo "job $JOB_ID"

# 3. Poll until it ends
while true; do
  JOB=$(api GET "/v1/text-to-speech/jobs/$JOB_ID")
  STATUS=$(echo "$JOB" | jq -r '.status')
  echo "$STATUS"
  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then break; fi
  sleep 3
done
if [ "$STATUS" = "failed" ]; then
  echo "failed: $(echo "$JOB" | jq -r '.error')" >&2
  exit 1
fi

# 4. Download the audio. The link is signed; send no Authorization header.
curl -s -o speech.wav "$(echo "$JOB" | jq -r '.audioUrl')"
echo "saved speech.wav"
echo "$JOB" | jq '{durationSeconds, creditsConsumed}'

يُعيد POST الكائن { "jobId", "status" } وقيمة status هي processing. يسمّي كائن المهمة المستعلَم معرّفه id، ويضيف text وvoiceId وcreatedAt وcreditsConsumed. يظهر audioUrl وdurationSeconds عندما تصبح المهمة completed، ويظهر error عندما تصبح failed. الملف بصيغة WAV. راجع دليل البدء لتحويل النص إلى كلام لكل استدعاء على حدة، وخيارات الأصوات في تحويل النص إلى كلام تشرح speed وcfg وnumSteps وtashkeel.

الخطوة 3: تحويل الكلام إلى نص، من الرفع إلى النص المفرّغ

يرسل البرنامج الملف audio.mp3 بوصفه الجزء file من طلب multipart/form-data، ويستعلم عن المهمة كل 5 ثوانٍ، ويطبع transcription وdurationSeconds عندما تصبح completed. يجب أن يبدأ Content-Type للجزء file بـ audio/، وكل عينة تضبطه صراحة.

set -eo pipefail
BASE_URL="https://api.echonova.ai"
AUTH="Authorization: Bearer YOUR_API_KEY"
AUDIO_FILE="audio.mp3"
CONTENT_TYPE="audio/mpeg"

# api METHOD PATH [curl options]: prints .data, or exits on an error envelope
api() {
  local method=$1 path=$2 body
  shift 2
  body=$(curl -s -X "$method" "$BASE_URL$path" -H "$AUTH" "$@")
  if [ "$(echo "$body" | jq -r '.success')" != "true" ]; then
    echo "error $(echo "$body" | jq -r '.statusCode'): $(echo "$body" | jq -r '.errorMessage')" >&2
    exit 1
  fi
  echo "$body" | jq '.data'
}

# 1. Upload the file and start the job
JOB_ID=$(api POST /v1/speech-to-text -F "file=@$AUDIO_FILE;type=$CONTENT_TYPE" | jq -r '.jobId')
echo "job $JOB_ID"

# 2. Poll until it ends
while true; do
  JOB=$(api GET "/v1/speech-to-text/jobs/$JOB_ID")
  STATUS=$(echo "$JOB" | jq -r '.status')
  echo "$STATUS"
  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then break; fi
  sleep 5
done
if [ "$STATUS" = "failed" ]; then
  echo "failed: $(echo "$JOB" | jq -r '.error')" >&2
  exit 1
fi

# 3. Read the transcript
echo "$JOB" | jq -r '.transcription'
echo "$JOB" | jq '{durationSeconds, creditsConsumed}'

أثناء بقاء المهمة في processing، تحمل durationSeconds تقديرًا مستخرجًا من الملف، ولا يظهر transcription. عندما تصبح completed، يحمل الحقلان قيمهما النهائية. وتحمل المهمة أيضًا language وnumbersAsDigits، وإذا أُنشئت مع identify_speakers=true وكانت لديها بيانات المتحدثين، فإنها تحمل segments وspeakers الموقّتة؛ وبدونها تكون هاتان القائمتان فارغتين. للحصول على ترجمة، نزّل المهمة من GET /v1/speech-to-text/jobs/{jobId}/export?format=srt. راجع دليل البدء لتحويل الكلام إلى نص لكل استدعاء على حدة، وصيغ تحويل الكلام إلى نص ومخرجاته للمدخلات المقبولة.

الخطوة 4: تنقية الصوت، رفع وتنزيل

تنقية الصوت متزامنة، لذلك لا يوجد استعلام دوري. يرفع البرنامج الملف noisy.wav (10 دقائق أو أقل، و150 MB أو أقل)، ويقرأ outputUrl من الاستجابة، ويحفظ ملف WAV المنقّى باسم cleaned.wav. يجب أن يطابق Content-Type للجزء file امتداد الملف.

set -eo pipefail
BASE_URL="https://api.echonova.ai"
AUTH="Authorization: Bearer YOUR_API_KEY"

RESPONSE=$(curl -sS -X POST "$BASE_URL/v1/sound-cleaning" -H "$AUTH" -F "file=@noisy.wav;type=audio/wav")
if [ "$(echo "$RESPONSE" | jq -r '.success')" != "true" ]; then
  echo "$RESPONSE" | jq -r '"\(.statusCode) \(.errorMessage)"' >&2
  exit 1
fi
curl -sS -o cleaned.wav "$(echo "$RESPONSE" | jq -r '.data.outputUrl')"
echo "$RESPONSE" | jq -r '.data.creditsConsumed'

راجع دليل البدء لتنقية الصوت لحقول الضبط والحدود.

ماذا يحدث بعد ذلك

  • تُسرد المهام تحت مفتاحك، قائمة لكل خدمة: GET /v1/text-to-speech/jobs، وGET /v1/speech-to-text/jobs، وGET /v1/sound-cleaning/jobs، الأحدث أولًا. يحمل كل منها creditsConsumed الذي خُصم له.
  • الملف speech.wav صار على القرص. الرابط audioUrl الذي جاء منه ينتهي؛ اقرأ المهمة من جديد للحصول على رابط جديد إذا احتجت الملف لاحقًا.
  • طُبع النص المفرّغ على الخرج القياسي. احفظه بنفسك؛ تحتفظ الواجهة به على المهمة، وهناك فقط.
  • إذا انتهت أي مهمة بحالة failed، فقد طُبع error الخاص بها، وأُعيدت أرصدتها. شغّل البرنامج مرة أخرى.

الحدود

الحد القيمة ينطبق على
طول text من 1 إلى 500 حرف POST /v1/text-to-speech
مدة الصوت 10 دقائق POST /v1/speech-to-text
حجم الملف 150 MB POST /v1/speech-to-text
Content-Type للجزء file يجب أن يبدأ بـ audio/ POST /v1/speech-to-text
الوقت في processing 10 دقائق، ثم تُعلَّم المهمة failed خلال 15 دقيقة من POST المهمتان
الطلبات 100 لكل 60 ثانية لكل مفتاح ولكل نقطة نهاية كل استدعاء، بما فيه الاستعلامات الدورية

استكشاف المشكلات

البرنامج يطبع رمز حالة ورسالة ثم يتوقف

أطلقت الدالة المساعدة خطأً بسبب غلاف الخطأ. الرقم هو statusCode والنص هو errorMessage. يعني 401 Unauthorized أن المفتاح غير صالح: تحقق من أنك استبدلت YOUR_API_KEY، وأن المفتاح مفعّل. يعني 402 Insufficient subscription balance أن مساحة العمل لا تكفي للمهمة، ولم يعمل شيء. يعني 403 مع does not have access to أن المفتاح مقيّد بالخدمات. راجع المصادقة.

البرنامج يطبع failed مع رسالة خطأ

انتهت المهمة بحالة failed. تسمّي الرسالة السبب: وهي AI server generation failed أو AI server transcription failed عندما لا يُعطى سبب، وJob timed out — AI server did not respond عندما تبقى المهمة في processing لأكثر من 10 دقائق. أُعيدت الأرصدة. شغّل البرنامج مرة أخرى.

البحث عن الصوت لا يجد شيئًا

لا يوجد صوت نشط قيمة language فيه ar، فتُطلق next() في Python الاستثناء StopIteration، ويُعيد voices.find في Node القيمة undefined، وتصبح VOICE_ID في الصدفة null. اعرض الأصوات واختر id يدويًا؛ راجع عرض الأصوات المتاحة.

400 Unsupported file type: application/octet-stream. Please upload an audio file.

أُرسل الجزء file دون نوع محتوى من نوع audio/. أبقِ قيمة CONTENT_TYPE في العينة؛ ولا تحذف type= من الوسيط -F في cURL، ولا type من Blob في Node.

تنزيل الصوت يفشل

انتهت صلاحية الرابط الموقّع. استدعِ GET /v1/text-to-speech/jobs/{jobId} مرة أخرى؛ يعيد كل استدعاء رابط audioUrl جديدًا. نزّله فورًا.

429 ThrottlerException: Too Many Requests

تشترك نسخ عدة من البرنامج في مفتاح واحد، وتتراكم استعلاماتها لتتجاوز 100 طلب لكل 60 ثانية على نقطة نهاية المهام. انتظر عدد الثواني الموجود في Retry-After، ثم استخدم فترة أطول بين الاستعلامات، أو مفتاحًا لكل عملية. راجع حدود المعدل.

الأسئلة الشائعة

أين النسخ المتزامنة؟

في دلائل البدء. يعيد POST /v1/text-to-speech/sync القيمة audioUrl في الاستجابة نفسها، ويعيد POST /v1/speech-to-text/sync القيمة transcription، دون استعلام دوري. راجع دليل البدء لتحويل النص إلى كلام ودليل البدء لتحويل الكلام إلى نص، والاستدعاءات المتزامنة وغير المتزامنة لتختار بينهما.

لماذا أتحقق من success بدلًا من رمز HTTP؟

كلاهما يعمل. كل استجابة خطأ تحمل success بقيمة false وstatusCode يساوي رمز HTTP، فيستطيع العميل أن يعتمد على أيهما. فحص الغلاف سطر واحد، ويعطيك errorMessage في الخطوة نفسها.

هل أستطيع تخطي استدعاء الأصوات؟

نعم. اضبط voiceId على id تعرفه مسبقًا. يجب أن يكون الصوت نشطًا؛ فالمعرّف المجهول أو غير النشط يعيد 404 Voice not found.

هل أستطيع استلام النتيجة دون استعلام دوري؟

نعم. سجّل Webhook للحدثين job.completed وjob.failed. يحمل الحدث job.completed القيمة audioUrl أو transcription، فلا يلزم أي استدعاء إضافي. راجع إعداد Webhook وأحداث Webhook.

هل تعيد البرامج المحاولة؟

لا. تتوقف عند أول خطأ. راجع إعادة الطلبات بأمان لحلقة الاستعلام التي تحترم Retry-After وتتراجع عند 5xx.