From 340fa075bdf2152b4e2bc5830ef73b256f24dd8a Mon Sep 17 00:00:00 2001 From: chyundunovDatamonsters Date: Mon, 31 Mar 2025 12:49:33 +0700 Subject: [PATCH] Adding files to deploy Translation application on ROCm vLLM (#1648) Signed-off-by: Chingis Yundunov Signed-off-by: Artem Astafev --- .../img/translation-ui-response-example.png | Bin 0 -> 31978 bytes .../img/translation-ui-starting-page.png | Bin 0 -> 29657 bytes .../docker_compose/amd/gpu/rocm/README.md | 432 +++++++++++++++--- .../docker_compose/amd/gpu/rocm/compose.yaml | 2 +- .../amd/gpu/rocm/compose_vllm.yaml | 107 +++++ .../amd/gpu/rocm/set_env_vllm.sh | 23 + Translation/docker_image_build/build.yaml | 5 + .../tests/test_compose_vllm_on_rocm.sh | 193 ++++++++ 8 files changed, 704 insertions(+), 58 deletions(-) create mode 100644 Translation/assets/img/translation-ui-response-example.png create mode 100644 Translation/assets/img/translation-ui-starting-page.png create mode 100644 Translation/docker_compose/amd/gpu/rocm/compose_vllm.yaml create mode 100644 Translation/docker_compose/amd/gpu/rocm/set_env_vllm.sh create mode 100644 Translation/tests/test_compose_vllm_on_rocm.sh diff --git a/Translation/assets/img/translation-ui-response-example.png b/Translation/assets/img/translation-ui-response-example.png new file mode 100644 index 0000000000000000000000000000000000000000..762ac8116098b4343252c725a0319e4285c73fa7 GIT binary patch literal 31978 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 BDW3oU literal 0 HcmV?d00001 diff --git a/Translation/assets/img/translation-ui-starting-page.png b/Translation/assets/img/translation-ui-starting-page.png new file mode 100644 index 0000000000000000000000000000000000000000..3257f8daa65c9e90af036fb04f4cf9d6f4acf2d8 GIT binary patch literal 29657 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 literal 0 HcmV?d00001 diff --git a/Translation/docker_compose/amd/gpu/rocm/README.md b/Translation/docker_compose/amd/gpu/rocm/README.md index 38b017634..b2a56bf1d 100644 --- a/Translation/docker_compose/amd/gpu/rocm/README.md +++ b/Translation/docker_compose/amd/gpu/rocm/README.md @@ -1,42 +1,117 @@ # Build and deploy Translation Application on AMD GPU (ROCm) -## Build images +## Build Docker Images -### Build the LLM Docker Image +### 1. Build Docker Image -```bash -### Cloning repo -git clone https://github.com/opea-project/GenAIComps.git -cd GenAIComps +- #### Create application install directory and go to it: -### Build Docker image -docker build -t opea/llm-textgen:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/llms/src/text-generation/Dockerfile . -``` + ```bash + mkdir ~/translation-install && cd translation-install + ``` -### Build the MegaService Docker Image +- #### Clone the repository GenAIExamples (the default repository branch "main" is used here): -```bash -### Cloning repo -git clone https://github.com/opea-project/GenAIExamples -cd GenAIExamples/Translation/ + ```bash + git clone https://github.com/opea-project/GenAIExamples.git + ``` -### Build Docker image -docker build -t opea/translation:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f Dockerfile . -``` + If you need to use a specific branch/tag of the GenAIExamples repository, then (v1.3 replace with its own value): -### Build the UI Docker Image + ```bash + git clone https://github.com/opea-project/GenAIExamples.git && cd GenAIExamples && git checkout v1.3 + ``` -```bash -cd GenAIExamples/Translation/ui -### Build UI Docker image -docker build -t opea/translation-ui:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f docker/Dockerfile . -``` + We remind you that when using a specific version of the code, you need to use the README from this version: -## Deploy Translation Application +- #### Go to build directory: -### Features of Docker compose for AMD GPUs + ```bash + cd ~/translation-install/GenAIExamples/Translation/docker_image_build + ``` -1. Added forwarding of GPU devices to the container TGI service with instructions: +- Cleaning up the GenAIComps repository if it was previously cloned in this directory. + This is necessary if the build was performed earlier and the GenAIComps folder exists and is not empty: + + ```bash + echo Y | rm -R GenAIComps + ``` + +- #### Clone the repository GenAIComps (the default repository branch "main" is used here): + + ```bash + git clone https://github.com/opea-project/GenAIComps.git + ``` + + If you use a specific tag of the GenAIExamples repository, + then you should also use the corresponding tag for GenAIComps. (v1.3 replace with its own value): + + ```bash + git clone https://github.com/opea-project/GenAIComps.git && cd GenAIComps && git checkout v1.3 + ``` + + We remind you that when using a specific version of the code, you need to use the README from this version. + +- #### Setting the list of images for the build (from the build file.yaml) + + If you want to deploy a vLLM-based or TGI-based application, then the set of services is installed as follows: + + #### vLLM-based application + + ```bash + service_list="vllm-rocm translation translation-ui llm-textgen nginx" + ``` + + #### TGI-based application + + ```bash + service_list="translation translation-ui llm-textgen nginx" + ``` + +- #### Optional. Pull TGI Docker Image (Do this if you want to use TGI) + + ```bash + docker pull ghcr.io/huggingface/text-generation-inference:2.3.1-rocm + ``` + +- #### Build Docker Images + + ```bash + docker compose -f build.yaml build ${service_list} --no-cache + ``` + + After the build, we check the list of images with the command: + + ```bash + docker image ls + ``` + + The list of images should include: + + ##### vLLM-based application: + + - opea/vllm-rocm:latest + - opea/llm-textgen:latest + - opea/nginx:latest + - opea/translation:latest + - opea/translation-ui:latest + + ##### TGI-based application: + + - ghcr.io/huggingface/text-generation-inference:2.3.1-rocm + - opea/llm-textgen:latest + - opea/nginx:latest + - opea/translation:latest + - opea/translation-ui:latest + +--- + +### Docker Compose Configuration for AMD GPUs + +To enable GPU support for AMD GPUs, the following configuration is added to the Docker Compose file: + +- compose_vllm.yaml - for vLLM-based application +- compose.yaml - for TGI-based ```yaml shm_size: 1g @@ -51,16 +126,14 @@ security_opt: - seccomp:unconfined ``` -In this case, all GPUs are thrown. To reset a specific GPU, you need to use specific device names cardN and renderN. - -For example: +This configuration forwards all available GPUs to the container. To use a specific GPU, specify its `cardN` and `renderN` device IDs. For example: ```yaml shm_size: 1g devices: - /dev/kfd:/dev/kfd - /dev/dri/card0:/dev/dri/card0 - - /dev/dri/render128:/dev/dri/render128 + - /dev/dri/renderD128:/dev/dri/renderD128 cap_add: - SYS_PTRACE group_add: @@ -69,60 +142,305 @@ security_opt: - seccomp:unconfined ``` -To find out which GPU device IDs cardN and renderN correspond to the same GPU, use the GPU driver utility +**How to Identify GPU Device IDs:** +Use AMD GPU driver utilities to determine the correct `cardN` and `renderN` IDs for your GPU. -### Go to the directory with the Docker compose file +### Set deploy environment variables + +#### Setting variables in the operating system environment: + +##### Set variable HUGGINGFACEHUB_API_TOKEN: ```bash -cd GenAIExamples/Translation/docker_compose/amd/gpu/rocm +### Replace the string 'your_huggingfacehub_token' with your HuggingFacehub repository access token. +export HUGGINGFACEHUB_API_TOKEN='your_huggingfacehub_token' ``` -### Set environments +#### Set variables value in set_env\*\*\*\*.sh file: -In the file "GenAIExamples/Translation/docker_compose/amd/gpu/rocm/set_env.sh " it is necessary to set the required values. Parameter assignments are specified in the comments for each variable setting command +Go to Docker Compose directory: + +```bash +cd ~/translation-install/GenAIExamples/Translation/docker_compose/amd/gpu/rocm +``` + +The example uses the Nano text editor. You can use any convenient text editor: + +#### If you use vLLM + +```bash +nano set_env_vllm.sh +``` + +#### If you use TGI + +```bash +nano set_env.sh +``` + +If you are in a proxy environment, also set the proxy-related environment variables: + +```bash +export http_proxy="Your_HTTP_Proxy" +export https_proxy="Your_HTTPs_Proxy" +``` + +Set the values of the variables: + +- **HOST_IP, HOST_IP_EXTERNAL** - These variables are used to configure the name/address of the service in the operating system environment for the application services to interact with each other and with the outside world. + + If your server uses only an internal address and is not accessible from the Internet, then the values for these two variables will be the same and the value will be equal to the server's internal name/address. + + If your server uses only an external, Internet-accessible address, then the values for these two variables will be the same and the value will be equal to the server's external name/address. + + If your server is located on an internal network, has an internal address, but is accessible from the Internet via a proxy/firewall/load balancer, then the HOST_IP variable will have a value equal to the internal name/address of the server, and the EXTERNAL_HOST_IP variable will have a value equal to the external name/address of the proxy/firewall/load balancer behind which the server is located. + + We set these values in the file set_env\*\*\*\*.sh + +- **Variables with names like "**\*\*\*\*\*\*\_PORT"\*\* - These variables set the IP port numbers for establishing network connections to the application services. + The values shown in the file set_env.sh or set_env_vllm they are the values used for the development and testing of the application, as well as configured for the environment in which the development is performed. These values must be configured in accordance with the rules of network access to your environment's server, and must not overlap with the IP ports of other applications that are already in use. + +#### Set variables with script set_env\*\*\*\*.sh + +#### If you use vLLM + +```bash +. set_env_vllm.sh +``` + +#### If you use TGI ```bash -chmod +x set_env.sh . set_env.sh ``` -### Run services +### Start the services: -``` -docker compose up -d -``` - -# Validate the MicroServices and MegaService - -## Validate TGI service +#### If you use vLLM ```bash -curl http://${TRANSLATION_HOST_IP}:${TRANSLATIONS_TGI_SERVICE_PORT}/generate \ +docker compose -f compose_vllm.yaml up -d +``` + +#### If you use TGI + +```bash +docker compose -f compose.yaml up -d +``` + +All containers should be running and should not restart: + +##### If you use vLLM: + +- translationn-vllm-service +- translation-tgi-service +- translation-llm +- translation-backend-server +- translation-ui-server +- translation-nginx-server + +##### If you use TGI: + +- translation-tgi-service +- translation-llm +- translation-backend-server +- translation-ui-server +- translation-nginx-server + +--- + +## Validate the Services + +### 1. Validate the vLLM/TGI Service + +#### If you use vLLM: + +```bash +DATA='{"model": "haoranxu/ALMA-13B", "prompt": "What is Deep Learning?", "max_tokens": 100, "temperature": 0}' + +curl http://${HOST_IP}:${TRANSLATION_VLLM_SERVICE_PORT}/v1/chat/completions \ -X POST \ - -d '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":17, "do_sample": true}}' \ + -d "$DATA" \ -H 'Content-Type: application/json' ``` -## Validate LLM service +Checking the response from the service. The response should be similar to JSON: + +```json +{ + "id": "cmpl-059dd7fb311a46c2b807e0b3315e730c", + "object": "text_completion", + "created": 1743063706, + "model": "haoranxu/ALMA-13B", + "choices": [ + { + "index": 0, + "text": " Deep Learning is a subset of machine learning. It attempts to mimic the way the human brain learns. Deep Learning is a subset of machine learning. It attempts to mimic the way the human brain learns. Deep Learning is a subset of machine learning. It attempts to mimic the way the human brain learns. Deep Learning is a subset of machine learning. It attempts to mimic the way the human brain learns. Deep Learning is a subset of machine learning", + "logprobs": null, + "finish_reason": "length", + "stop_reason": null, + "prompt_logprobs": null + } + ], + + "usage": { + "prompt_tokens": 6, + "total_tokens": 106, + "completion_tokens": 100, + "prompt_tokens_details": null + } +} +``` + +If the service response has a meaningful response in the value of the "choices.message.content" key, +then we consider the vLLM service to be successfully launched + +#### If you use TGI: ```bash -curl http://${TRANSLATION_HOST_IP}:9000/v1/chat/completions \ +DATA='{"inputs":"What is Deep Learning?",'\ +'"parameters":{"max_new_tokens":256,"do_sample": true}}' + +curl http://${HOST_IP}:${TRANSLATION_TGI_SERVICE_PORT}/generate \ -X POST \ - -d '{"query":"Translate this from Chinese to English:\nChinese: 我爱机器翻译。\nEnglish:"}' \ + -d "$DATA" \ -H 'Content-Type: application/json' ``` -## Validate MegaService +Checking the response from the service. The response should be similar to JSON: -```bash -curl http://${TRANSLATION_HOST_IP}:${TRANSLATION_BACKEND_SERVICE_PORT}/v1/translation -H "Content-Type: application/json" -d '{ - "language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' +```json +{ + "generated_text": "\n\n What can it Do? What's the Hype? What Should You Do If" +} ``` -## Validate Nginx service +If the service response has a meaningful response in the value of the "generated_text" key, +then we consider the TGI service to be successfully launched + +### 2. Validate the LLM Service ```bash -curl http://${TRANSLATION_HOST_IP}:${TRANSLATION_NGINX_PORT}/v1/translation \ - -H "Content-Type: application/json" \ - -d '{"language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' +DATA='{"query":"What is Deep Learning?",'\ +'"max_tokens":32,"top_k":10,"top_p":0.95,"typical_p":0.95,"temperature":0.01,'\ +'"repetition_penalty":1.03,"stream":false}' + +curl http://${HOST_IP}:${TRANSLATION_LLM_SERVICE_PORT}/v1/chat/completions \ + -X POST \ + -d "$DATA" \ + -H 'Content-Type: application/json' +``` + +Checking the response from the service. The response should be similar to JSON: + +```json +{ + "id": "", + "choices": [ + { + "finish_reason": "length", + "index": 0, + "logprobs": null, + "text": " Deep Learning is a subset of machine learning. It attempts to mimic the way the human brain learns. Deep Learning is a subset of machine learning." + } + ], + "created": 1742978568, + "model": "haoranxu/ALMA-13B", + "object": "text_completion", + "system_fingerprint": "2.3.1-sha-a094729-rocm", + "usage": { + "completion_tokens": 32, + "prompt_tokens": 6, + "total_tokens": 38, + "completion_tokens_details": null, + "prompt_tokens_details": null + } +} +``` + +### 3. Validate Nginx Service + +```bash +DATA='{"language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' + +curl http://${HOST_IP}:${TRANSLATION_LLM_SERVICE_PORT}/v1/translation \ + -d "$DATA" \ + -H 'Content-Type: application/json' +``` + +Checking the response from the service. The response should be similar to JSON: + +```textmate +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" I"}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" love"}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" machine"}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" translation"}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":"."}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"eos_token","index":0,"logprobs":null,"text":""}],"created":1743062099,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":{"completion_tokens":6,"prompt_tokens":3071,"total_tokens":3077,"completion_tokens_details":null,"prompt_tokens_details":null}} + +data: [DONE] +``` + +### 4. Validate MegaService + +```bash +DATA='{"language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' + +curl http://${HOST_IP}:${TRANSLATION_BACKEND_SERVICE_PORT}/v1/translation \ + -H "Content-Type: application/json" \ + -d "$DATA" +``` + +Checking the response from the service. The response should be similar to JSON: + +```textmate +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" I"}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" love"}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" machine"}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":" translation"}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"","index":0,"logprobs":null,"text":"."}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":null} + +data: {"id":"","choices":[{"finish_reason":"eos_token","index":0,"logprobs":null,"text":""}],"created":1742978968,"model":"haoranxu/ALMA-13B","object":"text_completion","system_fingerprint":"2.3.1-sha-a094729-rocm","usage":{"completion_tokens":6,"prompt_tokens":3071,"total_tokens":3077,"completion_tokens_details":null,"prompt_tokens_details":null}} + +data: [DONE] + +``` + +If the response text is similar to the one above, then we consider the service verification successful. + +### 5. Validate Frontend + +To access the UI, use the URL - http://${EXTERNAL_HOST_IP}:${TRANSLATION_FRONTEND_SERVICE_PORT} A page should open when you click through to this address: +![UI start page](../../../../assets/img/translation-ui-starting-page.png) + +If a page of this type has opened, then we believe that the service is running and responding, and we can proceed to functional UI testing. + +Let's enter the task for the service in the "Input" field. For example, "我爱机器翻译" with selected "German" as language source and press Enter. After that, a page with the result of the task should open: + +![UI start page](../../../../assets/img/translation-ui-response-example.png) +If the result shown on the page is correct, then we consider the verification of the UI service to be successful. + +### 6. Stop application + +#### If you use vLLM + +```bash +cd ~/translation-install/GenAIExamples/Translation/docker_compose/amd/gpu/rocm +docker compose -f compose_vllm.yaml down +``` + +#### If you use TGI + +```bash +cd ~/translation-install/GenAIExamples/Translation/docker_compose/amd/gpu/rocm +docker compose -f compose.yaml down ``` diff --git a/Translation/docker_compose/amd/gpu/rocm/compose.yaml b/Translation/docker_compose/amd/gpu/rocm/compose.yaml index 2ee2a9c2c..49914e671 100644 --- a/Translation/docker_compose/amd/gpu/rocm/compose.yaml +++ b/Translation/docker_compose/amd/gpu/rocm/compose.yaml @@ -90,7 +90,7 @@ services: - translation-backend-server - translation-ui-server ports: - - "${TRANSLATION_NGINX_PORT:-80}:80" + - "${TRANSLATION_NGINX_PORT:-80}:8080" environment: - no_proxy=${no_proxy} - https_proxy=${https_proxy} diff --git a/Translation/docker_compose/amd/gpu/rocm/compose_vllm.yaml b/Translation/docker_compose/amd/gpu/rocm/compose_vllm.yaml new file mode 100644 index 000000000..4e2207657 --- /dev/null +++ b/Translation/docker_compose/amd/gpu/rocm/compose_vllm.yaml @@ -0,0 +1,107 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +services: + translation-vllm-service: + image: ${REGISTRY:-opea}/vllm-rocm:${TAG:-latest} + container_name: translation-vllm-service + ports: + - "${TRANSLATION_VLLM_SERVICE_PORT:-8081}:8011" + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + HUGGINGFACEHUB_API_TOKEN: ${TRANSLATION_HUGGINGFACEHUB_API_TOKEN} + HF_TOKEN: ${TRANSLATION_HUGGINGFACEHUB_API_TOKEN} + HF_HUB_DISABLE_PROGRESS_BARS: 1 + HF_HUB_ENABLE_HF_TRANSFER: 0 + WILM_USE_TRITON_FLASH_ATTENTION: 0 + PYTORCH_JIT: 0 + volumes: + - "./data:/data" + shm_size: 20G + devices: + - /dev/kfd:/dev/kfd + - /dev/dri/:/dev/dri/ + cap_add: + - SYS_PTRACE + group_add: + - video + security_opt: + - seccomp:unconfined + - apparmor=unconfined + command: "--model ${TRANSLATION_LLM_MODEL_ID} --swap-space 16 --disable-log-requests --dtype float16 --tensor-parallel-size 1 --host 0.0.0.0 --port 8011 --num-scheduler-steps 1 --distributed-executor-backend \"mp\"" + ipc: host + translation-llm: + image: ${REGISTRY:-opea}/llm-textgen:${TAG:-latest} + container_name: translation-llm-textgen-server + depends_on: + - translation-vllm-service + ports: + - "${TRANSLATION_LLM_PORT:-9000}:9000" + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + LLM_ENDPOINT: ${TRANSLATION_LLM_ENDPOINT} + LLM_MODEL_ID: ${TRANSLATION_LLM_MODEL_ID} + HUGGINGFACEHUB_API_TOKEN: ${TRANSLATION_HUGGINGFACEHUB_API_TOKEN} + HF_TOKEN: ${TRANSLATION_HUGGINGFACEHUB_API_TOKEN} + LLM_COMPONENT_NAME: "OpeaTextGenService" + HF_HUB_DISABLE_PROGRESS_BARS: 1 + HF_HUB_ENABLE_HF_TRANSFER: 0 + restart: unless-stopped + translation-backend-server: + image: ${REGISTRY:-opea}/translation:${TAG:-latest} + container_name: translation-backend-server + depends_on: + - translation-vllm-service + - translation-llm + ports: + - "${TRANSLATION_BACKEND_SERVICE_PORT:-8888}:8888" + environment: + no_proxy: ${no_proxy} + https_proxy: ${https_proxy} + http_proxy: ${http_proxy} + MEGA_SERVICE_HOST_IP: ${TRANSLATION_MEGA_SERVICE_HOST_IP} + LLM_SERVICE_HOST_IP: ${TRANSLATION_LLM_SERVICE_HOST_IP} + LLM_SERVICE_PORT: ${TRANSLATION_LLM_PORT} + ipc: host + restart: always + translation-ui-server: + image: ${REGISTRY:-opea}/translation-ui:${TAG:-latest} + container_name: translation-ui-server + depends_on: + - translation-backend-server + ports: + - "${TRANSLATION_FRONTEND_SERVICE_PORT:-5173}:5173" + environment: + no_proxy: ${no_proxy} + https_proxy: ${https_proxy} + http_proxy: ${http_proxy} + BASE_URL: ${TRANSLATION_BACKEND_SERVICE_ENDPOINT} + ipc: host + restart: always + translation-nginx-server: + image: ${REGISTRY:-opea}/nginx:${TAG:-latest} + container_name: translation-nginx-server + depends_on: + - translation-backend-server + - translation-ui-server + ports: + - "${TRANSLATION_NGINX_PORT:-80}:8080" + environment: + no_proxy: ${no_proxy} + https_proxy: ${https_proxy} + http_proxy: ${http_proxy} + FRONTEND_SERVICE_IP: ${TRANSLATION_FRONTEND_SERVICE_IP} + FRONTEND_SERVICE_PORT: ${TRANSLATION_FRONTEND_SERVICE_PORT} + BACKEND_SERVICE_NAME: ${TRANSLATION_BACKEND_SERVICE_NAME} + BACKEND_SERVICE_IP: ${TRANSLATION_BACKEND_SERVICE_IP} + BACKEND_SERVICE_PORT: ${TRANSLATION_BACKEND_SERVICE_PORT} + ipc: host + restart: always +networks: + default: + driver: bridge diff --git a/Translation/docker_compose/amd/gpu/rocm/set_env_vllm.sh b/Translation/docker_compose/amd/gpu/rocm/set_env_vllm.sh new file mode 100644 index 000000000..0f3d89c53 --- /dev/null +++ b/Translation/docker_compose/amd/gpu/rocm/set_env_vllm.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# SPDX-License-Identifier: Apache-2.0 + +export HOST_IP='' +export EXTERNAL_HOST_IP='' +export TRANSLATION_LLM_MODEL_ID="haoranxu/ALMA-13B" +export TRANSLATION_VLLM_SERVICE_PORT=8088 +export TRANSLATION_LLM_ENDPOINT="http://${HOST_IP}:${TRANSLATION_VLLM_SERVICE_PORT}" +export TRANSLATION_LLM_PORT=9088 +export TRANSLATION_HUGGINGFACEHUB_API_TOKEN=${HUGGINGFACEHUB_API_TOKEN} +export TRANSLATION_MEGA_SERVICE_HOST_IP=${HOST_IP} +export TRANSLATION_LLM_SERVICE_HOST_IP=${HOST_IP} +export TRANSLATION_FRONTEND_SERVICE_IP=${HOST_IP} +export TRANSLATION_FRONTEND_SERVICE_PORT=18122 +export TRANSLATION_BACKEND_SERVICE_NAME=translation +export TRANSLATION_BACKEND_SERVICE_IP=${HOST_IP} +export TRANSLATION_BACKEND_SERVICE_PORT=18121 +export TRANSLATION_BACKEND_SERVICE_ENDPOINT="http://${EXTERNAL_HOST_IP}:${TRANSLATION_BACKEND_SERVICE_PORT}/v1/translation" +export TRANSLATION_NGINX_PORT=18123 diff --git a/Translation/docker_image_build/build.yaml b/Translation/docker_image_build/build.yaml index 1dad29cb7..6469e48fd 100644 --- a/Translation/docker_image_build/build.yaml +++ b/Translation/docker_image_build/build.yaml @@ -29,3 +29,8 @@ services: dockerfile: comps/third_parties/nginx/src/Dockerfile extends: translation image: ${REGISTRY:-opea}/nginx:${TAG:-latest} + vllm-rocm: + build: + context: GenAIComps + dockerfile: comps/third_parties/vllm/src/Dockerfile.amd_gpu + image: ${REGISTRY:-opea}/vllm-rocm:${TAG:-latest} diff --git a/Translation/tests/test_compose_vllm_on_rocm.sh b/Translation/tests/test_compose_vllm_on_rocm.sh new file mode 100644 index 000000000..e7db52010 --- /dev/null +++ b/Translation/tests/test_compose_vllm_on_rocm.sh @@ -0,0 +1,193 @@ +#!/bin/bash +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +set -xe +IMAGE_REPO=${IMAGE_REPO:-"opea"} +IMAGE_TAG=${IMAGE_TAG:-"latest"} +echo "REGISTRY=IMAGE_REPO=${IMAGE_REPO}" +echo "TAG=IMAGE_TAG=${IMAGE_TAG}" +export REGISTRY=${IMAGE_REPO} +export TAG=${IMAGE_TAG} + +WORKPATH=$(dirname "$PWD") +LOG_PATH="$WORKPATH/tests" +ip_address=$(hostname -I | awk '{print $1}') + +function build_docker_images() { + opea_branch=${opea_branch:-"main"} + # If the opea_branch isn't main, replace the git clone branch in Dockerfile. + if [[ "${opea_branch}" != "main" ]]; then + cd $WORKPATH + OLD_STRING="RUN git clone --depth 1 https://github.com/opea-project/GenAIComps.git" + NEW_STRING="RUN git clone --depth 1 --branch ${opea_branch} https://github.com/opea-project/GenAIComps.git" + find . -type f -name "Dockerfile*" | while read -r file; do + echo "Processing file: $file" + sed -i "s|$OLD_STRING|$NEW_STRING|g" "$file" + done + fi + + cd $WORKPATH/docker_image_build + git clone --depth 1 --branch ${opea_branch} https://github.com/opea-project/GenAIComps.git + + echo "Build all the images with --no-cache, check docker_image_build.log for details..." + service_list="translation translation-ui llm-textgen nginx vllm-rocm" + docker compose -f build.yaml build ${service_list} --no-cache > ${LOG_PATH}/docker_image_build.log + docker images && sleep 3s +} + +function start_services() { + cd $WORKPATH/docker_compose/amd/gpu/rocm/ + + export HOST_IP=${ip_address} + export EXTERNAL_HOST_IP=${ip_address} + export TRANSLATION_LLM_MODEL_ID="haoranxu/ALMA-13B" + export TRANSLATION_VLLM_SERVICE_PORT=8088 + export TRANSLATION_LLM_ENDPOINT="http://${HOST_IP}:${TRANSLATION_VLLM_SERVICE_PORT}" + export TRANSLATION_LLM_PORT=9088 + export TRANSLATION_HUGGINGFACEHUB_API_TOKEN=${HUGGINGFACEHUB_API_TOKEN} + export TRANSLATION_MEGA_SERVICE_HOST_IP=${HOST_IP} + export TRANSLATION_LLM_SERVICE_HOST_IP=${HOST_IP} + export TRANSLATION_FRONTEND_SERVICE_IP=${HOST_IP} + export TRANSLATION_FRONTEND_SERVICE_PORT=5173 + export TRANSLATION_BACKEND_SERVICE_NAME=translation + export TRANSLATION_BACKEND_SERVICE_IP=${HOST_IP} + export TRANSLATION_BACKEND_SERVICE_PORT=8089 + export TRANSLATION_BACKEND_SERVICE_ENDPOINT="http://${EXTERNAL_HOST_IP}:${TRANSLATION_BACKEND_SERVICE_PORT}/v1/translation" + export TRANSLATION_NGINX_PORT=8090 + + sed -i "s/backend_address/$ip_address/g" $WORKPATH/ui/svelte/.env + + # Start Docker Containers + docker compose -f compose_vllm.yaml up -d > ${LOG_PATH}/start_services_with_compose.log + + n=0 + # wait long for llm model download + until [[ "$n" -ge 500 ]]; do + docker logs translation-vllm-service >& ${LOG_PATH}/translation-vllm-service_start.log + if grep -q "Application startup complete" ${LOG_PATH}/translation-vllm-service_start.log; then + echo "vLLM check successful" + break + fi + sleep 10s + 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. + + # vLLM for llm service + validate_services \ + "${ip_address}:${TRANSLATION_VLLM_SERVICE_PORT}/v1/completions" \ + "choices" \ + "translation-vllm-service" \ + "translation-vllm-service" \ + '{"model": "haoranxu/ALMA-13B", "prompt": "What is Deep Learning?", "max_tokens": 100, "temperature": 0}' + + # llm microservice + validate_services \ + "${HOST_IP}:${TRANSLATION_LLM_PORT}/v1/chat/completions" \ + "data: " \ + "translation-llm" \ + "translation-llm-textgen-server" \ + '{"query":"Translate this from Chinese to English:\nChinese: 我爱机器翻译。\nEnglish:"}' +} + +function validate_megaservice() { + # Curl the Mega Service + validate_services \ + "${HOST_IP}:${TRANSLATION_BACKEND_SERVICE_PORT}/v1/translation" \ + "translation" \ + "translation-backend-server" \ + "translation-backend-server" \ + '{"language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' + + # test the megeservice via nginx + validate_services \ + "${HOST_IP}:${TRANSLATION_NGINX_PORT}/v1/translation" \ + "translation" \ + "translation-nginx-server" \ + "translation-nginx-server" \ + '{"language_from": "Chinese","language_to": "English","source_language": "我爱机器翻译。"}' +} + +function validate_frontend() { + cd $WORKPATH/ui/svelte + local conda_env_name="OPEA_e2e" + export PATH=${HOME}/miniconda3/bin/:$PATH + if conda info --envs | grep -q "$conda_env_name"; then + echo "$conda_env_name exist!" + else + conda create -n ${conda_env_name} python=3.12 -y + fi + source activate ${conda_env_name} + + sed -i "s/localhost/$ip_address/g" playwright.config.ts + + conda install -c conda-forge nodejs=22.6.0 -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_compose/amd/gpu/rocm/ + docker compose -f compose_vllm.yaml stop && docker compose -f compose_vllm.yaml rm -f +} + +function main() { + + stop_docker + + if [[ "$IMAGE_REPO" == "opea" ]]; then build_docker_images; fi + start_services + + validate_microservices + validate_megaservice + validate_frontend + + stop_docker + echo y | docker system prune + +} + +main