درگاه سه endpoint صوتی سازگار با OpenAI دارد: گفتار به متن، ترجمهٔ گفتار به انگلیسی و متن به گفتار. مدلهای این endpointها از OpenAI و Google هستند و فارسی را خوب میفهمند: کنار Whisper و سری GPT Transcribe، Gemini 3.5 Transcribe گویندهها را از هم جدا میکند و زیرنویس میسازد، و کنار صداهای OpenAI، Gemini TTS سی صدای آماده و گفتوگوی دو نفره دارد. همه را با همان کلید و همان قالب OpenAI صدا میزنید. مدلهای صوتی Groq روی درگاه فعال نیستند. فایل بلند را هم میتوانید مستقیم در /chat/completions به مدلهای Gemini بدهید و متن زمانبندیشده بگیرید؛ روشش را در بخش فایل صوتی بلند با Gemini نوشتهایم.
گفتار به متن
درخواست از نوع multipart/form-data با فیلد file (حداکثر ۲۵ مگابایت؛ mp3، mp4، mpeg، mpga، m4a, wav, webm, ogg) و model:
with open("meeting.mp3", "rb") as f:
text = client.audio.transcriptions.create(
model="whisper-1",
file=f,
language="fa", # دقت فارسی را بالا میبرد
response_format="text", # json | text | srt | vtt | verbose_json
)
print(text)
import fs from "node:fs";
const result = await client.audio.transcriptions.create({
model: "whisper-1",
file: fs.createReadStream("meeting.mp3"),
language: "fa",
response_format: "verbose_json",
timestamp_granularities: ["segment"],
});
console.log(result.text, result.duration);
curl https://netarz.ir/api/ai/v1/audio/transcriptions \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-F file=@meeting.mp3 \
-F model=whisper-1 \
-F language=fa \
-F response_format=srt
| فیلد | توضیح |
|---|---|
file الزامی | فایل صوتی، حداکثر ۲۵ مگابایت. |
model الزامی | whisper-1، gpt-transcribe، gpt-4o-transcribe، gpt-4o-mini-transcribe یا gpt-4o-transcribe-diarize (تفکیک گوینده) یا gemini-3.5-transcribe (جزئیات). فهرست |
language | کد زبان ISO-639-1؛ برای فارسی fa. دقت و سرعت را بهبود میدهد. |
response_format | json (پیشفرض) | text | srt | vtt | verbose_json (با زمانبندی؛ فقط مدلهایی که capabilities.verbose_json دارند). gemini-3.5-transcribe قالب diarized_json را هم دارد. |
prompt | متن راهنما (مثلاً اسامی خاص یا سبک نگارش) برای بهبود خروجی. |
temperature، timestamp_granularities | اختیاری؛ عبور مستقیم. |
فیلدهای دیگر نادیده گرفته میشوند. فایل بزرگتر از ۲۵ مگابایت را تکهتکه کنید، بیتریتش را پایین بیاورید یا به Gemini بدهید.
Gemini 3.5 Transcribe: جدا کردن گویندهها، زمانبندی و زیرنویس
gemini-3.5-transcribe از همین endpoint و با همین درخواست multipart/form-data کار میکند، با فایل تا ۲۵ مگابایت. کنار متن ساده، گویندهها را از هم جدا میکند (diarization)، زمان هر کلمه را میدهد و مستقیم فایل زیرنویس SRT یا VTT میسازد.
with open("interview.mp3", "rb") as f:
srt = client.audio.transcriptions.create(
model="gemini-3.5-transcribe",
file=f,
language="fa",
response_format="srt", # زیرنویس با زمانبندی کلمهبهکلمه
)
open("interview.srt", "w", encoding="utf-8").write(srt)
# جدا کردن گویندهها، برچسب هر نوبت داخل خود متن
curl https://netarz.ir/api/ai/v1/audio/transcriptions \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-F file=@meeting.mp3 \
-F model=gemini-3.5-transcribe \
-F language=fa \
-F diarize=true \
-F response_format=text
[spk_1] سلام، جلسه را شروع کنیم؟
[spk_2] بله، اول گزارش فروش هفته را مرور کنیم.
[spk_1] باشد، من شروع میکنم.
| فیلد | روی این مدل |
|---|---|
language | کد زبان، مثلاً fa. اگر نفرستید، مدل زبان را خودش تشخیص میدهد. |
response_format | json (پیشفرض) | text | verbose_json (متن، فهرست کلمهها با زمان شروع و پایان، و بخشها یا segments) | srt | vtt | diarized_json (بخشها با برچسب گوینده). |
diarize | با true گویندهها برچسب میگیرند: spk_1، spk_2 و… تا ۸ نفر. با json و text برچسب داخل خود متن میآید ([spk_1] …، هر نوبت در یک خط)؛ در srt و vtt اول هر زیرنویس. |
prompt | واژهنامهٔ اختصاصی (custom vocabulary): نامها و اصطلاحهایی که باید درست نوشته شوند، جداشده با ویرگول. فقط با json یا text اثر دارد؛ وقتی diarize، زمانبندی (verbose_json، srt، vtt، diarized_json) یا mode=smart روشن است، نادیده گرفته میشود. |
mode | با smart کلمههای پرکنندهٔ گفتار حذف میشوند و متن تمیزتری میگیرید. مثل prompt، فقط با json یا text و بدون diarize اثر دارد. |
timestamp_granularities | با ["word"] زمانبندی کلمهبهکلمه روشن میشود. |
نمونهٔ واژهنامه؛ اینطور اسم برند یا اصطلاح فنی در متن درست نوشته میشود:
curl https://netarz.ir/api/ai/v1/audio/transcriptions \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-F file=@support-call.mp3 \
-F model=gemini-3.5-transcribe \
-F language=fa \
-F prompt="نِت اَرز, Nano Banana, زرینپال, کلید API"
فایل صوتی بلند با Gemini (متن با زمانبندی)
فایل را با base64 در بخش input_audio کنار دستورتان بفرستید و از مدل بخواهید متن را با زمان هر جمله بنویسد. جلسه، کلاس یا مصاحبهٔ فارسی را همینطور به متن زمانبندیشده تبدیل میکنید. اگر پیشتر همین کار را با کلید Google AI Studio میکردید، فرقش این است که درگاه فقط قالب OpenAI را میپذیرد؛ کتابخانهٔ google-genai و آپلود فایل گوگل (Files API) اینجا کار نمیکنند.
| محدودیت | مقدار |
|---|---|
| بدنهٔ هر درخواست | ۲۰ مگابایت. base64 حجم فایل را یکسوم بیشتر میکند، پس هر درخواست حدود ۱۵ مگابایت صوت جا میدهد. |
| زمان پاسخ | هر درخواست حداکثر ۹۰ ثانیه فرصت دارد. |
| قالب فایل | mp3 یا wav در فیلد input_audio.format. |
فایل ۱۰۰ مگابایتی در یک درخواست جا نمیشود، ولی لازم هم نیست آن را یکجا بفرستید. Gemini پیش از شنیدن، صوت را تککاناله (mono) و ۱۶ کیلوبیت بر ثانیه میکند؛ پس اگر خودتان فایل را mono و ۳۲ کیلوبیت ذخیره کنید، دقت متن پایین نمیآید و هر ساعت صوت حدود ۱۴ مگابایت میشود. بعد فایل را به تکههای ۱۵ دقیقهای تقسیم کنید تا جواب هر تکه در مهلت پاسخ برسد:
# mono، ۱۶ کیلوهرتز، ۳۲ کیلوبیت؛ تکههای ۱۵ دقیقهای (۹۰۰ ثانیه)
ffmpeg -i lecture.wav -ac 1 -ar 16000 -b:a 32k \
-f segment -segment_time 900 -reset_timestamps 1 part-%03d.mp3
هر تکه را جدا بفرستید. زمانهایی که مدل در متن هر تکه مینویسد از صفر شروع میشوند؛ شروع همان تکه در فایل اصلی (۰، ۱۵، ۳۰ دقیقه…) را به آنها اضافه کنید:
import base64, glob, os
from openai import OpenAI
client = OpenAI(base_url="https://netarz.ir/api/ai/v1", api_key=os.environ["NETARZ_API_KEY"])
PROMPT = "Transcribe this Persian audio verbatim. Start every sentence with a [mm:ss] timestamp."
for i, path in enumerate(sorted(glob.glob("part-*.mp3"))):
with open(path, "rb") as f:
audio = base64.b64encode(f.read()).decode()
reply = client.chat.completions.create(
model="gemini-3.8-flash",
messages=[{"role": "user", "content": [
{"type": "text", "text": PROMPT},
{"type": "input_audio", "input_audio": {"data": audio, "format": "mp3"}},
]}],
)
print(f"--- تکهٔ {i + 1}، از دقیقهٔ {i * 15}") # زمانهای این تکه از صفر شروع میشوند
print(reply.choices[0].message.content)
$bytes = [IO.File]::ReadAllBytes("part-000.mp3")
$body = @{
model = "gemini-3.8-flash"
messages = @(@{
role = "user"
content = @(
@{ type = "text"; text = "Transcribe this Persian audio verbatim. Start every sentence with a [mm:ss] timestamp." },
@{ type = "input_audio"; input_audio = @{ data = [Convert]::ToBase64String($bytes); format = "mp3" } }
)
})
} | ConvertTo-Json -Depth 10 # بدون -Depth، بخش صوت از دست میرود
$reply = Invoke-RestMethod -Method Post -Uri "https://netarz.ir/api/ai/v1/chat/completions" `
-Headers @{ Authorization = "Bearer $env:NETARZ_API_KEY" } `
-ContentType "application/json; charset=utf-8" `
-Body ([Text.Encoding]::UTF8.GetBytes($body)) # بدنه با UTF-8
$reply.choices[0].message.content
دو چیز درخواست را خراب میکند. یکی، ConvertTo-Json بدون -Depth فقط دو سطح را مینویسد و بخش صوت را از دست میدهد. دیگر، خودِ PowerShell بدنهٔ متنی را بدون UTF-8 میفرستد و متن فارسی بههم میریزد یا خطای invalid_json برمیگردد. -Depth 10 بگذارید و بدنه را با [Text.Encoding]::UTF8.GetBytes() بفرستید؛ مثل نمونهٔ بالا.
هزینه: Gemini هر ثانیه صوت را حدود ۳۲ توکن ورودی میشمارد (هر ساعت ۱۱۵٬۲۰۰ توکن) و ما همین توکنها را با قیمت ورودی همان مدل حساب میکنیم. یک ساعت صوت با gemini-3.8-flash، اگر حدود ۲۰ هزار توکن متن برگردد، نزدیک $0.19 میشود؛ با نرخ امروز حدود ۵۴٬۰۰۰ تومان. پیش از هر درخواست، مبلغ رزرو را از حجم فایل برآورد میکنیم و بعد از پاسخ، با مصرف واقعی تسویه میکنیم.
ترجمهٔ گفتار به انگلیسی
curl https://netarz.ir/api/ai/v1/audio/translations \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-F file=@voice-message.ogg \
-F model=whisper-1
# → متن انگلیسی گفتار (هر زبانی به انگلیسی)
متن به گفتار
خروجی فایل صوتی باینری است (پیشفرض mp3). حداکثر طول متن ۴٬۰۹۶ کاراکتر است و در مدلهای Gemini TTS ۳٬۰۰۰ کاراکتر؛ سقف هر مدل در capabilities.max_input_chars آمده است. متن بلندتر را در چند درخواست بفرستید.
speech = client.audio.speech.create(
model="tts-1",
voice="alloy", # alloy | echo | fable | onyx | nova | shimmer
input="به نِت اَرز خوش آمدید. سفارش شما ثبت شد.",
response_format="mp3", # mp3 | opus | aac | flac | wav | pcm
)
speech.write_to_file("welcome.mp3")
import fs from "node:fs";
const speech = await client.audio.speech.create({
model: "gpt-4o-mini-tts",
voice: "nova",
input: "به نِت اَرز خوش آمدید. سفارش شما ثبت شد.",
instructions: "گرم و آرام صحبت کنید.", // فقط gpt-4o-mini-tts
});
fs.writeFileSync("welcome.mp3", Buffer.from(await speech.arrayBuffer()));
curl https://netarz.ir/api/ai/v1/audio/speech \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "tts-1", "voice": "alloy", "input": "به نِت اَرز خوش آمدید."}' \
--output welcome.mp3
پارامترها: model، input، voice (صداهای هر مدل در capabilities.voices)، response_format، speed (۰٫۲۵ تا ۴) و برای gpt-4o-mini-tts و مدلهای Gemini TTS فیلد instructions برای لحن.
Gemini TTS: سی صدا، لحن جدا از متن و گفتوگوی دو نفره
gemini-3.8-flash-tts و gemini-3.8-flash-lite-tts از همین endpoint کار میکنند و فارسی را طبیعی میخوانند. هر چیزی که در input بنویسید، همانطور که نوشته شده خوانده میشود؛ پس دستور لحن را داخل متن ننویسید و در instructions بفرستید (مثلاً «گرم و دوستانه» یا «لحن خبری»). این دستور روی شیوهٔ خواندن اثر دارد و بلند خوانده نمیشود.
speech = client.audio.speech.create(
model="gemini-3.8-flash-tts",
voice="Sulafat", # یکی از ۳۰ صدای Gemini
input="به نِت اَرز خوش آمدید. سفارش شما ثبت شد.",
instructions="گرم و دوستانه، با سرعت معمولی",
response_format="mp3",
)
speech.write_to_file("welcome.mp3")
curl https://netarz.ir/api/ai/v1/audio/speech \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash-lite-tts",
"voice": "Charon",
"input": "خبر امروز: نرخ دلار نسبت به دیروز تغییری نکرد.",
"instructions": "لحن خبری، رسمی و آرام",
"speed": 1.1
}' --output news.mp3
| پارامتر | روی این مدلها |
|---|---|
voice | یکی از ۳۰ صدای Gemini (فهرست پایین). اگر نام صداهای OpenAI مثل alloy یا nova را بفرستید، نزدیکترین صدای Gemini انتخاب میشود؛ پس کد فعلیتان جز نام مدل تغییری لازم ندارد. |
instructions | لحن و حالت گفتار، جدا از متن. |
speakers | برای گفتوگوی دو نفره: دو گوینده، هر کدام با نام و صدای خودش (پایینتر). |
speed | سرعت خواندن، ۰٫۲۵ تا ۴. |
response_format | mp3 (پیشفرض) | opus | aac | flac | wav | pcm. |
input | متن، حداکثر ۳٬۰۰۰ کاراکتر در هر درخواست؛ متن بلندتر خطای ۴۰۰ با کد input_too_long میگیرد، پیش از آنکه هزینهای کم شود. |
صداهای Gemini: Zephyr، Puck، Charon، Kore، Fenrir، Leda، Orus، Aoede، Callirrhoe، Autonoe، Enceladus، Iapetus، Umbriel، Algieba، Despina، Erinome، Algenib، Rasalgethi، Laomedeia، Achernar، Alnilam، Schedar، Gacrux، Pulcherrima، Achird، Zubenelgenubi، Vindemiatrix، Sadachbia، Sadaltager، Sulafat
گفتوگوی دو نفره
در speakers دقیقاً دو گوینده را با نام و صدا تعریف کنید و هر خط input را با نام گوینده و دونقطه شروع کنید. خطی که نام نداشته باشد، مال گویندهٔ خط قبلی است. اگر فقط یک گوینده بفرستید، گفتوگو ساخته نمیشود و متن با صدای voice خوانده میشود. این حالت برای پادکست، تبلیغ دیالوگی یا آموزش پرسش و پاسخ مناسب است.
curl https://netarz.ir/api/ai/v1/audio/speech \
-H "Authorization: Bearer $NETARZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash-tts",
"input": "سارا: امروز دربارهٔ API هوش مصنوعی حرف میزنیم.\nعلی: یعنی با یک کلید به چند مدل وصل میشویم؟\nسارا: دقیقاً همینطور است.",
"speakers": [
{"speaker": "سارا", "voice": "Leda"},
{"speaker": "علی", "voice": "Puck"}
],
"instructions": "گفتوگوی صمیمی یک پادکست"
}' --output podcast.mp3
گفتار و صدا از راه OpenRouter
مدلهای صوتی دیگر هم با شناسهٔ openrouter/… از همین دو endpoint کار میکنند: برای متن به گفتار ElevenLabs، MiniMax، Deepgram Aura، Fish Audio و Qwen TTS، و برای گفتار به متن ElevenLabs Scribe، Deepgram Nova، AssemblyAI، Voxtral و Qwen ASR. چند تفاوت دارند:
- متن به گفتار: خروجی
mp3است، یاpcmاگر صریح بخواهید؛ قالبهای دیگر به mp3 برمیگردند. هر درخواست حداکثر ۳٬۰۰۰ کاراکتر. نام صداهای هر مدل درcapabilities.voicesآمده است (مثلاًsarahدر ElevenLabs). - گفتار به متن: پاسخ
jsonیاverbose_jsonاست؛srtوvttاز این مدلها نمیآید و مسیر/audio/translationsبرایشان نیست. - هزینه: هزینهٔ واقعیای که سرویسدهنده برای همان درخواست حساب میکند. واحد قیمت هر مدل در فهرست آمده است: هر یک میلیون کاراکتر، هر دقیقه، یا توکنی.
قیمتگذاری
- گفتار به متن دقیقهای (
whisper-1وgpt-transcribe): بهازای هر دقیقه (per_minute)، با محاسبهٔ دقیق به ثانیه بر اساس مدتزمانی که ارائهدهنده گزارش میکند. اگر مدت گزارش نشود، از حجم فایل برآورد میشود. - مدلهای توکنی (سری
gpt-4o-transcribe): بر اساس توکنهای صوتی ورودی و متن خروجی که OpenAI گزارش میکند. - Gemini 3.5 Transcribe: توکنی؛ صوت ورودی حدود ۲۵ توکن برای هر ثانیه، بهعلاوهٔ توکنهای متن خروجی، با نرخ توکن همان مدل.
- متن به گفتار OpenAI: بهازای هر یک میلیون کاراکتر ورودی (
per_million_characters). - Gemini TTS: توکنی؛ مبنای هزینه طول صدای ساختهشده است، هر ثانیه گفتار حدود ۲۵ توکن صوتی، بهعلاوهٔ توکنهای متن ورودی.
نرخ هر مدل به تومان و دلار در صفحهٔ مدلها آمده است.
مبلغ رزرو پیش از درخواست از حجم فایل (برای صوت) یا طول متن (برای گفتار) برآورد میشود و پس از پاسخ با مصرف واقعی تسویه میشود.