diff --git a/DocSum/Dockerfile.openEuler b/DocSum/Dockerfile.openEuler new file mode 100644 index 0000000000..c13ab7a2b0 --- /dev/null +++ b/DocSum/Dockerfile.openEuler @@ -0,0 +1,17 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +ARG IMAGE_REPO=opea +ARG BASE_TAG=latest +FROM $IMAGE_REPO/comps-base:$BASE_TAG-openeuler + +USER root +# FFmpeg needed for media processing +RUN yum update -y && \ + yum install -y ffmpeg && \ + yum clean all && rm -rf /var/cache/yum +USER user + +COPY ./docsum.py $HOME/docsum.py + +ENTRYPOINT ["python", "docsum.py"] diff --git a/DocSum/docker_compose/intel/cpu/xeon/compose_openeuler.yaml b/DocSum/docker_compose/intel/cpu/xeon/compose_openeuler.yaml new file mode 100644 index 0000000000..b1f447adce --- /dev/null +++ b/DocSum/docker_compose/intel/cpu/xeon/compose_openeuler.yaml @@ -0,0 +1,100 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +services: + vllm-service: + image: openeuler/vllm-cpu:0.10.1-oe2403lts + container_name: docsum-xeon-vllm-service + ports: + - ${LLM_ENDPOINT_PORT:-8008}:80 + volumes: + - "${MODEL_CACHE:-./data}:/root/.cache/huggingface/hub" + shm_size: 1g + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + HF_TOKEN: ${HF_TOKEN} + LLM_MODEL_ID: ${LLM_MODEL_ID} + VLLM_TORCH_PROFILER_DIR: "/mnt" + VLLM_CPU_KVCACHE_SPACE: 40 + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:80/health || exit 1"] + interval: 10s + timeout: 10s + retries: 100 + command: --model $LLM_MODEL_ID --host 0.0.0.0 --port 80 + + llm-docsum-vllm: + image: ${REGISTRY:-opea}/llm-docsum:${TAG:-latest}-openeuler + container_name: docsum-xeon-llm-server + depends_on: + vllm-service: + condition: service_healthy + ports: + - ${LLM_PORT:-9000}:9000 + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + LLM_ENDPOINT: ${LLM_ENDPOINT} + LLM_MODEL_ID: ${LLM_MODEL_ID} + HF_TOKEN: ${HF_TOKEN} + MAX_INPUT_TOKENS: ${MAX_INPUT_TOKENS} + MAX_TOTAL_TOKENS: ${MAX_TOTAL_TOKENS} + DocSum_COMPONENT_NAME: ${DocSum_COMPONENT_NAME} + LOGFLAG: ${LOGFLAG:-False} + restart: unless-stopped + + whisper: + image: ${REGISTRY:-opea}/whisper:${TAG:-latest}-openeuler + container_name: docsum-xeon-whisper-server + ports: + - ${ASR_SERVICE_PORT:-7066}:7066 + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + restart: unless-stopped + + docsum-xeon-backend-server: + image: ${REGISTRY:-opea}/docsum:${TAG:-latest}-openeuler + container_name: docsum-xeon-backend-server + depends_on: + - vllm-service + - llm-docsum-vllm + ports: + - "${BACKEND_SERVICE_PORT:-8888}:8888" + environment: + - no_proxy=${no_proxy} + - https_proxy=${https_proxy} + - http_proxy=${http_proxy} + - MEGA_SERVICE_HOST_IP=${MEGA_SERVICE_HOST_IP} + - LLM_SERVICE_HOST_IP=${LLM_SERVICE_HOST_IP} + - LLM_SERVICE_PORT=${LLM_PORT} + - ASR_SERVICE_HOST_IP=${ASR_SERVICE_HOST_IP} + - ASR_SERVICE_PORT=${ASR_SERVICE_PORT} + ipc: host + restart: always + + docsum-gradio-ui: + image: ${REGISTRY:-opea}/docsum-gradio-ui:${TAG:-latest}-openeuler + container_name: docsum-xeon-ui-server + depends_on: + - docsum-xeon-backend-server + ports: + - "${FRONTEND_SERVICE_PORT:-5173}:5173" + environment: + - no_proxy=${no_proxy} + - https_proxy=${https_proxy} + - http_proxy=${http_proxy} + - BACKEND_SERVICE_ENDPOINT=${BACKEND_SERVICE_ENDPOINT} + - DOC_BASE_URL=${BACKEND_SERVICE_ENDPOINT} + ipc: host + restart: always + +networks: + default: + driver: bridge diff --git a/DocSum/docker_compose/intel/cpu/xeon/compose_tgi_openeuler.yaml b/DocSum/docker_compose/intel/cpu/xeon/compose_tgi_openeuler.yaml new file mode 100644 index 0000000000..da94b7dd4e --- /dev/null +++ b/DocSum/docker_compose/intel/cpu/xeon/compose_tgi_openeuler.yaml @@ -0,0 +1,99 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +services: + tgi-server: + image: openeuler/text-generation-inference-cpu:2.4.0-oe2403lts + container_name: docsum-xeon-tgi-server + ports: + - ${LLM_ENDPOINT_PORT:-8008}:80 + volumes: + - "${MODEL_CACHE:-./data}:/data" + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + TGI_LLM_ENDPOINT: ${TGI_LLM_ENDPOINT} + HF_TOKEN: ${HF_TOKEN} + host_ip: ${host_ip} + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:80/health || exit 1"] + interval: 10s + timeout: 10s + retries: 100 + shm_size: 1g + command: --model-id ${LLM_MODEL_ID} --cuda-graphs 0 --max-input-length ${MAX_INPUT_TOKENS} --max-total-tokens ${MAX_TOTAL_TOKENS} + + llm-docsum-tgi: + image: ${REGISTRY:-opea}/llm-docsum:${TAG:-latest}-openeuler + container_name: docsum-xeon-llm-server + depends_on: + tgi-server: + condition: service_healthy + ports: + - ${LLM_PORT:-9000}:9000 + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + LLM_ENDPOINT: ${LLM_ENDPOINT} + LLM_MODEL_ID: ${LLM_MODEL_ID} + HF_TOKEN: ${HF_TOKEN} + MAX_INPUT_TOKENS: ${MAX_INPUT_TOKENS} + MAX_TOTAL_TOKENS: ${MAX_TOTAL_TOKENS} + DocSum_COMPONENT_NAME: ${DocSum_COMPONENT_NAME} + LOGFLAG: ${LOGFLAG:-False} + restart: unless-stopped + + whisper: + image: ${REGISTRY:-opea}/whisper:${TAG:-latest}-openeuler + container_name: docsum-xeon-whisper-server + ports: + - ${ASR_SERVICE_PORT:-7066}:7066 + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + restart: unless-stopped + + docsum-xeon-backend-server: + image: ${REGISTRY:-opea}/docsum:${TAG:-latest}-openeuler + container_name: docsum-xeon-backend-server + depends_on: + - tgi-server + - llm-docsum-tgi + ports: + - "${BACKEND_SERVICE_PORT:-8888}:8888" + environment: + - no_proxy=${no_proxy} + - https_proxy=${https_proxy} + - http_proxy=${http_proxy} + - MEGA_SERVICE_HOST_IP=${MEGA_SERVICE_HOST_IP} + - LLM_SERVICE_HOST_IP=${LLM_SERVICE_HOST_IP} + - LLM_SERVICE_PORT=${LLM_PORT} + - ASR_SERVICE_HOST_IP=${ASR_SERVICE_HOST_IP} + - ASR_SERVICE_PORT=${ASR_SERVICE_PORT} + ipc: host + restart: always + + docsum-gradio-ui: + image: ${REGISTRY:-opea}/docsum-gradio-ui:${TAG:-latest}-openeuler + container_name: docsum-xeon-ui-server + depends_on: + - docsum-xeon-backend-server + ports: + - "${FRONTEND_SERVICE_PORT:-5173}:5173" + environment: + - no_proxy=${no_proxy} + - https_proxy=${https_proxy} + - http_proxy=${http_proxy} + - BACKEND_SERVICE_ENDPOINT=${BACKEND_SERVICE_ENDPOINT} + - DOC_BASE_URL=${BACKEND_SERVICE_ENDPOINT} + ipc: host + restart: always + +networks: + default: + driver: bridge diff --git a/DocSum/docker_image_build/build.yaml b/DocSum/docker_image_build/build.yaml index dcd4433ad0..f1bc90a8b8 100644 --- a/DocSum/docker_image_build/build.yaml +++ b/DocSum/docker_image_build/build.yaml @@ -13,6 +13,17 @@ services: context: ../ dockerfile: ./Dockerfile image: ${REGISTRY:-opea}/docsum:${TAG:-latest} + docsum-openeuler: + build: + args: + IMAGE_REPO: ${REGISTRY} + BASE_TAG: ${TAG} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + no_proxy: ${no_proxy} + context: ../ + dockerfile: ./Dockerfile.openEuler + image: ${REGISTRY:-opea}/docsum:${TAG:-latest}-openeuler docsum-gradio-ui: build: args: @@ -22,18 +33,39 @@ services: dockerfile: ./docker/Dockerfile.gradio extends: docsum image: ${REGISTRY:-opea}/docsum-gradio-ui:${TAG:-latest} + docsum-gradio-ui-openeuler: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + context: ../ui + dockerfile: ./docker/Dockerfile.gradio.openEuler + extends: docsum + image: ${REGISTRY:-opea}/docsum-gradio-ui:${TAG:-latest}-openeuler docsum-ui: build: context: ../ui dockerfile: ./docker/Dockerfile extends: docsum image: ${REGISTRY:-opea}/docsum-ui:${TAG:-latest} + docsum-ui-openeuler: + build: + context: ../ui + dockerfile: ./docker/Dockerfile.openEuler + extends: docsum + image: ${REGISTRY:-opea}/docsum-ui:${TAG:-latest}-openeuler docsum-react-ui: build: context: ../ui dockerfile: ./docker/Dockerfile.react extends: docsum image: ${REGISTRY:-opea}/docsum-react-ui:${TAG:-latest} + docsum-react-ui-openeuler: + build: + context: ../ui + dockerfile: ./docker/Dockerfile.react.openEuler + extends: docsum + image: ${REGISTRY:-opea}/docsum-react-ui:${TAG:-latest}-openeuler whisper: build: args: @@ -43,12 +75,27 @@ services: dockerfile: comps/third_parties/whisper/src/Dockerfile extends: docsum image: ${REGISTRY:-opea}/whisper:${TAG:-latest} + whisper-openeuler: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + context: GenAIComps + dockerfile: comps/third_parties/whisper/src/Dockerfile.openEuler + extends: docsum + image: ${REGISTRY:-opea}/whisper:${TAG:-latest}-openeuler llm-docsum: build: context: GenAIComps dockerfile: comps/llms/src/doc-summarization/Dockerfile extends: docsum image: ${REGISTRY:-opea}/llm-docsum:${TAG:-latest} + llm-docsum: + build: + context: GenAIComps + dockerfile: comps/llms/src/doc-summarization/Dockerfile.openEuler + extends: docsum + image: ${REGISTRY:-opea}/llm-docsum:${TAG:-latest}-openeuler vllm-rocm: build: context: GenAIComps diff --git a/DocSum/tests/test_compose_openeuler_on_xeon.sh b/DocSum/tests/test_compose_openeuler_on_xeon.sh new file mode 100644 index 0000000000..70d1a95ccb --- /dev/null +++ b/DocSum/tests/test_compose_openeuler_on_xeon.sh @@ -0,0 +1,390 @@ +#!/bin/bash +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +set -xe + +IMAGE_REPO=${IMAGE_REPO:-"opea"} +IMAGE_TAG=${IMAGE_TAG:-"latest"} +export http_proxy=$http_proxy +export https_proxy=$https_proxy +export host_ip=$(hostname -I | awk '{print $1}') + +WORKPATH=$(dirname "$PWD") +LOG_PATH="$WORKPATH/tests" +echo "REGISTRY=IMAGE_REPO=${IMAGE_REPO}" +echo "TAG=IMAGE_TAG=${IMAGE_TAG}" +export REGISTRY=${IMAGE_REPO} +export TAG=${IMAGE_TAG} + +source $WORKPATH/docker_compose/intel/set_env.sh +export MODEL_CACHE=${model_cache:-"./data"} + +export MAX_INPUT_TOKENS=2048 +export MAX_TOTAL_TOKENS=4096 + +# Get the root folder of the current script +ROOT_FOLDER=$(dirname "$(readlink -f "$0")") + +function build_docker_images() { + opea_branch=${opea_branch:-"main"} + + cd $WORKPATH/docker_image_build + git clone --depth 1 --branch ${opea_branch} https://github.com/opea-project/GenAIComps.git + pushd GenAIComps + echo "GenAIComps test commit is $(git rev-parse HEAD)" + docker build --no-cache -t ${REGISTRY}/comps-base:${TAG}-openeuler --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f Dockerfile.openEuler . + popd && sleep 1s + + echo "Build all the images with --no-cache, check docker_image_build.log for details..." + service_list="docsum-openeuler docsum-gradio-ui-openeuler whisper-openeuler llm-docsum-openeuler" + docker compose -f build.yaml build ${service_list} --no-cache > ${LOG_PATH}/docker_image_build.log + + docker images && sleep 1s +} + +function start_services() { + cd $WORKPATH/docker_compose/intel/cpu/xeon/ + export no_proxy="localhost,127.0.0.1,$ip_address" + docker compose -f compose_openeuler.yaml up -d > ${LOG_PATH}/start_services_with_compose.log + sleep 1m +} + +get_base64_str() { + local file_name=$1 + base64 -w 0 "$file_name" +} + +# Function to generate input data for testing based on the document type +input_data_for_test() { + local document_type=$1 + case $document_type in + ("text") + echo "THIS IS A TEST >>>> and a number of states are starting to adopt them voluntarily special correspondent john delenco of education week reports it takes just 10 minutes to cross through gillette wyoming this small city sits in the northeast corner of the state surrounded by 100s of miles of prairie but schools here in campbell county are on the edge of something big the next generation science standards you are going to build a strand of dna and you are going to decode it and figure out what that dna actually says for christy mathis at sage valley junior high school the new standards are about learning to think like a scientist there is a lot of really good stuff in them every standard is a performance task it is not you know the child needs to memorize these things it is the student needs to be able to do some pretty intense stuff we are analyzing we are critiquing we are." + ;; + ("audio") + get_base64_str "$ROOT_FOLDER/data/test.wav" + ;; + ("video") + get_base64_str "$ROOT_FOLDER/data/test.mp4" + ;; + (*) + echo "Invalid document type" >&2 + exit 1 + ;; + esac +} + +function validate_service() { + local URL="$1" + local EXPECTED_RESULT="$2" + local SERVICE_NAME="$3" + local DOCKER_NAME="$4" + local VALIDATE_TYPE="$5" + local INPUT_DATA="$6" + local FORM_DATA1="$7" + local FORM_DATA2="$8" + local FORM_DATA3="$9" + local FORM_DATA4="${10}" + local FORM_DATA5="${11}" + local FORM_DATA6="${12}" + + if [[ $VALIDATE_TYPE == *"json"* ]]; then + HTTP_RESPONSE=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X POST -d "$INPUT_DATA" -H 'Content-Type: application/json' "$URL") + else + CURL_CMD=(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X POST -F "$FORM_DATA1" -F "$FORM_DATA2" -F "$FORM_DATA3" -F "$FORM_DATA4" -F "$FORM_DATA5" -H 'Content-Type: multipart/form-data' "$URL") + if [[ -n "$FORM_DATA6" ]]; then + CURL_CMD+=(-F "$FORM_DATA6") + fi + HTTP_RESPONSE=$("${CURL_CMD[@]}") + fi + HTTP_STATUS=$(echo $HTTP_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') + RESPONSE_BODY=$(echo $HTTP_RESPONSE | sed -e 's/HTTPSTATUS\:.*//g') + + docker logs ${DOCKER_NAME} >> ${LOG_PATH}/${SERVICE_NAME}.log + + # check response status + if [ "$HTTP_STATUS" -ne "200" ]; then + echo "[ $SERVICE_NAME ] HTTP status is not 200. Received status was $HTTP_STATUS" + exit 1 + else + echo "[ $SERVICE_NAME ] HTTP status is 200. Checking content..." + fi + # check response body + if [[ "$RESPONSE_BODY" != *"$EXPECTED_RESULT"* ]]; then + echo "EXPECTED_RESULT==> $EXPECTED_RESULT" + echo "RESPONSE_BODY==> $RESPONSE_BODY" + echo "[ $SERVICE_NAME ] Content does not match the expected result: $RESPONSE_BODY" + exit 1 + else + echo "[ $SERVICE_NAME ] Content is as expected." + fi + + sleep 1s +} + +function validate_microservices() { + # Check if the microservices are running correctly. + + # llm microservice + validate_service \ + "${host_ip}:${LLM_PORT}/v1/docsum" \ + "text" \ + "llm-docsum-vllm" \ + "docsum-xeon-llm-server" \ + "json" \ + '{"messages":"Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5."}' + + # whisper microservice + ulimit -s 65536 + validate_service \ + "${host_ip}:7066/v1/asr" \ + '{"asr_result":"well"}' \ + "whisper" \ + "docsum-xeon-whisper-server" \ + "json" \ + "{\"audio\": \"$(input_data_for_test "audio")\"}" + +} + +function validate_megaservice_text() { + echo ">>> Checking text data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + '{"type": "text", "messages": "Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5."}' + + echo ">>> Checking text data in form format, set language=en" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5." \ + "max_tokens=32" \ + "language=en" \ + "stream=True" + + echo ">>> Checking text data in form format, set language=zh" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=2024年9月26日,北京——今日,英特尔正式发布英特尔® 至强® 6性能核处理器(代号Granite Rapids),为AI、数据分析、科学计算等计算密集型业务提供卓越性能。" \ + "max_tokens=32" \ + "language=zh" \ + "stream=True" + + echo ">>> Checking text data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "TEI" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/short.txt" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" +} + +function validate_megaservice_multimedia() { + echo ">>> Checking audio data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "well" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + "{\"type\": \"audio\", \"messages\": \"$(input_data_for_test "audio")\", \"stream\": \"False\"}" + + echo ">>> Checking audio data in form format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "you" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=audio" \ + "messages=UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking audio data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "well" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=audio" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/test.wav" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking video data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + "{\"type\": \"video\", \"messages\": \"$(input_data_for_test "video")\", \"stream\": \"False\"}" + + echo ">>> Checking video data in form format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=video" \ + "messages=\"$(input_data_for_test "video")\"" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking video data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=video" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/test.mp4" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" +} + +function validate_megaservice_long_text() { + echo ">>> Checking long text data in form format, set summary_type=auto" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=auto" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=stuff" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "TEI" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/short.txt" \ + "max_tokens=128" \ + "summary_type=stuff" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=truncate" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=truncate" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=map_reduce" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=map_reduce" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=refine" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=refine" \ + "stream=False" +} + +function stop_service() { + cd $WORKPATH/docker_compose/intel/cpu/xeon/ + docker compose -f compose_openeuler.yaml stop && docker compose rm -f +} + +function main() { + + echo "::group:: Stopping any running Docker containers..." + stop_service + echo "::endgroup::" + + echo "::group::build_docker_images" + if [[ "$IMAGE_REPO" == "opea" ]]; then build_docker_images; fi + echo "::endgroup::" + + echo "::group::start_services" + start_services + echo "::endgroup::" + + echo "::group:: Validating microservices" + validate_microservices + echo "::endgroup::" + + echo "::group::validate_megaservice_text" + validate_megaservice_text + echo "::endgroup::" + + echo "::group::validate_megaservice_multimedia" + validate_megaservice_multimedia + echo "::endgroup::" + + echo "::group::validate_megaservice_long_text" + validate_megaservice_long_text + echo "::endgroup::" + + echo "::group::stop_service" + stop_service + echo "::endgroup::" + + docker system prune -f + +} + +main diff --git a/DocSum/tests/test_compose_tgi_openeuler_on_xeon.sh b/DocSum/tests/test_compose_tgi_openeuler_on_xeon.sh new file mode 100644 index 0000000000..7a89bcd882 --- /dev/null +++ b/DocSum/tests/test_compose_tgi_openeuler_on_xeon.sh @@ -0,0 +1,399 @@ +#!/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"} +export http_proxy=$http_proxy +export https_proxy=$https_proxy +export host_ip=$(hostname -I | awk '{print $1}') +WORKPATH=$(dirname "$PWD") +LOG_PATH="$WORKPATH/tests" +echo "REGISTRY=IMAGE_REPO=${IMAGE_REPO}" +echo "TAG=IMAGE_TAG=${IMAGE_TAG}" +export REGISTRY=${IMAGE_REPO} +export TAG=${IMAGE_TAG} + +source $WORKPATH/docker_compose/intel/set_env.sh +export MODEL_CACHE=${model_cache:-"./data"} + +export MAX_INPUT_TOKENS=2048 +export MAX_TOTAL_TOKENS=4096 + +export DocSum_COMPONENT_NAME="OpeaDocSumTgi" + +# Get the root folder of the current script +ROOT_FOLDER=$(dirname "$(readlink -f "$0")") + +function build_docker_images() { + opea_branch=${opea_branch:-"main"} + cd $WORKPATH/docker_image_build + git clone --depth 1 --branch ${opea_branch} https://github.com/opea-project/GenAIComps.git + pushd GenAIComps + echo "GenAIComps test commit is $(git rev-parse HEAD)" + docker build --no-cache -t ${REGISTRY}/comps-base:${TAG}-openeuler --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f Dockerfile.openEuler . + popd && sleep 1s + + echo "Build all the images with --no-cache, check docker_image_build.log for details..." + service_list="docsum-openeuler docsum-gradio-ui-openeuler whisper-openeuler llm-docsum-openeuler" + docker compose -f build.yaml build ${service_list} --no-cache > ${LOG_PATH}/docker_image_build.log + + docker images && sleep 1s +} + +function start_services() { + cd $WORKPATH/docker_compose/intel/cpu/xeon/ + export no_proxy="localhost,127.0.0.1,$ip_address" + docker compose -f compose_tgi_openeuler.yaml up -d > ${LOG_PATH}/start_services_with_compose.log + sleep 1m +} + +get_base64_str() { + local file_name=$1 + base64 -w 0 "$file_name" +} + +# Function to generate input data for testing based on the document type +input_data_for_test() { + local document_type=$1 + case $document_type in + ("text") + echo "THIS IS A TEST >>>> and a number of states are starting to adopt them voluntarily special correspondent john delenco of education week reports it takes just 10 minutes to cross through gillette wyoming this small city sits in the northeast corner of the state surrounded by 100s of miles of prairie but schools here in campbell county are on the edge of something big the next generation science standards you are going to build a strand of dna and you are going to decode it and figure out what that dna actually says for christy mathis at sage valley junior high school the new standards are about learning to think like a scientist there is a lot of really good stuff in them every standard is a performance task it is not you know the child needs to memorize these things it is the student needs to be able to do some pretty intense stuff we are analyzing we are critiquing we are." + ;; + ("audio") + get_base64_str "$ROOT_FOLDER/data/test.wav" + ;; + ("video") + get_base64_str "$ROOT_FOLDER/data/test.mp4" + ;; + (*) + echo "Invalid document type" >&2 + exit 1 + ;; + esac +} + +function validate_service() { + local URL="$1" + local EXPECTED_RESULT="$2" + local SERVICE_NAME="$3" + local DOCKER_NAME="$4" + local VALIDATE_TYPE="$5" + local INPUT_DATA="$6" + local FORM_DATA1="$7" + local FORM_DATA2="$8" + local FORM_DATA3="$9" + local FORM_DATA4="${10}" + local FORM_DATA5="${11}" + local FORM_DATA6="${12}" + + if [[ $VALIDATE_TYPE == *"json"* ]]; then + HTTP_RESPONSE=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X POST -d "$INPUT_DATA" -H 'Content-Type: application/json' "$URL") + else + CURL_CMD=(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X POST -F "$FORM_DATA1" -F "$FORM_DATA2" -F "$FORM_DATA3" -F "$FORM_DATA4" -F "$FORM_DATA5" -H 'Content-Type: multipart/form-data' "$URL") + if [[ -n "$FORM_DATA6" ]]; then + CURL_CMD+=(-F "$FORM_DATA6") + fi + HTTP_RESPONSE=$("${CURL_CMD[@]}") + fi + HTTP_STATUS=$(echo $HTTP_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') + RESPONSE_BODY=$(echo $HTTP_RESPONSE | sed -e 's/HTTPSTATUS\:.*//g') + + docker logs ${DOCKER_NAME} >> ${LOG_PATH}/${SERVICE_NAME}.log + + # check response status + if [ "$HTTP_STATUS" -ne "200" ]; then + echo "[ $SERVICE_NAME ] HTTP status is not 200. Received status was $HTTP_STATUS" + exit 1 + else + echo "[ $SERVICE_NAME ] HTTP status is 200. Checking content..." + fi + # check response body + if [[ "$RESPONSE_BODY" != *"$EXPECTED_RESULT"* ]]; then + echo "EXPECTED_RESULT==> $EXPECTED_RESULT" + echo "RESPONSE_BODY==> $RESPONSE_BODY" + echo "[ $SERVICE_NAME ] Content does not match the expected result: $RESPONSE_BODY" + exit 1 + else + echo "[ $SERVICE_NAME ] Content is as expected." + fi + + sleep 1s +} + +function validate_microservices() { + # Check if the microservices are running correctly. + + # tgi for llm service + validate_service \ + "${host_ip}:${LLM_ENDPOINT_PORT}/generate" \ + "generated_text" \ + "tgi-server" \ + "docsum-xeon-tgi-server" \ + "json" \ + '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":17, "do_sample": true}}' + + # llm microservice + validate_service \ + "${host_ip}:${LLM_PORT}/v1/docsum" \ + "text" \ + "llm-docsum-tgi" \ + "docsum-xeon-llm-server" \ + "json" \ + '{"messages":"Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5."}' + + # whisper microservice + ulimit -s 65536 + validate_service \ + "${host_ip}:7066/v1/asr" \ + '{"asr_result":"well"}' \ + "whisper" \ + "docsum-xeon-whisper-server" \ + "json" \ + "{\"audio\": \"$(input_data_for_test "audio")\"}" + +} + +function validate_megaservice_text() { + echo ">>> Checking text data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + '{"type": "text", "messages": "Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5."}' + + echo ">>> Checking text data in form format, set language=en" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=Text Embeddings Inference (TEI) is a toolkit for deploying and serving open source text embeddings and sequence classification models. TEI enables high-performance extraction for the most popular models, including FlagEmbedding, Ember, GTE and E5." \ + "max_tokens=32" \ + "language=en" \ + "stream=True" + + echo ">>> Checking text data in form format, set language=zh" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "[DONE]" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=2024年9月26日,北京——今日,英特尔正式发布英特尔® 至强® 6性能核处理器(代号Granite Rapids),为AI、数据分析、科学计算等计算密集型业务提供卓越性能。" \ + "max_tokens=32" \ + "language=zh" \ + "stream=True" + + echo ">>> Checking text data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "TEI" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/short.txt" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" +} + +function validate_megaservice_multimedia() { + echo ">>> Checking audio data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "well" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + "{\"type\": \"audio\", \"messages\": \"$(input_data_for_test "audio")\", \"stream\": \"False\"}" + + echo ">>> Checking audio data in form format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "you" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=audio" \ + "messages=UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking audio data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "well" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=audio" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/test.wav" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking video data in json format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "json" \ + "{\"type\": \"video\", \"messages\": \"$(input_data_for_test "video")\", \"stream\": \"False\"}" + + echo ">>> Checking video data in form format" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=video" \ + "messages=\"$(input_data_for_test "video")\"" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" + + echo ">>> Checking video data in form format, upload file" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "bye" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=video" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/test.mp4" \ + "max_tokens=32" \ + "language=en" \ + "stream=False" +} + +function validate_megaservice_long_text() { + echo ">>> Checking long text data in form format, set summary_type=auto" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=auto" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=stuff" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "TEI" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/short.txt" \ + "max_tokens=128" \ + "summary_type=stuff" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=truncate" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=truncate" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=map_reduce" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=map_reduce" \ + "stream=False" + + echo ">>> Checking long text data in form format, set summary_type=refine" + validate_service \ + "${host_ip}:${BACKEND_SERVICE_PORT}/v1/docsum" \ + "Intel" \ + "docsum-xeon-backend-server" \ + "docsum-xeon-backend-server" \ + "media" "" \ + "type=text" \ + "messages=" \ + "files=@$ROOT_FOLDER/data/long.txt" \ + "max_tokens=128" \ + "summary_type=refine" \ + "stream=False" +} + +function stop_service() { + cd $WORKPATH/docker_compose/intel/cpu/xeon/ + docker compose -f compose_tgi_openeuler.yaml stop && docker compose rm -f +} + +function main() { + + echo "::group:: Stopping any running Docker containers..." + stop_service + echo "::endgroup::" + + echo "::group::build_docker_images" + if [[ "$IMAGE_REPO" == "opea" ]]; then build_docker_images; fi + echo "::endgroup::" + + echo "::group::start_services" + start_services + echo "::endgroup::" + + echo "::group:: Validating microservices" + validate_microservices + echo "::endgroup::" + + echo "::group::validate_megaservice_text" + validate_megaservice_text + echo "::endgroup::" + + echo "::group::validate_megaservice_multimedia" + validate_megaservice_multimedia + echo "::endgroup::" + + echo "::group::validate_megaservice_long_text" + validate_megaservice_long_text + echo "::endgroup::" + + echo "::group::stop_service" + stop_service + echo "::endgroup::" + + docker system prune -f + +} + +main diff --git a/DocSum/ui/docker/Dockerfile.gradio.openEuler b/DocSum/ui/docker/Dockerfile.gradio.openEuler new file mode 100644 index 0000000000..769399d298 --- /dev/null +++ b/DocSum/ui/docker/Dockerfile.gradio.openEuler @@ -0,0 +1,37 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +# Use the openEuler Python 3.11 image as the base image +FROM openeuler/python:3.11.13-oe2403lts + +# Set the default language environment variable +ENV LANG=C.UTF-8 + +# Define a build argument for architecture (default is "cpu") +ARG ARCH="cpu" + +# Update the package list and install necessary packages +RUN yum update -y && \ + yum install -y \ + gcc gcc-c++ make && \ + yum clean all && rm -rf /var/cache/yum + +# Create a directory for the application +RUN mkdir -p /home/user + +# Copy the application code and requirements file to the container +COPY ./gradio/docsum_ui_gradio.py /home/user/docsum_ui_gradio.py +COPY ./gradio/requirements.txt /home/user/requirements.txt + +# Install Python dependencies +RUN pip install --no-cache-dir --upgrade pip setuptools && \ + pip install --no-cache-dir -r /home/user/requirements.txt + +# Set the working directory +WORKDIR /home/user/ + +# Expose the port that the application will run on +EXPOSE 5173 + +# Define the command to run the application +CMD ["python", "docsum_ui_gradio.py"] diff --git a/DocSum/ui/docker/Dockerfile.openEuler b/DocSum/ui/docker/Dockerfile.openEuler new file mode 100644 index 0000000000..0a4d701592 --- /dev/null +++ b/DocSum/ui/docker/Dockerfile.openEuler @@ -0,0 +1,30 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +# Use node 20.11.1 as the base image +FROM openeuler/node:20.11.1-oe2403lts + +# Update package manager and install Git +RUN yum update -y && \ + yum install -y \ + git && \ + yum clean all && \ + rm -rf /var/cache/yum + +# Copy the front-end code repository +COPY svelte /home/user/svelte + +# Set the working directory +WORKDIR /home/user/svelte + +# Install front-end dependencies +RUN npm install + +# Build the front-end application +RUN npm run build + +# Expose the port of the front-end application +EXPOSE 5173 + +# Run the front-end application in preview mode +CMD ["npm", "run", "preview", "--", "--port", "5173", "--host", "0.0.0.0"] diff --git a/DocSum/ui/docker/Dockerfile.react.openEuler b/DocSum/ui/docker/Dockerfile.react.openEuler new file mode 100644 index 0000000000..c8092b4c5e --- /dev/null +++ b/DocSum/ui/docker/Dockerfile.react.openEuler @@ -0,0 +1,24 @@ +# Copyright (C) 2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +# Use node 20.11.1 as the base image +FROM openeuler/node:20.11.1-oe2403lts as vite-app + +COPY . /usr/app +WORKDIR /usr/app/react + +ARG BACKEND_SERVICE_ENDPOINT +ENV VITE_DOC_SUM_URL=$BACKEND_SERVICE_ENDPOINT + +RUN ["npm", "install"] +RUN ["npm", "run", "build"] + + +FROM openeuler/nginx:1.29.0-oe2403lts +EXPOSE 80 + + +COPY --from=vite-app /usr/app/react/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=vite-app /usr/app/react/dist /usr/share/nginx/html + +ENTRYPOINT ["nginx", "-g", "daemon off;"]