Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
Atlaschevron-right

Audio Find - Atlas Vector Search para áudio

Ran Shir, Pavel Duchovny11 min read • Published Sep 09, 2024 • Updated Sep 09, 2024
IADjangoAWSAcionadoresJavaScriptPythonAtlas
SNIPPET
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty

Introdução

À medida que nos afundamos no domínio do áudio digital, as limites da descoberta de músicas estão se expandindo. A busca por uma experiência de áudio mais personalizada nos levou a desenvolver um sistema de catálogo de músicas de última geração. Este sistema não apenas arquiva músicas; ele entende isso. Ao utilizar incorporações avançadas de som e aproveitar o poder do MongoDB Atlas Vector Search, criamos uma plataforma innovadora que recomenda músicas não por gênero ou artista, mas pelas qualidades intrínsecas da própria músicas. Ilustração de pesquisa
Este artigo foi escrito em conjunto com um co-escritor, Ran Shir, compositor musical e fundador da Cues Assets , um grupo de produção musical. Pesquisamos e desenvolvemos a seguinte arquitetura para permitir que as empresas aproveitem seus materiais de áudio para pesquisas.

vídeo de demonstração do fluxo principal

Visão geral da arquitetura do sistema

No centro deste catálogo de músicas está um serviço Python, detalhado em nosso views.py baseado em Django. Esse serviço é o carro-chefe para gerar incorporações de som, usando o modelo de inferência de Panns para analisar e destilar as assinaturas exclusivas de arquivos de áudio carregados pelos usuários. Veja como nosso sofisticado sistema funciona:
Upload e armazenamento de arquivos de áudio:
Um usuário começa fazendo upload de um arquivo MP3 por meio do front-end do aplicativo. Esse arquivo é então transferido com segurança para o Amazon S3, garantindo que o áudio do usuário seja armazenado com segurança na nuvem.
Geração de incorporação de som: quando um arquivo de áudio chega em nosso armazenamento em nuvem, nosso serviço Django entra em ação. Ele baixa o arquivo de S3, usando a biblioteca de solicitações do Python, para um armazenamento temporário no servidor para evitar qualquer perda de dados durante o processamento.
Processamento de normalização e incorporação:
O arquivo de áudio baixado é então processado para extrair seus recursos. Usando a libROSa, uma biblioteca Python para análise de áudio, o serviço carrega o arquivo de áudio e o passa para nosso modelo de inferência de Panns. O modelo, executado em uma GPU para computação acelerada, calcula um vetor de incorporação de membros 4096 brutos que captura a essência do áudio.
Normalização de incorporação:
A incorporação bruta é então normalizada para garantir escalas de comparação consistentes ao realizar pesquisas por similaridade. Essa etapa de normalização é crucial para a eficácia da busca vetorial, permitindo uma recuperação justa e precisa de músicas semelhantes.
Integração do Atlas Vector Search do MongoDB Atlas:
A incorporação normalizada está então pronta para ser ingerida pelo MongoDB Atlas. Aqui, ele é indexado junto com os metadados do arquivo de áudio no campo "embeddings". Essa indexação é o que impulsiona a pesquisa vetorial, permitindo que o aplicativo realize uma pesquisa de K-Nearest Neighbor (KNN) para encontrar e sugerir as músicas mais parecidas com a enviada pelo usuário.
Interação e feedback do usuário:
No front-end, o aplicativo se comunica com o usuário, fornecendo atualizações de status durante o processo de carregamento e, eventualmente, servindo os resultados da similaridade do Atlas Search, tudo de forma amigável e interativa.
Arquitetura de similaridade do catálogo de som
Essa arquitetura encapsula uma mistura de tecnologia de nuvem, aprendizado de máquina e gerenciamento de banco de dados para oferecer uma experiência única de descoberta música que é tão intuitiva quanto disruptiva.

Enviando e armazenando arquivos MP3

A jornada de um arquivo MP3 através do nosso sistema começa no momento em que um usuário seleciona uma faixa para upload. O front-end do aplicativo, criado com a interação do usuário em mente, pega o primeiro arquivo dos arquivos descartados e o prepara para upload. Esse processo é iniciado com uma chamada assíncrona para um endpoint que gera uma URL assinada a partir do AWS S3. Esse URL assinado é uma espécie de token, concedendo permissão temporária para carregar o arquivo diretamente em nosso bucket S3 sem comprometer a segurança ou expor credenciais confidenciais.

Código frontend para upload de arquivos

O código de front-end, normalmente escrito em JavaScript para um aplicativo da Web, usa a bibliotecaaxiospara lidar com solicitações HTTP. Quando o usuário seleciona um arquivo, o código envia uma solicitação ao nosso back-end para recuperar um URL assinado. Com esse URL, o arquivo pode ser carregado no S3. O aplicativo lida com o status do upload, fornecendo feedback em tempo real para o usuário, como "Uploading..." e, em seguida, "Searching based on audio..." após o upload bem-sucedido. Esse ciclo de feedback interativo é fundamental para a satisfação e o envolvimento do usuário.
1async uploadFiles(files) {
2 const file = files[0]; // Get the first file from the dropped files
3 if (file) {
4 try {
5 this.imageStatus = "Uploading...";
6 // Post a request to the backend to get a signed URL for uploading the file
7 const response = await axios.post('https://[backend-endpoint]/getSignedURL', {
8 fileName: file.name,
9 fileType: file.type
10 });
11 const { url } = response.data;
12 // Upload the file to the signed URL
13 const resUpload = await axios.put(url, file, {
14 headers: {
15 'Content-Type': file.type
16 }
17 });
18 console.log('File uploaded successfully');
19 console.log(resUpload.data);
20
21 this.imageStatus = "Searching based on image...";
22 // Post a request to trigger the audio description generation
23 const describeResponse = await axios.post('https://[backend-endpoint]/labelsToDescribe', {
24 fileName: file.name
25 });
26
27 const prompt = describeResponse.data;
28 this.searchQuery = prompt;
29 this.$refs.dropArea.classList.remove('drag-over');
30 if (prompt === "I'm sorry, I can't provide assistance with that request.") {
31 this.imageStatus = "I'm sorry, I can't provide assistance with that request."
32 throw new Error("I'm sorry, I can't provide assistance with that request.");
33 }
34 this.fetchListings();
35 // If the request is successful, show a success message
36 this.showSuccessPopup = true;
37 this.imageStatus = "Drag and drop an image here"
38
39 // Auto-hide the success message after 3 seconds
40 setTimeout(() => {
41 this.showSuccessPopup = false;
42 }, 3000);
43 } catch (error) {
44 console.error('File upload failed:', error);
45 // In case of an error, reset the UI and show an error message
46 this.$refs.dropArea.classList.remove('drag-over');
47 this.showErrorPopup = true;
48
49 // Auto-hide the error message after 3 seconds
50 setTimeout(() => {
51 this.showErrorPopup = false;
52 }, 3000);
53
54 // Reset the status message after 6 seconds
55 setTimeout(() => {
56 this.imageStatus = "Drag and drop an image here"
57 }, 6000);
58
59 }
60 }
61}

Código de back-end para geração de URLs assinados

No backend, uma função sem servidor que interage com o Amazon Web Services SDK. Ele usa credenciais armazenadas Amazon Web Services para acessar S3 e criar uma URL assinada , que é enviada de volta para o frontend. Essa URL contém todas as informações necessárias para o upload do arquivo, incluindo o nome do arquivo, o tipo de conteúdo e as configurações de controle de acesso.
1// Serverless function to generate a signed URL for file uploads to AWS S3
2exports = async function({ query, headers, body}, response) {
3
4 // Import the AWS SDK
5 const AWS = require('aws-sdk');
6
7 // Update the AWS configuration with your access keys and region
8 AWS.config.update({
9 accessKeyId: context.values.get('YOUR_AWS_ACCESS_KEY'), // Replace with your actual AWS access key
10 secretAccessKey: context.values.get('YOUR_AWS_SECRET_KEY'), // Replace with your actual AWS secret key
11 region: 'eu-central-1' // The AWS region where your S3 bucket is hosted
12 });
13
14 // Create a new instance of the S3 service
15 const s3 = new AWS.S3();
16 // Parse the file name and file type from the request body
17 const { fileName, fileType } = JSON.parse(body.text())
18
19 // Define the parameters for the signed URL
20 const params = {
21 Bucket: 'YOUR_S3_BUCKET_NAME', // Replace with your actual S3 bucket name
22 Key: fileName, // The name of the file to be uploaded
23 ContentType: fileType, // The content type of the file to be uploaded
24 ACL: 'public-read' // Access control list setting to allow public read access
25 };
26
27 // Generate the signed URL for the 'putObject' operation
28 const url = await s3.getSignedUrl('putObject', params);
29
30 // Return the signed URL in the response
31 return { 'url' : url }
32};

Incorporação de som com modelo de inferência Panns

Depois que um arquivo MP3 é carregado com segurança para S3, um serviço Python, que interface com nosso backend Django, assume. Esse serviço é onde o arquivo de áudio é transformado em algo mais — uma representação compacta de suas características sonoras conhecida como incorporação de som. Usando a biblioteca librosa, o serviço lê o arquivo de áudio, padronizando a taxa de amostragem para garantir a consistência em todos os arquivos. O modelo de inferência de Panns então pega uma fatia da forma de onda de áudio e infere sua incorporação.
1import tempfile
2from django.http import JsonResponse
3from django.views.decorators.csrf import csrf_exempt
4from panns_inference import AudioTagging
5import librosa
6import numpy as np
7import os
8import json
9import requests
10
11# Function to normalize a vector
12def normalize(v):
13 norm = np.linalg.norm(v)
14 return v / norm if norm != 0 else v
15
16# Function to generate sound embeddings from an audio file
17def get_embedding(audio_file):
18 # Initialize the AudioTagging model with the specified device
19 model = AudioTagging(checkpoint_path=None, device='gpu')
20 # Load the audio file with librosa, normalizing the sample rate to 44100
21 a, _ = librosa.load(audio_file, sr=44100)
22 # Add an extra dimension to the array to fit the model's input requirements
23 query_audio = a[None, :]
24 # Perform inference to get the embedding
25 _, emb = model.inference(query_audio)
26 # Normalize the embedding before returning
27 return normalize(emb[0])
28
29# Django view to handle the POST request for downloading and embedding
30@csrf_exempt
31def download_and_embed(request):
32 if request.method == 'POST':
33 try:
34 # Parse the request body to get the file name
35 body_data = json.loads(request.body.decode('utf-8'))
36 file_name = body_data.get('file_name')
37
38 # If the file name is not provided, return an error
39 if not file_name:
40 return JsonResponse({'error': 'Missing file_name in the request body'}, status=400)
41
42 # Construct the file URL (placeholder) and send a request to get the file
43 file_url = f"https://[s3-bucket-url].amazonaws.com/{file_name}"
44 response = requests.get(file_url)
45
46 # If the file is successfully retrieved
47 if response.status_code == 200:
48 # Create a temporary file to store the downloaded content
49 with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio_file:
50 temp_audio_file.write(response.content)
51 temp_audio_file.flush()
52 # Log the temporary file's name and size for debugging
53 print(f"Temp file: {temp_audio_file.name}, size: {os.path.getsize(temp_audio_file.name)}")
54
55 # Generate the embedding for the downloaded file
56 embedding = get_embedding(temp_audio_file.name)
57 # Return the embedding as a JSON response
58 return JsonResponse({'embedding': embedding.tolist()})
59 else:
60 # If the file could not be downloaded, return an error
61 return JsonResponse({'error': 'Failed to download the file'}, status=400)
62 except json.JSONDecodeError:
63 # If there is an error in the JSON data, return an error
64 return JsonResponse({'error': 'Invalid JSON data in the request body'}, status=400)
65
66 # If the request method is not POST, return an error
67 return JsonResponse({'error': 'Invalid request'}, status=400)

Papel do modelo de inferência de Panns

O modeloPanns-inference é um modelo de aprendizado profundo treinamento para entender e capturar as nuances do conteúdo de áudio. Ele gera um vetor para cada arquivo de áudio, que é uma representação numérica das funcionalidades mais definidoras do arquivo. Esse processo transforma um arquivo de áudio complexo em uma forma simplificada e quantificável que pode ser facilmente comparada a outras.
Para obter mais informações e configurar este modelo, consulte o seguinte exemplo doGithub.

Pesquisa vetorial com o MongoDB Atlas

Armazenando e indexando embeddings no MongoDB Atlas
O MongoDB Atlas é onde a milagrosidade da pesquisa ganha vida. As incorporações geradas pelo nosso serviço Python são armazenadas em uma coleção MongoDB Atlas. O Atlas, com seus recursos de indexação robustos, nos permite indexar essas incorporações de forma eficiente, permitindo pesquisas vetoriais rápidas e precisas. Esta é a definição do índice utilizada na collection “songs:
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "embeddings": {
6 "dimensions": 4096,
7 "similarity": "dotProduct",
8 "type": "knnVector"
9 },
10 "file": {
11 "normalizer": "none",
12 "type": "token"
13 }
14 }
15 }
16}
O campo " file " é indexado com um tipo " token " para a lógica de filtragem de nomes de arquivos, explicada posteriormente neste artigo.
Documento de exemplo da collection de músicas:
1{
2_id : ObjectId("6534dd09164a19b0ac1f7311"),
3 file : "Glorious Outcame Full Mix.mp3",
4embeddings : [Array (4096)]
5}

Funcionalidade do Vector Atlas Search

A pesquisa vetorial no MongoDB Atlas emprega um algoritmo de K-Nearest Neighbor (KNN) para encontrar as incorporações mais próximas daquela fornecida pelo arquivo carregado pelo usuário. Quando um usuário inicia uma pesquisa, o sistema faz uma query da collection do Atlas, pesquisando nas incorporações indexadas para encontrar e retornar uma lista de músicas com os perfis áudio mais semelhantes. Essa combinação de tecnologias — desde o armazenamento S3 da AWS e a geração de URL assinada até a capacidade de processamento do modelo de inferência PANNS, até os recursos de pesquisa do MongoDB Atlas — cria uma experiência perfeita. Os usuários podem não apenas fazer upload de suas faixas favoritas, mas também descobrir novas que carregam uma essência auditiva semelhante, tudo dentro de uma arquitetura criada para escala, velocidade e precisão.
Funcionalidade '"Get Songs " O recurso "Get Songs " é a base do catálogo de músicas, permitindo que os usuários encontrem músicas com um perfil auditório semelhante ao da faixa escolhida. Quando um usuário carrega uma faixa, o sistema não apenas armazena o arquivo; ele procura e sugere ativamente faixas com incorporações de som semelhantes. Isso é feito por meio de uma pesquisa de similaridade, que usa as incorporações de som armazenadas na collection do MongoDB Atlas.
1// Serverless function to perform a similarity search on the 'songs' collection in MongoDB Atlas
2exports = async function({ query, body }, response) {
3 // Initialize the connection to MongoDB Atlas
4 const mongodb = context.services.get('mongodb-atlas');
5 // Connect to the specific database
6 const db = mongodb.db('YourDatabaseName'); // Replace with your actual database name
7 // Connect to the specific collection within the database
8 const songsCollection = db.collection('YourSongsCollectionName'); // Replace with your actual collection name
9
10 // Parse the incoming request body to extract the embedding vector
11 const parsedBody = JSON.parse(body.text());
12 console.log(JSON.stringify(parsedBody)); // Log the parsed body for debugging
13
14 // Perform a vector search using the parsed embedding vector
15 let foundSongs = await songs.aggregate([
16 { "$vectorSearch": {
17 "index" : "default",
18 "queryVector": parsedBody.embedding,
19 "path": "embeddings",
20 "numCandidates": 15,
21 "limit" : 15
22 }
23 }
24 ]).toArray()
25
26 // Map the found songs to a more readable format by stripping unnecessary path components
27 let searchableSongs = foundSongs.map((song) => {
28 // Extract a cleaner, more readable song title
29 let shortName = song.name.replace('.mp3', '');
30 return shortName.replace('.wav', ''); // Handle both .mp3 and .wav file extensions
31 });
32
33 // Prepare an array of $unionWith stages to combine results from multiple collections if needed
34 let unionWithStages = searchableSongs.slice(1).map((songTitle) => {
35 return {
36 $unionWith: {
37 coll: 'RelatedSongsCollection', // Name of the other collection to union with
38 pipeline: [
39 { $match: { "songTitleField": songTitle } }, // Match the song titles against the related collection
40 ],
41 },
42 };
43 });
44
45 // Execute the aggregation query with a $match stage for the first song, followed by any $unionWith stages
46 const relatedSongsCollection = db.collection('YourRelatedSongsCollectionName'); // Replace with your actual related collection name
47 const locatedSongs = await relatedSongsCollection.aggregate([
48 { $match: { "songTitleField": searchableSongs[0] } }, // Start with the first song's match stage
49 ...unionWithStages, // Include additional stages for related songs
50 ]).toArray();
51
52 // Return the array of located songs as the response
53 return locatedSongs;
54};
Como os embeddings são armazenados junto com os dados das músicas, podemos usar o campo de embedding ao fazer uma pesquisa dos N vizinhos mais próximos. Essa abordagem implementa o botão "Mais como esta".
1// Get input song 3 neighbours which are not itself. "More Like This"
2 let foundSongs = await songs.aggregate([
3 { "$vectorSearch": {
4 "index" : "default",
5 "queryVector": songDetails.embeddings,
6 "path": "embeddings",
7 "filter" : { "file" : { "$ne" : fullSongName}},
8 "numCandidates": 15,
9 "limit" : 3
10 }}
11 ]).toArray()
O código filtra a própria música pesquisada.
O código de backend responsável pela pesquisa de similaridade é uma função sem servidor dentro do MongoDB Atlas. Ele executa um pipeline de agregação que começa com um estágio de pesquisa vetorial, aproveitando o $vectorSearch operador com queryVector para realizar uma pesquisa do K- vizinhos mais próximos. A pesquisa é realizada no campo "embeddings", comparando a incorporação da faixa carregada com as da collection para encontrar as correspondências mais próximas. Os resultados são então mapeados para um formato mais legível por humanos, omitindo informações de caminho de arquivo desnecessárias para conveniência do usuário.
1 let foundSongs = await songs.aggregate([
2 { "$vectorSearch": {
3 "index" : "default",
4 "queryVector": parsedBody.embedding,
5 "path": "embeddings",
6 "numCandidates": 15,
7 "limit" : 15
8 }
9 }
10 ]).toArray()

Funcionalidade de front-end

Fazendo upload e pesquisando músicas semelhantes
O front-end fornece uma interface de arrastar e soltar para que os usuários carreguem seus arquivos MP3 facilmente. Depois que um arquivo é selecionado e carregado, o front-end se comunica com o back-end para iniciar a busca por músicas semelhantes com base na incorporação gerada. Esse processo é transparente para o usuário por meio de atualizações de status em tempo real.
** Interface do usuário e mecanismos de feedback **
A interface do usuário foi projetada para ser intuitiva, com indicações claras do processo atual – seja fazendo upload, pesquisando ou exibindo resultados. Os pop-ups de sucesso e erro informam o usuário sobre o status de sua solicitação. Um pop-up de sucesso confirma o upload e a pesquisa bem-sucedida, enquanto um pop-up de erro alerta o usuário sobre qualquer problema que tenha ocorrido durante o processo. Esses pop-ups são projetados para serem desativados automaticamente após um curto período para manter a interface limpa e fácil de usar.

Desafios e soluções

Desafios de desenvolvimento

Um dos desafios enfrentados foi garantir a integração perfeita de vários serviços, como AWS S3, MongoDB Atlas e o serviço Python para incorporações de som. O manuseio de grandes arquivos de áudio e seu processamento eficiente exigiram uma consideração cuidadosa do gerenciamento de arquivos e dos recursos do servidor.

Superando os desafios

Para superar esses problemas, utilizamos armazenamento temporário para processamento e otimizamos o serviço Python para lidar com arquivos grandes sem sobrecarga significativa de memória. Além disso, o uso de funções sem servidor no MongoDB Atlas nos permitido gerenciar recursos de computação de forma eficaz, dimensionando com a demanda conforme necessário.

Conclusão

Este catálogo de músicas representa uma fusão de armazenamento em nuvem, processamento avançado de áudio e recursos modernos do banco de dados Atlas Search. Ele oferece uma maneira alternativa de explorar a músicas pelo som e não pelos metadados, proporcionando aos usuários uma experiência exclusivamente personalizada.
Olhando para o futuro, as melhorias potenciais podem incluir o aprimoramento do modelode inferência de Panns para uma geração de incorporação ainda mais precisa e a expansão do banco de dados para acomodar uma variedade maior de conteúdo de áudio. Refinamentos adicionais na interface do usuário também podem ser feitos, como incorporar feedback do usuário para melhorar o algoritmo de recomendação continuamente. Olhando para o futuro, as melhorias potenciais podem incluir o aprimoramento do modelo para uma geração de incorporação ainda mais precisa e a expansão do banco de dados para acomodar uma variedade maior de conteúdo de áudio. Refinamentos adicionais na interface do usuário também podem ser feitos, como incorporar feedback do usuário para melhorar o algoritmo de recomendação continuamente. Em conclusão, o sistema é uma prova das possibilidades da tecnologia de áudio moderna e do gerenciamento de banco de dados, oferecendo aos usuários uma ferramenta poderosa para descoberta de música e caminhos promissores para desenvolvimento futuro.
Agradecimentos especiais: Ran Shir e Cues Assets group pelo trabalho, esforços de pesquisa e materiais.
Quer continuar a conversa? Encontre-nos nos MongoDB Community!
Principais comentários nos fóruns
Avatar do Comentarista do Fórum
Mona_Li_Sampouco cháúltimo trimestre

Artigo muito interessante

Veja mais nos fóruns

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

Correspondências exatas no Atlas Search: guia para desenvolvedores


Oct 09, 2024 | 5 min read
Tutorial

Raspador da web da bolsa de valores de Nairóbi


Apr 02, 2024 | 20 min read
Tutorial

Como utilizar funções do Azure com MongoDB Atlas em Java


Apr 14, 2023 | 8 min read
Tutorial

Como avaliar seu aplicativo LLM


Jun 24, 2024 | 20 min read
Sumário