{ "swagger": "2.0", "info": { "title": "go-whisper-api", "version": "1.0.0", "description": "HTTP API распознавания речи на whisper.cpp: SPR (/spr/*) и OpenAI-совместимый STT (/v1/*). Swagger UI: GET /" }, "host": "localhost:8080", "schemes": ["http"], "basePath": "/", "consumes": ["application/json", "multipart/form-data"], "produces": ["application/json", "text/plain", "audio/wav", "application/octet-stream"], "tags": [ { "name": "spr", "description": "Short Phrase Recognizer (асинхронная очередь, модели, waveform)" }, { "name": "openai", "description": "OpenAI Whisper API (синхронная транскрипция, Open WebUI)" }, { "name": "meta", "description": "Документация API" } ], "paths": { "/swagger.json": { "get": { "tags": ["meta"], "summary": "OpenAPI/Swagger 2.0 спецификация", "operationId": "getSwaggerJSON", "produces": ["application/json"], "responses": { "200": { "description": "Спецификация JSON", "schema": { "type": "object" } } } } }, "/spr/models": { "get": { "tags": ["spr"], "summary": "Список моделей STT", "description": "Имена файлов `*.bin` в корне `api.models_dir` (без подкаталогов vad/punctuation).", "operationId": "sprListModels", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/modelList" } }, "500": { "description": "Ошибка чтения каталога", "schema": { "$ref": "#/definitions/plainError" } } } } }, "/spr/hostname": { "get": { "tags": ["spr"], "summary": "Информация о хосте и сервере", "operationId": "sprHostname", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/hostnameInfo" } } } } }, "/spr/queue": { "get": { "tags": ["spr"], "summary": "Список задач в кэше", "description": "Все задачи в `cache/waiting` и `cache/ready`: для каждого id — `created`, `status`.", "operationId": "sprListQueue", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/queueList" } }, "500": { "description": "Ошибка", "schema": { "$ref": "#/definitions/plainError" } } } } }, "/spr/queue/{taskID}": { "parameters": [ { "name": "taskID", "in": "path", "required": true, "type": "string", "description": "UUID задачи" } ], "get": { "tags": ["spr"], "summary": "Статус задачи", "description": "При `status=ready` и каталоге в waiting — промоут в ready. `message=Success` когда готово.", "operationId": "sprGetQueueTask", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/queueStatus" } }, "404": { "description": "Задача не найдена или ошибка транскрипции", "schema": { "$ref": "#/definitions/apiError" } } } }, "delete": { "tags": ["spr"], "summary": "Удалить задачу и каталог кэша", "operationId": "sprDeleteQueueTask", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/apiSuccess" } }, "404": { "description": "TaskNotFound", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/spr/stt/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string", "description": "ID модели (имя файла без .bin, например ggml-small)" } ], "post": { "tags": ["spr"], "summary": "Транскрипция аудио", "description": "Загрузка multipart: одно из полей `audio`, `wav`, `file`. Аудио конвертируется в 16 kHz mono WAV. По умолчанию async (`async=1`) — ответ `taskID`; при `async=0` — синхронный JSON с `text` и `words`.", "operationId": "sprTranscribe", "consumes": ["multipart/form-data"], "parameters": [ { "name": "audio", "in": "formData", "type": "file", "description": "Аудиофайл (wav, mp3, flac, ogg, m4a, mp4, aac)" }, { "name": "wav", "in": "formData", "type": "file", "description": "Алиас для audio" }, { "name": "file", "in": "formData", "type": "file", "description": "Алиас для audio" }, { "name": "async", "in": "query", "type": "integer", "enum": [0, 1], "default": 1, "description": "1 — поставить в очередь; 0 — синхронный ответ" }, { "name": "language", "in": "query", "type": "string", "description": "Язык распознавания (по умолчанию из config `api.language`, обычно ru). Значение `auto` — автоопределение whisper." }, { "name": "punctuation", "in": "query", "type": "integer", "enum": [0, 1], "description": "Восстановление пунктуации (если `punctuation.enabled` в config)" }, { "name": "speakers", "in": "query", "type": "integer", "enum": [0, 1], "description": "1 — диаризация и метки «Спикер N:» (нужен build-sherpa и модели)" }, { "name": "speaker_counter", "in": "query", "type": "integer", "description": "Число спикеров: 0 — авто, -1 — отключить диаризацию для запроса, N>0 — подсказка" } ], "responses": { "200": { "description": "Синхронный результат или taskID (async)", "schema": { "$ref": "#/definitions/sttResponse" } }, "400": { "description": "Нет файла / неверные параметры", "schema": { "$ref": "#/definitions/apiError" } }, "404": { "description": "Модель не найдена", "schema": { "$ref": "#/definitions/apiError" } }, "405": { "description": "Ошибка транскрипции (sync)", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/spr/result/{taskID}": { "parameters": [ { "name": "taskID", "in": "path", "required": true, "type": "string" } ], "get": { "tags": ["spr"], "summary": "Результат async-задачи", "operationId": "sprGetResult", "responses": { "200": { "description": "waiting/processing/ready", "schema": { "$ref": "#/definitions/resultResponse" } }, "404": { "description": "TaskNotFound или ошибка", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/spr/audio/{taskID}": { "parameters": [ { "name": "taskID", "in": "path", "required": true, "type": "string" } ], "get": { "tags": ["spr"], "summary": "WAV задачи (16 kHz mono)", "operationId": "sprGetTaskAudio", "produces": ["audio/wav"], "responses": { "200": { "description": "Файл audio.wav" }, "404": { "description": "Задача не найдена", "schema": { "$ref": "#/definitions/plainError" } } } } }, "/spr/waveform/{taskID}": { "parameters": [ { "name": "taskID", "in": "path", "required": true, "type": "string" } ], "get": { "tags": ["spr"], "summary": "Пики waveform для UI", "operationId": "sprGetWaveform", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/waveformResponse" } }, "400": { "description": "Неверный taskID", "schema": { "$ref": "#/definitions/apiError" } }, "500": { "description": "Ошибка чтения audio.json", "schema": { "$ref": "#/definitions/plainError" } } } } }, "/spr/import/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string", "description": "ID новой модели (имя файла без расширения)" } ], "post": { "tags": ["spr"], "summary": "Загрузить модель .bin", "operationId": "sprImportModel", "consumes": ["multipart/form-data"], "parameters": [ { "name": "zip-model", "in": "formData", "type": "file", "required": true, "description": "Файл модели ggml (*.bin). ZIP не поддерживается." }, { "name": "model", "in": "formData", "type": "file", "description": "Алиас для zip-model" } ], "responses": { "200": { "description": "Модель сохранена" }, "400": { "description": "Нет файла / zip / ошибка записи", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/spr/export/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string" } ], "get": { "tags": ["spr"], "summary": "Скачать модель .bin", "operationId": "sprExportModel", "produces": ["application/octet-stream"], "responses": { "200": { "description": "Бинарный файл модели" }, "404": { "description": "Модель не найдена", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/spr/delete/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string" } ], "delete": { "tags": ["spr"], "summary": "Удалить файл модели", "operationId": "sprDeleteModel", "responses": { "200": { "description": "OK" }, "404": { "description": "Модель не найдена", "schema": { "$ref": "#/definitions/apiError" } } } } }, "/v1/models": { "get": { "tags": ["openai"], "summary": "Список моделей (OpenAI format)", "operationId": "openaiListModels", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/openAIModelList" } }, "500": { "description": "server_error", "schema": { "$ref": "#/definitions/openAIError" } } } } }, "/v1/audio/transcriptions": { "post": { "tags": ["openai"], "summary": "Транскрипция (OpenAI Whisper)", "description": "Всегда синхронно. Поле `model`: id локальной модели или `whisper-1` (маппинг через `api.default_model`). Пунктуация: query `?punctuation=1`.", "operationId": "openaiTranscribe", "consumes": ["multipart/form-data"], "parameters": [ { "name": "file", "in": "formData", "type": "file", "required": true, "description": "Аудио (алиасы: audio, wav)" }, { "name": "model", "in": "formData", "type": "string", "required": true, "description": "Например whisper-1 или ggml-large-v3-turbo" }, { "name": "language", "in": "formData", "type": "string", "description": "Код языка (ru, en, auto)" }, { "name": "response_format", "in": "formData", "type": "string", "enum": ["json", "text"], "default": "json", "description": "json — {\"text\":\"...\"}; text — plain body" }, { "name": "punctuation", "in": "query", "type": "integer", "enum": [0, 1], "description": "Пунктуация (как в SPR)" } ], "responses": { "200": { "description": "Транскрипт", "schema": { "$ref": "#/definitions/openAITranscription" } }, "400": { "description": "invalid_request_error", "schema": { "$ref": "#/definitions/openAIError" } }, "500": { "description": "server_error", "schema": { "$ref": "#/definitions/openAIError" } } } } }, "/v1/audio/transcriptions/": { "post": { "tags": ["openai"], "summary": "Транскрипция (trailing slash)", "operationId": "openaiTranscribeSlash", "consumes": ["multipart/form-data"], "parameters": [ { "$ref": "#/parameters/openAIFile" }, { "$ref": "#/parameters/openAIModel" } ], "responses": { "200": { "description": "Транскрипт", "schema": { "$ref": "#/definitions/openAITranscription" } }, "400": { "schema": { "$ref": "#/definitions/openAIError" } }, "500": { "schema": { "$ref": "#/definitions/openAIError" } } } } } }, "parameters": { "openAIFile": { "name": "file", "in": "formData", "type": "file", "required": true }, "openAIModel": { "name": "model", "in": "formData", "type": "string", "required": true } }, "definitions": { "modelList": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "string" }, "description": "ID моделей" } } }, "hostnameInfo": { "type": "object", "properties": { "error": { "type": "integer", "example": 0 }, "message": { "type": "string", "example": "Success" }, "hostname": { "type": "string" }, "version": { "type": "string", "example": "go-whisper-api" }, "cwd": { "type": "string" }, "models": { "type": "string", "description": "api.models_dir" }, "cache": { "type": "string", "description": "api.cache_dir" } } }, "queueList": { "type": "object", "additionalProperties": { "type": "object", "properties": { "created": { "type": "string", "description": "2006-01-02 15:04:05" }, "status": { "type": "string", "enum": ["waiting", "processing", "ready", "error"] } } }, "description": "Ключ — taskID" }, "queueStatus": { "type": "object", "properties": { "error": { "type": "integer" }, "message": { "type": "string", "description": "Success, waiting, processing, …" }, "status": { "type": "string" } } }, "apiSuccess": { "type": "object", "properties": { "error": { "type": "integer", "example": 0 }, "message": { "type": "string", "example": "Success" } } }, "apiError": { "type": "object", "properties": { "error": { "type": "integer", "example": 1 }, "message": { "type": "string" } } }, "plainError": { "type": "string", "description": "Текст ошибки (http.Error)" }, "sttResponse": { "type": "object", "description": "async: только taskID; sync: model, text, words", "properties": { "taskID": { "type": "string" }, "model": { "type": "string" }, "text": { "type": "string" }, "words": { "type": "array", "items": { "$ref": "#/definitions/wordToken" } } } }, "resultResponse": { "type": "object", "properties": { "status": { "type": "string", "enum": ["waiting", "processing", "ready", "error"], "description": "Краткий статус (не готово)" }, "model": { "type": "string" }, "text": { "type": "string" }, "words": { "type": "array", "items": { "$ref": "#/definitions/wordToken" } }, "taskID": { "type": "string" }, "created": { "type": "string" }, "processed": { "type": "string" }, "toxicity": { "$ref": "#/definitions/toxicityStub" }, "emotion": { "type": "object" }, "voice_analysis": { "type": "object" } } }, "wordToken": { "type": "object", "properties": { "word": { "type": "string" }, "start": { "type": "integer", "description": "мс" }, "stop": { "type": "integer", "description": "мс" } } }, "toxicityStub": { "type": "object", "description": "Заглушка SPR (всегда нули)", "properties": { "insult": { "type": "number" }, "obscenity": { "type": "number" }, "threat": { "type": "number" }, "politeness": { "type": "number" } } }, "waveformResponse": { "type": "object", "properties": { "error": { "type": "integer", "example": 0 }, "waveform": { "type": "array", "items": { "type": "number" }, "description": "Пики для отрисовки" } } }, "openAIModelList": { "type": "object", "properties": { "object": { "type": "string", "example": "list" }, "data": { "type": "array", "items": { "$ref": "#/definitions/openAIModel" } } } }, "openAIModel": { "type": "object", "properties": { "id": { "type": "string" }, "object": { "type": "string", "example": "model" }, "created": { "type": "integer" }, "owned_by": { "type": "string", "example": "go-whisper-api" } } }, "openAITranscription": { "type": "object", "properties": { "text": { "type": "string" } } }, "openAIError": { "type": "object", "properties": { "error": { "type": "object", "properties": { "message": { "type": "string" }, "type": { "type": "string", "enum": [ "invalid_request_error", "authentication_error", "not_found_error", "server_error" ] } } } } } } }