AACSearch
Руководства

Голос и изображения

Поиск по записи и по картинке — POST /voice и POST /image, оба сначала превращают вход в текстовый запрос.

Оба эндпоинта решают одну задачу: в индексе текст, а у пользователя — что-то другое. Платформа преобразует вход в запрос и выполняет обычный поиск с фильтром тенанта, поэтому фильтры, фасеты и квоты ведут себя так же, как при набранном запросе.

Голос

curl -sS -X POST "$AAC_API/indexes/documentation/voice" \
  -H "Authorization: Bearer $AAC_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile audio clip.webm \
    '{ audio: ($audio | @base64), mime_type: "webm", language: "ru" }')"
{
	"index": "documentation",
	"mode": "ai",
	"transcript": "сколько стоит тариф pro",
	"found": 3,
	"hits": [
		{
			"id": "pricing",
			"score": 2180,
			"document": { "title": "Тарифы", "url": "https://example.com/pricing" },
			"highlights": []
		}
	],
	"latency_ms": 940,
	"charged_cents": 0,
	"request_id": "req_1a3c5e7b9d0f2a4c6e8b0d1f"
}
ПолеТипКомментарий
audiostringАудио в base64, от 16 символов до 8 МБ
mime_typestringwav (по умолчанию), mp3, webm, ogg, m4a
languagestring ≤ 8Подсказка языка в формате ISO
model_idstring ≤ 128Голосовая модель движка; использует настроенную голосовую модель
query_bystringПоля для получившегося запроса

Два режима работы

  1. Распознавание ИИ (mode: "ai"). Если функция настроена, платформа распознаёт аудио и ищет по полученному тексту. Ответ содержит transcript и обычные результаты поиска.
  2. Управляемое распознавание (mode: "native"). Настроенная голосовая модель распознаёт аудио. Полученный текст проходит общий поиск с проверкой организации, доступа к документам, приватных полей и квот. Ответ использует контракт поиска приложения:
{
	"index": "documentation",
	"mode": "native",
	"transcript": "example query",
	"found": 2,
	"hits": [],
	"result": { "transcription": "example query", "results": [{ "found": 2, "hits": [] }] },
	"request_id": "req_7c9e1b3d5f7a9c1e3b5d7f9a"
}

Ошибки

СтатусКодПричина
422EMPTY_TRANSCRIPTIONАудио декодировано, но речи в нём нет
422INVALID_AUDIOПолезную нагрузку не удалось декодировать как аудио
413AUDIO_TOO_LARGEФрагмент превышает допустимый размер
503VOICE_MODEL_NOT_CONFIGUREDГолосовой поиск не настроен для этого развёртывания

Голосовой поиск списывает одну единицу поиска, а транскрипт попадает в журнал аудита — не отправляйте аудио с секретами, которые не хотели бы видеть в логах.

Изображение

curl -sS -X POST "$AAC_API/indexes/documentation/image" \
  -H "Authorization: Bearer $AAC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/uploads/price-table.png",
    "hint": "скриншот таблицы тарифов",
    "query_by": "title,content",
    "per_page": 5
  }'
{
	"index": "documentation",
	"mode": "ai",
	"description": "таблица сравнения тарифов с помесячной оплатой",
	"model": "gpt-4o-mini",
	"found": 2,
	"hits": [
		{
			"id": "pricing",
			"score": 1540,
			"document": { "title": "Тарифы", "url": "https://example.com/pricing" },
			"highlights": []
		}
	],
	"latency_ms": 1180,
	"charged_cents": 0,
	"request_id": "req_3e5b7d9f1a3c5e7b9d1f3a5c"
}
ПолеТипКомментарий
imagestringBase64 или http(s)-URL, от 16 символов до 12 МБ
mime_typestringОпционально; для URL определяется автоматически
hintstring ≤ 200Дополнительный контекст для модели («какой тариф выделен?»)
query_bystringПоля для сгенерированного запроса
filter_bystring ≤ 1000Сузить набор кандидатов до ранжирования
per_pageint 1–50По умолчанию 10, жёсткий потолок 50

description — промежуточный запрос, который построила модель. Его стоит показывать в отладочной панели, писать в лог или возвращать пользователю как «ищем: …» — тогда странная выдача становится объяснимой.

Ошибки

Поиску по изображению нужен провайдер, запасного пути через движок нет:

{
	"error": {
		"code": "AI_NOT_CONFIGURED",
		"message": "Set OPENAI_API_KEY to use image search",
		"request_id": "req_9f1b3d5c7a9e1b3d5f7c9a1b"
	}
}

Это 503. Слишком большой или некорректный image отклоняется валидацией как 422 VALIDATION_ERROR ещё до вызова провайдера.

Что это и что это не

  • Это текстовый поиск с другим вводом. Изображение описывается словами и сопоставляется с текстом. Скриншот графика не найдёт «документ с похожим графиком».
  • Это не CLIP и не мультимодальный индекс. Векторы изображений не хранятся. Если нужна визуальная близость, держите свой конвейер векторов и используйте vector_query в /search.
  • Стоимость разная. Голосовые и графические вызовы списывают единицу поиска плюс AI-токены за описание или транскрипт; charged_cents показывает списание с кошелька.

Как встроить в интерфейс

Браузерную часть для голоса умеет готовый виджет: включите Voice search в панели встраивания, и в строке поиска появится виджет voiceSearch из InstantSearch, использующий Speech Recognition браузера — на этом пути аудио вообще не покидает клиент. Для своего интерфейса:

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
const chunks: Blob[] = [];

recorder.ondataavailable = (event) => chunks.push(event.data);
recorder.onstop = async () => {
	const base64 = await new Promise<string>((resolve) => {
		const reader = new FileReader();
		reader.onload = () => resolve(String(reader.result).split(",")[1] ?? "");
		reader.readAsDataURL(new Blob(chunks, { type: "audio/webm" }));
	});

	const response = await fetch("/api/v1/indexes/documentation/voice", {
		method: "POST",
		headers: { Authorization: `Bearer ${sessionKey}`, "Content-Type": "application/json" },
		body: JSON.stringify({ audio: base64, mime_type: "webm" }),
	});
	const { transcript, hits } = await response.json();
	render(transcript, hits);
};

recorder.start();

Никогда не вызывайте этот эндпоинт из браузера с ключом aac_live_…: выпускайте ограниченный ключ на сервере (Сессия встраивания) или проксируйте вызов через бэкенд — для голоса и изображений это лучший вариант, потому что нагрузки большие, а вызовы дорогие.

On this page