Evgeny Naumov
Добавлена асинхронная транскрипция с отслеживанием прогресса и увеличенными таймаутами
6232404

Whisper API Документация

Обзор

Whisper API предоставляет REST API для транскрипции аудио файлов с использованием моделей Whisper. API работает на порту 3001 и поддерживает как синхронные, так и асинхронные запросы для длинных транскрипций.

Базовый URL: http://localhost:3001/api

Endpoints

1. Проверка здоровья сервера

GET /health

Проверяет, что сервер работает.

Ответ:

{
  "status": "ok",
  "message": "Whisper API сервер работает",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

2. Асинхронная транскрипция аудио файла

POST /transcribe

Загружает и транскрибирует аудио файл асинхронно. Возвращает ID задачи для отслеживания прогресса.

Параметры:

  • audio (file) - аудио файл (обязательно)
  • language (string) - язык аудио (по умолчанию: "auto")
  • model (string) - модель Whisper (по умолчанию: "base")

Поддерживаемые форматы: mp3, wav, m4a, webm, ogg

Максимальный размер файла: 50MB

Пример запроса (cURL):

curl -X POST http://localhost:3001/api/transcribe \
  -F "audio=@/path/to/audio.mp3" \
  -F "language=ru" \
  -F "model=base"

Ответ:

{
  "success": true,
  "taskId": "abc123def456",
  "status": "processing",
  "message": "Транскрипция началась",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

3. Проверка статуса задачи

GET /status/{taskId}

Проверяет статус и прогресс транскрипции.

Пример запроса:

curl http://localhost:3001/api/status/abc123def456

Ответ:

{
  "success": true,
  "task": {
    "id": "abc123def456",
    "filename": "audio.mp3",
    "language": "ru",
    "model": "base",
    "status": "processing",
    "progress": 45,
    "result": null,
    "error": null,
    "createdAt": "2024-01-01T12:00:00.000Z",
    "updatedAt": "2024-01-01T12:05:00.000Z"
  },
  "timestamp": "2024-01-01T12:05:00.000Z"
}

4. Получение результата транскрипции

GET /result/{taskId}

Получает готовый результат транскрипции.

Пример запроса:

curl http://localhost:3001/api/result/abc123def456

Ответ (если транскрипция завершена):

{
  "success": true,
  "status": "completed",
  "transcription": {
    "text": "Транскрибированный текст",
    "language": "ru",
    "model": "base",
    "duration": 120.5,
    "segments": [
      {
        "start": 0,
        "end": 10,
        "text": "Первая часть текста"
      }
    ],
    "timestamp": "2024-01-01T12:10:00.000Z"
  },
  "timestamp": "2024-01-01T12:10:00.000Z"
}

Ответ (если транскрипция еще выполняется):

{
  "success": true,
  "status": "processing",
  "progress": 75,
  "message": "Транскрипция еще выполняется"
}

Ответ (если произошла ошибка):

{
  "success": false,
  "status": "error",
  "error": "Описание ошибки"
}

5. Асинхронная транскрипция по URL

POST /transcribe/url

Транскрибирует аудио файл по URL асинхронно.

Тело запроса:

{
  "url": "https://example.com/audio.mp3",
  "language": "ru",
  "model": "base"
}

Пример запроса (cURL):

curl -X POST http://localhost:3001/api/transcribe/url \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/audio.mp3",
    "language": "ru",
    "model": "base"
  }'

Ответ:

{
  "success": true,
  "taskId": "def456ghi789",
  "status": "processing",
  "message": "Транскрипция по URL началась",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

6. Список доступных моделей

GET /models

Возвращает список доступных моделей Whisper.

Ответ:

{
  "models": [
    {
      "id": "tiny",
      "name": "Tiny",
      "size": "39 MB",
      "languages": "multilingual"
    },
    {
      "id": "base",
      "name": "Base",
      "size": "74 MB",
      "languages": "multilingual"
    },
    {
      "id": "small",
      "name": "Small",
      "size": "244 MB",
      "languages": "multilingual"
    },
    {
      "id": "medium",
      "name": "Medium",
      "size": "769 MB",
      "languages": "multilingual"
    },
    {
      "id": "large",
      "name": "Large",
      "size": "1550 MB",
      "languages": "multilingual"
    }
  ],
  "default": "base"
}

7. Список поддерживаемых языков

GET /languages

Возвращает список поддерживаемых языков.

Ответ:

{
  "languages": [
    {
      "code": "auto",
      "name": "Автоопределение"
    },
    {
      "code": "ru",
      "name": "Русский"
    },
    {
      "code": "en",
      "name": "English"
    },
    {
      "code": "es",
      "name": "Español"
    },
    {
      "code": "fr",
      "name": "Français"
    },
    {
      "code": "de",
      "name": "Deutsch"
    },
    {
      "code": "it",
      "name": "Italiano"
    },
    {
      "code": "pt",
      "name": "Português"
    },
    {
      "code": "pl",
      "name": "Polski"
    },
    {
      "code": "tr",
      "name": "Türkçe"
    },
    {
      "code": "ja",
      "name": "日本語"
    },
    {
      "code": "ko",
      "name": "한국어"
    },
    {
      "code": "zh",
      "name": "中文"
    }
  ],
  "default": "auto"
}

Коды ошибок

  • 400 - Неверный запрос (отсутствует файл, неподдерживаемый формат)
  • 404 - Endpoint не найден или задача не найдена
  • 500 - Внутренняя ошибка сервера
  • 202 - Задача в процессе выполнения (для /result/{taskId})

Таймауты

  • Таймаут сервера: 1 час (3600000 мс)
  • Таймаут запроса: 1 час
  • Таймаут ответа: 1 час

Примеры использования

Python

import requests
import time

# Асинхронная транскрипция файла
with open('audio.mp3', 'rb') as f:
    files = {'audio': f}
    data = {'language': 'ru', 'model': 'base'}
    response = requests.post('http://localhost:3001/api/transcribe', files=files, data=data)
    result = response.json()
    task_id = result['taskId']
    print(f"Задача создана: {task_id}")

# Проверка статуса
while True:
    status_response = requests.get(f'http://localhost:3001/api/status/{task_id}')
    status_data = status_response.json()
    
    if status_data['task']['status'] == 'completed':
        break
    elif status_data['task']['status'] == 'error':
        print(f"Ошибка: {status_data['task']['error']}")
        break
    
    print(f"Прогресс: {status_data['task']['progress']}%")
    time.sleep(5)  # Проверяем каждые 5 секунд

# Получение результата
result_response = requests.get(f'http://localhost:3001/api/result/{task_id}')
final_result = result_response.json()
print(f"Транскрипция: {final_result['transcription']['text']}")

# Асинхронная транскрипция по URL
data = {
    'url': 'https://example.com/audio.mp3',
    'language': 'ru',
    'model': 'base'
}
response = requests.post('http://localhost:3001/api/transcribe/url', json=data)
result = response.json()
task_id = result['taskId']

# Ожидание завершения и получение результата
while True:
    result_response = requests.get(f'http://localhost:3001/api/result/{task_id}')
    result_data = result_response.json()
    
    if result_data['status'] == 'completed':
        print(f"Транскрипция: {result_data['transcription']['text']}")
        break
    elif result_data['status'] == 'error':
        print(f"Ошибка: {result_data['error']}")
        break
    
    print(f"Статус: {result_data['status']}, Прогресс: {result_data.get('progress', 0)}%")
    time.sleep(5)

JavaScript

// Асинхронная транскрипция файла
async function transcribeFile(file) {
    const formData = new FormData();
    formData.append('audio', file);
    formData.append('language', 'ru');
    formData.append('model', 'base');
    
    const response = await fetch('http://localhost:3001/api/transcribe', {
        method: 'POST',
        body: formData
    });
    
    const result = await response.json();
    return result.taskId;
}

// Проверка статуса
async function checkStatus(taskId) {
    const response = await fetch(`http://localhost:3001/api/status/${taskId}`);
    return await response.json();
}

// Получение результата
async function getResult(taskId) {
    const response = await fetch(`http://localhost:3001/api/result/${taskId}`);
    return await response.json();
}

// Полный процесс транскрипции
async function transcribeWithProgress(file) {
    const taskId = await transcribeFile(file);
    console.log(`Задача создана: ${taskId}`);
    
    while (true) {
        const status = await checkStatus(taskId);
        
        if (status.task.status === 'completed') {
            const result = await getResult(taskId);
            console.log(`Транскрипция: ${result.transcription.text}`);
            break;
        } else if (status.task.status === 'error') {
            console.error(`Ошибка: ${status.task.error}`);
            break;
        }
        
        console.log(`Прогресс: ${status.task.progress}%`);
        await new Promise(resolve => setTimeout(resolve, 5000));
    }
}

C#

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

public class TranscriptionClient
{
    private readonly HttpClient _client;
    private readonly string _baseUrl = "http://localhost:3001/api";
    
    public TranscriptionClient()
    {
        _client = new HttpClient();
    }
    
    public async Task<string> TranscribeFileAsync(string filePath, string language = "ru", string model = "base")
    {
        using var form = new MultipartFormDataContent();
        using var fileStream = File.OpenRead(filePath);
        form.Add(new StreamContent(fileStream), "audio", Path.GetFileName(filePath));
        form.Add(new StringContent(language), "language");
        form.Add(new StringContent(model), "model");
        
        var response = await _client.PostAsync($"{_baseUrl}/transcribe", form);
        var result = await response.Content.ReadAsStringAsync();
        var data = JsonConvert.DeserializeObject<dynamic>(result);
        
        return data.taskId.ToString();
    }
    
    public async Task<dynamic> GetStatusAsync(string taskId)
    {
        var response = await _client.GetAsync($"{_baseUrl}/status/{taskId}");
        var result = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<dynamic>(result);
    }
    
    public async Task<dynamic> GetResultAsync(string taskId)
    {
        var response = await _client.GetAsync($"{_baseUrl}/result/{taskId}");
        var result = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<dynamic>(result);
    }
    
    public async Task<string> TranscribeWithProgressAsync(string filePath)
    {
        var taskId = await TranscribeFileAsync(filePath);
        Console.WriteLine($"Задача создана: {taskId}");
        
        while (true)
        {
            var status = await GetStatusAsync(taskId);
            
            if (status.task.status == "completed")
            {
                var result = await GetResultAsync(taskId);
                return result.transcription.text.ToString();
            }
            else if (status.task.status == "error")
            {
                throw new Exception($"Ошибка транскрипции: {status.task.error}");
            }
            
            Console.WriteLine($"Прогресс: {status.task.progress}%");
            await Task.Delay(5000);
        }
    }
}

Развертывание

Локально

cd whisper-web
npm install
npm run build
node server/simple-server.js

На Hugging Face Spaces

Проект автоматически развертывается на Hugging Face Spaces с использованием Gradio интерфейса. Сервер запускается на порту 3001.

Примечания

  • Все транскрипции выполняются асинхронно для предотвращения таймаутов
  • Прогресс транскрипции можно отслеживать через endpoint /status/{taskId}
  • Результаты сохраняются в памяти сервера (не в базе данных)
  • Таймауты увеличены до 1 часа для поддержки длинных аудио файлов