https://api.echonova.aiالمطورون
الاستدعاءات المتزامنة وغير المتزامنة
أي أسلوب استدعاء يناسب الطلب، وكيف تمر المهمة بحالاتها الأربع، وكيف تستعلم عن النتيجة دوريًا.
تقدّم تحويل النص إلى كلام وتحويل الكلام إلى نص أسلوبي الاستدعاء نفسيهما. يُبقي الاستدعاء المتزامن الاتصال مفتوحًا، ويعيد النتيجة في استجابته. أما الاستدعاء غير المتزامن فيعيد معرّف المهمة فورًا، ويُنجز العمل في الخلفية، ثم تقرأ النتيجة من نقطة نهاية المهمة، أو تستقبلها عبر Webhook. تشرح هذه الصفحة ما يفعله كل أسلوب، ومتى تستخدمه، وكيف تنتقل المهمة من البداية إلى النهاية.
الأسلوبان
| متزامن | غير متزامن | |
|---|---|---|
| تحويل النص إلى كلام | POST /v1/text-to-speech/sync |
POST /v1/text-to-speech |
| تحويل الكلام إلى نص | POST /v1/speech-to-text/sync |
POST /v1/speech-to-text |
| ما يعيده | jobId وstatus، مع النتيجة: audioUrl أو transcription، مع durationSeconds وcreditsConsumed. |
jobId وstatus فقط. |
| الاتصال | مفتوح حتى تصبح النتيجة جاهزة. | يُغلق بمجرد قبول المهمة. |
status في الاستجابة |
completed |
processing |
| مكان النتيجة | في الاستجابة. | في GET .../jobs/{jobId}، أو في Webhook من نوع job.completed. |
| أحداث المهمة | لا شيء. لا يُرسل الاستدعاء المتزامن أي حدث Webhook أبدًا. | job.completed أو job.failed. |
tashkeel |
مُطبَّق. | مقبول، والنص يُركَّب كما هو مكتوب. استخدم نقطة النهاية المتزامنة للتشكيل. |
جسم الطلب واحد في نقطتي تحويل النص إلى كلام، ورفع multipart/form-data واحد في نقطتي تحويل الكلام إلى نص. تسرد صفحات المرجع كل حقل: توليد الكلام بشكل متزامن، وتوليد الكلام من النص، وتفريغ الصوت بشكل متزامن، وتفريغ ملف صوتي.
ما يشتركان فيه
- الخصم يأتي أولًا. يسعّر الـ API الطلب، ويخصم من مساحة العمل، ثم ينفّذ العمل. إذا لم يغطِّ الرصيد التكلفة، يُرفض الاستدعاء بالرمز
402والرسالةInsufficient subscription balanceقبل أن يُشغَّل أي شيء. انظر الرصيد. - كل استدعاء ينشئ مهمة. ينشئ الاستدعاء المتزامن المهمة وهي
completedبالفعل، وينشئ الاستدعاء غير المتزامن المهمة وهيpending. تظهر كلتاهما فيGET /v1/text-to-speech/jobsأوGET /v1/speech-to-text/jobs، الأحدث أولًا، ويمكن قراءتهما منGET .../jobs/{jobId}. يستطيع أي مفتاح في مساحة العمل له وصول إلى ذلك المنتج قراءة المهمة. - الفشل يُسترد. حين يفشل استدعاء متزامن، تحصل على استجابة خطأ ويُسترد الخصم. وحين تفشل مهمة غير متزامنة، تصبح حالتها
failed، ويحملerrorالسبب، ويُسترد الخصم. - الغلاف نفسه. كل استجابة هي
{ "success", "statusCode", "errorMessage", "data" }، وكل استدعاء ناجح، بما فيهPOST، يعيد الرمز HTTP200. انظر نظرة عامة على Developer API.
اختيار الأسلوب
استخدم نقطة النهاية المتزامنة حين تتحقق كل هذه الشروط:
- تحتاج إلى النتيجة داخل الطلب نفسه، مثلًا للرد على رسالة في محادثة، أو لتشغيل عبارة أثناء مكالمة.
- المدخل ضمن الحد: صوت مدته 10 دقائق أو أقل لتحويل الكلام إلى نص، و500 حرف لتحويل النص إلى كلام. تشترك نقطتا كل خدمة في الحد، فحجم المدخل لا يفرض الاختيار أبدًا.
- يستطيع عميلك إبقاء اتصال HTTP مفتوحًا طوال مدة العمل. لا تضع الـ API مهلة خاصة به على الاستدعاء المتزامن، لذا اضبط مهلة عميلك مع أخذ حجم المدخل في الحسبان.
استخدم نقطة النهاية غير المتزامنة في كل الحالات الأخرى:
- الدفعات. أرسل مهام كثيرة، ثم استعلم عنها دوريًا، أو دع Webhook يخبرك بانتهاء كل واحدة.
- العملاء ذوو مهلة HTTP قصيرة، أو الأعمال التي لا تريد أن تحجزها.
- أي حالة تريد فيها أن يُسلَّم حدث
job.completedأوjob.failedإلى نقطة نهايتك، بدلًا من إبقاء الاتصال مفتوحًا.
يكلّف الأسلوبان الرصيد نفسه للمدخل نفسه. الاختيار يتعلق بكيفية استلامك النتيجة، لا بالسعر.
اربط الأسلوب بمن ينتظر. الشخص الذي ينتظر ردًا يريد رحلة ذهاب وإياب واحدة، والدفعة تريد اتصالًا غير محجوز وWebhook.
الموصى به
- رد في محادثة:
POST /v1/text-to-speech/sync، والنتيجة في الاستجابة. - خمسمئة تسجيل ليلًا:
POST /v1/speech-to-textلكل تسجيل، مع Webhook علىjob.completedوjob.failed.
الأقل فاعلية
- رد في محادثة:
POST /v1/text-to-speech، ثم حلقة استعلام تُبقي المستخدم منتظرًا المدة نفسها مضافًا إليها فاصل الاستعلام. - خمسمئة تسجيل ليلًا:
POST /v1/speech-to-text/syncبالتوازي، مع مهلة عميل 30 دقيقة على كل اتصال.
دورة حياة المهمة
للمهمة أربع حالات: pending وprocessing وcompleted وfailed. تمر المهمة غير المتزامنة بها بهذا الترتيب:
POST accepted
|
v
pending --> processing --> completed
|
+---------> failed| الحالة | ماذا تعني | ما يحمله كائن المهمة |
|---|---|---|
pending |
خُصم الرصيد وأُنشئت المهمة، وهي تنتظر القبول للمعالجة. لا يعود POST إلا بعد أن تغادر المهمة هذه الحالة، لذلك لا يمكنك رؤيتها إلا في قائمة مهام تُجلب أثناء بقاء POST قيد التنفيذ. |
لا توجد حقول نتيجة. |
processing |
تجري معالجة المهمة. | تحويل النص إلى كلام: لا audioUrl ولا durationSeconds. تحويل الكلام إلى نص: يحمل durationSeconds تقديرًا مأخوذًا من الملف، والحقل transcription غائب. |
completed |
النتيجة جاهزة. | تحويل النص إلى كلام: audioUrl وdurationSeconds. تحويل الكلام إلى نص: transcription وdurationSeconds كما قيست. |
failed |
فشلت المهمة، أو انتهت مهلتها. يُسترد الرصيد. | error ويحمل السبب. يبقى creditsConsumed يُظهر المبلغ الذي خُصم ثم أُعيد. |
ثلاث قواعد تسري على كل مهمة:
- تنتهي المهمة مرة واحدة. لا تنتقل المهمة من
completedإلىfailed، ولا تُكمَل مرتين. - لا تبقى المهمة في
processingإلى الأبد. المهمة التي بقيتprocessingلأكثر من 10 دقائق تُعلَّمfailedمعerrorبالقيمةJob timed out — AI server did not respond، ويتغير الحالة خلال 15 دقيقة منPOST. يُسترد الرصيد. هذه المهلة لا ترسل حدثjob.failedعبر Webhook، لذلك فحلقة الاستعلام، أو استعلام احتياطي بعد 15 دقيقة من الصمت، هما الطريقة لمعرفة ذلك. - الرفض عند الإرسال يُبلَّغ عنه مرتين. إذا رفضت الخدمة المهمة وقت إرسالها عبر
POST، تُعلَّم المهمةfailed، ويُسترد الرصيد، ويعيدPOSTنفسه خطأً، غالبًا503معSpeech generation is temporarily unavailable. Please try again.أوTranscription is temporarily unavailable. Please try again.. تبقى المهمة الفاشلة في قائمة مهامك.
للاستدعاء المتزامن قصة أقصر: تظهر المهمة completed حين تصبح النتيجة جاهزة، وإذا فشل الاستدعاء فلا تُنشأ أي مهمة. تحصل على استجابة الخطأ والاسترداد.
الاستعلام عن المهمة
اقرأ المهمة عبر GET /v1/text-to-speech/jobs/{jobId} أو GET /v1/speech-to-text/jobs/{jobId}، مستخدمًا jobId من استجابة POST. توقف حين يصبح status إما completed أو failed.
curl https://api.echonova.ai/v1/text-to-speech/jobs/JOB_ID \
-H "Authorization: Bearer YOUR_API_KEY"import time
import requests
headers = {"Authorization": "Bearer YOUR_API_KEY"}
while True:
job = requests.get(
f"https://api.echonova.ai/v1/text-to-speech/jobs/{job_id}",
headers=headers,
).json()["data"]
if job["status"] in ("completed", "failed"):
break
time.sleep(3)
print(job["status"], job.get("audioUrl") or job.get("error"))const headers = { Authorization: 'Bearer YOUR_API_KEY' };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let job;
for (;;) {
const response = await fetch(`https://api.echonova.ai/v1/text-to-speech/jobs/${jobId}`, { headers });
job = (await response.json()).data;
if (job.status === 'completed' || job.status === 'failed') break;
await sleep(3000);
}
console.log(job.status, job.audioUrl ?? job.error);كائن المهمة يسمي معرّفه id، بينما أعاد POST الذي بدأها jobId. الحقول:
| الحقل | مهمة تحويل النص إلى كلام | مهمة تحويل الكلام إلى نص |
|---|---|---|
id |
دائمًا | دائمًا |
status |
دائمًا | دائمًا |
createdAt |
دائمًا | دائمًا |
creditsConsumed |
دائمًا | دائمًا |
text |
دائمًا | غير موجود |
voiceId |
دائمًا | غير موجود |
durationSeconds |
عند completed |
دائمًا؛ تقدير حتى completed |
audioUrl |
عند completed |
غير موجود |
transcription |
غير موجود | عند completed |
error |
عند failed |
عند failed |
language |
غير موجود | دائمًا |
numbersAsDigits |
غير موجود | دائمًا |
audioUrl رابط موقّع إلى ملف WAV، وله مدة صلاحية تنتهي. كل GET للمهمة يعيد رابطًا جديدًا، فاستعلم مرة أخرى بدلًا من تخزين الرابط. انزل الملف بطلب GET عادي دون ترويسة Authorization.
أمران يجب تذكرهما أثناء الاستعلام:
- كل استعلام يُحتسب من حد المعدل، وهو 100 طلب كل 60 ثانية لكل مفتاح على تلك النقطة. انتظر بضع ثوانٍ بين الاستعلامات. انظر حدود معدل الطلبات.
- ضع للحلقة موعدًا نهائيًا. تصل كل مهمة إلى
completedأوfailedخلال 15 دقيقة من دخولهاprocessing.
النمط الكامل، مع التراجع التدريجي عند 429 و5xx، موجود في إعادة المحاولة بأمان.
Webhook بدلًا من الاستعلام
حين تنتهي مهمة غير متزامنة، يرسل الـ API الحدث job.completed أو job.failed إلى كل Webhook مفعّل في مساحة العمل يشترك في ذلك الحدث. يحمل job.completed النتيجة نفسها: audioUrl لتحويل النص إلى كلام، وtranscription لتحويل الكلام إلى نص، فلا تحتاج إلى استدعاء نقطة نهاية المهمة بعد ذلك. ويحمل job.failed القيمة error. لا يرسل الاستدعاء المتزامن أيًا من الحدثين، ولا تُرسل مهلة الـ 10 دقائق أيضًا. انظر إعداد Webhook وأحداث Webhook.
الحدود
| الحد | القيمة | ينطبق على |
|---|---|---|
طول text |
من 1 إلى 500 حرف | POST /v1/text-to-speech وPOST /v1/text-to-speech/sync |
| مدة الصوت | 10 دقائق | POST /v1/speech-to-text/sync وPOST /v1/speech-to-text |
| حجم الملف | 150 ميجابايت | نقطتا رفع تحويل الكلام إلى نص |
الوقت في processing |
10 دقائق، ثم تُعلَّم failed خلال 15 دقيقة من POST |
المهام غير المتزامنة |
| الطلبات | 100 كل 60 ثانية لكل مفتاح ولكل نقطة نهاية | كل نقطة نهاية، بما فيها الاستعلامات |
الأسئلة الشائعة
هل تقبل نقطة النهاية غير المتزامنة مدخلًا أطول؟
لا. تقبل نقطتا تحويل النص إلى كلام حتى 500 حرف، وتقبل نقطتا تحويل الكلام إلى نص حتى 10 دقائق من الصوت.
هل يمكنني الحصول على تشكيل في مهمة غير متزامنة؟
لا. يُطبَّق tashkeel على POST /v1/text-to-speech/sync فقط. تقبل نقطة النهاية غير المتزامنة الحقل، وتركّب النص كما هو مكتوب.
هل يظهر الاستدعاء المتزامن في قائمة مهامي؟
نعم، وهو completed بالفعل، بالقيمة نفسها لـ creditsConsumed وaudioUrl أو transcription الموجودة في الاستجابة.
لماذا انتهت مهمتي بحالة failed دون Webhook؟
انتهت مهلتها بعد أكثر من 10 دقائق في processing، ولا ترسل المهلة أي حدث. استعلم عن المهمة حين تمر 15 دقيقة دون أن تصل نتيجة.
هل تبقى النتيجة محفوظة بعد انتهاء المهمة؟
نعم. يعيد GET .../jobs/{jobId} النص المفرّغ، أو audioUrl جديدًا، حتى تحذف المهمة عبر DELETE .../jobs/{jobId} أو تُغلق حسابك. يستطيع أي مفتاح في مساحة العمل له وصول إلى ذلك المنتج حذف مهامه. ومهمة من مساحة عمل أخرى تعيد 404.