From b1f11ccd652b16b2c2fbe81b5321d721a83135a0 Mon Sep 17 00:00:00 2001 From: qingen Date: Tue, 8 Mar 2022 17:43:36 +0800 Subject: [PATCH 1/9] [wip][vec] add demo for searching vectors base on MySQL and Milvus, test=doc #1543 --- demos/audio_searching/README.md | 95 +++++++++ demos/audio_searching/docker-compose.yaml | 73 +++++++ demos/audio_searching/requirements.txt | 12 ++ demos/audio_searching/src/config.py | 37 ++++ demos/audio_searching/src/encode.py | 37 ++++ demos/audio_searching/src/logs.py | 164 +++++++++++++++ demos/audio_searching/src/main.py | 166 ++++++++++++++++ demos/audio_searching/src/milvus_helpers.py | 186 ++++++++++++++++++ demos/audio_searching/src/mysql_helpers.py | 133 +++++++++++++ .../src/operations/__init__.py | 13 ++ demos/audio_searching/src/operations/count.py | 33 ++++ demos/audio_searching/src/operations/drop.py | 34 ++++ demos/audio_searching/src/operations/load.py | 86 ++++++++ .../audio_searching/src/operations/search.py | 40 ++++ demos/audio_searching/src/test_main.py | 96 +++++++++ 15 files changed, 1205 insertions(+) create mode 100644 demos/audio_searching/README.md create mode 100644 demos/audio_searching/docker-compose.yaml create mode 100644 demos/audio_searching/requirements.txt create mode 100644 demos/audio_searching/src/config.py create mode 100644 demos/audio_searching/src/encode.py create mode 100644 demos/audio_searching/src/logs.py create mode 100644 demos/audio_searching/src/main.py create mode 100644 demos/audio_searching/src/milvus_helpers.py create mode 100644 demos/audio_searching/src/mysql_helpers.py create mode 100644 demos/audio_searching/src/operations/__init__.py create mode 100644 demos/audio_searching/src/operations/count.py create mode 100644 demos/audio_searching/src/operations/drop.py create mode 100644 demos/audio_searching/src/operations/load.py create mode 100644 demos/audio_searching/src/operations/search.py create mode 100644 demos/audio_searching/src/test_main.py diff --git a/demos/audio_searching/README.md b/demos/audio_searching/README.md new file mode 100644 index 000000000..0ee781ad2 --- /dev/null +++ b/demos/audio_searching/README.md @@ -0,0 +1,95 @@ +([简体中文](./README_cn.md)|English) + +# Audio Searching + +## Introduction +This demo uses ECAPA-TDNN(or other models) for Speaker Recognition base on MySQL to store user-info/id and Milvus to search vectors. + +## Usage +### 1. Prepare MySQL and Milvus services by docker-compose +The molecular similarity search system requires Milvus, MySQL services. We can start these containers with one click through [docker-compose.yaml](./docker-compose.yaml), so please make sure you have [installed Docker Engine](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) before running. then + +```bash +docker-compose -f docker-compose.yaml up -d +``` + +Then you will see the that all containers are created: + +```bash +Creating network "quick_deploy_app_net" with driver "bridge" +Creating milvus-minio ... done +Creating milvus-etcd ... done +Creating audio-mysql ... done +Creating milvus-standalone ... done +``` + +And show all containers with `docker ps`, and you can use `docker logs audio-mysql` to get the logs of server container + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +b2bcf279e599 milvusdb/milvus:v2.0.1 "/tini -- milvus run…" 22 hours ago Up 22 hours 0.0.0.0:19530->19530/tcp milvus-standalone +d8ef4c84e25c mysql:5.7 "docker-entrypoint.s…" 22 hours ago Up 22 hours 0.0.0.0:3306->3306/tcp, 33060/tcp audio-mysql +8fb501edb4f3 quay.io/coreos/etcd:v3.5.0 "etcd -advertise-cli…" 22 hours ago Up 22 hours 2379-2380/tcp milvus-etcd +ffce340b3790 minio/minio:RELEASE.2020-12-03T00-03-10Z "/usr/bin/docker-ent…" 22 hours ago Up 22 hours (healthy) 9000/tcp milvus-minio + +``` + +### 2. Start API Server +Then to start the system server, and it provides HTTP backend services. + +- Install the Python packages + +```bash +pip install -r requirements.txt +``` +- Set configuration + +```bash +vim src/config.py +``` + +Modify the parameters according to your own environment. Here listing some parameters that need to be set, for more information please refer to [config.py](./src/config.py). + +| **Parameter** | **Description** | **Default setting** | +| ---------------- | ----------------------------------------------------- | ------------------- | +| MILVUS_HOST | The IP address of Milvus, you can get it by ifconfig. If running everything on one machine, most likely 127.0.0.1 | 127.0.0.1 | +| MILVUS_PORT | Port of Milvus. | 19530 | +| VECTOR_DIMENSION | Dimension of the vectors. | 2048 | +| MYSQL_HOST | The IP address of Mysql. | 127.0.0.1 | +| MYSQL_PORT | Port of Milvus. | 3306 | +| DEFAULT_TABLE | The milvus and mysql default collection name. | audio_table | + +- Run the code + +Then start the server with Fastapi. + +```bash +python src/main.py +``` + +Then you will see the Application is started: + +```bash +INFO: Started server process [3949] +2022-03-07 17:39:14,864 | INFO | server.py | serve | 75 | Started server process [3949] +INFO: Waiting for application startup. +2022-03-07 17:39:14,865 | INFO | on.py | startup | 45 | Waiting for application startup. +INFO: Application startup complete. +2022-03-07 17:39:14,866 | INFO | on.py | startup | 59 | Application startup complete. +INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) +2022-03-07 17:39:14,867 | INFO | server.py | _log_started_message | 206 | Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) +``` + +### 3. Usage + + ```bash + python ./src/test_main.py + ``` + +### 4.Pretrained Models + +Here is a list of pretrained models released by PaddleSpeech that can be used by command and python API: + +| Model | Sample Rate +| :--- | :---: +| ecapa_tdnn | 16000 diff --git a/demos/audio_searching/docker-compose.yaml b/demos/audio_searching/docker-compose.yaml new file mode 100644 index 000000000..7e16ee8a0 --- /dev/null +++ b/demos/audio_searching/docker-compose.yaml @@ -0,0 +1,73 @@ +version: '3.5' + +services: + etcd: + container_name: milvus-etcd + image: quay.io/coreos/etcd:v3.5.0 + networks: + app_net: + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd + command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + + minio: + container_name: milvus-minio + image: minio/minio:RELEASE.2020-12-03T00-03-10Z + networks: + app_net: + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data + command: minio server /minio_data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + standalone: + container_name: milvus-standalone + image: milvusdb/milvus:v2.0.1 + networks: + app_net: + ipv4_address: 172.16.23.10 + command: ["milvus", "run", "standalone"] + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus + ports: + - "19530:19530" + depends_on: + - "etcd" + - "minio" + + + mysql: + container_name: audio-mysql + image: mysql:5.7 + networks: + app_net: + ipv4_address: 172.16.23.11 + environment: + - MYSQL_ROOT_PASSWORD=123456 + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/mysql:/var/lib/mysql + ports: + - "3306:3306" + +networks: + app_net: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.16.23.0/24 + gateway: 172.16.23.1 diff --git a/demos/audio_searching/requirements.txt b/demos/audio_searching/requirements.txt new file mode 100644 index 000000000..9e73361b4 --- /dev/null +++ b/demos/audio_searching/requirements.txt @@ -0,0 +1,12 @@ +soundfile==0.10.3.post1 +librosa==0.8.0 +numpy +pymysql +fastapi +uvicorn +diskcache==5.2.1 +pymilvus==2.0.1 +python-multipart +typing +starlette +pydantic \ No newline at end of file diff --git a/demos/audio_searching/src/config.py b/demos/audio_searching/src/config.py new file mode 100644 index 000000000..72a8fb4be --- /dev/null +++ b/demos/audio_searching/src/config.py @@ -0,0 +1,37 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +############### Milvus Configuration ############### +MILVUS_HOST = os.getenv("MILVUS_HOST", "127.0.0.1") +MILVUS_PORT = int(os.getenv("MILVUS_PORT", "19530")) +VECTOR_DIMENSION = int(os.getenv("VECTOR_DIMENSION", "2048")) +INDEX_FILE_SIZE = int(os.getenv("INDEX_FILE_SIZE", "1024")) +METRIC_TYPE = os.getenv("METRIC_TYPE", "L2") +DEFAULT_TABLE = os.getenv("DEFAULT_TABLE", "audio_table") +TOP_K = int(os.getenv("TOP_K", "10")) + +############### MySQL Configuration ############### +MYSQL_HOST = os.getenv("MYSQL_HOST", "127.0.0.1") +MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306")) +MYSQL_USER = os.getenv("MYSQL_USER", "root") +MYSQL_PWD = os.getenv("MYSQL_PWD", "123456") +MYSQL_DB = os.getenv("MYSQL_DB", "mysql") + +############### Data Path ############### +UPLOAD_PATH = os.getenv("UPLOAD_PATH", "tmp/audio-data") + +############### Number of Log Files ############### +LOGS_NUM = int(os.getenv("logs_num", "0")) diff --git a/demos/audio_searching/src/encode.py b/demos/audio_searching/src/encode.py new file mode 100644 index 000000000..391822c76 --- /dev/null +++ b/demos/audio_searching/src/encode.py @@ -0,0 +1,37 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import librosa +import numpy as np +from logs import LOGGER + + +def get_audio_embedding(path): + """ + Use vpr_inference to generate embedding of audio + """ + try: + RESAMPLE_RATE = 16000 + audio, _ = librosa.load(path, sr=RESAMPLE_RATE, mono=True) + + # TODO add infer/python interface to get embedding, now fake it by rand + # vpr = ECAPATDNN(checkpoint_path=None, device='cuda') + # embedding = vpr.inference(audio) + + embedding = np.random.rand(1, 2048) + embedding = embedding / np.linalg.norm(embedding) + embedding = embedding.tolist()[0] + return embedding + except Exception as e: + LOGGER.error(f"Error with embedding:{e}") + return None diff --git a/demos/audio_searching/src/logs.py b/demos/audio_searching/src/logs.py new file mode 100644 index 000000000..ba3ed069c --- /dev/null +++ b/demos/audio_searching/src/logs.py @@ -0,0 +1,164 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import codecs +import datetime +import logging +import os +import re +import sys + +from config import LOGS_NUM + + +class MultiprocessHandler(logging.FileHandler): + """ + A handler class which writes formatted logging records to disk files + """ + + def __init__(self, + filename, + when='D', + backupCount=0, + encoding=None, + delay=False): + """ + Open the specified file and use it as the stream for logging + """ + self.prefix = filename + self.backupCount = backupCount + self.when = when.upper() + self.extMath = r"^\d{4}-\d{2}-\d{2}" + + self.when_dict = { + 'S': "%Y-%m-%d-%H-%M-%S", + 'M': "%Y-%m-%d-%H-%M", + 'H': "%Y-%m-%d-%H", + 'D': "%Y-%m-%d" + } + + self.suffix = self.when_dict.get(when) + if not self.suffix: + print('The specified date interval unit is invalid: ', self.when) + sys.exit(1) + + self.filefmt = os.path.join('.', "logs", + f"{self.prefix}-{self.suffix}.log") + + self.filePath = datetime.datetime.now().strftime(self.filefmt) + + _dir = os.path.dirname(self.filefmt) + try: + if not os.path.exists(_dir): + os.makedirs(_dir) + except Exception as e: + print('Failed to create log file: ', e) + print("log_path:" + self.filePath) + sys.exit(1) + + logging.FileHandler.__init__(self, self.filePath, 'a+', encoding, delay) + + def should_change_file_to_write(self): + """ + To write the file + """ + _filePath = datetime.datetime.now().strftime(self.filefmt) + if _filePath != self.filePath: + self.filePath = _filePath + return True + return False + + def do_change_file(self): + """ + To change file states + """ + self.baseFilename = os.path.abspath(self.filePath) + if self.stream: + self.stream.close() + self.stream = None + + if not self.delay: + self.stream = self._open() + if self.backupCount > 0: + for s in self.get_files_to_delete(): + os.remove(s) + + def get_files_to_delete(self): + """ + To delete backup files + """ + dir_name, _ = os.path.split(self.baseFilename) + file_names = os.listdir(dir_name) + result = [] + prefix = self.prefix + '-' + for file_name in file_names: + if file_name[:len(prefix)] == prefix: + suffix = file_name[len(prefix):-4] + if re.compile(self.extMath).match(suffix): + result.append(os.path.join(dir_name, file_name)) + result.sort() + + if len(result) < self.backupCount: + result = [] + else: + result = result[:len(result) - self.backupCount] + return result + + def emit(self, record): + """ + Emit a record + """ + try: + if self.should_change_file_to_write(): + self.do_change_file() + logging.FileHandler.emit(self, record) + except (KeyboardInterrupt, SystemExit): + raise + except: + self.handleError(record) + + +def write_log(): + """ + Init a logger + """ + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + # formatter = '%(asctime)s | %(levelname)s | %(filename)s | %(funcName)s | %(module)s | %(lineno)s | %(message)s' + fmt = logging.Formatter( + '%(asctime)s | %(levelname)s | %(filename)s | %(funcName)s | %(lineno)s | %(message)s' + ) + + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.INFO) + stream_handler.setFormatter(fmt) + + log_name = "audio-searching" + file_handler = MultiprocessHandler(log_name, when='D', backupCount=LOGS_NUM) + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(fmt) + file_handler.do_change_file() + + logger.addHandler(stream_handler) + logger.addHandler(file_handler) + + return logger + + +LOGGER = write_log() + +if __name__ == "__main__": + message = 'test writing logs' + LOGGER.info(message) + LOGGER.debug(message) + LOGGER.error(message) diff --git a/demos/audio_searching/src/main.py b/demos/audio_searching/src/main.py new file mode 100644 index 000000000..89c037a0e --- /dev/null +++ b/demos/audio_searching/src/main.py @@ -0,0 +1,166 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from typing import Optional + +import uvicorn +from config import UPLOAD_PATH +from diskcache import Cache +from fastapi import FastAPI +from fastapi import File +from fastapi import UploadFile +from logs import LOGGER +from milvus_helpers import MilvusHelper +from mysql_helpers import MySQLHelper +from operations.count import do_count +from operations.drop import do_drop +from operations.load import do_load +from operations.search import do_search +from pydantic import BaseModel +from starlette.middleware.cors import CORSMiddleware +from starlette.requests import Request +from starlette.responses import FileResponse + +app = FastAPI() +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"]) + +MODEL = None +MILVUS_CLI = MilvusHelper() +MYSQL_CLI = MySQLHelper() + +# Mkdir 'tmp/audio-data' +if not os.path.exists(UPLOAD_PATH): + os.makedirs(UPLOAD_PATH) + LOGGER.info(f"Mkdir the path: {UPLOAD_PATH}") + + +@app.get('/data') +def audio_path(audio_path): + # Get the audio file + try: + LOGGER.info(f"Successfully load audio: {audio_path}") + return FileResponse(audio_path) + except Exception as e: + LOGGER.error(f"upload audio error: {e}") + return {'status': False, 'msg': e}, 400 + + +@app.get('/progress') +def get_progress(): + # Get the progress of dealing with data + try: + cache = Cache('./tmp') + return f"current: {cache['current']}, total: {cache['total']}" + except Exception as e: + LOGGER.error(f"Upload data error: {e}") + return {'status': False, 'msg': e}, 400 + + +class Item(BaseModel): + Table: Optional[str] = None + File: str + + +@app.post('/audio/load') +async def load_audios(item: Item): + # Insert all the audio files under the file path to Milvus/MySQL + try: + total_num = do_load(item.Table, item.File, MILVUS_CLI, MYSQL_CLI) + LOGGER.info(f"Successfully loaded data, total count: {total_num}") + return {'status': True, 'msg': "Successfully loaded data!"} + except Exception as e: + LOGGER.error(e) + return {'status': False, 'msg': e}, 400 + + +@app.post('/audio/search') +async def search_audio(request: Request, + table_name: str=None, + audio: UploadFile=File(...)): + # Search the uploaded audio in Milvus/MySQL + try: + # Save the upload data to server. + content = await audio.read() + query_audio_path = os.path.join(UPLOAD_PATH, audio.filename) + with open(query_audio_path, "wb+") as f: + f.write(content) + host = request.headers['host'] + _, paths, distances = do_search(host, table_name, query_audio_path, + MILVUS_CLI, MYSQL_CLI) + names = [] + for i in paths: + names.append(os.path.basename(i)) + res = dict(zip(paths, zip(names, distances))) + # Sort results by distance metric, closest distances first + res = sorted(res.items(), key=lambda item: item[1][1]) + LOGGER.info("Successfully searched similar audio!") + return res + except Exception as e: + LOGGER.error(e) + return {'status': False, 'msg': e}, 400 + + +@app.post('/audio/search/local') +async def search_local_audio(request: Request, + query_audio_path: str, + table_name: str=None): + # Search the uploaded audio in Milvus/MySQL + try: + host = request.headers['host'] + _, paths, distances = do_search(host, table_name, query_audio_path, + MILVUS_CLI, MYSQL_CLI) + names = [] + for i in paths: + names.append(os.path.basename(i)) + res = dict(zip(paths, zip(names, distances))) + # Sort results by distance metric, closest distances first + res = sorted(res.items(), key=lambda item: item[1][1]) + LOGGER.info("Successfully searched similar audio!") + return res + except Exception as e: + LOGGER.error(e) + return {'status': False, 'msg': e}, 400 + + +@app.get('/audio/count') +async def count_audio(table_name: str=None): + # Returns the total number of vectors in the system + try: + num = do_count(table_name, MILVUS_CLI) + LOGGER.info("Successfully count the number of data!") + return num + except Exception as e: + LOGGER.error(e) + return {'status': False, 'msg': e}, 400 + + +@app.post('/audio/drop') +async def drop_tables(table_name: str=None): + # Delete the collection of Milvus and MySQL + try: + status = do_drop(table_name, MILVUS_CLI, MYSQL_CLI) + LOGGER.info("Successfully drop tables in Milvus and MySQL!") + return status + except Exception as e: + LOGGER.error(e) + return {'status': False, 'msg': e}, 400 + + +if __name__ == '__main__': + uvicorn.run(app=app, host='127.0.0.1', port=8002) diff --git a/demos/audio_searching/src/milvus_helpers.py b/demos/audio_searching/src/milvus_helpers.py new file mode 100644 index 000000000..8ba3776be --- /dev/null +++ b/demos/audio_searching/src/milvus_helpers.py @@ -0,0 +1,186 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys + +from config import METRIC_TYPE +from config import MILVUS_HOST +from config import MILVUS_PORT +from config import VECTOR_DIMENSION +from logs import LOGGER +from pymilvus import Collection +from pymilvus import CollectionSchema +from pymilvus import connections +from pymilvus import DataType +from pymilvus import FieldSchema +from pymilvus import utility + + +class MilvusHelper: + """ + the basic operations of PyMilvus + + # This example shows how to: + # 1. connect to Milvus server + # 2. create a collection + # 3. insert entities + # 4. create index + # 5. search + # 6. delete a collection + + """ + + def __init__(self): + try: + self.collection = None + connections.connect(host=MILVUS_HOST, port=MILVUS_PORT) + LOGGER.debug( + f"Successfully connect to Milvus with IP:{MILVUS_HOST} and PORT:{MILVUS_PORT}" + ) + except Exception as e: + LOGGER.error(f"Failed to connect Milvus: {e}") + sys.exit(1) + + def set_collection(self, collection_name): + try: + if self.has_collection(collection_name): + self.collection = Collection(name=collection_name) + else: + raise Exception( + f"There is no collection named:{collection_name}") + except Exception as e: + LOGGER.error(f"Failed to load data to Milvus: {e}") + sys.exit(1) + + def has_collection(self, collection_name): + # Return if Milvus has the collection + try: + return utility.has_collection(collection_name) + except Exception as e: + LOGGER.error(f"Failed to load data to Milvus: {e}") + sys.exit(1) + + def create_collection(self, collection_name): + # Create milvus collection if not exists + try: + if not self.has_collection(collection_name): + field1 = FieldSchema( + name="id", + dtype=DataType.INT64, + descrition="int64", + is_primary=True, + auto_id=True) + field2 = FieldSchema( + name="embedding", + dtype=DataType.FLOAT_VECTOR, + descrition="speaker embeddings", + dim=VECTOR_DIMENSION, + is_primary=False) + schema = CollectionSchema( + fields=[field1, field2], description="embeddings info") + self.collection = Collection( + name=collection_name, schema=schema) + LOGGER.debug(f"Create Milvus collection: {collection_name}") + else: + self.set_collection(collection_name) + return "OK" + except Exception as e: + LOGGER.error(f"Failed to load data to Milvus: {e}") + sys.exit(1) + + def insert(self, collection_name, vectors): + # Batch insert vectors to milvus collection + try: + self.create_collection(collection_name) + data = [vectors] + self.set_collection(collection_name) + mr = self.collection.insert(data) + ids = mr.primary_keys + self.collection.load() + LOGGER.debug( + f"Insert vectors to Milvus in collection: {collection_name} with {len(vectors)} rows" + ) + return ids + except Exception as e: + LOGGER.error(f"Failed to load data to Milvus: {e}") + sys.exit(1) + + def create_index(self, collection_name): + # Create IVF_FLAT index on milvus collection + try: + self.set_collection(collection_name) + default_index = { + "index_type": "IVF_SQ8", + "metric_type": METRIC_TYPE, + "params": { + "nlist": 16384 + } + } + status = self.collection.create_index( + field_name="embedding", index_params=default_index) + if not status.code: + LOGGER.debug( + f"Successfully create index in collection:{collection_name} with param:{default_index}" + ) + return status + else: + raise Exception(status.message) + except Exception as e: + LOGGER.error(f"Failed to create index: {e}") + sys.exit(1) + + def delete_collection(self, collection_name): + # Delete Milvus collection + try: + self.set_collection(collection_name) + self.collection.drop() + LOGGER.debug("Successfully drop collection!") + return "ok" + except Exception as e: + LOGGER.error(f"Failed to drop collection: {e}") + sys.exit(1) + + def search_vectors(self, collection_name, vectors, top_k): + # Search vector in milvus collection + try: + self.set_collection(collection_name) + search_params = { + "metric_type": METRIC_TYPE, + "params": { + "nprobe": 16 + } + } + # data = [vectors] + res = self.collection.search( + vectors, + anns_field="embedding", + param=search_params, + limit=top_k) + LOGGER.debug(f"Successfully search in collection: {res}") + return res + except Exception as e: + LOGGER.error(f"Failed to search vectors in Milvus: {e}") + sys.exit(1) + + def count(self, collection_name): + # Get the number of milvus collection + try: + self.set_collection(collection_name) + num = self.collection.num_entities + LOGGER.debug( + f"Successfully get the num:{num} of the collection:{collection_name}" + ) + return num + except Exception as e: + LOGGER.error(f"Failed to count vectors in Milvus: {e}") + sys.exit(1) diff --git a/demos/audio_searching/src/mysql_helpers.py b/demos/audio_searching/src/mysql_helpers.py new file mode 100644 index 000000000..303838399 --- /dev/null +++ b/demos/audio_searching/src/mysql_helpers.py @@ -0,0 +1,133 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys + +import pymysql +from config import MYSQL_DB +from config import MYSQL_HOST +from config import MYSQL_PORT +from config import MYSQL_PWD +from config import MYSQL_USER +from logs import LOGGER + + +class MySQLHelper(): + """ + the basic operations of PyMySQL + + # This example shows how to: + # 1. connect to MySQL server + # 2. create a table + # 3. insert data to table + # 4. search by milvus ids + # 5. delete table + """ + + def __init__(self): + self.conn = pymysql.connect( + host=MYSQL_HOST, + user=MYSQL_USER, + port=MYSQL_PORT, + password=MYSQL_PWD, + database=MYSQL_DB, + local_infile=True) + self.cursor = self.conn.cursor() + + def test_connection(self): + try: + self.conn.ping() + except Exception: + self.conn = pymysql.connect( + host=MYSQL_HOST, + user=MYSQL_USER, + port=MYSQL_PORT, + password=MYSQL_PWD, + database=MYSQL_DB, + local_infile=True) + self.cursor = self.conn.cursor() + + def create_mysql_table(self, table_name): + # Create mysql table if not exists + self.test_connection() + sql = "create table if not exists " + table_name + "(milvus_id TEXT, audio_path TEXT);" + try: + self.cursor.execute(sql) + LOGGER.debug(f"MYSQL create table: {table_name} with sql: {sql}") + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) + + def load_data_to_mysql(self, table_name, data): + # Batch insert (Milvus_ids, img_path) to mysql + self.test_connection() + sql = "insert into " + table_name + " (milvus_id,audio_path) values (%s,%s);" + try: + self.cursor.executemany(sql, data) + self.conn.commit() + LOGGER.debug( + f"MYSQL loads data to table: {table_name} successfully") + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) + + def search_by_milvus_ids(self, ids, table_name): + # Get the img_path according to the milvus ids + self.test_connection() + str_ids = str(ids).replace('[', '').replace(']', '') + sql = "select audio_path from " + table_name + " where milvus_id in (" + str_ids + ") order by field (milvus_id," + str_ids + ");" + try: + self.cursor.execute(sql) + results = self.cursor.fetchall() + results = [res[0] for res in results] + LOGGER.debug("MYSQL search by milvus id.") + return results + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) + + def delete_table(self, table_name): + # Delete mysql table if exists + self.test_connection() + sql = "drop table if exists " + table_name + ";" + try: + self.cursor.execute(sql) + LOGGER.debug(f"MYSQL delete table:{table_name}") + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) + + def delete_all_data(self, table_name): + # Delete all the data in mysql table + self.test_connection() + sql = 'delete from ' + table_name + ';' + try: + self.cursor.execute(sql) + self.conn.commit() + LOGGER.debug(f"MYSQL delete all data in table:{table_name}") + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) + + def count_table(self, table_name): + # Get the number of mysql table + self.test_connection() + sql = "select count(milvus_id) from " + table_name + ";" + try: + self.cursor.execute(sql) + results = self.cursor.fetchall() + LOGGER.debug(f"MYSQL count table:{table_name}") + return results[0][0] + except Exception as e: + LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}") + sys.exit(1) diff --git a/demos/audio_searching/src/operations/__init__.py b/demos/audio_searching/src/operations/__init__.py new file mode 100644 index 000000000..97043fd7b --- /dev/null +++ b/demos/audio_searching/src/operations/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/demos/audio_searching/src/operations/count.py b/demos/audio_searching/src/operations/count.py new file mode 100644 index 000000000..9a1f42082 --- /dev/null +++ b/demos/audio_searching/src/operations/count.py @@ -0,0 +1,33 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys + +from config import DEFAULT_TABLE +from logs import LOGGER + + +def do_count(table_name, milvus_cli): + """ + Returns the total number of vectors in the system + """ + if not table_name: + table_name = DEFAULT_TABLE + try: + if not milvus_cli.has_collection(table_name): + return None + num = milvus_cli.count(table_name) + return num + except Exception as e: + LOGGER.error(f"Error attempting to count table {e}") + sys.exit(1) diff --git a/demos/audio_searching/src/operations/drop.py b/demos/audio_searching/src/operations/drop.py new file mode 100644 index 000000000..f8278ddd0 --- /dev/null +++ b/demos/audio_searching/src/operations/drop.py @@ -0,0 +1,34 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys + +from config import DEFAULT_TABLE +from logs import LOGGER + + +def do_drop(table_name, milvus_cli, mysql_cli): + """ + Delete the collection of Milvus and MySQL + """ + if not table_name: + table_name = DEFAULT_TABLE + try: + if not milvus_cli.has_collection(table_name): + return "Collection is not exist" + status = milvus_cli.delete_collection(table_name) + mysql_cli.delete_table(table_name) + return status + except Exception as e: + LOGGER.error(f"Error attempting to drop table: {e}") + sys.exit(1) diff --git a/demos/audio_searching/src/operations/load.py b/demos/audio_searching/src/operations/load.py new file mode 100644 index 000000000..792434fbe --- /dev/null +++ b/demos/audio_searching/src/operations/load.py @@ -0,0 +1,86 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import sys + +from diskcache import Cache +from encode import get_audio_embedding + +from ..config import DEFAULT_TABLE +from ..logs import LOGGER + + +def get_audios(path): + """ + List all wav and aif files recursively under the path folder. + """ + supported_formats = [".wav", ".mp3", ".ogg", ".flac", ".m4a"] + return [ + item + for sublist in [[os.path.join(dir, file) for file in files] + for dir, _, files in list(os.walk(path))] + for item in sublist if os.path.splitext(item)[1] in supported_formats + ] + + +def extract_features(audio_dir): + """ + Get the vector of audio + """ + try: + cache = Cache('./tmp') + feats = [] + names = [] + audio_list = get_audios(audio_dir) + total = len(audio_list) + cache['total'] = total + for i, audio_path in enumerate(audio_list): + norm_feat = get_audio_embedding(audio_path) + if norm_feat is None: + continue + feats.append(norm_feat) + names.append(audio_path.encode()) + cache['current'] = i + 1 + print( + f"Extracting feature from audio No. {i + 1} , {total} audios in total" + ) + return feats, names + except Exception as e: + LOGGER.error(f"Error with extracting feature from audio {e}") + sys.exit(1) + + +def format_data(ids, names): + """ + Combine the id of the vector and the name of the audio into a list + """ + data = [] + for i in range(len(ids)): + value = (str(ids[i]), names[i]) + data.append(value) + return data + + +def do_load(table_name, audio_dir, milvus_cli, mysql_cli): + """ + Import vectors to Milvus and data to Mysql respectively + """ + if not table_name: + table_name = DEFAULT_TABLE + vectors, names = extract_features(audio_dir) + ids = milvus_cli.insert(table_name, vectors) + milvus_cli.create_index(table_name) + mysql_cli.create_mysql_table(table_name) + mysql_cli.load_data_to_mysql(table_name, format_data(ids, names)) + return len(ids) diff --git a/demos/audio_searching/src/operations/search.py b/demos/audio_searching/src/operations/search.py new file mode 100644 index 000000000..861fee01a --- /dev/null +++ b/demos/audio_searching/src/operations/search.py @@ -0,0 +1,40 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys + +from config import DEFAULT_TABLE +from config import TOP_K +from encode import get_audio_embedding +from logs import LOGGER + + +def do_search(host, table_name, audio_path, milvus_cli, mysql_cli): + """ + Search the uploaded audio in Milvus/MySQL + """ + try: + if not table_name: + table_name = DEFAULT_TABLE + feat = get_audio_embedding(audio_path) + vectors = milvus_cli.search_vectors(table_name, [feat], TOP_K) + vids = [str(x.id) for x in vectors[0]] + paths = mysql_cli.search_by_milvus_ids(vids, table_name) + distances = [x.distance for x in vectors[0]] + for i in range(len(paths)): + tmp = "http://" + str(host) + "/data?audio_path=" + str(paths[i]) + paths[i] = tmp + return vids, paths, distances + except Exception as e: + LOGGER.error(f"Error with search: {e}") + sys.exit(1) diff --git a/demos/audio_searching/src/test_main.py b/demos/audio_searching/src/test_main.py new file mode 100644 index 000000000..24405f388 --- /dev/null +++ b/demos/audio_searching/src/test_main.py @@ -0,0 +1,96 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import zipfile + +import gdown +from fastapi.testclient import TestClient +from main import app + +client = TestClient(app) + + +def download_audio_data(): + """ + download audio data + """ + url = 'https://drive.google.com/uc?id=1bKu21JWBfcZBuEuzFEvPoAX6PmRrgnUp' + gdown.download(url) + + with zipfile.ZipFile('example_audio.zip', 'r') as zip_ref: + zip_ref.extractall('./example_audio') + + +def test_drop(): + """ + Delete the collection of Milvus and MySQL + """ + response = client.post("/audio/drop") + assert response.status_code == 200 + + +def test_load(): + """ + Insert all the audio files under the file path to Milvus/MySQL + """ + response = client.post("/audio/load", json={"File": "./example_audio"}) + assert response.status_code == 200 + assert response.json() == { + 'status': True, + 'msg': "Successfully loaded data!" + } + + +def test_progress(): + """ + Get the progress of dealing with data + """ + response = client.get("/progress") + assert response.status_code == 200 + assert response.json() == "current: 20, total: 20" + + +def test_count(): + """ + Returns the total number of vectors in the system + """ + response = client.get("audio/count") + assert response.status_code == 200 + assert response.json() == 20 + + +def test_search(): + """ + Search the uploaded audio in Milvus/MySQL + """ + response = client.post( + "/audio/search/local?query_audio_path=.%2Fexample_audio%2Ftest.wav") + assert response.status_code == 200 + assert len(response.json()) == 10 + + +def test_data(): + """ + Get the audio file + """ + response = client.get("/data?audio_path=.%2Fexample_audio%2Ftest.wav") + assert response.status_code == 200 + + +if __name__ == "__main__": + download_audio_data() + test_drop() + test_load() + test_count() + test_search() + test_drop() From 7fd0b98eee3393fa5134f51dce5e6cfaf18cb545 Mon Sep 17 00:00:00 2001 From: qingen Date: Wed, 9 Mar 2022 17:58:26 +0800 Subject: [PATCH 2/9] [wip][vec] update readme, test=doc #1543 --- demos/audio_searching/README.md | 44 ++++++- demos/audio_searching/README_cn.md | 132 ++++++++++++++++++++ demos/audio_searching/src/main.py | 5 +- demos/audio_searching/src/milvus_helpers.py | 9 +- demos/audio_searching/src/test_main.py | 1 - 5 files changed, 179 insertions(+), 12 deletions(-) create mode 100644 demos/audio_searching/README_cn.md diff --git a/demos/audio_searching/README.md b/demos/audio_searching/README.md index 0ee781ad2..dc34b61bc 100644 --- a/demos/audio_searching/README.md +++ b/demos/audio_searching/README.md @@ -3,11 +3,19 @@ # Audio Searching ## Introduction -This demo uses ECAPA-TDNN(or other models) for Speaker Recognition base on MySQL to store user-info/id and Milvus to search vectors. +As the Internet continues to evolve, unstructured data such as emails, social media photos, live videos, and customer service voice calls have become increasingly common. If we want to process the data on a computer, we need to use embedding technology to transform the data into vector and store, index, and query it + +However, when there is a large amount of data, such as hundreds of millions of audio tracks, it is more difficult to do a similarity search. The exhaustive method is feasible, but very time consuming. For this scenario, this demo will introduce how to build an audio similarity retrieval system using the open source vector database Milvus + +Audio retrieval (speech, music, speaker, etc.) enables querying and finding similar sounds (or the same speaker) in a large amount of audio data. The audio similarity retrieval system can be used to identify similar sound effects, minimize intellectual property infringement, quickly retrieve the voice print library, and help enterprises control fraud and identity theft. Audio retrieval also plays an important role in the classification and statistical analysis of audio data + +In this demo, you will learn how to build an audio retrieval system to retrieve similar sound snippets. The uploaded audio clips are converted into vector data using paddlespeech-based pre-training models (audio classification model, speaker recognition model, etc.) and stored in Milvus. Milvus automatically generates a unique ID for each vector, then stores the ID and the corresponding audio information (audio ID, audio speaker ID, etc.) in MySQL to complete the library construction. During retrieval, users upload test audio to obtain vector, and then conduct vector similarity search in Milvus. The retrieval result returned by Milvus is vector ID, and the corresponding audio information can be queried in MySQL by ID + +The demo uses the [CN-Celeb](http://openslr.org/82/) dataset of at least 650,000 audio entries and 3000 speakers to build the audio vector library, which is then retrieved using a preset distance calculation. The dataset can also use other, Adjust as needed, e.g. Librispeech, VoxCeleb, UrbanSound, etc ## Usage ### 1. Prepare MySQL and Milvus services by docker-compose -The molecular similarity search system requires Milvus, MySQL services. We can start these containers with one click through [docker-compose.yaml](./docker-compose.yaml), so please make sure you have [installed Docker Engine](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) before running. then +The audio similarity search system requires Milvus, MySQL services. We can start these containers with one click through [docker-compose.yaml](./docker-compose.yaml), so please make sure you have [installed Docker Engine](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) before running. then ```bash docker-compose -f docker-compose.yaml up -d @@ -81,15 +89,43 @@ INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) ``` ### 3. Usage - +- Prepare data + ```bash + wget -c https://www.openslr.org/resources/82/cn-celeb_v2.tar.gz && tar -xvf cn-celeb_v2.tar.gz + ``` + Note: If you want to build a quick demo, you can use ./src/test_main.py:download_audio_data function, it download 20 audio files , Subsequent results show this collection as an example + + - Run + The internal process is downloading data, loading the Paddlespeech model, extracting embedding, storing library, retrieving and deleting library ```bash python ./src/test_main.py ``` + Output: + ```bash + Checkpoint path: %your model path% + Extracting feature from audio No. 1 , 20 audios in total + Extracting feature from audio No. 2 , 20 audios in total + ... + 2022-03-09 17:22:13,870 | INFO | main.py | load_audios | 85 | Successfully loaded data, total count: 20 + 2022-03-09 17:22:13,898 | INFO | main.py | count_audio | 147 | Successfully count the number of data! + 2022-03-09 17:22:13,918 | INFO | main.py | audio_path | 57 | Successfully load audio: ./example_audio/test.wav + ... + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/test.wav, distance 0.0 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_chopping.wav, distance 0.021805256605148315 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_cut_into_flesh.wav, distance 0.052762262523174286 + ... + 2022-03-09 17:22:32,582 | INFO | main.py | search_local_audio | 135 | Successfully searched similar audio! + 2022-03-09 17:22:33,658 | INFO | main.py | drop_tables | 159 | Successfully drop tables in Milvus and MySQL! + ``` + ### 4.Pretrained Models -Here is a list of pretrained models released by PaddleSpeech that can be used by command and python API: +Here is a list of pretrained models released by PaddleSpeech : | Model | Sample Rate | :--- | :---: | ecapa_tdnn | 16000 +| panns_cnn6| 32000 +| panns_cnn10| 32000 +| panns_cnn14| 32000 diff --git a/demos/audio_searching/README_cn.md b/demos/audio_searching/README_cn.md new file mode 100644 index 000000000..a76c1118f --- /dev/null +++ b/demos/audio_searching/README_cn.md @@ -0,0 +1,132 @@ + +(简体中文|[English](./README.md)) + +# 音频相似性检索 +## 介绍 + +随着互联网不断发展,电子邮件、社交媒体照片、直播视频、客服语音等非结构化数据已经变得越来越普遍。如果想要使用计算机来处理这些数据,需要使用 embedding 技术将这些数据转化为向量 vector,然后进行存储、建索引、并查询 + +但是,当数据量很大,比如上亿条音频要做相似度搜索,就比较困难了。穷举法固然可行,但非常耗时。针对这种场景,该demo 将介绍如何使用开源向量数据库 Milvus 搭建音频相似度检索系统 + +音频检索(如演讲、音乐、说话人等检索)实现了在海量音频数据中查询并找出相似声音(或相同说话人)片段。音频相似性检索系统可用于识别相似的音效、最大限度减少知识产权侵权等,还可以快速的检索声纹库、帮助企业控制欺诈和身份盗用等。在音频数据的分类和统计分析中,音频检索也发挥着重要作用 + +在本 demo 中,你将学会如何构建一个音频检索系统,用来检索相似的声音片段。使用基于 PaddleSpeech 预训练模型(音频分类模型,说话人识别模型等)将上传的音频片段转换为向量数据,并存储在 Milvus 中。Milvus 自动为每个向量生成唯一的 ID,然后将 ID 和 相应的音频信息(音频id,音频的说话人id等等)存储在 MySQL,这样就完成建库的工作。用户在检索时,上传测试音频,得到向量,然后在 Milvus 中进行向量相似度搜索,Milvus 返回的检索结果为向量 ID,通过 ID 在 MySQL 内部查询相应的音频信息即可 + +这个 demo 使用 [CN-Celeb](http://openslr.org/82/) 数据集,包括至少 650000 条音频,3000 个说话人,来建立音频向量库,然后通过预设的距离计算方式进行检索,这里面数据集也可以使用其他的,根据需要调整,如Librispeech,VoxCeleb,UrbanSound等 + +## 使用方法 +### 1. MySQL 和 Milvus 安装 +音频相似度搜索系统需要Milvus, MySQL服务。 我们可以通过[Docker-Compose.yaml](./ Docker-Compose.yaml)一键启动这些容器,所以请确保在运行之前已经安装了[Docker Engine](https://docs.docker.com/engine/install/) 和[Docker Compose](https://docs.docker.com/compose/install/)。 即 + +```bash +docker-compose -f docker-compose.yaml up -d +``` + +然后你会看到所有的容器都被创建: + +```bash +Creating network "quick_deploy_app_net" with driver "bridge" +Creating milvus-minio ... done +Creating milvus-etcd ... done +Creating audio-mysql ... done +Creating milvus-standalone ... done +``` + +可以采用'docker ps'来显示所有的容器,还可以使用'docker logs audio-mysql'来获取服务器容器的日志: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +b2bcf279e599 milvusdb/milvus:v2.0.1 "/tini -- milvus run…" 22 hours ago Up 22 hours 0.0.0.0:19530->19530/tcp milvus-standalone +d8ef4c84e25c mysql:5.7 "docker-entrypoint.s…" 22 hours ago Up 22 hours 0.0.0.0:3306->3306/tcp, 33060/tcp audio-mysql +8fb501edb4f3 quay.io/coreos/etcd:v3.5.0 "etcd -advertise-cli…" 22 hours ago Up 22 hours 2379-2380/tcp milvus-etcd +ffce340b3790 minio/minio:RELEASE.2020-12-03T00-03-10Z "/usr/bin/docker-ent…" 22 hours ago Up 22 hours (healthy) 9000/tcp milvus-minio + +``` + +### 2. 配置并启动 API 服务 +启动系统服务程序,它会提供基于 Http 后端服务 + +- 安装服务依赖的 python 基础包 + +```bash +pip install -r requirements.txt +``` +- 修改配置 + +```bash +vim src/config.py +``` + +请根据实际环境进行修改。 这里列出了一些需要设置的参数,更多信息请参考[config.py](./src/config.py) + +| **Parameter** | **Description** | **Default setting** | +| ---------------- | ----------------------------------------------------- | ------------------- | +| MILVUS_HOST | The IP address of Milvus, you can get it by ifconfig. If running everything on one machine, most likely 127.0.0.1 | 127.0.0.1 | +| MILVUS_PORT | Port of Milvus. | 19530 | +| VECTOR_DIMENSION | Dimension of the vectors. | 2048 | +| MYSQL_HOST | The IP address of Mysql. | 127.0.0.1 | +| MYSQL_PORT | Port of Milvus. | 3306 | +| DEFAULT_TABLE | The milvus and mysql default collection name. | audio_table | + +- 运行程序 + +启动用 Fastapi 构建的服务 + +```bash +python src/main.py +``` + +然后你会看到应用程序启动: + +```bash +INFO: Started server process [3949] +2022-03-07 17:39:14,864 | INFO | server.py | serve | 75 | Started server process [3949] +INFO: Waiting for application startup. +2022-03-07 17:39:14,865 | INFO | on.py | startup | 45 | Waiting for application startup. +INFO: Application startup complete. +2022-03-07 17:39:14,866 | INFO | on.py | startup | 59 | Application startup complete. +INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) +2022-03-07 17:39:14,867 | INFO | server.py | _log_started_message | 206 | Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) +``` + +### 3. 使用方法 +- 准备数据 + ```bash + wget -c https://www.openslr.org/resources/82/cn-celeb_v2.tar.gz && tar -xvf cn-celeb_v2.tar.gz + ``` + 注:如果希望快速搭建 demo,可以采用 ./src/test_main.py:download_audio_data 内部的 20 条音频,后续结果展示以该集合为例 + + - 运行测试程序 + 内部将依次下载数据,加载 paddlespeech 模型,提取 embedding,存储建库,检索,删库 + ```bash + python ./src/test_main.py + ``` + + 输出: + ```bash + Checkpoint path: %your model path% + Extracting feature from audio No. 1 , 20 audios in total + Extracting feature from audio No. 2 , 20 audios in total + ... + 2022-03-09 17:22:13,870 | INFO | main.py | load_audios | 85 | Successfully loaded data, total count: 20 + 2022-03-09 17:22:13,898 | INFO | main.py | count_audio | 147 | Successfully count the number of data! + 2022-03-09 17:22:13,918 | INFO | main.py | audio_path | 57 | Successfully load audio: ./example_audio/test.wav + ... + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/test.wav, distance 0.0 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_chopping.wav, distance 0.021805256605148315 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_cut_into_flesh.wav, distance 0.052762262523174286 + ... + 2022-03-09 17:22:32,582 | INFO | main.py | search_local_audio | 135 | Successfully searched similar audio! + 2022-03-09 17:22:33,658 | INFO | main.py | drop_tables | 159 | Successfully drop tables in Milvus and MySQL! + ``` + +### 4. 预训练模型 + +以下是 PaddleSpeech 提供的预训练模型列表: + +| 模型 | 采样率 +| :--- | :---: +| ecapa_tdnn| 16000 +| panns_cnn6| 32000 +| panns_cnn10| 32000 +| panns_cnn14| 32000 diff --git a/demos/audio_searching/src/main.py b/demos/audio_searching/src/main.py index 89c037a0e..082fc6512 100644 --- a/demos/audio_searching/src/main.py +++ b/demos/audio_searching/src/main.py @@ -126,8 +126,9 @@ async def search_local_audio(request: Request, _, paths, distances = do_search(host, table_name, query_audio_path, MILVUS_CLI, MYSQL_CLI) names = [] - for i in paths: - names.append(os.path.basename(i)) + for path, dist in zip(paths, distances): + names.append(os.path.basename(path)) + LOGGER.info(f"search result {path}, distance {dist}") res = dict(zip(paths, zip(names, distances))) # Sort results by distance metric, closest distances first res = sorted(res.items(), key=lambda item: item[1][1]) diff --git a/demos/audio_searching/src/milvus_helpers.py b/demos/audio_searching/src/milvus_helpers.py index 8ba3776be..1699e892e 100644 --- a/demos/audio_searching/src/milvus_helpers.py +++ b/demos/audio_searching/src/milvus_helpers.py @@ -59,7 +59,7 @@ class MilvusHelper: raise Exception( f"There is no collection named:{collection_name}") except Exception as e: - LOGGER.error(f"Failed to load data to Milvus: {e}") + LOGGER.error(f"Failed to set collection in Milvus: {e}") sys.exit(1) def has_collection(self, collection_name): @@ -67,7 +67,7 @@ class MilvusHelper: try: return utility.has_collection(collection_name) except Exception as e: - LOGGER.error(f"Failed to load data to Milvus: {e}") + LOGGER.error(f"Failed to check state of collection in Milvus: {e}") sys.exit(1) def create_collection(self, collection_name): @@ -95,7 +95,7 @@ class MilvusHelper: self.set_collection(collection_name) return "OK" except Exception as e: - LOGGER.error(f"Failed to load data to Milvus: {e}") + LOGGER.error(f"Failed to create collection in Milvus: {e}") sys.exit(1) def insert(self, collection_name, vectors): @@ -112,7 +112,7 @@ class MilvusHelper: ) return ids except Exception as e: - LOGGER.error(f"Failed to load data to Milvus: {e}") + LOGGER.error(f"Failed to insert data to Milvus: {e}") sys.exit(1) def create_index(self, collection_name): @@ -160,7 +160,6 @@ class MilvusHelper: "nprobe": 16 } } - # data = [vectors] res = self.collection.search( vectors, anns_field="embedding", diff --git a/demos/audio_searching/src/test_main.py b/demos/audio_searching/src/test_main.py index 24405f388..331208ff1 100644 --- a/demos/audio_searching/src/test_main.py +++ b/demos/audio_searching/src/test_main.py @@ -89,7 +89,6 @@ def test_data(): if __name__ == "__main__": download_audio_data() - test_drop() test_load() test_count() test_search() From 508f2f5b6246e5073dfd2b65c04a51fc26509f21 Mon Sep 17 00:00:00 2001 From: qingen Date: Fri, 11 Mar 2022 22:08:17 +0800 Subject: [PATCH 3/9] [wip][vec] update readme and yaml, test=doc #1543 --- demos/audio_searching/README.md | 4 +- demos/audio_searching/README_cn.md | 129 ++++++++++-------- demos/audio_searching/docker-compose.yaml | 17 ++- demos/audio_searching/img/audio_searching.png | Bin 0 -> 29649 bytes demos/audio_searching/img/insert.png | Bin 0 -> 81912 bytes demos/audio_searching/img/search.png | Bin 0 -> 90201 bytes 6 files changed, 91 insertions(+), 59 deletions(-) create mode 100644 demos/audio_searching/img/audio_searching.png create mode 100644 demos/audio_searching/img/insert.png create mode 100644 demos/audio_searching/img/search.png diff --git a/demos/audio_searching/README.md b/demos/audio_searching/README.md index dc34b61bc..e347d6aae 100644 --- a/demos/audio_searching/README.md +++ b/demos/audio_searching/README.md @@ -11,7 +11,9 @@ Audio retrieval (speech, music, speaker, etc.) enables querying and finding simi In this demo, you will learn how to build an audio retrieval system to retrieve similar sound snippets. The uploaded audio clips are converted into vector data using paddlespeech-based pre-training models (audio classification model, speaker recognition model, etc.) and stored in Milvus. Milvus automatically generates a unique ID for each vector, then stores the ID and the corresponding audio information (audio ID, audio speaker ID, etc.) in MySQL to complete the library construction. During retrieval, users upload test audio to obtain vector, and then conduct vector similarity search in Milvus. The retrieval result returned by Milvus is vector ID, and the corresponding audio information can be queried in MySQL by ID -The demo uses the [CN-Celeb](http://openslr.org/82/) dataset of at least 650,000 audio entries and 3000 speakers to build the audio vector library, which is then retrieved using a preset distance calculation. The dataset can also use other, Adjust as needed, e.g. Librispeech, VoxCeleb, UrbanSound, etc +![Workflow of an audio searching system](./img/audo_searching.png) + +Note:this demo uses the [CN-Celeb](http://openslr.org/82/) dataset of at least 650,000 audio entries and 3000 speakers to build the audio vector library, which is then retrieved using a preset distance calculation. The dataset can also use other, Adjust as needed, e.g. Librispeech, VoxCeleb, UrbanSound, etc ## Usage ### 1. Prepare MySQL and Milvus services by docker-compose diff --git a/demos/audio_searching/README_cn.md b/demos/audio_searching/README_cn.md index a76c1118f..bba37965c 100644 --- a/demos/audio_searching/README_cn.md +++ b/demos/audio_searching/README_cn.md @@ -12,11 +12,13 @@ 在本 demo 中,你将学会如何构建一个音频检索系统,用来检索相似的声音片段。使用基于 PaddleSpeech 预训练模型(音频分类模型,说话人识别模型等)将上传的音频片段转换为向量数据,并存储在 Milvus 中。Milvus 自动为每个向量生成唯一的 ID,然后将 ID 和 相应的音频信息(音频id,音频的说话人id等等)存储在 MySQL,这样就完成建库的工作。用户在检索时,上传测试音频,得到向量,然后在 Milvus 中进行向量相似度搜索,Milvus 返回的检索结果为向量 ID,通过 ID 在 MySQL 内部查询相应的音频信息即可 -这个 demo 使用 [CN-Celeb](http://openslr.org/82/) 数据集,包括至少 650000 条音频,3000 个说话人,来建立音频向量库,然后通过预设的距离计算方式进行检索,这里面数据集也可以使用其他的,根据需要调整,如Librispeech,VoxCeleb,UrbanSound等 +![音频检索程图](./img/audio_searching.png) + +注:该 demo 使用 [CN-Celeb](http://openslr.org/82/) 数据集,包括至少 650000 条音频,3000 个说话人,来建立音频向量库(音频特征,或音频说话人特征),然后通过预设的距离计算方式进行音频(或说话人)检索,这里面数据集也可以使用其他的,根据需要调整,如Librispeech,VoxCeleb,UrbanSound等 ## 使用方法 ### 1. MySQL 和 Milvus 安装 -音频相似度搜索系统需要Milvus, MySQL服务。 我们可以通过[Docker-Compose.yaml](./ Docker-Compose.yaml)一键启动这些容器,所以请确保在运行之前已经安装了[Docker Engine](https://docs.docker.com/engine/install/) 和[Docker Compose](https://docs.docker.com/compose/install/)。 即 +音频相似度搜索系统需要用到 Milvus, MySQL 服务。 我们可以通过 [docker-compose.yaml](./docker-compose.yaml) 一键启动这些容器,所以请确保在运行之前已经安装了 [Docker Engine](https://docs.docker.com/engine/install/) 和 [Docker Compose](https://docs.docker.com/compose/install/)。 即 ```bash docker-compose -f docker-compose.yaml up -d @@ -30,6 +32,7 @@ Creating milvus-minio ... done Creating milvus-etcd ... done Creating audio-mysql ... done Creating milvus-standalone ... done +Creating audio-webclient ... done ``` 可以采用'docker ps'来显示所有的容器,还可以使用'docker logs audio-mysql'来获取服务器容器的日志: @@ -40,6 +43,7 @@ b2bcf279e599 milvusdb/milvus:v2.0.1 "/tini -- milvus run…" 22 hours ago Up d8ef4c84e25c mysql:5.7 "docker-entrypoint.s…" 22 hours ago Up 22 hours 0.0.0.0:3306->3306/tcp, 33060/tcp audio-mysql 8fb501edb4f3 quay.io/coreos/etcd:v3.5.0 "etcd -advertise-cli…" 22 hours ago Up 22 hours 2379-2380/tcp milvus-etcd ffce340b3790 minio/minio:RELEASE.2020-12-03T00-03-10Z "/usr/bin/docker-ent…" 22 hours ago Up 22 hours (healthy) 9000/tcp milvus-minio +15c84a506754 iregistry.baidu-int.com/paddlespeech/audio-search-client:1.0 "/bin/bash -c '/usr/…" 22 hours ago Up 22 hours (healthy) 0.0.0.0:8068->80/tcp audio-webclient ``` @@ -48,77 +52,88 @@ ffce340b3790 minio/minio:RELEASE.2020-12-03T00-03-10Z "/usr/bin/docker-ent…" - 安装服务依赖的 python 基础包 -```bash -pip install -r requirements.txt -``` + ```bash + pip install -r requirements.txt + ``` - 修改配置 -```bash -vim src/config.py -``` + ```bash + vim src/config.py + ``` -请根据实际环境进行修改。 这里列出了一些需要设置的参数,更多信息请参考[config.py](./src/config.py) + 请根据实际环境进行修改。 这里列出了一些需要设置的参数,更多信息请参考 [config.py](./src/config.py) -| **Parameter** | **Description** | **Default setting** | -| ---------------- | ----------------------------------------------------- | ------------------- | -| MILVUS_HOST | The IP address of Milvus, you can get it by ifconfig. If running everything on one machine, most likely 127.0.0.1 | 127.0.0.1 | -| MILVUS_PORT | Port of Milvus. | 19530 | -| VECTOR_DIMENSION | Dimension of the vectors. | 2048 | -| MYSQL_HOST | The IP address of Mysql. | 127.0.0.1 | -| MYSQL_PORT | Port of Milvus. | 3306 | -| DEFAULT_TABLE | The milvus and mysql default collection name. | audio_table | + | **Parameter** | **Description** | **Default setting** | + | ---------------- | ----------------------------------------------------- | ------------------- | + | MILVUS_HOST | The IP address of Milvus, you can get it by ifconfig. If running everything on one machine, most likely 127.0.0.1 | 127.0.0.1 | + | MILVUS_PORT | Port of Milvus. | 19530 | + | VECTOR_DIMENSION | Dimension of the vectors. | 2048 | + | MYSQL_HOST | The IP address of Mysql. | 127.0.0.1 | + | MYSQL_PORT | Port of Milvus. | 3306 | + | DEFAULT_TABLE | The milvus and mysql default collection name. | audio_table | - 运行程序 -启动用 Fastapi 构建的服务 + 启动用 Fastapi 构建的服务 -```bash -python src/main.py -``` + ```bash + python src/main.py + ``` -然后你会看到应用程序启动: + 然后你会看到应用程序启动: -```bash -INFO: Started server process [3949] -2022-03-07 17:39:14,864 | INFO | server.py | serve | 75 | Started server process [3949] -INFO: Waiting for application startup. -2022-03-07 17:39:14,865 | INFO | on.py | startup | 45 | Waiting for application startup. -INFO: Application startup complete. -2022-03-07 17:39:14,866 | INFO | on.py | startup | 59 | Application startup complete. -INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) -2022-03-07 17:39:14,867 | INFO | server.py | _log_started_message | 206 | Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) -``` + ```bash + INFO: Started server process [3949] + 2022-03-07 17:39:14,864 | INFO | server.py | serve | 75 | Started server process [3949] + INFO: Waiting for application startup. + 2022-03-07 17:39:14,865 | INFO | on.py | startup | 45 | Waiting for application startup. + INFO: Application startup complete. + 2022-03-07 17:39:14,866 | INFO | on.py | startup | 59 | Application startup complete. + INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) + 2022-03-07 17:39:14,867 | INFO | server.py | _log_started_message | 206 | Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit) + ``` -### 3. 使用方法 +### 3. 测试方法 - 准备数据 ```bash wget -c https://www.openslr.org/resources/82/cn-celeb_v2.tar.gz && tar -xvf cn-celeb_v2.tar.gz ``` - 注:如果希望快速搭建 demo,可以采用 ./src/test_main.py:download_audio_data 内部的 20 条音频,后续结果展示以该集合为例 + 注:如果希望快速搭建 demo,可以采用 ./src/test_main.py:download_audio_data 内部的 20 条音频,另外后续结果展示以该集合为例 - - 运行测试程序 - 内部将依次下载数据,加载 paddlespeech 模型,提取 embedding,存储建库,检索,删库 - ```bash - python ./src/test_main.py - ``` - - 输出: - ```bash - Checkpoint path: %your model path% - Extracting feature from audio No. 1 , 20 audios in total - Extracting feature from audio No. 2 , 20 audios in total - ... - 2022-03-09 17:22:13,870 | INFO | main.py | load_audios | 85 | Successfully loaded data, total count: 20 - 2022-03-09 17:22:13,898 | INFO | main.py | count_audio | 147 | Successfully count the number of data! - 2022-03-09 17:22:13,918 | INFO | main.py | audio_path | 57 | Successfully load audio: ./example_audio/test.wav - ... - 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/test.wav, distance 0.0 - 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_chopping.wav, distance 0.021805256605148315 - 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_cut_into_flesh.wav, distance 0.052762262523174286 - ... - 2022-03-09 17:22:32,582 | INFO | main.py | search_local_audio | 135 | Successfully searched similar audio! - 2022-03-09 17:22:33,658 | INFO | main.py | drop_tables | 159 | Successfully drop tables in Milvus and MySQL! - ``` + - 脚本测试(推荐) + + ```bash + python ./src/test_main.py + ``` + 注:内部将依次下载数据,加载 paddlespeech 模型,提取 embedding,存储建库,检索,删库 + + 输出: + ```bash + Checkpoint path: %your model path% + Extracting feature from audio No. 1 , 20 audios in total + Extracting feature from audio No. 2 , 20 audios in total + ... + 2022-03-09 17:22:13,870 | INFO | main.py | load_audios | 85 | Successfully loaded data, total count: 20 + 2022-03-09 17:22:13,898 | INFO | main.py | count_audio | 147 | Successfully count the number of data! + 2022-03-09 17:22:13,918 | INFO | main.py | audio_path | 57 | Successfully load audio: ./example_audio/test.wav + ... + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/test.wav, distance 0.0 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_chopping.wav, distance 0.021805256605148315 + 2022-03-09 17:22:32,580 | INFO | main.py | search_local_audio | 131 | search result http://testserver/data?audio_path=./example_audio/knife_cut_into_flesh.wav, distance 0.052762262523174286 + ... + 2022-03-09 17:22:32,582 | INFO | main.py | search_local_audio | 135 | Successfully searched similar audio! + 2022-03-09 17:22:33,658 | INFO | main.py | drop_tables | 159 | Successfully drop tables in Milvus and MySQL! + ``` + - 前端测试(可选) + + 在浏览器中输入 127.0.0.1:8068 访问前端页面 + - 上传音频 + + ![](./img/insert.png) + + - 检索相似音频 + + ![](./img/search.png) ### 4. 预训练模型 diff --git a/demos/audio_searching/docker-compose.yaml b/demos/audio_searching/docker-compose.yaml index 7e16ee8a0..6e3f94ef5 100644 --- a/demos/audio_searching/docker-compose.yaml +++ b/demos/audio_searching/docker-compose.yaml @@ -48,7 +48,6 @@ services: depends_on: - "etcd" - "minio" - mysql: container_name: audio-mysql @@ -63,6 +62,22 @@ services: ports: - "3306:3306" + webclient: + container_name: audio-webclient + image: iregistry.baidu-int.com/paddlespeech/audio-search-client:1.0 + networks: + app_net: + ipv4_address: 172.16.23.13 + environment: + API_URL: 'http://127.0.0.1:8002' + ports: + - "8068:80" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/"] + interval: 30s + timeout: 20s + retries: 3 + networks: app_net: driver: bridge diff --git a/demos/audio_searching/img/audio_searching.png b/demos/audio_searching/img/audio_searching.png new file mode 100644 index 0000000000000000000000000000000000000000..b145dd49947ebfc1fcb8331f572e4f181de6dfbd GIT binary patch literal 29649 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�s$1u@S+0DTJD!dL%39|0(%Cn&C zKC$1zYJtm3(M_Uvgs4WRqZTu}xAIkv0CL%fN3 zxdQi@YT8(GywcOm$ZVFUF0|2Sa2M;vh)mMpdHBNKp(h^K^^*)Jb*n;#xY?}^!0>U@ z{oVb$H2xuRCa!;G+97H-h4?3Gv6b95cnQw3kX7YHKFNvJ`W6OYJwfOAZV)W-5u%Cs z#9tDYz8wT62pb3YdH2KA0Hf8f zCdo6AZAg&x{oMVxUAvK|^|CUE?T(w1hl1y4E{iUYaNDkxyfrKKE)6JVKL@18mYo_ycU;#*dGVc;hmHzB8sssE zS(!0XMndo1q(Hdv&nCYE^sf!^Vv?0^p;UNCnACDoTW*q54W^qn-{SzX65qXNp8M-3 z(Y=8)iAQ+0X32}|Aw~Wb_RTNIrn;lqR+y6^88zR?$rh?5STM81?g~gg=|%;S-1{FO zQ&q+MMexqps6+TKMut`4$A3k%FM}4OLvPW;SvOOrZYcDf=v(52!V)pSW`%z$bV%%) z_(i?(Ufz^O6UnN@FTD+P4&+*(<@D~qtNiT&)Bxsh5lI>0g098>nTcI7HadoR(tURN zpe0+;QyTjYw+neGGyDVuRw-|-JEcgqzawSpQ;OFm3w(g!$loGUIBL9+APlm>e-O`TaWq4 zhHMmFvmUV<=M9Dg(7wVoteiC#u^=-M`bj#Kb1iAGq^oiS3W|Mao}b$WxP0LD(W^_QkG>>f|P2nX{DYWuG7m^^Oc}y>uzW*%BMfvH3(sd!`=i!pS4Qk_u|% zxvESCl)<2%i+a?owIZ5ls}+weZQ06R80{)c!sacA07#f{s1o|`$!6%5E91dT)%;lg9`GFCn{bUgM+zFoV+ zl0IC$cJCq-?KCqv4o0WED9mRUjp57lm(3+y^(i+rApnh;REkMqmiZJ z+_RS6-L0T?|E>J%z45|za`qC4&*9MK$pN2CPCVIQ_dd3T9 zi=?3ccJ?^w2y|PK5N+3q{ACim;-#mnvITdSYKp!R+}iR)26pD5z_wv7fRYv(1_8d!kM`I{K|cfgYDj8McOpUdW!;zuPRdd{cR{{G!DH6G(DI<6q0q5! zNm`oMcms;7#cKZe{AMVT2$>|gW_@@?Ey%J`G$rD1Q3qC3 zL)zAcWxSX;^|{e;0=k#subJE9R5;t>Q8Dqk4(BlfI#uu7^qE0gT^{?T3Q^C{K7Ptg z&?PeSzP3u})V%h@@c0CJKEi|?%@mSVg)jH*OqyW$Uh;*NUUtvuK~xMtd1z zICmZ{SUYBdrNJyg@b8_M2mQO*_S1|9~P>wSc1>F&e7IEkHV zH{uki_<@UW8|*e?TN&w%Rn1~u=;)K^QD+dXj&sqml>n6LCuRB4FfUv-z4T^(m7Cm3&4~(e^3Z zbddYsik^KnE^7k{03&sw_O$*4A-Fhtt`+{X*in|5s^1h_^GwIjoJItdj(9NW^f$1@ zo7WwpBt1~>s4hyo=QU7U$N1)4*9|2$$Hh~O5U<|AX%e!kBsd-HZ%qR=f#{jZFWpuP z$qW4pdxuLJO&@@W(|kb_^`pq_GumJ~)Cd3)rrJLx(CMp@VN!s~HTvpKBNg&MuorFW zVjk|YbI1sblLv07)WO~hAi1fPB5dHi`-0nTcQ^wks{-dt?*vw*%VfDFQ?mxjjF~Hh zjJD#YLmjsCBbq?}bpLK@W2HB)+)Jz3sFps}c4D7qszdy!&T_I<{up%8^}0PKOXh2% zBUY_?wC(;Vh;$&F`sx2o%4QNYC3rQsL@UXOf3Lt5>E#&zJenJp+{^?etcI~3rDN;o z`GYnoOK1g)p&H}!*Ex_+H{M}WQOo!dWY%_-T$X~?rBUX&w?R5Gxucp%YD=_opB$u@P@0#qSW2W00YVnkv@W5i>mNFpRr(gmyf zEw*v~zB6h}cs04u;qkhUvBiJ*7V8stilLa&#a+9XFf9xF(H8zNnCNER0kz#(z?Fb! zY%9T-lN{BGslBwA#+qz;l;-8-O%3j{y38%S$YBj|Gj zRVDXLcdi?NtPeV73AuthcNHnTJE&Y`5Bl&<57{I1>3U9P_?UH{S9cq|qSD>*`SWDc zr;h$jp!@Ak?HC?=qzKjxxn^TJTa|kzrr*Wc*|(UBnmd^Zf;UMfP1JJ^w9a6cAwyF^ zI`eajC*aZo>%ze!Buj6#dEe-QFsZ2f=NozJdw^>2L711m111?!ms~V_902p1Aa+z}^y~Gp}ui z7q0xm3Ut{(6>rd9^D`E^w|Bhb`>)RY|832{z|`soA@oa?f*wg=2)jiQw`(w}X&_V|KNWPXU)h=c&LiU;v6na5A&!Ve`63wm=7MoX zx$CQ6D^OGvD9M#AsOaUQI6KG?o@fLi(+`QT*92)yC?ZCij-;_c-~N-}rFMg^kJ;{Z zE*q_qoi~aXI7f?`|TZRtCs3Lv=Qf3({xPw`Cm7 zxSZjU@i-%QTX?`clw_&Nk5M0go_nYP%vU+Y**(w+=6>Ko>A5Jat@S^l*dw2YeOrBV zjQ_pT73|&r*UzAMK+m9PtB4J%+x_7Ije4{jk>Lzk?x-!`8~v++kWnor0|^ILI&{tH zf#{x6DJIZ#N3OPu(H2nKQT_d6-8G3T(4!pfbfqyhzJ{@~0PvEWE+xBu3u?(JL8lVV z;5@efhxzjONL@oge|up`lS?#8<*Lg1Qz@r@J(Us;YRVr9yyifkkS@iuVGF7l`_*7Y zcBsx6j{|NJxE~Wh=dt>G`OMv*c_6IF>z2LkF6rt@zRRw`eqgi&Jih^D-O3A+e(eG9 zC~o=Rdw{u5rH>Ck7=}9R3B#2am?g{p>j{-#xbU7(=~7c1?=up1E9P8^(j91LhfbDermXcr%PV>Ft$w>Jfrd}izjUM za^81;vaW7bix5l1`gZP4Q$7i+yXO#^1(A*m{UR!(8jeV%dA~96VXSk`Tu+AA{ry1a z`nKGd!9V|v2}<~nQ%&G~k^tYlQA4dO4woLn#ynYwmPl9caywRN;=v; z(K}huCS-rV&Oo~M#Wd8>$UFt-Mmj^=;guo;Ruq6$ ztqSip@cKKHd#(`u)4vP{<6jRb;7On`oSHP9NzL~`#jH38=`%##S} z?cPlc=+UE8meE2)^9=FECZ^4U4L6)%;2v7#lXm|Wlg77ODUdi zc~x_j<6kc-dg!cFko+JXD)ce`zIf~fN&tKJ2Zzn#R~Bx2FVk?((P&wq(Aq2zB%HvL zfR09+L=aDYVLxbKWd3iOz6~~^do|`!Pzv;F3`DT?S7US+h#rFXN0Pv+G4)CZ z)3w87oXtlU*S<-chHsPU{&aeOLs-^Tb&5Th&T3rDql}b{Qg!?=nU{oi|rYtZc@RS-1Ps+#EgS@y#R$s9Cxm&E&0q}oU)xxhE;b0E>w-GAk|x1k-_44xitRjF?}L==L-2k9 zy?6lsJRXJz4;F%>hztCh(EP_N+9+D6gF&d^5ik_`89UWc-Eq1_T=cbN>V%-PSi4Sy zniJwI@@X>PnWO(V45lp@e;f7pFy4Rx-jjoCLKa7Rap1|uw)jc#tYBMmPjtb(>i}gJ z$NjuPaxhq`@R#%ejwkJ=Ws4k&G?<}@q~j z&I$tqDc~^#FwTlFW=?W=0+3S~mjWg#rddld#h}M~6!#d`dUHQ8A8FwTzWVjiUVG+p z@3Xvq*TOdyGbXBjc}0|8w%n#9H}rc%Z7*-|*f+ZFcFrM|sv^E;?$i_g15YAZ@q4Jd z5Lcj~a~Tm|CgOE!C;o2pYuSOgWC3Ygoq`3UhLB2O zoCB1XP^|LJITVq`p19C@$F2%IpHPrarDvVkAg|c?!Zh{Vi5nmUozlds{XgxU`9G9v z|G-I)oElp-Az4qSgF%*q2H8j2sO;H7C_=Ktu_bF$mUFW2OOcE*C6v7)Wt$u!#B}W2 zs4<8!_8*yGnyGY7mv9^q^bw6vP{6|J22$ znBU4HJ|=zdY4upKs3n9}+jH3CG&W~pVV(d{#ADW8EQZQ-OAPx9(tsOw>1IsHFTYT- zEl1?L?LCL}-s+@=;GqzREqWdo+W+$|U&gMseegvmyuuSG%nr&mV(mh!HfO}|bo(z)2OY}vKH*2W$-J!_X8n1c>4iV;x z9EXQyE+fl{3m-!B}|8FGYKP#fRk@`e#d8xtnN; zv*)AGB?RB4F5_A6(_T4qo}(0CC4m`)kTddP0ozJZdS*v|e9EFLXCYYSa6oCD#s=O# zTbZIk4MF!lO)3IF0eF0=O+K2-tS-!qErkfG5c&7*aV8e>LE|dvy2Q}M_>J@QflaDV z*1CQvUPC!4_&QbyyX$qpDIChcyYA7Agf!!fHr41U*}YMpa_i+x(f`nAR3DMY4oB6oKwGuAhuL%oeWk z3SVpcSpp)LzlXLP7fVK?c@=OUn;@3!%}<4^fCM0iESCose=?uw(cEa+^jEf7C6pi7 z3|{p$$4+xHLg%o_GRJmEZ&2XlYxyuw%5PnZ&hkm9Xq^`67AIW#S%DD4`c;jx+BpFT zL*YfrS5KqUar6RR!xNpSsN*)KT>3Q(8i7BxXxZy>O-t&{5br)we-0<8(r@-SyWqt{ z#;5(?Wcnz?YR0qzNm4|!RS8o_MO3~o<(L1(XHBZ`d7^GA{#Yg@MNt~)Ie+*Sg^fAl zl8RgtwNHG~Y$k)0zq-FDEYq9$Fw3*>B09??MpP`t>DD>F{V#0ICwT|5%v*El@~`tD z%-yZaktpGp)cp{XxJFZ9paVvHgv-1;nwhv z$Q!Gh*B9Opj3AN)OC&&aaNWF@^=2X-+?!A;uv7P*Eztj;DVzsYy?$A!xe?JNqqM`R6_w7p3b1Z-4tkBi9hBn=g+G9d;p zfVOF+xY;-cL$w?->$>IrLf#%_3#;^Fc@hT#^GWrNn3VviMdk*rmv1RFawVXL3st#i zw@!b66XH>sbalqh9@nSpRAFas2dn_*uxG>7%JAZ=$)wv(v67$*xHP#`^u%_NJpNg} zH?|(THoIKy6^I|z3M2`JQx|9h;lmaUwa0B;P>%-5d`WCni=tqw9Ar{-Z&x!k`gvXO zVC?`ACTb|SmbNSeW&5t5bcG5>pnu$hVIcehTnlfK=7|>cQ$=QTh%ne@i-{XYNoGlw+_C9CflXg5~A9>MJfCD(F1*XX$ccb^2MbsLl5P2@y zvLwt_iU15DA9H4^+RmJR?~S3Z2(+%+dVzW<;V@x}*x*09THePWS|~ky&GjOhZ~acg zBv+dPkC`P5zB=Pd639jJpTMFHt9N^&qhTAtD)}m$xTI(hBZWK1(>9>3^Ohw3IMe30 zZ�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 literal 0 HcmV?d00001 diff --git a/demos/audio_searching/img/insert.png b/demos/audio_searching/img/insert.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e766bda96f7f3046a6eafae5cfb58f7fc7a378 GIT binary patch literal 81912 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 literal 0 HcmV?d00001 diff --git a/demos/audio_searching/img/search.png b/demos/audio_searching/img/search.png new file mode 100644 index 0000000000000000000000000000000000000000..e84f7537915cee2230e6661d647f274de867f6c2 GIT binary patch literal 90201 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%0APgpjM~tV8KxR`AkK*eT8|;*- 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

+9b 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