Поиск по аудио - это не про слова. Это про чувства
Представьте: у вас терабайты подкастов, интервью, записей встреч. Вы пытаетесь найти момент, где говорили "про важный проект, кажется, в прошлом месяце, голос был взволнованный". Транскрипция через ASR (автоматическое распознавание речи) дает только текст. И вы теряете все - интонацию, сарказм, эмоциональный подтекст, фоновые звуки. Классический поиск по словам тут бессилен.
ASR (Automatic Speech Recognition) - это просто перевод аудио в текст. Он убивает 80% смысла, который передается невербально. Сарказм превращается в утверждение, вопрос - в констатацию факта, а взволнованный тон - в сухой набор слов.
Проблема в том, что аудио - это многомерный сигнал. Текст - лишь одна его проекция. Нам нужен инструмент, который понимает аудио так же, как человек - целостно.
Nova Embeddings V2: аудио как вектор эмоций
Решение пришло от Amazon. Их мультимодальная модель Amazon Nova Multimodal Embeddings V2 (актуальна на апрель 2026) научилась превращать аудио в плотные векторы (эмбеддинги), которые хранят не слова, а смыслы. Это не просто спектрограмма в числах. Модель кодирует семантику, тон, эмоциональную окраску, даже акустические паттерны.
Зачем это? Вы можете искать аудио по описанию на естественном языке ("веселая музыка с синтезатором"), по эмоции ("гневная речь"), по звуковому контексту ("разговор в шумном баре"). Это не магия, а математика близости векторов.
1 Готовим поле боя: аудио перед векторизацией
Сырое аудио - это бесполезный груз для модели. Нужна предобработка. И вот где большинство падает на старте.
# КАК НЕ НАДО ДЕЛАТЬ
import librosa
# Загружаем 2-часовой файл целиком
audio, sr = librosa.load('2_hour_meeting.wav') # Модель просто захлебнется
# И пытаемся получить эмбеддинг
# ...
Amazon Nova Multimodal Embeddings V2, доступная через Bedrock API, принимает аудио в определенном формате. Лучшая практика - сегментировать.
# ПРАВИЛЬНЫЙ ПУТЬ: сегментация по смыслу
import whisperx # Используем современный инструмент для ASR с выравниванием
import numpy as np
def segment_audio_by_speech(audio_path):
device = "cuda" # или "cpu"
model = whisperx.load_model("large-v3", device)
audio = whisperx.load_audio(audio_path)
result = model.transcribe(audio, batch_size=16)
# Выравниваем для точных временных меток
model_a, metadata = whisperx.load_align_model(language_code=result["language"], device=device)
result_aligned = whisperx.align(result["segments"], model_a, metadata, audio, device, return_char_alignments=False)
segments = []
for seg in result_aligned["segments"]:
start, end = seg["start"], seg["end"]
# Извлекаем аудио сегмент (например, с помощью pydub)
audio_segment = audio[int(start*sr):int(end*sr)]
segments.append({
'audio': audio_segment,
'start': start,
'end': end,
'text': seg['text']
})
return segments, audio.shape[0] / sr # возвращаем сегменты и общую длительность
Зачем сегментировать? Потому что эмбеддинг целого часа - это "усреднение" всего, что там было. Вы потеряете детализацию. Идеальный сегмент - 5-30 секунд осмысленной речи или звука. Если у вас музыка, можно сегментировать по ритмическим паттернам (смотрите наш гайд по NEWAVE).
2 Вызов Bedrock API: тонкости, которые съедят ваш бюджет
Допустим, сегменты готовы. Теперь нужно отправить их в модель для получения эмбеддингов. AWS Bedrock предоставляет API. Но есть нюансы, особенно после миграции на Nova V2.
На апрель 2026 актуальна модель amazon.nova-embedding-v2:0. Убедитесь, что ваш регион поддерживает эту модель. Контекстное окно для аудио ограничено, проверяйте документацию - обычно это до 30 секунд аудио на запрос для качественного эмбеддинга.
import boto3
import json
import base64
import io
import soundfile as sf
# Инициализация клиента Bedrock
client = boto3.client('bedrock-runtime', region_name='us-east-1')
def audio_to_embeddings(audio_segment, sample_rate=16000):
"""Конвертируем аудио-сегмент в эмбеддинг через Nova V2."""
# 1. Конвертируем аудио в WAV байты (модель ожидает определенный формат)
buffer = io.BytesIO()
sf.write(buffer, audio_segment, sample_rate, format='WAV')
audio_bytes = buffer.getvalue()
# 2. Кодируем в base64
audio_b64 = base64.b64encode(audio_bytes).decode('utf-8')
# 3. Формируем тело запроса согласно актуальному API на 2026
body = json.dumps({
"inputText": None, # Мы не передаем текст, только аудио
"inputImage": None,
"inputAudio": {
"format": "wav",
"source": {
"bytes": audio_b64
}
},
"embeddingConfig": {
"outputEmbeddingLength": 1024 # Или 4096 для более детальных эмбеддингов (дороже)
}
})
# 4. Вызов API
response = client.invoke_model(
modelId='amazon.nova-embedding-v2:0',
body=body
)
response_body = json.loads(response['body'].read())
# Nova V2 возвращает эмбеддинг в поле 'embedding'
embedding = response_body.get('embedding')
return embedding
Обратите внимание на outputEmbeddingLength. 1024 измерения - это баланс между качеством и стоимостью. Для сложных задач (различение голосов, детальное распознавание эмоций) используйте 4096. Но помните: каждый вызов API стоит денег. Векторизация 1000 часов аудио в 4096-мерном пространстве может обойтись в тысячи долларов. Планируйте бюджет.
Если вы переходите с Nova 1, учтите изменения в API. Детали в нашей инструкции по миграции.
3 Хранилище векторов: куда складывать эти числа
Получили массив чисел для каждого сегмента. Теперь нужно хранить и индексировать. Не вздумайте пихать в PostgreSQL массивом. Это убьет производительность.
Используйте векторные базы данных. На 2026 год топовые варианты:
- Pinecone - managed-сервис, легко начать, но может стать дорогим.
- Weaviate - open-source, с хорошей поддержкой мультимодальности.
- Qdrant - написан на Rust, очень быстрый, облачная версия тоже есть.
- PGVector - расширение для PostgreSQL, если вы уже в экосистеме.
# Пример индексации в Qdrant (актуальный синтаксис на 2026)
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
import uuid
client = QdrantClient(host="localhost", port=6333) # или cloud-адрес
# Создаем коллекцию
client.create_collection(
collection_name="audio_embeddings",
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
# Подготавливаем точки
points = []
for idx, segment in enumerate(segments):
embedding = audio_to_embeddings(segment['audio']) # из предыдущего шага
point = PointStruct(
id=idx,
vector=embedding,
payload={
"audio_path": segment.get('audio_path', ''),
"start_time": segment['start'],
"end_time": segment['end'],
"transcript": segment.get('text', ''), # храним и текст для гибридного поиска
"original_file": "meeting_2026_04_08.wav"
}
)
points.append(point)
# Загружаем батчем
client.upsert(collection_name="audio_embeddings", points=points)
4 Поиск: от голого вектора до смыслового запроса
Теперь самое интересное. Как искать? У вас есть три пути:
- Похожее аудио: у вас есть образец - нашли фрагмент, который нравится, ищите семантически близкие.
- Текстовый запрос: "найди моменты, где говорят взволнованно о дедлайне".
- Гибридный поиск: комбинация семантики (вектор) и ключевых слов (текст транскрипции).
Для текстового запроса нужно превратить текст в вектор в том же пространстве, что и аудио. К счастью, Nova Multimodal Embeddings V2 - это кросс-модальная модель. Она понимает и текст, и аудио, и изображения, и размещает их в одном векторном пространстве.
def text_to_embedding(query_text):
"""Преобразуем текстовый запрос в эмбеддинг с помощью той же модели."""
body = json.dumps({
"inputText": query_text, # Теперь передаем текст
"inputImage": None,
"inputAudio": None,
"embeddingConfig": {
"outputEmbeddingLength": 1024
}
})
response = client.invoke_model(
modelId='amazon.nova-embedding-v2:0',
body=body
)
response_body = json.loads(response['body'].read())
return response_body.get('embedding')
# Пример поиска
query = "радостный смех в толпе"
query_vector = text_to_embedding(query)
# Ищем в Qdrant
search_result = client.search(
collection_name="audio_embeddings",
query_vector=query_vector,
limit=5,
with_payload=True
)
for result in search_result:
print(f"Скор: {result.score}")
print(f"Время: {result.payload['start_time']} - {result.payload['end_time']}")
print(f"Транскрипт: {result.payload['transcript'][:100]}...")
Гибридный поиск - это когда вы комбинируете семантический (векторный) поиск с полнотекстовым по транскрипции. Например, вы ищете "деньги" (ключевое слово) в сочетании с семантикой "нервный смех" (вектор). Реализация зависит от векторной БД. В Weaviate и Qdrant это есть из коробки. Подробнее в нашем руководстве по гибридному поиску для RAG.
Где все ломается: практические грабли
| Ошибка | Почему происходит | Как исправить |
|---|---|---|
| Низкий cosine similarity даже для очевидно похожих аудио | Сегменты слишком длинные или содержат нерелевантный шум. Модель усредняет смыслы. | Сегментируйте по паузам или сменам говорящего. Используйте VAD (Voice Activity Detection). Очищайте аудио от постоянного фонового шума с помощью инструментов вроде RNNoise. |
| Запрос "грустная музыка" находит рок-баллады, а не джазовые композиции | Модель обучена на общих данных. Она может не различать жанровые nuances. | Дообучите модель на своих данных (fine-tuning, если AWS позволяет) или используйте специализированные аудио-эмбеддинги (например, из SLAY-ASR) для конкретной области. |
| Поиск по запросу "что-то сказали про бюджет" возвращает пустоту | Текстовый запрос слишком абстрактный. Модель не понимает местоимения и контекст. | Конкретизируйте запрос. Вместо "что-то сказали" - "обсуждали распределение бюджета на следующий квартал". Или используйте RAG с предварительным извлечением контекста из транскрипции. |
А что если видео? Или прямые трансляции?
Nova Multimodal Embeddings V2 работает и с видео (извлекает ключевые кадры и аудиодорожку). Для поиска по видео в реальном времени (например, мониторинг эфиров) нужно строить потоковый пайплайн: сегментация аудио по окнам (скажем, каждые 10 секунд), быстрая векторизация, поиск по pre-built индексу. Задержка будет определяться скоростью инференса модели. На апрель 2026 AWS Bedrock предлагает асинхронные и batch-вызовы, что ускоряет обработку. Для деталей смотрите наш кейс поиска по видео для геймдева и обзор мультимодального RAG в Bedrock.
Неочевидный совет: заставьте модель слушать как профессионал
Большинство используют Nova Embeddings как черный ящик: засунул аудио - получил вектор. Но вы можете "настроить" внимание модели через prompt-инжиниринг в текстовых запросах. Например, запрос "[акцент на эмоции] радостный смех" даст эмбеддинг, более чувствительный к эмоциональной окраске, чем просто "радостный смех". Экспериментируйте с модификаторами в текстовых запросах. Это тонкая настройка, но она работает, потому что текстовая и аудио-модальности влияют друг на друга внутри модели.
И последнее: не забывайте про стоимость. Векторизация 1 часа аудио в 4096-мерном пространстве с помощью Nova V2 может стоить около $2-5 (цены на 2026). Умножьте на ваши объемы. Иногда дешевле и эффективнее использовать каскадную архитектуру: сначала быстрый и дешевый фильтр по ключевым словам (ASR + Elasticsearch), а потом семантический поиск только по отфильтрованным сегментам. Как в революционной архитектуре Amazon Nova Sonic, но наоборот.
Семантический поиск по аудио - это не будущее. Это настоящее, которое требует внимания к деталям. От сегментации до выбора размерности вектора. Ошибитесь на старте - получите дорогую и бесполезную систему. Сделайте правильно - и ваши аудиоархивы заговорят на языке эмоций, который вы наконец-то сможете понять.