diff --git a/ChatQnA/docker/xeon/README_pinecone.md b/ChatQnA/docker/xeon/README_pinecone.md index 5c1a50c2e..2b365c70f 100644 --- a/ChatQnA/docker/xeon/README_pinecone.md +++ b/ChatQnA/docker/xeon/README_pinecone.md @@ -148,7 +148,7 @@ Then run the command `docker images`, you will have the following 7 Docker Image ### Setup Environment Variables -Since the `docker_compose_pinecone.yaml` will consume some environment variables, you need to setup them in advance as below. +Since the `compose_pinecone.yaml` will consume some environment variables, you need to setup them in advance as below. **Export the value of the public IP address of your Xeon server to the `host_ip` environment variable** @@ -212,7 +212,7 @@ Note: Please replace with `host_ip` with you external IP address, do not use loc ```bash cd GenAIExamples/ChatQnA/docker/xeon/ -docker compose -f docker_compose_pinecone.yaml up -d +docker compose -f compose_pinecone.yaml up -d ``` ### Validate Microservices @@ -330,7 +330,7 @@ curl -X POST "http://${host_ip}:6008/v1/dataprep/get_file" \ ## Enable LangSmith for Monotoring Application (Optional) -LangSmith offers tools to debug, evaluate, and monitor language models and intelligent agents. It can be used to assess benchmark data for each microservice. Before launching your services with `docker compose -f docker_compose_pinecone.yaml up -d`, you need to enable LangSmith tracing by setting the `LANGCHAIN_TRACING_V2` environment variable to true and configuring your LangChain API key. +LangSmith offers tools to debug, evaluate, and monitor language models and intelligent agents. It can be used to assess benchmark data for each microservice. Before launching your services with `docker compose -f compose_pinecone.yaml up -d`, you need to enable LangSmith tracing by setting the `LANGCHAIN_TRACING_V2` environment variable to true and configuring your LangChain API key. Here's how you can do it: diff --git a/ChatQnA/docker/xeon/docker_compose_pinecone.yaml b/ChatQnA/docker/xeon/compose_pinecone.yaml similarity index 100% rename from ChatQnA/docker/xeon/docker_compose_pinecone.yaml rename to ChatQnA/docker/xeon/compose_pinecone.yaml diff --git a/ChatQnA/tests/_test_chatqna_pinecone_on_xeon.sh b/ChatQnA/tests/_test_chatqna_pinecone_on_xeon.sh new file mode 100644 index 000000000..392941994 --- /dev/null +++ b/ChatQnA/tests/_test_chatqna_pinecone_on_xeon.sh @@ -0,0 +1,232 @@ +#!/bin/bash +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +set -e +echo "IMAGE_REPO=${IMAGE_REPO}" + +WORKPATH=$(dirname "$PWD") +LOG_PATH="$WORKPATH/tests" +ip_address=$(hostname -I | awk '{print $1}') + +function build_docker_images() { + cd $WORKPATH + git clone https://github.com/opea-project/GenAIComps.git + cd GenAIComps + + docker build -t opea/embedding-tei:latest -f comps/embeddings/langchain/docker/Dockerfile . + docker build -t opea/retriever-pinecone:latest -f comps/retrievers/langchain/pinecone/docker/Dockerfile . + docker build -t opea/reranking-tei:latest -f comps/reranks/tei/docker/Dockerfile . + docker build -t opea/llm-tgi:latest -f comps/llms/text-generation/tgi/Dockerfile . + docker build -t opea/dataprep-pinecone:latest -f comps/dataprep/pinecone/docker/Dockerfile . + + cd $WORKPATH/docker + docker build --no-cache -t opea/chatqna:latest -f Dockerfile . + + cd $WORKPATH/docker/ui + docker build --no-cache -t opea/chatqna-ui:latest -f docker/Dockerfile . + + docker images +} + +function start_services() { + cd $WORKPATH/docker/xeon + + export EMBEDDING_MODEL_ID="BAAI/bge-base-en-v1.5" + export RERANK_MODEL_ID="BAAI/bge-reranker-base" + export LLM_MODEL_ID="Intel/neural-chat-7b-v3-3" + export TEI_EMBEDDING_ENDPOINT="http://${ip_address}:6006" + export TEI_RERANKING_ENDPOINT="http://${ip_address}:8808" + export TGI_LLM_ENDPOINT="http://${ip_address}:9009" + export PINECONE_API_KEY=${PINECONE_KEY} + export PINECONE_INDEX_NAME="langchain-test" + export INDEX_NAME="langchain-test" + export HUGGINGFACEHUB_API_TOKEN=${HUGGINGFACEHUB_API_TOKEN} + export MEGA_SERVICE_HOST_IP=${ip_address} + export EMBEDDING_SERVICE_HOST_IP=${ip_address} + export RETRIEVER_SERVICE_HOST_IP=${ip_address} + export RERANK_SERVICE_HOST_IP=${ip_address} + export LLM_SERVICE_HOST_IP=${ip_address} + export BACKEND_SERVICE_ENDPOINT="http://${ip_address}:8888/v1/chatqna" + export DATAPREP_SERVICE_ENDPOINT="http://${ip_address}:6007/v1/dataprep" + export DATAPREP_GET_FILE_ENDPOINT="http://${ip_address}:6007/v1/dataprep/get_file" + export DATAPREP_DELETE_FILE_ENDPOINT="http://${ip_address}:6007/v1/dataprep/delete_file" + + sed -i "s/backend_address/$ip_address/g" $WORKPATH/docker/ui/svelte/.env + + if [[ "$IMAGE_REPO" != "" ]]; then + # Replace the container name with a test-specific name + echo "using image repository $IMAGE_REPO and image tag $IMAGE_TAG" + sed -i "s#image: opea/chatqna:latest#image: opea/chatqna:${IMAGE_TAG}#g" compose_pinecone.yaml + sed -i "s#image: opea/chatqna-ui:latest#image: opea/chatqna-ui:${IMAGE_TAG}#g" compose_pinecone.yaml + sed -i "s#image: opea/chatqna-conversation-ui:latest#image: opea/chatqna-conversation-ui:${IMAGE_TAG}#g" compose_pinecone.yaml + sed -i "s#image: opea/*#image: ${IMAGE_REPO}opea/#g" compose_pinecone.yaml + cat compose_pinecone.yaml + fi + + # Start Docker Containers + docker compose -f compose_pinecone.yaml up -d + n=0 + until [[ "$n" -ge 200 ]]; do + docker logs tgi-service > tgi_service_start.log + if grep -q Connected tgi_service_start.log; then + break + fi + sleep 1s + n=$((n+1)) + done +} + +function validate_services() { + local URL="$1" + local EXPECTED_RESULT="$2" + local SERVICE_NAME="$3" + local DOCKER_NAME="$4" + local INPUT_DATA="$5" + + local HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST -d "$INPUT_DATA" -H 'Content-Type: application/json' "$URL") + if [ "$HTTP_STATUS" -eq 200 ]; then + echo "[ $SERVICE_NAME ] HTTP status is 200. Checking content..." + + local CONTENT=$(curl -s -X POST -d "$INPUT_DATA" -H 'Content-Type: application/json' "$URL" | tee ${LOG_PATH}/${SERVICE_NAME}.log) + + if echo "$CONTENT" | grep -q "$EXPECTED_RESULT"; then + echo "[ $SERVICE_NAME ] Content is as expected." + else + echo "[ $SERVICE_NAME ] Content does not match the expected result: $CONTENT" + docker logs ${DOCKER_NAME} >> ${LOG_PATH}/${SERVICE_NAME}.log + exit 1 + fi + else + echo "[ $SERVICE_NAME ] HTTP status is not 200. Received status was $HTTP_STATUS" + docker logs ${DOCKER_NAME} >> ${LOG_PATH}/${SERVICE_NAME}.log + exit 1 + fi + sleep 1s +} + +function validate_microservices() { + # Check if the microservices are running correctly. + + # tei for embedding service + validate_services \ + "${ip_address}:6006/embed" \ + "\[\[" \ + "tei-embedding" \ + "tei-embedding-server" \ + '{"inputs":"What is Deep Learning?"}' + + # embedding microservice + validate_services \ + "${ip_address}:6000/v1/embeddings" \ + '"text":"What is Deep Learning?","embedding":\[' \ + "embedding" \ + "embedding-tei-server" \ + '{"text":"What is Deep Learning?"}' + + sleep 1m # retrieval can't curl as expected, try to wait for more time + + # retrieval microservice + test_embedding=$(python3 -c "import random; embedding = [random.uniform(-1, 1) for _ in range(768)]; print(embedding)") + validate_services \ + "${ip_address}:7000/v1/retrieval" \ + " " \ + "retrieval" \ + "retriever-pinecone-server" \ + "{\"text\":\"What is the revenue of Nike in 2023?\",\"embedding\":${test_embedding}}" + + # tei for rerank microservice + validate_services \ + "${ip_address}:8808/rerank" \ + '{"index":1,"score":' \ + "tei-rerank" \ + "tei-reranking-server" \ + '{"query":"What is Deep Learning?", "texts": ["Deep Learning is not...", "Deep learning is..."]}' + + # rerank microservice + validate_services \ + "${ip_address}:8000/v1/reranking" \ + "Deep learning is..." \ + "rerank" \ + "reranking-tei-xeon-server" \ + '{"initial_query":"What is Deep Learning?", "retrieved_docs": [{"text":"Deep Learning is not..."}, {"text":"Deep learning is..."}]}' + + # tgi for llm service + validate_services \ + "${ip_address}:9009/generate" \ + "generated_text" \ + "tgi-llm" \ + "tgi-service" \ + '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":17, "do_sample": true}}' + + # llm microservice + validate_services \ + "${ip_address}:9000/v1/chat/completions" \ + "data: " \ + "llm" \ + "llm-tgi-server" \ + '{"query":"What is Deep Learning?"}' + +} + +function validate_megaservice() { + # Curl the Mega Service + validate_services \ + "${ip_address}:8888/v1/chatqna" \ + "billion" \ + "mega-chatqna" \ + "chatqna-xeon-backend-server" \ + '{"messages": "What is the revenue of Nike in 2023?"}' + +} + +function validate_frontend() { + cd $WORKPATH/docker/ui/svelte + local conda_env_name="OPEA_e2e" + export PATH=${HOME}/miniforge3/bin/:$PATH +# conda remove -n ${conda_env_name} --all -y +# conda create -n ${conda_env_name} python=3.12 -y + source activate ${conda_env_name} + + sed -i "s/localhost/$ip_address/g" playwright.config.ts + +# conda install -c conda-forge nodejs -y + npm install && npm ci && npx playwright install --with-deps + node -v && npm -v && pip list + + exit_status=0 + npx playwright test || exit_status=$? + + if [ $exit_status -ne 0 ]; then + echo "[TEST INFO]: ---------frontend test failed---------" + exit $exit_status + else + echo "[TEST INFO]: ---------frontend test passed---------" + fi +} + +function stop_docker() { + cd $WORKPATH/docker/xeon + docker compose stop && docker compose rm -f +} + +function main() { + + stop_docker + if [[ "$IMAGE_REPO" == "" ]]; then build_docker_images; fi + start_time=$(date +%s) + start_services + end_time=$(date +%s) + duration=$((end_time-start_time)) + echo "Mega service start duration is $duration s" && sleep 1s + + validate_microservices + validate_megaservice + validate_frontend + + stop_docker + echo y | docker system prune + +} + +main