HTTP API · без ключей · те же цены, что на сайте

API: расшифровка и озвучка из кода

Оба сервиса доступны программно по адресу https://bowhard.ru/api/tools. Отдельный ключ не нужен: сервис выдаёт подписанную cookie tools_id, по ней считаются ваши задачи и бесплатные лимиты. Запрос принимает файл или текст, возвращает идентификатор задачи, дальше результат забирается опросом. Примеры ниже — на curl, Python и Node.js, всё без сторонних библиотек.

Методы

МетодЧто делаетТело запроса
POST /api/tools/stt Расшифровка аудио и видео multipart/form-data, поле file; до 2048 МБ (mp3, wav, ogg, m4a, mp4, mov, mkv — всё, что читает ffmpeg)
POST /api/tools/link Расшифровка по ссылке application/json: {"url": "https://disk.yandex.ru/..."}. Только публичные ссылки Яндекс.Диска и Dropbox, не больше 10 в час с одного адреса
POST /api/tools/tts Озвучка текста {"text": "...", "voice": "alena", "speed": 1.0} — от 3 до 100 000 знаков, скорость от 0,5 до 2,0
GET /api/tools/job/<id> Состояние задачи Поля ответа: status, durationSec, chars, cost, urls
GET /api/tools/job/<id>/file/<kind> Результат kind: txt — текст, srt — субтитры, json — текст со словами и таймкодами, mp3 — озвучка
GET /api/tools/prices Цены и остатки Тарифы, свободные минуты и знаки на сегодня
GET /api/tools/voices Список голосов 15 русских голосов, у каждого — подсказка, кому подходит

Расшифровка: загрузка файла

Cookie сохраняйте между запросами — иначе следующая задача откроется как чужая.

# 1. отправляем файл (cookie пишем в файл)
curl -c cookie.txt -b cookie.txt \
  -F "file=@meeting.mp3" \
  https://bowhard.ru/api/tools/stt
{"jobId":"2f1c…","status":"queued"}

# 2. опрашиваем состояние раз в пару секунд
curl -c cookie.txt -b cookie.txt \
  https://bowhard.ru/api/tools/job/2f1c…
{"status":"done","durationSec":1834.4,"cost":0}

# 3. забираем результат: текст, субтитры или JSON с таймкодами слов
curl -c cookie.txt -b cookie.txt \
  https://bowhard.ru/api/tools/job/2f1c…/file/srt -o meeting.srt

Озвучка: текст в mp3

curl -c cookie.txt -b cookie.txt \
  -H "Content-Type: application/json" \
  -d '{"text":"Здравствуйте! Это проверка озвучки.","voice":"alena","speed":1.0}' \
  https://bowhard.ru/api/tools/tts
{"jobId":"8a04…","status":"queued","chars":38}

curl -c cookie.txt -b cookie.txt \
  https://bowhard.ru/api/tools/job/8a04…/file/mp3 -o voice.mp3

Python — только стандартная библиотека

import http.cookiejar, json, time, urllib.request

BASE = "https://bowhard.ru/api/tools"
opener = urllib.request.build_opener(
    urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar())
)

def request(path, data=None, headers=None):
    req = urllib.request.Request(BASE + path, data=data, headers=headers or {})
    with opener.open(req, timeout=600) as r:
        body = r.read()
        return json.loads(body) if body[:1] in (b"{", b"[") else body

def transcribe(path):
    boundary = "----bowhard"
    with open(path, "rb") as fh:
        payload = fh.read()
    body = (
        f"--{boundary}\r\nContent-Disposition: form-data; "
        f'name="file"; filename="{path.split("/")[-1]}"\r\n'
        f"Content-Type: application/octet-stream\r\n\r\n"
    ).encode() + payload + f"\r\n--{boundary}--\r\n".encode()
    job = request("/stt", body, {"Content-Type": f"multipart/form-data; boundary={boundary}"})
    while True:
        state = request(f"/job/{job['jobId']}")
        if state["status"] in ("done", "error"):
            return state
        time.sleep(2)

state = transcribe("meeting.mp3")
print(state["status"], state["durationSec"])
print(request(f"/job/{state['jobId']}/file/txt").decode())

Node.js — обычный fetch

const BASE = 'https://bowhard.ru/api/tools';
let cookie = '';

async function call(path, init = {}) {
  const res = await fetch(BASE + path, {
    ...init,
    headers: { ...(init.headers || {}), cookie },
  });
  const set = res.headers.getSetCookie?.() || [];
  if (set.length) cookie = set.map((c) => c.split(';')[0]).join('; ');
  return res;
}

const form = new FormData();
form.append('file', new Blob([await fs.readFile('meeting.mp3')]), 'meeting.mp3');
const job = await (await call('/stt', { method: 'POST', body: form })).json();

let state;
do {
  await new Promise((r) => setTimeout(r, 2000));
  state = await (await call(`/job/${job.jobId}`)).json();
} while (!['done', 'error'].includes(state.status));

console.log(await (await call(`/job/${job.jobId}/file/txt`)).text());

n8n

Отдельного узла не нужно — хватает штатного HTTP Request. Схема для голосовых из Telegram: триггер → узел Telegram (Get File) → HTTP Request на /api/tools/stt → узел Wait (2 секунды) → HTTP Request на /api/tools/job/<id> → проверка status → HTTP Request на …/file/txt → ответ в чат. Готовые шаблоны наших сценариев лежат в открытом репозитории github.com/VavilkinAlex/n8n-bowhard-templates.

Готовые клиенты

Если не хочется писать обёртку самому, возьмите наш клиент — он без зависимостей, работает поверх того же HTTP API и умеет всё: загрузку файла, ожидание задачи, текст, SRT и JSON с таймкодами слов, озвучку в MP3. Репозиторий открыт: github.com/VavilkinAlex/bowhard-speech.

  • Python 3.9+ — pip install https://github.com/VavilkinAlex/bowhard-speech/releases/download/v0.1.0/bowhard_speech-0.1.0-py3-none-any.whl, затем from bowhard_speech import Client. Есть и консольная команда bowhard-speech.
  • Node 18+ — npm install https://github.com/VavilkinAlex/bowhard-speech/releases/download/v0.1.0/bowhard-speech-0.1.0.tgz либо из реестра GitHub: npm install @vavilkinalex/bowhard-speech --registry=https://npm.pkg.github.com.

Лимиты, цены и хранение

  • Расшифровка. 15 минут в сутки бесплатно, дальше 25 ₽ за час записи (минимальный платёж 15 ₽). Пакеты: 4 часа — 99 ₽, 10 часов — 249 ₽.
  • Озвучка. 5 000 знаков в сутки бесплатно, дальше 3,9 ₽ за 1 000 знаков. Пакеты: 25 000 знаков — 99 ₽, 100 000 знаков — 390 ₽.
  • Очередь. Два файла обрабатываются одновременно, остальные ждут — статус видно в поле status (queued, processing, done, error).
  • Хранение. Файлы и результаты удаляются через 24 часа; статистика по задачам — 90 дней.
  • Данные. Расшифровка и синтез идут на серверах Яндекса в России, за границу данные не уходят.

Частые вопросы

Нужен ли ключ для доступа к API?

Отдельный ключ не нужен: сервис выдаёт подписанную cookie tools_id, по ней и считается ваш объём. Сохраняйте cookie между запросами — тогда видно историю задач и остаток бесплатных лимитов.

Сколько стоит расшифровка и озвучка через API?

Цены те же, что на сайте: расшифровка — 15 минут в сутки бесплатно, дальше 25 ₽ за час; озвучка — 5 000 знаков в сутки бесплатно, дальше 3,9 ₽ за 1 000 знаков. Пакеты выгоднее: 4 часа за 99 ₽, 10 часов за 249 ₽, 25 000 знаков за 99 ₽, 100 000 знаков за 390 ₽.

Как быстро приходит результат?

Идентификатор задачи приходит сразу, состояние опрашивается раз в пару секунд. Расшифровка идёт примерно со скоростью, близкой к реальному времени записи; озвучка 10 000 знаков занимает около минуты.

Можно ли отдать файл ссылкой?

Да, методом /link. Принимаются публичные ссылки Яндекс.Диска и Dropbox — не больше десяти в час с одного адреса. Приватные ссылки и произвольные адреса не принимаются: сервис проверяет адрес после всех перенаправлений.

Сколько хранятся файлы и результаты?

Файлы и результаты удаляются через 24 часа. Расшифровка идёт на серверах Яндекса в России, за границу данные не уходят.

Есть ли готовые клиенты?

API — обычный HTTP, поэтому достаточно штатных средств: urllib в Python, fetch в Node, HTTP Request в n8n. Если нужна обёртка под вашу систему или пакетная обработка папки, напишите на mail@bowhard.ru — соберём под задачу.

Проверить сервис без интеграции можно на страницах расшифровки и озвучки — там те же методы, но мышкой.