From ac30d1af2b4008ca39be0f4a63c07450db562d71 Mon Sep 17 00:00:00 2001 From: Tiep Le Date: Thu, 29 Aug 2024 22:00:32 +0000 Subject: [PATCH 1/8] updates Signed-off-by: Tiep Le --- .../multimodal_langchain/redis/README.md | 120 ++++++++++++++++++ .../multimodal_langchain/redis/__init__.py | 2 + .../redis/docker/Dockerfile | 29 +++++ .../docker/docker_compose_retriever.yaml | 33 +++++ .../redis/multimodal_config.py | 80 ++++++++++++ .../redis/redis_schema.yml | 20 +++ .../redis/requirements.txt | 14 ++ .../redis/retriever_redis.py | 100 +++++++++++++++ 8 files changed, 398 insertions(+) create mode 100644 comps/retrievers/multimodal_langchain/redis/README.md create mode 100644 comps/retrievers/multimodal_langchain/redis/__init__.py create mode 100644 comps/retrievers/multimodal_langchain/redis/docker/Dockerfile create mode 100644 comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml create mode 100644 comps/retrievers/multimodal_langchain/redis/multimodal_config.py create mode 100644 comps/retrievers/multimodal_langchain/redis/redis_schema.yml create mode 100644 comps/retrievers/multimodal_langchain/redis/requirements.txt create mode 100644 comps/retrievers/multimodal_langchain/redis/retriever_redis.py diff --git a/comps/retrievers/multimodal_langchain/redis/README.md b/comps/retrievers/multimodal_langchain/redis/README.md new file mode 100644 index 0000000000..a8d8e2fb0c --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/README.md @@ -0,0 +1,120 @@ +# Retriever Microservice + +This retriever microservice is a highly efficient search service designed for handling and retrieving embedding vectors from multimodal data. It operates by receiving an embedding vector as input and conducting a similarity search against vectors stored in a VectorDB database. Users must specify the VectorDB's URL and the index name, and the service searches within that index to find documents with the highest similarity to the input vector. + +The service primarily utilizes similarity measures in vector space to rapidly retrieve contentually similar documents. The vector-based retrieval approach is particularly suited for handling large datasets, offering fast and accurate search results that significantly enhance the efficiency and quality of information retrieval. + +Overall, this microservice provides robust backend support for applications requiring efficient similarity searches, playing a vital role in scenarios such as recommendation systems, information retrieval, or any other context where precise measurement of document similarity is crucial. + +## 🚀1. Start Microservice with Python (Option 1) + +To start the retriever microservice, you must first install the required python packages. + +### 1.1 Install Requirements + +```bash +pip install -r requirements.txt +``` +### 1.2 Setup VectorDB Service + +You need to setup your own VectorDB service (Redis in this example), and ingest your knowledge documents into the vector database. + +As for Redis, you could start a docker container using the following commands. +Remember to ingest data into it manually. + +```bash +docker run -d --name="redis-vector-db" -p 6379:6379 -p 8001:8001 redis/redis-stack:7.2.0-v9 +``` +### 1.3 Ingest images or video + +Upload a video or images using the dataprep microservice, instructions can be found [here](https://github.com/opea-project/GenAIComps/tree/main/comps/dataprep/redis/multimodal_langchain/README.md). + +### 1.4 Start Retriever Service + +```bash +python langchain_multimodal/retriever_redis.py +``` + +## 🚀2. Start Microservice with Docker (Option 2) + +### 2.1 Setup Environment Variables + +```bash +export REDIS_URL="redis://${your_ip}:6379" +export INDEX_NAME=${your_index_name} +``` + +### 2.2 Build Docker Image + +```bash +cd ../../ +docker build -t opea/multimodal-retriever-redis:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/retrievers/langchain_multimodal/redis/docker/Dockerfile . +``` + +To start a docker container, you have two options: + +- A. Run Docker with CLI +- B. Run Docker with Docker Compose + +You can choose one as needed. + +### 2.3 Run Docker with CLI (Option A) + +```bash +docker run -d --name="retriever-redis-server" -p 7000:7000 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e REDIS_URL=$REDIS_URL -e INDEX_NAME=$INDEX_NAME opea/multimodal-retriever-redis:latest +``` + +### 2.4 Run Docker with Docker Compose (Option B) + +```bash +cd langchain_multimodal/docker +docker compose -f docker_compose_retriever.yaml up -d +``` + +## 🚀3. Consume Retriever Service + +### 3.1 Consume Embedding Service + +To consume the Retriever Microservice, you can generate a mock embedding vector of length 512 with Python. + +```bash +your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") +curl http://${your_ip}:7000/v1/retrieval \ + -X POST \ + -d {\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding}}" \ + -H 'Content-Type: application/json' +``` + +You can set the parameters for the retriever. + +```bash +your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") +curl http://localhost:7000/v1/retrieval \ + -X POST \ + -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity\", \"k\":4}" \ + -H 'Content-Type: application/json' +``` + +```bash +your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") +curl http://localhost:7000/v1/retrieval \ + -X POST \ + -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity_distance_threshold\", \"k\":4, \"distance_threshold\":1.0}" \ + -H 'Content-Type: application/json' +``` + +```bash +your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") +curl http://localhost:7000/v1/retrieval \ + -X POST \ + -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity_score_threshold\", \"k\":4, \"score_threshold\":0.2}" \ + -H 'Content-Type: application/json' +``` + +```bash +your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") +curl http://localhost:7000/v1/retrieval \ + -X POST \ + -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"mmr\", \"k\":4, \"fetch_k\":20, \"lambda_mult\":0.5}" \ + -H 'Content-Type: application/json' +``` diff --git a/comps/retrievers/multimodal_langchain/redis/__init__.py b/comps/retrievers/multimodal_langchain/redis/__init__.py new file mode 100644 index 0000000000..916f3a44b2 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile b/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile new file mode 100644 index 0000000000..ed1258c579 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile @@ -0,0 +1,29 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +FROM langchain/langchain:latest + +ARG ARCH="cpu" + +RUN apt-get update -y && apt-get install -y --no-install-recommends --fix-missing \ + libgl1-mesa-glx \ + libjemalloc-dev \ + vim + +RUN useradd -m -s /bin/bash user && \ + mkdir -p /home/user && \ + chown -R user /home/user/ + +COPY comps /home/user/comps + +USER user + +RUN pip install --no-cache-dir --upgrade pip && \ + if [ ${ARCH} = "cpu" ]; then pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu; fi && \ + pip install --no-cache-dir -r /home/user/comps/retrievers/langchain_multimodal/redis/requirements.txt + +ENV PYTHONPATH=$PYTHONPATH:/home/user + +WORKDIR /home/user/comps/retrievers/multimodal_langchain/redis + +ENTRYPOINT ["python", "retriever_redis.py"] diff --git a/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml new file mode 100644 index 0000000000..4129a4c782 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml @@ -0,0 +1,33 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +version: "3.8" + +services: + tei_xeon_service: + image: retriever-redis:cpu-1.2 + container_name: tei-xeon-server + ports: + - "6060:80" + volumes: + - "./data:/data" + shm_size: 1g + command: --model-id "BridgeTower/bridgetower-large-itm-mlm-itc" + retriever: + image: opea/retriever-redis:latest + container_name: retriever-redis-server + ports: + - "7000:7000" + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + REDIS_URL: ${REDIS_URL} + INDEX_NAME: ${INDEX_NAME} + LANGCHAIN_API_KEY: ${LANGCHAIN_API_KEY} + restart: unless-stopped + +networks: + default: + driver: bridge diff --git a/comps/retrievers/multimodal_langchain/redis/multimodal_config.py b/comps/retrievers/multimodal_langchain/redis/multimodal_config.py new file mode 100644 index 0000000000..2ae183bfb8 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/multimodal_config.py @@ -0,0 +1,80 @@ +import os + + +def get_boolean_env_var(var_name, default_value=False): + """Retrieve the boolean value of an environment variable. + Args: + var_name (str): The name of the environment variable to retrieve. + default_value (bool): The default value to return if the variable + is not found. + Returns: + bool: The value of the environment variable, interpreted as a boolean. + """ + true_values = {"true", "1", "t", "y", "yes"} + false_values = {"false", "0", "f", "n", "no"} + + # Retrieve the environment variable's value + value = os.getenv(var_name, "").lower() + + # Decide the boolean value based on the content of the string + if value in true_values: + return True + elif value in false_values: + return False + else: + return default_value + + +# Check for openai API key +#if "OPENAI_API_KEY" not in os.environ: +# raise Exception("Must provide an OPENAI_API_KEY as an env var.") + + +# Whether or not to enable langchain debugging +DEBUG = get_boolean_env_var("DEBUG", False) +# Set DEBUG env var to "true" if you wish to enable LC debugging module +if DEBUG: + import langchain + + langchain.debug = True + + +# Embedding model +EMBED_MODEL = os.getenv("EMBED_MODEL", "BridgeTower/bridgetower-large-itm-mlm-itc") + +# Redis Connection Information +REDIS_HOST = os.getenv("REDIS_HOST", "localhost") +REDIS_PORT = int(os.getenv("REDIS_PORT", 6379)) + + +def format_redis_conn_from_env(): + redis_url = os.getenv("REDIS_URL", None) + if redis_url: + return redis_url + else: + using_ssl = get_boolean_env_var("REDIS_SSL", False) + start = "rediss://" if using_ssl else "redis://" + + # if using RBAC + password = os.getenv("REDIS_PASSWORD", None) + username = os.getenv("REDIS_USERNAME", "default") + if password is not None: + start += f"{username}:{password}@" + + return start + f"{REDIS_HOST}:{REDIS_PORT}" + + +REDIS_URL = format_redis_conn_from_env() + +# Vector Index Configuration +INDEX_NAME = os.getenv("INDEX_NAME", "test-index") + +current_file_path = os.path.abspath(__file__) +parent_dir = os.path.dirname(current_file_path) +REDIS_SCHEMA = os.getenv("REDIS_SCHEMA", "redis_schema.yml") +schema_path = os.path.join(parent_dir, REDIS_SCHEMA) +INDEX_SCHEMA = schema_path +TGI_ENDPOINT = os.getenv("TGI_ENDPOINT", "http://localhost:8080") +TGI_ENDPOINT_NO_RAG = os.getenv("TGI_ENDPOINT_NO_RAG", "http://localhost:8081") +NUM_RETRIEVED_RESULTS = int(os.getenv("NUM_RETRIEVED_RESULTS", 1)) +MULTIMODAL_CHAT_MODEL = os.getenv("MULTIMODAL_CHAT_MODEL", "llava-hf/llava-1.5-13b-hf") diff --git a/comps/retrievers/multimodal_langchain/redis/redis_schema.yml b/comps/retrievers/multimodal_langchain/redis/redis_schema.yml new file mode 100644 index 0000000000..f0d1bd5674 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/redis_schema.yml @@ -0,0 +1,20 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +text: +- name: content +- name: b64_img_str +- name: video_id +- name: source_video +- name: embedding_type +- name: title +- name: description +- name: transcript_for_inference +numeric: +- name: time_of_frame_ms +vector: +- name: content_vector + algorithm: HNSW + datatype: FLOAT32 + dims: 512 + distance_metric: COSINE diff --git a/comps/retrievers/multimodal_langchain/redis/requirements.txt b/comps/retrievers/multimodal_langchain/redis/requirements.txt new file mode 100644 index 0000000000..3720190d3e --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/requirements.txt @@ -0,0 +1,14 @@ +docarray[full] +easyocr +fastapi +langchain_community +langsmith +opentelemetry-api +opentelemetry-exporter-otlp +opentelemetry-sdk +prometheus-fastapi-instrumentator +pymupdf +redis +sentence_transformers +shortuuid +uvicorn diff --git a/comps/retrievers/multimodal_langchain/redis/retriever_redis.py b/comps/retrievers/multimodal_langchain/redis/retriever_redis.py new file mode 100644 index 0000000000..bb90623421 --- /dev/null +++ b/comps/retrievers/multimodal_langchain/redis/retriever_redis.py @@ -0,0 +1,100 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import os +import time +from typing import Union + +from comps import BridgeTowerEmbedding +from langchain_community.vectorstores import Redis +from langsmith import traceable +from multimodal_config import INDEX_NAME, REDIS_URL, REDIS_SCHEMA + +from comps import ( + EmbedMultimodalDoc, + SearchedMultimodalDoc, + ServiceType, + TextDoc, + opea_microservices, + register_microservice, + register_statistics, + statistics_dict, +) +from comps.cores.proto.api_protocol import ( + ChatCompletionRequest, + RetrievalRequest, + RetrievalResponse, + RetrievalResponseData, +) + +@register_microservice( + name="opea_service@retriever_redis", + service_type=ServiceType.RETRIEVER, + endpoint="/v1/retrieval", + host="0.0.0.0", + port=7000, +) +@traceable(run_type="retriever") +@register_statistics(names=["opea_service@retriever_redis"]) +def retrieve( + input: Union[EmbedMultimodalDoc, RetrievalRequest, ChatCompletionRequest] +) -> Union[SearchedMultimodalDoc, RetrievalResponse, ChatCompletionRequest]: + + start = time.time() + # check if the Redis index has data + if vector_db.client.keys() == []: + search_res = [] + else: + if isinstance(input, EmbedMultimodalDoc): + query = input.text + else: + # for RetrievalRequest, ChatCompletionRequest + query = input.input + # if the Redis index has data, perform the search + if input.search_type == "similarity": + search_res = vector_db.similarity_search_by_vector(embedding=input.embedding, k=input.k) + elif input.search_type == "similarity_distance_threshold": + if input.distance_threshold is None: + raise ValueError("distance_threshold must be provided for " + "similarity_distance_threshold retriever") + search_res = vector_db.similarity_search_by_vector( + embedding=input.embedding, k=input.k, distance_threshold=input.distance_threshold + ) + elif input.search_type == "similarity_score_threshold": + docs_and_similarities = vector_db.similarity_search_with_relevance_scores( + query=input.text, k=input.k, score_threshold=input.score_threshold + ) + search_res = [doc for doc, _ in docs_and_similarities] + elif input.search_type == "mmr": + search_res = vector_db.max_marginal_relevance_search( + query=input.text, k=input.k, fetch_k=input.fetch_k, lambda_mult=input.lambda_mult + ) + else: + raise ValueError(f"{input.search_type} not valid") + + # return different response format + retrieved_docs = [] + if isinstance(input, EmbedMultimodalDoc): + metadata_list = [] + for r in search_res: + metadata_list.append(r.metadata) + retrieved_docs.append(TextDoc(text=r.page_content)) + result = SearchedMultimodalDoc(retrieved_docs=retrieved_docs, initial_query=input.text, metadata=metadata_list) + else: + for r in search_res: + retrieved_docs.append(RetrievalResponseData(text=r.page_content, metadata=r.metadata)) + if isinstance(input, RetrievalRequest): + result = RetrievalResponse(retrieved_docs=retrieved_docs) + elif isinstance(input, ChatCompletionRequest): + input.retrieved_docs = retrieved_docs + input.documents = [doc.text for doc in retrieved_docs] + result = input + + statistics_dict["opea_service@retriever_redis"].append_latency(time.time() - start, None) + return result + + +if __name__ == "__main__": + + embeddings = BridgeTowerEmbedding() + vector_db = Redis.from_existing_index(embedding=embeddings, schema=REDIS_SCHEMA, index_name=INDEX_NAME, redis_url=REDIS_URL) + opea_microservices["opea_service@retriever_redis"].start() From 77632f2686fbdebe723edc80b3ee6faba7532f30 Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Fri, 30 Aug 2024 19:04:08 +0000 Subject: [PATCH 2/8] cosmetic Signed-off-by: siddhivelankar23 --- comps/retrievers/multimodal_langchain/redis/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comps/retrievers/multimodal_langchain/redis/README.md b/comps/retrievers/multimodal_langchain/redis/README.md index a8d8e2fb0c..31bdaff384 100644 --- a/comps/retrievers/multimodal_langchain/redis/README.md +++ b/comps/retrievers/multimodal_langchain/redis/README.md @@ -8,7 +8,7 @@ Overall, this microservice provides robust backend support for applications requ ## 🚀1. Start Microservice with Python (Option 1) -To start the retriever microservice, you must first install the required python packages. +To start the retriever microservice, you must first install the required python packages. ### 1.1 Install Requirements From 4c3ea33bfa9848107282561522a1b97fb61e048f Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 00:17:07 +0000 Subject: [PATCH 3/8] update redis schema Signed-off-by: siddhivelankar23 --- .../redis/redis_schema.yml | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/comps/retrievers/multimodal_langchain/redis/redis_schema.yml b/comps/retrievers/multimodal_langchain/redis/redis_schema.yml index f0d1bd5674..32f4a79ae4 100644 --- a/comps/retrievers/multimodal_langchain/redis/redis_schema.yml +++ b/comps/retrievers/multimodal_langchain/redis/redis_schema.yml @@ -2,19 +2,18 @@ # SPDX-License-Identifier: Apache-2.0 text: -- name: content -- name: b64_img_str -- name: video_id -- name: source_video -- name: embedding_type -- name: title -- name: description -- name: transcript_for_inference + - name: content + - name: b64_img_str + - name: video_id + - name: source_video + - name: embedding_type + - name: title + - name: transcript_for_inference numeric: -- name: time_of_frame_ms + - name: time_of_frame_ms vector: -- name: content_vector - algorithm: HNSW - datatype: FLOAT32 - dims: 512 - distance_metric: COSINE + - name: content_vector + algorithm: HNSW + datatype: FLOAT32 + dims: 512 + distance_metric: COSINE From 168803315e27f58767ba3b7d5e3ab7aeaf2527d1 Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 00:30:48 +0000 Subject: [PATCH 4/8] update multimodal config and docker compose retriever Signed-off-by: siddhivelankar23 --- .../redis/docker/docker_compose_retriever.yaml | 12 +----------- .../multimodal_langchain/redis/multimodal_config.py | 12 ++++++------ 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml index 4129a4c782..044e723ac0 100644 --- a/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml +++ b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml @@ -1,18 +1,9 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -version: "3.8" +version: "1.0" services: - tei_xeon_service: - image: retriever-redis:cpu-1.2 - container_name: tei-xeon-server - ports: - - "6060:80" - volumes: - - "./data:/data" - shm_size: 1g - command: --model-id "BridgeTower/bridgetower-large-itm-mlm-itc" retriever: image: opea/retriever-redis:latest container_name: retriever-redis-server @@ -25,7 +16,6 @@ services: https_proxy: ${https_proxy} REDIS_URL: ${REDIS_URL} INDEX_NAME: ${INDEX_NAME} - LANGCHAIN_API_KEY: ${LANGCHAIN_API_KEY} restart: unless-stopped networks: diff --git a/comps/retrievers/multimodal_langchain/redis/multimodal_config.py b/comps/retrievers/multimodal_langchain/redis/multimodal_config.py index 2ae183bfb8..f92d5755d7 100644 --- a/comps/retrievers/multimodal_langchain/redis/multimodal_config.py +++ b/comps/retrievers/multimodal_langchain/redis/multimodal_config.py @@ -1,5 +1,10 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + import os +current_file_path = os.path.abspath(__file__) +parent_dir = os.path.dirname(current_file_path) def get_boolean_env_var(var_name, default_value=False): """Retrieve the boolean value of an environment variable. @@ -69,12 +74,7 @@ def format_redis_conn_from_env(): # Vector Index Configuration INDEX_NAME = os.getenv("INDEX_NAME", "test-index") -current_file_path = os.path.abspath(__file__) -parent_dir = os.path.dirname(current_file_path) REDIS_SCHEMA = os.getenv("REDIS_SCHEMA", "redis_schema.yml") schema_path = os.path.join(parent_dir, REDIS_SCHEMA) INDEX_SCHEMA = schema_path -TGI_ENDPOINT = os.getenv("TGI_ENDPOINT", "http://localhost:8080") -TGI_ENDPOINT_NO_RAG = os.getenv("TGI_ENDPOINT_NO_RAG", "http://localhost:8081") -NUM_RETRIEVED_RESULTS = int(os.getenv("NUM_RETRIEVED_RESULTS", 1)) -MULTIMODAL_CHAT_MODEL = os.getenv("MULTIMODAL_CHAT_MODEL", "llava-hf/llava-1.5-13b-hf") +NUM_RETRIEVED_RESULTS = int(os.getenv("NUM_RETRIEVED_RESULTS", 1)) \ No newline at end of file From bc1699f2b0efad7348249139af563ff54728bf19 Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 00:34:02 +0000 Subject: [PATCH 5/8] update requirements Signed-off-by: siddhivelankar23 --- comps/retrievers/multimodal_langchain/redis/requirements.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/comps/retrievers/multimodal_langchain/redis/requirements.txt b/comps/retrievers/multimodal_langchain/redis/requirements.txt index 3720190d3e..e6ceddd4ef 100644 --- a/comps/retrievers/multimodal_langchain/redis/requirements.txt +++ b/comps/retrievers/multimodal_langchain/redis/requirements.txt @@ -1,14 +1,11 @@ docarray[full] -easyocr fastapi langchain_community -langsmith opentelemetry-api opentelemetry-exporter-otlp opentelemetry-sdk prometheus-fastapi-instrumentator -pymupdf redis -sentence_transformers shortuuid uvicorn +transformers \ No newline at end of file From 5ecbfdb11c56bee8b3fcca90a6404762df8a3fe1 Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 00:47:09 +0000 Subject: [PATCH 6/8] update retriever redis Signed-off-by: siddhivelankar23 --- .../redis/retriever_redis.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/comps/retrievers/multimodal_langchain/redis/retriever_redis.py b/comps/retrievers/multimodal_langchain/redis/retriever_redis.py index bb90623421..50d567f821 100644 --- a/comps/retrievers/multimodal_langchain/redis/retriever_redis.py +++ b/comps/retrievers/multimodal_langchain/redis/retriever_redis.py @@ -1,13 +1,11 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -import os import time from typing import Union -from comps import BridgeTowerEmbedding +from comps.embeddings.multimodal_embeddings.bridgetower import BridgeTowerEmbedding from langchain_community.vectorstores import Redis -from langsmith import traceable from multimodal_config import INDEX_NAME, REDIS_URL, REDIS_SCHEMA from comps import ( @@ -28,14 +26,14 @@ ) @register_microservice( - name="opea_service@retriever_redis", + name="opea_service@multimodal_retriever_redis", service_type=ServiceType.RETRIEVER, - endpoint="/v1/retrieval", + endpoint="/v1/multimodal_retrieval", host="0.0.0.0", port=7000, ) -@traceable(run_type="retriever") -@register_statistics(names=["opea_service@retriever_redis"]) + +@register_statistics(names=["opea_service@multimodal_retriever_redis"]) def retrieve( input: Union[EmbedMultimodalDoc, RetrievalRequest, ChatCompletionRequest] ) -> Union[SearchedMultimodalDoc, RetrievalResponse, ChatCompletionRequest]: @@ -45,11 +43,6 @@ def retrieve( if vector_db.client.keys() == []: search_res = [] else: - if isinstance(input, EmbedMultimodalDoc): - query = input.text - else: - # for RetrievalRequest, ChatCompletionRequest - query = input.input # if the Redis index has data, perform the search if input.search_type == "similarity": search_res = vector_db.similarity_search_by_vector(embedding=input.embedding, k=input.k) @@ -89,7 +82,7 @@ def retrieve( input.documents = [doc.text for doc in retrieved_docs] result = input - statistics_dict["opea_service@retriever_redis"].append_latency(time.time() - start, None) + statistics_dict["opea_service@multimodal_retriever_redis"].append_latency(time.time() - start, None) return result @@ -97,4 +90,4 @@ def retrieve( embeddings = BridgeTowerEmbedding() vector_db = Redis.from_existing_index(embedding=embeddings, schema=REDIS_SCHEMA, index_name=INDEX_NAME, redis_url=REDIS_URL) - opea_microservices["opea_service@retriever_redis"].start() + opea_microservices["opea_service@multimodal_retriever_redis"].start() From bc2329071c454db261821634ce0f85f9f3e99f0c Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 02:17:28 +0000 Subject: [PATCH 7/8] multimodal retriever implementation Signed-off-by: siddhivelankar23 --- .../multimodal_langchain/redis/README.md | 21 ++++++++++--------- .../redis/docker/Dockerfile | 2 +- .../docker/docker_compose_retriever.yaml | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/comps/retrievers/multimodal_langchain/redis/README.md b/comps/retrievers/multimodal_langchain/redis/README.md index 31bdaff384..1b7fa72584 100644 --- a/comps/retrievers/multimodal_langchain/redis/README.md +++ b/comps/retrievers/multimodal_langchain/redis/README.md @@ -40,6 +40,7 @@ python langchain_multimodal/retriever_redis.py ### 2.1 Setup Environment Variables ```bash +export your_ip=$(hostname -I | awk '{print $1}') export REDIS_URL="redis://${your_ip}:6379" export INDEX_NAME=${your_index_name} ``` @@ -47,8 +48,8 @@ export INDEX_NAME=${your_index_name} ### 2.2 Build Docker Image ```bash -cd ../../ -docker build -t opea/multimodal-retriever-redis:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/retrievers/langchain_multimodal/redis/docker/Dockerfile . +cd ../../../../ +docker build -t opea/multimodal-retriever-redis:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/retrievers/multimodal_langchain/redis/docker/Dockerfile . ``` To start a docker container, you have two options: @@ -61,13 +62,13 @@ You can choose one as needed. ### 2.3 Run Docker with CLI (Option A) ```bash -docker run -d --name="retriever-redis-server" -p 7000:7000 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e REDIS_URL=$REDIS_URL -e INDEX_NAME=$INDEX_NAME opea/multimodal-retriever-redis:latest +docker run -d --name="multimodal-retriever-redis-server" -p 7000:7000 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e REDIS_URL=$REDIS_URL -e INDEX_NAME=$INDEX_NAME opea/multimodal-retriever-redis:latest ``` ### 2.4 Run Docker with Docker Compose (Option B) ```bash -cd langchain_multimodal/docker +cd docker docker compose -f docker_compose_retriever.yaml up -d ``` @@ -79,9 +80,9 @@ To consume the Retriever Microservice, you can generate a mock embedding vector ```bash your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") -curl http://${your_ip}:7000/v1/retrieval \ +curl http://${your_ip}:7000/v1/multimodal_retrieval \ -X POST \ - -d {\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding}}" \ + -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding}}" \ -H 'Content-Type: application/json' ``` @@ -89,7 +90,7 @@ You can set the parameters for the retriever. ```bash your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") -curl http://localhost:7000/v1/retrieval \ +curl http://localhost:7000/v1/multimodal_retrieval \ -X POST \ -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity\", \"k\":4}" \ -H 'Content-Type: application/json' @@ -97,7 +98,7 @@ curl http://localhost:7000/v1/retrieval \ ```bash your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") -curl http://localhost:7000/v1/retrieval \ +curl http://localhost:7000/v1/multimodal_retrieval \ -X POST \ -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity_distance_threshold\", \"k\":4, \"distance_threshold\":1.0}" \ -H 'Content-Type: application/json' @@ -105,7 +106,7 @@ curl http://localhost:7000/v1/retrieval \ ```bash your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") -curl http://localhost:7000/v1/retrieval \ +curl http://localhost:7000/v1/multimodal_retrieval \ -X POST \ -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"similarity_score_threshold\", \"k\":4, \"score_threshold\":0.2}" \ -H 'Content-Type: application/json' @@ -113,7 +114,7 @@ curl http://localhost:7000/v1/retrieval \ ```bash your_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") -curl http://localhost:7000/v1/retrieval \ +curl http://localhost:7000/v1/multimodal_retrieval \ -X POST \ -d "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${your_embedding},\"search_type\":\"mmr\", \"k\":4, \"fetch_k\":20, \"lambda_mult\":0.5}" \ -H 'Content-Type: application/json' diff --git a/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile b/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile index ed1258c579..33077c3037 100644 --- a/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile +++ b/comps/retrievers/multimodal_langchain/redis/docker/Dockerfile @@ -20,7 +20,7 @@ USER user RUN pip install --no-cache-dir --upgrade pip && \ if [ ${ARCH} = "cpu" ]; then pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu; fi && \ - pip install --no-cache-dir -r /home/user/comps/retrievers/langchain_multimodal/redis/requirements.txt + pip install --no-cache-dir -r /home/user/comps/retrievers/multimodal_langchain/redis/requirements.txt ENV PYTHONPATH=$PYTHONPATH:/home/user diff --git a/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml index 044e723ac0..efba29a4e1 100644 --- a/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml +++ b/comps/retrievers/multimodal_langchain/redis/docker/docker_compose_retriever.yaml @@ -5,8 +5,8 @@ version: "1.0" services: retriever: - image: opea/retriever-redis:latest - container_name: retriever-redis-server + image: opea/multimodal-retriever-redis:latest + container_name: multimodal-retriever-redis-server ports: - "7000:7000" ipc: host From c56151d32e5143e181132495f1e9773e069accaa Mon Sep 17 00:00:00 2001 From: siddhivelankar23 Date: Tue, 3 Sep 2024 02:30:00 +0000 Subject: [PATCH 8/8] test for multimodal retriever Signed-off-by: siddhivelankar23 --- ...t_retrievers_multimodal_langchain_redis.sh | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/test_retrievers_multimodal_langchain_redis.sh diff --git a/tests/test_retrievers_multimodal_langchain_redis.sh b/tests/test_retrievers_multimodal_langchain_redis.sh new file mode 100644 index 0000000000..3d3c37ac30 --- /dev/null +++ b/tests/test_retrievers_multimodal_langchain_redis.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +set -x + +WORKPATH=$(dirname "$PWD") +LOG_PATH="$WORKPATH/tests" +ip_address=$(hostname -I | awk '{print $1}') + +function build_docker_images() { + cd $WORKPATH + docker build --no-cache -t opea/multimodal-retriever-redis:comps --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/retrievers/multimodal_langchain/redis/docker/Dockerfile . + if [ $? -ne 0 ]; then + echo "opea/multimodal-retriever-redis built fail" + exit 1 + else + echo "opea/multimodal-retriever-redis built successful" + fi +} + +function start_service() { + # redis + docker run -d --name test-comps-multimodal-retriever-redis-vector-db -p 5010:6379 -p 5011:8001 -e HTTPS_PROXY=$https_proxy -e HTTP_PROXY=$https_proxy redis/redis-stack:7.2.0-v9 + sleep 10s + + # redis retriever + export REDIS_URL="redis://${ip_address}:5010" + export INDEX_NAME="rag-redis" + retriever_port=5009 + unset http_proxy + docker run -d --name="test-comps-multimodal-retriever-redis-server" -p ${retriever_port}:7000 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e REDIS_URL=$REDIS_URL -e INDEX_NAME=$INDEX_NAME opea/multimodal-retriever-redis:comps + + sleep 3m +} + +function validate_microservice() { + retriever_port=5009 + export PATH="${HOME}/miniforge3/bin:$PATH" + source activate + URL="http://${ip_address}:$retriever_port/v1/multimodal_retrieval" + test_embedding=$(python -c "import random; embedding = [random.uniform(-1, 1) for _ in range(512)]; print(embedding)") + + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST -d "{\"text\":\"test\",\"embedding\":${test_embedding}}" -H 'Content-Type: application/json' "$URL") + if [ "$HTTP_STATUS" -eq 200 ]; then + echo "[ retriever ] HTTP status is 200. Checking content..." + local CONTENT=$(curl -s -X POST -d "{\"text\":\"test\",\"embedding\":${test_embedding}}" -H 'Content-Type: application/json' "$URL" | tee ${LOG_PATH}/retriever.log) + + if echo "$CONTENT" | grep -q "retrieved_docs"; then + echo "[ retriever ] Content is as expected." + else + echo "[ retriever ] Content does not match the expected result: $CONTENT" + docker logs test-comps-multimodal-retriever-redis-server >> ${LOG_PATH}/retriever.log + exit 1 + fi + else + echo "[ retriever ] HTTP status is not 200. Received status was $HTTP_STATUS" + docker logs test-comps-multimodal-retriever-redis-server >> ${LOG_PATH}/retriever.log + exit 1 + fi +} + +function stop_docker() { + cid_retrievers=$(docker ps -aq --filter "name=test-comps-multimodal-retriever*") + if [[ ! -z "$cid_retrievers" ]]; then + docker stop $cid_retrievers && docker rm $cid_retrievers && sleep 1s + fi +} + +function main() { + + stop_docker + + build_docker_images + start_service + + validate_microservice + + stop_docker + # echo y | docker system prune + +} + +main