NexaraNexara

LLM анализ

Узнайте, как проанализировать результат транскрибации языковой моделью.

Помимо транскрибации, Nexara API может сразу проанализировать её языковой моделью. Вы передаёте инструкцию в параметре prompt, и модель выполняет её над текстом расшифровки — например, делает краткое резюме, выделяет ключевые пункты, определяет тему или извлекает нужные поля.

Анализ включается, как только вы передаёте prompt. Возможны два режима:

Свободный анализ

Только prompt — модель возвращает ответ в свободной форме (текстом).

Структурированный вывод

prompt + json_schema — модель возвращает JSON строго по заданной вами схеме.

Когда включён анализ, ответ содержит и расшифровку, и результат работы модели:

{
  "transcription": { "task": "transcribe", "text": "...", "segments": [ ... ] },
  "llm_output": "..."
}

Поле transcription — это полная расшифровка (в формате verbose_json), а llm_output — результат анализа: строка в свободном режиме или JSON-объект при использовании схемы.

json_schema учитывается только вместе с prompt. Отдельно, без prompt, анализ не запускается.

Свободный анализ

Передайте prompt с инструкцией. Замените nx-XXXXXXXXXXXXXXXXXXXXXXXX на свой API-ключ, а call.mp3 — на путь к вашему файлу.

curl https://api.nexara.ru/v1/audio/transcriptions \
  -H "Authorization: Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" \
  -F "file=@call.mp3" \
  -F "model=whisper-1" \
  -F "prompt=Сделай краткое резюме разговора в трёх предложениях."
import requests

with open("call.mp3", "rb") as audio_file:
    response = requests.post(
        "https://api.nexara.ru/v1/audio/transcriptions",
        headers={"Authorization": "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"},
        files={"file": audio_file},
        data={
            "model": "whisper-1",
            "prompt": "Сделай краткое резюме разговора в трёх предложениях.",
        },
    )

print(response.json()["llm_output"])

Node.js 18+:

import fs from "fs";

const form = new FormData();
form.append("file", new Blob([fs.readFileSync("call.mp3")]), "call.mp3");
form.append("model", "whisper-1");
form.append("prompt", "Сделай краткое резюме разговора в трёх предложениях.");

const response = await fetch(
  "https://api.nexara.ru/v1/audio/transcriptions",
  {
    method: "POST",
    headers: { Authorization: "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" },
    body: form,
  },
);

const result = await response.json();
console.log(result.llm_output);
package main

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	file, _ := os.Open("call.mp3")
	defer file.Close()

	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)
	part, _ := writer.CreateFormFile("file", "call.mp3")
	io.Copy(part, file)
	writer.WriteField("model", "whisper-1")
	writer.WriteField("prompt", "Сделай краткое резюме разговора в трёх предложениях.")
	writer.Close()

	req, _ := http.NewRequest("POST", "https://api.nexara.ru/v1/audio/transcriptions", &buf)
	req.Header.Set("Authorization", "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX")
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "uri"
require "json"

uri = URI("https://api.nexara.ru/v1/audio/transcriptions")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"
request.set_form(
  [
    ["file", File.open("call.mp3")],
    ["model", "whisper-1"],
    ["prompt", "Сделай краткое резюме разговора в трёх предложениях."],
  ],
  "multipart/form-data",
)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts JSON.parse(response.body)["llm_output"]

В свободном режиме llm_output — это строка с ответом модели:

{
  "transcription": { "task": "transcribe", "text": "...", "segments": [ ... ] },
  "llm_output": "Клиент обратился с вопросом о возврате товара. Оператор объяснил условия и оформил заявку. Стороны договорились о звонке на следующий день."
}

Структурированный вывод

Чтобы получить не текст, а данные с предсказуемой структурой, добавьте json_schemaJSON Schema, описывающую форму ответа. Модель вернёт JSON, который строго ей соответствует, — такой ответ удобно сразу разбирать в коде без парсинга свободного текста.

Как устроена схема

json_schema — это обычная JSON Schema (черновик 2020-12). Обычно это объект ("type": "object") с описанием полей в properties. Основные возможности:

  • Типы полейstring, number, integer, boolean, array, object.
  • Обязательные поля — перечислите их в массиве required, чтобы модель всегда возвращала эти ключи.
  • Фиксированный набор значенийenum ограничивает поле списком допустимых вариантов (удобно для категорий и тональности).
  • Списки"type": "array" с items, описывающим тип элементов.
  • Вложенные объекты — поле само может быть "type": "object" со своими properties.

Например, схема для анализа звонка в поддержку:

{
  "type": "object",
  "properties": {
    "topic": {
      "type": "string",
      "description": "Краткая тема обращения"
    },
    "sentiment": {
      "type": "string",
      "enum": ["положительная", "нейтральная", "отрицательная"]
    },
    "summary": {
      "type": "string",
      "description": "Резюме разговора в одном-двух предложениях"
    },
    "action_items": {
      "type": "array",
      "items": { "type": "string" }
    }
  },
  "required": ["topic", "sentiment", "summary", "action_items"]
}

Схема проверяется при приёме запроса. Если json_schema — не корректная JSON Schema или пустой объект, запрос отклоняется с ошибкой 400 ещё до распознавания. Используйте description у полей, чтобы точнее подсказать модели, что в них ожидается.

Запрос

json_schema передаётся строкой с JSON. В prompt опишите задачу, а форму ответа задаст схема.

curl https://api.nexara.ru/v1/audio/transcriptions \
  -H "Authorization: Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" \
  -F "file=@call.mp3" \
  -F "model=whisper-1" \
  -F "prompt=Проанализируй разговор в поддержке." \
  -F 'json_schema={"type":"object","properties":{"topic":{"type":"string"},"sentiment":{"type":"string","enum":["положительная","нейтральная","отрицательная"]},"summary":{"type":"string"},"action_items":{"type":"array","items":{"type":"string"}}},"required":["topic","sentiment","summary","action_items"]}'
import json
import requests

schema = {
    "type": "object",
    "properties": {
        "topic": {"type": "string"},
        "sentiment": {
            "type": "string",
            "enum": ["положительная", "нейтральная", "отрицательная"],
        },
        "summary": {"type": "string"},
        "action_items": {"type": "array", "items": {"type": "string"}},
    },
    "required": ["topic", "sentiment", "summary", "action_items"],
}

with open("call.mp3", "rb") as audio_file:
    response = requests.post(
        "https://api.nexara.ru/v1/audio/transcriptions",
        headers={"Authorization": "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"},
        files={"file": audio_file},
        data={
            "model": "whisper-1",
            "prompt": "Проанализируй разговор в поддержке.",
            "json_schema": json.dumps(schema),
        },
    )

print(response.json()["llm_output"])

Node.js 18+:

import fs from "fs";

const schema = {
  type: "object",
  properties: {
    topic: { type: "string" },
    sentiment: {
      type: "string",
      enum: ["положительная", "нейтральная", "отрицательная"],
    },
    summary: { type: "string" },
    action_items: { type: "array", items: { type: "string" } },
  },
  required: ["topic", "sentiment", "summary", "action_items"],
};

const form = new FormData();
form.append("file", new Blob([fs.readFileSync("call.mp3")]), "call.mp3");
form.append("model", "whisper-1");
form.append("prompt", "Проанализируй разговор в поддержке.");
form.append("json_schema", JSON.stringify(schema));

const response = await fetch(
  "https://api.nexara.ru/v1/audio/transcriptions",
  {
    method: "POST",
    headers: { Authorization: "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" },
    body: form,
  },
);

const result = await response.json();
console.log(result.llm_output);
package main

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	schema := `{"type":"object","properties":{"topic":{"type":"string"},"sentiment":{"type":"string","enum":["положительная","нейтральная","отрицательная"]},"summary":{"type":"string"},"action_items":{"type":"array","items":{"type":"string"}}},"required":["topic","sentiment","summary","action_items"]}`

	file, _ := os.Open("call.mp3")
	defer file.Close()

	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)
	part, _ := writer.CreateFormFile("file", "call.mp3")
	io.Copy(part, file)
	writer.WriteField("model", "whisper-1")
	writer.WriteField("prompt", "Проанализируй разговор в поддержке.")
	writer.WriteField("json_schema", schema)
	writer.Close()

	req, _ := http.NewRequest("POST", "https://api.nexara.ru/v1/audio/transcriptions", &buf)
	req.Header.Set("Authorization", "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX")
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "uri"
require "json"

schema = {
  "type" => "object",
  "properties" => {
    "topic" => { "type" => "string" },
    "sentiment" => {
      "type" => "string",
      "enum" => ["положительная", "нейтральная", "отрицательная"],
    },
    "summary" => { "type" => "string" },
    "action_items" => { "type" => "array", "items" => { "type" => "string" } },
  },
  "required" => ["topic", "sentiment", "summary", "action_items"],
}

uri = URI("https://api.nexara.ru/v1/audio/transcriptions")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"
request.set_form(
  [
    ["file", File.open("call.mp3")],
    ["model", "whisper-1"],
    ["prompt", "Проанализируй разговор в поддержке."],
    ["json_schema", schema.to_json],
  ],
  "multipart/form-data",
)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts JSON.parse(response.body)["llm_output"]

Теперь llm_output — это JSON-объект, соответствующий вашей схеме:

{
  "transcription": { "task": "transcribe", "text": "...", "segments": [ ... ] },
  "llm_output": {
    "topic": "Возврат товара",
    "sentiment": "нейтральная",
    "summary": "Клиент попросил оформить возврат, оператор объяснил условия и создал заявку.",
    "action_items": [
      "Отправить клиенту инструкцию по возврату",
      "Перезвонить на следующий день"
    ]
  }
}

LLM анализ тарифицируется дополнительно к стоимости распознавания. Стоимость услуги смотрите на странице тарифов.

On this page