From 13a75c6349c18f5c92a5d15575c20d2823b99f6c Mon Sep 17 00:00:00 2001 From: llin60 Date: Wed, 27 Aug 2025 13:59:41 +0800 Subject: [PATCH 1/5] add funasr paraformer asr service impl --- .../docker_compose/README_paraformer.md | 167 ++++++++++++++++++ .../deployment/docker_compose/compose.yaml | 10 ++ comps/asr/src/README.md | 3 + .../asr/src/integrations/funasr_paraformer.py | 93 ++++++++++ comps/asr/src/opea_asr_microservice.py | 1 + .../deployment/docker_compose/compose.yaml | 23 +++ comps/third_parties/funasr/src/Dockerfile | 28 +++ comps/third_parties/funasr/src/__init__.py | 2 + .../funasr/src/check_paraformer_server.py | 30 ++++ .../funasr/src/funasr_paraformer_model.py | 42 +++++ .../third_parties/funasr/src/funasr_server.py | 111 ++++++++++++ .../funasr/src/requirements-cpu.txt | 15 ++ tests/asr/test_asr_funasr_paraformer.sh | 93 ++++++++++ 13 files changed, 618 insertions(+) create mode 100644 comps/asr/deployment/docker_compose/README_paraformer.md create mode 100644 comps/asr/src/integrations/funasr_paraformer.py create mode 100644 comps/third_parties/funasr/deployment/docker_compose/compose.yaml create mode 100644 comps/third_parties/funasr/src/Dockerfile create mode 100644 comps/third_parties/funasr/src/__init__.py create mode 100644 comps/third_parties/funasr/src/check_paraformer_server.py create mode 100644 comps/third_parties/funasr/src/funasr_paraformer_model.py create mode 100644 comps/third_parties/funasr/src/funasr_server.py create mode 100644 comps/third_parties/funasr/src/requirements-cpu.txt create mode 100644 tests/asr/test_asr_funasr_paraformer.sh diff --git a/comps/asr/deployment/docker_compose/README_paraformer.md b/comps/asr/deployment/docker_compose/README_paraformer.md new file mode 100644 index 0000000000..78ef2d1cce --- /dev/null +++ b/comps/asr/deployment/docker_compose/README_paraformer.md @@ -0,0 +1,167 @@ +# Deploying ASR Service + +This document provides a comprehensive guide to deploying the ASR microservice pipeline with the Paraformer model on Intel platforms. + +**Note:** This is an alternative of the [Whisper ASR service](./README.md). The Paraformer model supports both English and Mandarin audio input, and empirically it shows better performance in Mandarin than English. + +This guide covers two deployment methods: + +- [🚀 1. Quick Start with Docker Compose](#-1-quick-start-with-docker-compose): The recommended method for a fast and easy setup. +- [🚀 2. Manual Step-by-Step Deployment (Advanced)](#-2-manual-step-by-step-deployment-advanced): For users who want to build and run each container individually. +- [🚀 3. Start Microservice with Python](#-3-start-microservice-with-python): For users who prefer to run the ASR microservice directly with Python scripts. + +## 🚀 1. Quick Start with Docker Compose + +This method uses Docker Compose to start all necessary services with a single command. It is the fastest and easiest way to get the service running. + +### 1.1. Access the Code + +Clone the repository and navigate to the deployment directory: + +```bash +git clone https://github.com/opea-project/GenAIComps.git +cd GenAIComps/comps/asr/deployment/docker_compose +``` + +### 1.2. Deploy the Service + +Choose the command corresponding to your target platform. + +```bash +export ip_address=$(hostname -I | awk '{print $1}') +export ASR_ENDPOINT=http://$ip_address:7066 +export no_proxy=localhost,$no_proxy +``` + +- **For Intel® Core® CPU:** + ```bash + docker compose -f ../docker_compose/compose.yaml up funasr-paraformer-service asr-funasr-paraformer -d + ``` + **Note:** it might take some time for `funasr-paraformer-service` to get ready, depending on the model download time in your network environment. If it fails to start with error message `dependency failed to start: container funasr-paraformer-service is unhealthy`, try increasing healthcheck retries in `GenAIComps/comps/third_parties/funasr/deployment/docker_compose/compose.yaml` + +### 1.3. Validate the Service + +Once the containers are running, you can validate the service. **Note:** Run these commands from the root of the `GenAIComps` repository. + +```bash +# Test +wget https://github.com/intel/intel-extension-for-transformers/raw/main/intel_extension_for_transformers/neural_chat/assets/audio/sample.wav +curl http://localhost:9099/v1/audio/transcriptions \ + -H "Content-Type: multipart/form-data" \ + -F file="@./sample.wav" \ + -F model="paraformer-zh" +``` + +### 1.4. Clean Up the Deployment + +To stop and remove the containers, run the following command from the `comps/asr/deployment/docker_compose` directory: + +```bash +docker compose down +``` + +--- + +## 🚀 2. Manual Step-by-Step Deployment (Advanced) + +This section provides detailed instructions for building the Docker images and running each microservice container individually. + +### 2.1. Clone the Repository + +If you haven't already, clone the repository and navigate to the root directory: + +```bash +git clone https://github.com/opea-project/GenAIComps.git +cd GenAIComps +``` + +### 2.2. Build the Docker Images + +#### 2.2.1. Build FunASR Paraformer Server Image + +- **For Intel® Core® CPU:** + ```bash + docker build -t opea/funasr-paraformer:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/third_parties/funasr/src/Dockerfile . + ``` + +#### 2.2.2. Build ASR Service Image + +```bash +docker build -t opea/asr:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/asr/src/Dockerfile . +``` + +### 2.3 Start FunASR Paraformer and ASR Service + +#### 2.3.1 Start FunASR Paraformer Server + +- Core CPU + +```bash +docker run -p 7066:7066 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e no_proxy=$no_proxy opea/funasr-paraformer:latest +``` + +#### 2.3.2 Start ASR service + +```bash +ip_address=$(hostname -I | awk '{print $1}') + +docker run -d -p 9099:9099 --ipc=host -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e no_proxy=$no_proxy -e ASR_ENDPOINT=http://$ip_address:7066 opea/asr:latest +``` + +### 2.4 Validate the Service + +After starting both containers, test the asr service endpoint. Make sure you are in the root directory of the `GenAIComps` repository. + +```bash +# Use curl or python + +# curl +wget https://github.com/intel/intel-extension-for-transformers/raw/main/intel_extension_for_transformers/neural_chat/assets/audio/sample.wav +curl http://localhost:9099/v1/audio/transcriptions \ + -H "Content-Type: multipart/form-data" \ + -F file="@./sample.wav" \ + -F model="paraformer-zh" + +# python +python check_asr_server.py +``` + +### 2.6. Clean Up the Deployment + +To stop and remove the containers you started manually, use the `docker stop` and `docker rm` commands. + +- **For Intel® Core® CPU:** + ```bash + docker stop funasr-paraformer-service asr-funasr-paraformer-service + docker rm funasr-paraformer-service asr-funasr-paraformer-service + ``` + +## 🚀 3. Start Microservice with Python + +To start the ASR microservice with Python, you need to first install python packages. + +### 3.1 Install Requirements + +```bash +pip install -r requirements-cpu.txt +``` + +### 3.2 Start FunASR Paraformer Service/Test + +- Core CPU + +```bash +cd comps/third_parties/funasr/src +nohup python funasr_server.py --device=cpu & +python check_funasr_server.py +``` + +Note: please make sure that port 7066 is not occupied by other services. Otherwise, use the command `npx kill-port 7066` to free the port. + +### 3.3 Start ASR Service/Test + +```bash +cd ../../.. +python opea_asr_microservice.py +python check_asr_server.py +``` diff --git a/comps/asr/deployment/docker_compose/compose.yaml b/comps/asr/deployment/docker_compose/compose.yaml index 4b0ac07da3..cab09a2705 100644 --- a/comps/asr/deployment/docker_compose/compose.yaml +++ b/comps/asr/deployment/docker_compose/compose.yaml @@ -3,6 +3,7 @@ include: - ../../../third_parties/whisper/deployment/docker_compose/compose.yaml + - ../../../third_parties/funasr/deployment/docker_compose/compose.yaml services: asr: @@ -33,6 +34,15 @@ services: depends_on: whisper-gaudi-service: condition: service_healthy + asr-funasr-paraformer: + extends: asr + container_name: asr-funasr-paraformer-service + environment: + ASR_COMPONENT_NAME: ${ASR_COMPONENT_NAME:-OPEA_PARAFORMER_ASR} + ENABLE_MCP: ${ENABLE_MCP:-False} + depends_on: + funasr-paraformer-service: + condition: service_healthy networks: default: diff --git a/comps/asr/src/README.md b/comps/asr/src/README.md index 43b227384e..6adc09deb7 100644 --- a/comps/asr/src/README.md +++ b/comps/asr/src/README.md @@ -12,6 +12,7 @@ ASR (Audio-Speech-Recognition) microservice helps users convert speech to text. - **ASR Server**: This microservice is responsible for converting speech audio into text. It receives an audio file as input and returns the transcribed text, enabling downstream applications such as conversational bots to process spoken language. The ASR server supports deployment on both CPU and HPU platforms. - **Whisper Server**: This microservice is responsible for converting speech audio into text using the Whisper model. It exposes an API endpoint that accepts audio files and returns the transcribed text, supporting both CPU and HPU deployments. The Whisper server acts as the backend for ASR functionality in the overall architecture. +- **FunASR Paraformer Server**: This microservice is responsible for converting speech audio into text using the Paraformer model with the FunASR toolkit. Similar to the Whisper Server, it exposes an API endpoint that accepts audio files and returns the transcribed text, supporting CPU deployments. The FunASR Paraformer server acts as the backend for ASR functionality in the overall architecture. ## Deployment Options @@ -20,6 +21,7 @@ For detailed, step-by-step instructions on how to deploy the ASR microservice us | Platform | Deployment Method | Link | | ----------------- | ----------------- | ---------------------------------------------------------- | | Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](../deployment/docker_compose/README.md) | +| Intel Core | Docker Compose | [Deployment Guide](../deployment/docker_compose/README_paraformer.md) | ## Validated Configurations @@ -28,3 +30,4 @@ The following configurations have been validated for the ASR microservice. | **Deploy Method** | **Core Models** | **Platform** | | ----------------- | --------------- | ----------------- | | Docker Compose | Whisper | Intel Xeon/Gaudi2 | +| Docker Compose | Paraformer | Intel Core | diff --git a/comps/asr/src/integrations/funasr_paraformer.py b/comps/asr/src/integrations/funasr_paraformer.py new file mode 100644 index 0000000000..cb6fec0a81 --- /dev/null +++ b/comps/asr/src/integrations/funasr_paraformer.py @@ -0,0 +1,93 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import asyncio +import os +from typing import List, Union + +import requests +from fastapi import File, Form, UploadFile + +from comps import CustomLogger, OpeaComponent, OpeaComponentRegistry, ServiceType +from comps.cores.proto.api_protocol import AudioTranscriptionResponse + +logger = CustomLogger("opea_paraformer") +logflag = os.getenv("LOGFLAG", False) + + +@OpeaComponentRegistry.register("OPEA_PARAFORMER_ASR") +class OpeaParaformerAsr(OpeaComponent): + """A specialized ASR (Automatic Speech Recognition) component derived from OpeaComponent for FUNASR Paraformer ASR services. + + Attributes: + model_name (str): The name of the ASR model used. + """ + + def __init__(self, name: str, description: str, config: dict = None): + super().__init__(name, ServiceType.ASR.name.lower(), description, config) + self.base_url = os.getenv("ASR_ENDPOINT", "http://localhost:7066") + health_status = self.check_health() + if not health_status: + logger.error("OpeaParaformerAsr health check failed.") + + async def invoke( + self, + file: Union[str, UploadFile], # accept base64 string or UploadFile + model: str = Form("paraformer-zh"), + language: str = Form("english"), + prompt: str = Form(None), + response_format: str = Form("json"), + temperature: float = Form(0), + timestamp_granularities: List[str] = Form(None), + ) -> AudioTranscriptionResponse: + """Involve the ASR service to generate transcription for the provided input.""" + if isinstance(file, str): + data = {"audio": file} + # Send the file and model to the server + response = await asyncio.to_thread( + requests.post, + f"{self.base_url}/v1/asr", + json=data, + ) + res = response.json()["asr_result"] + return AudioTranscriptionResponse(text=res) + else: + # Read the uploaded file + file_contents = await file.read() + + # Prepare the files and data + files = { + "file": (file.filename, file_contents, file.content_type), + } + data = { + "model": model, + "language": language, + "prompt": prompt, + "response_format": response_format, + "temperature": temperature, + "timestamp_granularities": timestamp_granularities, + } + + # Send the file and model to the server + response = await asyncio.to_thread( + requests.post, f"{self.base_url}/v1/audio/transcriptions", files=files, data=data + ) + res = response.json()["text"] + return AudioTranscriptionResponse(text=res) + + def check_health(self) -> bool: + """Checks the health of the embedding service. + + Returns: + bool: True if the service is reachable and healthy, False otherwise. + """ + try: + response = requests.get(f"{self.base_url}/health") + if response.status_code == 200: + return True + else: + return False + except Exception as e: + # Handle connection errors, timeouts, etc. + logger.error(f"Health check failed: {e}") + return False diff --git a/comps/asr/src/opea_asr_microservice.py b/comps/asr/src/opea_asr_microservice.py index db9bb37947..819a27bef9 100644 --- a/comps/asr/src/opea_asr_microservice.py +++ b/comps/asr/src/opea_asr_microservice.py @@ -7,6 +7,7 @@ from fastapi import File, Form, UploadFile from integrations.whisper import OpeaWhisperAsr +from integrations.funasr_paraformer import OpeaParaformerAsr from comps import ( Base64ByteStrDoc, diff --git a/comps/third_parties/funasr/deployment/docker_compose/compose.yaml b/comps/third_parties/funasr/deployment/docker_compose/compose.yaml new file mode 100644 index 0000000000..8f6835e783 --- /dev/null +++ b/comps/third_parties/funasr/deployment/docker_compose/compose.yaml @@ -0,0 +1,23 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +services: + funasr-paraformer-service: + image: ${REGISTRY:-opea}/funasr-paraformer:${TAG:-latest} + container_name: funasr-paraformer-service + ports: + - ${FUNASR_PARAFORMER_PORT:-7066}:7066 + ipc: host + environment: + no_proxy: ${no_proxy} + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:7066/health"] + interval: 10s + timeout: 6s + retries: 60 + # mount a host directory to cache models if needed, make sure it exists before starting the container + # volumes: + # - /home/user/.cache:/home/user/.cache:rw diff --git a/comps/third_parties/funasr/src/Dockerfile b/comps/third_parties/funasr/src/Dockerfile new file mode 100644 index 0000000000..c0239dc925 --- /dev/null +++ b/comps/third_parties/funasr/src/Dockerfile @@ -0,0 +1,28 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +FROM python:3.11-slim + +RUN useradd -m -s /bin/bash user && \ + mkdir -p /home/user && \ + chown -R user /home/user/ + +# Set environment variables +ENV LANG=en_US.UTF-8 +ARG ARCH=cpu + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends --fix-missing \ + curl \ + ffmpeg + +COPY --chown=user:user comps /home/user/comps + +RUN pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu && \ + pip install -r /home/user/comps/third_parties/funasr/src/requirements-cpu.txt + +ENV PYTHONPATH=$PYTHONPATH:/home/user +USER user +WORKDIR /home/user/comps/third_parties/funasr/src + +ENTRYPOINT ["python", "funasr_server.py", "--device", "cpu"] diff --git a/comps/third_parties/funasr/src/__init__.py b/comps/third_parties/funasr/src/__init__.py new file mode 100644 index 0000000000..f5263137c4 --- /dev/null +++ b/comps/third_parties/funasr/src/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/comps/third_parties/funasr/src/check_paraformer_server.py b/comps/third_parties/funasr/src/check_paraformer_server.py new file mode 100644 index 0000000000..edd3a53964 --- /dev/null +++ b/comps/third_parties/funasr/src/check_paraformer_server.py @@ -0,0 +1,30 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import base64 +import json +import os +import urllib.request +import uuid + +import requests + +# https://gist.github.com/novwhisky/8a1a0168b94f3b6abfaa +# test_audio_base64_str = "UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA" + +uid = str(uuid.uuid4()) +file_name = uid + ".wav" + +urllib.request.urlretrieve( + "https://github.com/intel/intel-extension-for-transformers/raw/main/intel_extension_for_transformers/neural_chat/assets/audio/sample.wav", + file_name, +) + +with open(file_name, "rb") as f: + test_audio_base64_str = base64.b64encode(f.read()).decode("utf-8") +os.remove(file_name) + +endpoint = "http://localhost:7066/v1/asr" +inputs = {"audio": test_audio_base64_str} +response = requests.post(url=endpoint, data=json.dumps(inputs), proxies={"http": None}) +print(response.json()) diff --git a/comps/third_parties/funasr/src/funasr_paraformer_model.py b/comps/third_parties/funasr/src/funasr_paraformer_model.py new file mode 100644 index 0000000000..279825820a --- /dev/null +++ b/comps/third_parties/funasr/src/funasr_paraformer_model.py @@ -0,0 +1,42 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +from funasr import AutoModel + +import logging +logger = logging.getLogger(__name__) + +FUNASR_MODEL_MAP = { + "paraformer-zh": "iic/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch", + "paraformer-en": "iic/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020", + "paraformer-online": "iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", +} + +class Paraformer: + def __init__(self, model_name, device="cpu", revision="v2.0.4"): + if model_name not in FUNASR_MODEL_MAP: + raise ValueError(f"Invalid ASR model name {model_name}. Supported models are: {list(FUNASR_MODEL_MAP.keys())}") + + self.model_name = model_name + model_name = FUNASR_MODEL_MAP[model_name] + # use same vad and punc model for different ASR models + self.model = AutoModel(model=model_name, model_revision=revision, + vad_model="fsmn-vad", vad_model_revision="v2.0.4", + punc_model="iic/punc_ct-transformer_zh-cn-common-vocab272727-pytorch", punc_model_revision="v2.0.4", + # spk_model="cam++", spk_model_revision="v2.0.2", + device=device, disable_update=True + ) + + def transcribe(self, audio_path: str) -> str: + try: + res = self.model.generate(input=audio_path) + # res [{'key': , 'text': '...', , 'timestamp': [[], [], ...]}] + if len(res) > 0: + return res[0]["text"] + else: + logger.error("ASR transcription generated empty result.") + return None + except Exception as e: + logger.error(f"Error during transcription: {e}") + return None + \ No newline at end of file diff --git a/comps/third_parties/funasr/src/funasr_server.py b/comps/third_parties/funasr/src/funasr_server.py new file mode 100644 index 0000000000..7f2a6374bb --- /dev/null +++ b/comps/third_parties/funasr/src/funasr_server.py @@ -0,0 +1,111 @@ +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import base64 +import os +import uuid +from typing import List + +import uvicorn +from fastapi import FastAPI, File, Form, Request, UploadFile +from fastapi.responses import Response +from pydub import AudioSegment +from starlette.middleware.cors import CORSMiddleware +from funasr_paraformer_model import Paraformer + +from comps import CustomLogger +from comps.cores.proto.api_protocol import AudioTranscriptionResponse + +logger = CustomLogger("funasr_paraformer") +logflag = os.getenv("LOGFLAG", False) + +app = FastAPI() +asr = None + +app.add_middleware( + CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] +) + + +@app.get("/health") +async def health() -> Response: + """Health check.""" + return Response(status_code=200) + + +@app.post("/v1/asr") +async def audio_to_text(request: Request): + logger.info("Paraformer generation begin.") + uid = str(uuid.uuid4()) + file_name = uid + ".wav" + request_dict = await request.json() + audio_b64_str = request_dict.pop("audio") + with open(file_name, "wb") as f: + f.write(base64.b64decode(audio_b64_str)) + + try: + asr_result = asr.transcribe(file_name) + except Exception as e: + logger.error(e) + asr_result = e + finally: + os.remove(file_name) + return {"asr_result": asr_result} + + +@app.post("/v1/audio/transcriptions") +async def audio_transcriptions( + file: UploadFile = File(...), # Handling the uploaded file directly + model: str = Form("paraformer-zh"), + language: str = Form("english"), + prompt: str = Form(None), + response_format: str = Form("json"), + temperature: float = Form(0), + timestamp_granularities: List[str] = Form(None), +): + logger.info("Paraformer generation begin.") + audio_content = await file.read() + # validate the request parameters + if model != asr.model_name: + raise Exception( + f"ASR model mismatch! Please make sure you pass --model_name to {model}" + ) + if prompt is not None or response_format != "json" or temperature != 0 or timestamp_granularities is not None: + logger.warning( + "Currently parameters 'prompt', 'response_format', 'temperature', 'timestamp_granularities' are not supported!" + ) + + uid = str(uuid.uuid4()) + file_name = uid + ".wav" + # Save the uploaded file + with open(file_name, "wb") as buffer: + buffer.write(audio_content) + + try: + asr_result = asr.transcribe(file_name) + except Exception as e: + logger.error(e) + asr_result = e + finally: + os.remove(file_name) + + return AudioTranscriptionResponse(text=asr_result) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--host", type=str, default="0.0.0.0") + parser.add_argument("--port", type=int, default=7066) + parser.add_argument("--model_name_or_path", type=str, default="paraformer-zh") + parser.add_argument("--device", type=str, default="cpu") + parser.add_argument("--revision", type=str, default="v2.0.4") + + args = parser.parse_args() + asr = Paraformer( + model_name=args.model_name_or_path, + device=args.device, + revision=args.revision, + ) + + uvicorn.run(app, host=args.host, port=args.port) diff --git a/comps/third_parties/funasr/src/requirements-cpu.txt b/comps/third_parties/funasr/src/requirements-cpu.txt new file mode 100644 index 0000000000..86222eb53f --- /dev/null +++ b/comps/third_parties/funasr/src/requirements-cpu.txt @@ -0,0 +1,15 @@ +aiohttp +datasets +docarray[full] +fastapi +funasr +mcp +opentelemetry-api +opentelemetry-exporter-otlp +opentelemetry-sdk +prometheus-fastapi-instrumentator +pydantic==2.7.2 +pydub +python-multipart +shortuuid +uvicorn \ No newline at end of file diff --git a/tests/asr/test_asr_funasr_paraformer.sh b/tests/asr/test_asr_funasr_paraformer.sh new file mode 100644 index 0000000000..761b96768c --- /dev/null +++ b/tests/asr/test_asr_funasr_paraformer.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +set -x + +WORKPATH=$(dirname "$PWD") +ip_address=$(hostname -I | awk '{print $1}') +export TAG=comps +export FUNASR_PARAFORMER_PORT=10100 +export ASR_PORT=10101 +cd $WORKPATH + + +function build_docker_images() { + echo $(pwd) + docker build --no-cache -t opea/funasr-paraformer:$TAG --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/third_parties/funasr/src/Dockerfile . + + if [ $? -ne 0 ]; then + echo "opea/funasr-paraformer built fail" + exit 1 + else + echo "opea/funasr-paraformer built successful" + fi + + docker build --no-cache -t opea/asr:$TAG --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/asr/src/Dockerfile . + + if [ $? -ne 0 ]; then + echo "opea/asr built fail" + exit 1 + else + echo "opea/asr built successful" + fi +} + +function start_service() { + unset http_proxy + export ASR_ENDPOINT=http://$ip_address:$FUNASR_PARAFORMER_PORT + + docker compose -f comps/asr/deployment/docker_compose/compose.yaml up funasr-paraformer-service asr-funasr-paraformer -d + sleep 1m +} + +function validate_microservice() { + wget https://github.com/intel/intel-extension-for-transformers/raw/main/intel_extension_for_transformers/neural_chat/assets/audio/sample.wav + result=$(http_proxy="" curl http://localhost:$ASR_PORT/v1/audio/transcriptions -H "Content-Type: multipart/form-data" -F file="@./sample.wav" -F model="paraformer-zh") + rm -f sample.wav + shopt -s nocasematch + if [[ $result =~ who\ is ]]; then + echo "Result correct." + else + echo "Result wrong." + docker logs funasr-paraformer-service + docker logs asr-funasr-paraformer-service + exit 1 + fi + shopt -u nocasematch + + wget https://github.com/intel/intel-extension-for-transformers/raw/refs/tags/v1.5/intel_extension_for_transformers/neural_chat/ui/customized/talkingbot/src/lib/components/talkbot/assets/mid-age-man.mp3 -O sample.mp3 + result=$(http_proxy="" curl http://localhost:$ASR_PORT/v1/audio/transcriptions -H "Content-Type: multipart/form-data" -F file="@./sample.mp3" -F model="paraformer-zh") + rm -f sample.mp3 + shopt -s nocasematch + if [[ $result =~ welcome\ to ]]; then + echo "Result correct." + else + echo "Result wrong." + docker logs funasr-paraformer-service + docker logs asr-funasr-paraformer-service + exit 1 + fi + shopt -u nocasematch + +} + +function stop_docker() { + docker ps -a --filter "name=funasr-paraformer-service" --filter "name=asr-funasr-paraformer-service" --format "{{.Names}}" | xargs -r docker stop +} + +function main() { + + stop_docker + + build_docker_images + start_service + + validate_microservice + + stop_docker + echo y | docker system prune + +} + +main From c01c5e72be5a7d20af4702cf7cdf62b56a0ed980 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 06:37:41 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- comps/asr/src/README.md | 6 ++-- comps/asr/src/opea_asr_microservice.py | 2 +- comps/third_parties/funasr/src/__init__.py | 2 +- .../funasr/src/funasr_paraformer_model.py | 28 ++++++++++++------- .../third_parties/funasr/src/funasr_server.py | 6 ++-- .../funasr/src/requirements-cpu.txt | 2 +- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/comps/asr/src/README.md b/comps/asr/src/README.md index 6adc09deb7..3509005ff1 100644 --- a/comps/asr/src/README.md +++ b/comps/asr/src/README.md @@ -18,9 +18,9 @@ ASR (Audio-Speech-Recognition) microservice helps users convert speech to text. For detailed, step-by-step instructions on how to deploy the ASR microservice using Docker Compose on different Intel platforms, please refer to the deployment guide. The guide contains all necessary steps, including building images, configuring the environment, and running the service. -| Platform | Deployment Method | Link | -| ----------------- | ----------------- | ---------------------------------------------------------- | -| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](../deployment/docker_compose/README.md) | +| Platform | Deployment Method | Link | +| ----------------- | ----------------- | --------------------------------------------------------------------- | +| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](../deployment/docker_compose/README.md) | | Intel Core | Docker Compose | [Deployment Guide](../deployment/docker_compose/README_paraformer.md) | ## Validated Configurations diff --git a/comps/asr/src/opea_asr_microservice.py b/comps/asr/src/opea_asr_microservice.py index 819a27bef9..aa4c2d8f96 100644 --- a/comps/asr/src/opea_asr_microservice.py +++ b/comps/asr/src/opea_asr_microservice.py @@ -6,8 +6,8 @@ from typing import List, Union from fastapi import File, Form, UploadFile -from integrations.whisper import OpeaWhisperAsr from integrations.funasr_paraformer import OpeaParaformerAsr +from integrations.whisper import OpeaWhisperAsr from comps import ( Base64ByteStrDoc, diff --git a/comps/third_parties/funasr/src/__init__.py b/comps/third_parties/funasr/src/__init__.py index f5263137c4..4057dc0163 100644 --- a/comps/third_parties/funasr/src/__init__.py +++ b/comps/third_parties/funasr/src/__init__.py @@ -1,2 +1,2 @@ # Copyright (C) 2025 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 \ No newline at end of file +# SPDX-License-Identifier: Apache-2.0 diff --git a/comps/third_parties/funasr/src/funasr_paraformer_model.py b/comps/third_parties/funasr/src/funasr_paraformer_model.py index 279825820a..1da2ff3244 100644 --- a/comps/third_parties/funasr/src/funasr_paraformer_model.py +++ b/comps/third_parties/funasr/src/funasr_paraformer_model.py @@ -1,9 +1,10 @@ # Copyright (C) 2025 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +import logging + from funasr import AutoModel -import logging logger = logging.getLogger(__name__) FUNASR_MODEL_MAP = { @@ -12,20 +13,28 @@ "paraformer-online": "iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", } + class Paraformer: def __init__(self, model_name, device="cpu", revision="v2.0.4"): if model_name not in FUNASR_MODEL_MAP: - raise ValueError(f"Invalid ASR model name {model_name}. Supported models are: {list(FUNASR_MODEL_MAP.keys())}") - + raise ValueError( + f"Invalid ASR model name {model_name}. Supported models are: {list(FUNASR_MODEL_MAP.keys())}" + ) + self.model_name = model_name model_name = FUNASR_MODEL_MAP[model_name] # use same vad and punc model for different ASR models - self.model = AutoModel(model=model_name, model_revision=revision, - vad_model="fsmn-vad", vad_model_revision="v2.0.4", - punc_model="iic/punc_ct-transformer_zh-cn-common-vocab272727-pytorch", punc_model_revision="v2.0.4", - # spk_model="cam++", spk_model_revision="v2.0.2", - device=device, disable_update=True - ) + self.model = AutoModel( + model=model_name, + model_revision=revision, + vad_model="fsmn-vad", + vad_model_revision="v2.0.4", + punc_model="iic/punc_ct-transformer_zh-cn-common-vocab272727-pytorch", + punc_model_revision="v2.0.4", + # spk_model="cam++", spk_model_revision="v2.0.2", + device=device, + disable_update=True, + ) def transcribe(self, audio_path: str) -> str: try: @@ -39,4 +48,3 @@ def transcribe(self, audio_path: str) -> str: except Exception as e: logger.error(f"Error during transcription: {e}") return None - \ No newline at end of file diff --git a/comps/third_parties/funasr/src/funasr_server.py b/comps/third_parties/funasr/src/funasr_server.py index 7f2a6374bb..e91084ed0e 100644 --- a/comps/third_parties/funasr/src/funasr_server.py +++ b/comps/third_parties/funasr/src/funasr_server.py @@ -10,9 +10,9 @@ import uvicorn from fastapi import FastAPI, File, Form, Request, UploadFile from fastapi.responses import Response +from funasr_paraformer_model import Paraformer from pydub import AudioSegment from starlette.middleware.cors import CORSMiddleware -from funasr_paraformer_model import Paraformer from comps import CustomLogger from comps.cores.proto.api_protocol import AudioTranscriptionResponse @@ -68,9 +68,7 @@ async def audio_transcriptions( audio_content = await file.read() # validate the request parameters if model != asr.model_name: - raise Exception( - f"ASR model mismatch! Please make sure you pass --model_name to {model}" - ) + raise Exception(f"ASR model mismatch! Please make sure you pass --model_name to {model}") if prompt is not None or response_format != "json" or temperature != 0 or timestamp_granularities is not None: logger.warning( "Currently parameters 'prompt', 'response_format', 'temperature', 'timestamp_granularities' are not supported!" diff --git a/comps/third_parties/funasr/src/requirements-cpu.txt b/comps/third_parties/funasr/src/requirements-cpu.txt index 86222eb53f..9c0e39e062 100644 --- a/comps/third_parties/funasr/src/requirements-cpu.txt +++ b/comps/third_parties/funasr/src/requirements-cpu.txt @@ -12,4 +12,4 @@ pydantic==2.7.2 pydub python-multipart shortuuid -uvicorn \ No newline at end of file +uvicorn From 37f688e259383f60cccfaad8b0551cc7e3606fe4 Mon Sep 17 00:00:00 2001 From: llin60 Date: Thu, 28 Aug 2025 16:46:28 +0800 Subject: [PATCH 3/5] fix requirements deps; modify ASR READMEs --- comps/asr/src/README.md | 4 +- .../README_paraformer.md | 2 +- .../README.md => src/README_whisper.md} | 2 +- comps/third_parties/funasr/src/Dockerfile | 7 +- .../funasr/src/requirements-cpu.txt | 504 +++++++++++++++++- .../third_parties/funasr/src/requirements.in | 18 + tests/asr/test_asr_funasr_paraformer.sh | 2 +- 7 files changed, 518 insertions(+), 21 deletions(-) rename comps/asr/{deployment/docker_compose => src}/README_paraformer.md (99%) rename comps/asr/{deployment/docker_compose/README.md => src/README_whisper.md} (99%) create mode 100644 comps/third_parties/funasr/src/requirements.in diff --git a/comps/asr/src/README.md b/comps/asr/src/README.md index 6adc09deb7..bd5c1841ac 100644 --- a/comps/asr/src/README.md +++ b/comps/asr/src/README.md @@ -20,8 +20,8 @@ For detailed, step-by-step instructions on how to deploy the ASR microservice us | Platform | Deployment Method | Link | | ----------------- | ----------------- | ---------------------------------------------------------- | -| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](../deployment/docker_compose/README.md) | -| Intel Core | Docker Compose | [Deployment Guide](../deployment/docker_compose/README_paraformer.md) | +| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](./README_whisper.md) | +| Intel Core | Docker Compose | [Deployment Guide](./README_paraformer.md) | ## Validated Configurations diff --git a/comps/asr/deployment/docker_compose/README_paraformer.md b/comps/asr/src/README_paraformer.md similarity index 99% rename from comps/asr/deployment/docker_compose/README_paraformer.md rename to comps/asr/src/README_paraformer.md index 78ef2d1cce..f8db8f3443 100644 --- a/comps/asr/deployment/docker_compose/README_paraformer.md +++ b/comps/asr/src/README_paraformer.md @@ -4,7 +4,7 @@ This document provides a comprehensive guide to deploying the ASR microservice p **Note:** This is an alternative of the [Whisper ASR service](./README.md). The Paraformer model supports both English and Mandarin audio input, and empirically it shows better performance in Mandarin than English. -This guide covers two deployment methods: +## Table of contents - [🚀 1. Quick Start with Docker Compose](#-1-quick-start-with-docker-compose): The recommended method for a fast and easy setup. - [🚀 2. Manual Step-by-Step Deployment (Advanced)](#-2-manual-step-by-step-deployment-advanced): For users who want to build and run each container individually. diff --git a/comps/asr/deployment/docker_compose/README.md b/comps/asr/src/README_whisper.md similarity index 99% rename from comps/asr/deployment/docker_compose/README.md rename to comps/asr/src/README_whisper.md index 4e14960ed9..dc387a57f3 100644 --- a/comps/asr/deployment/docker_compose/README.md +++ b/comps/asr/src/README_whisper.md @@ -2,7 +2,7 @@ This document provides a comprehensive guide to deploying the ASR microservice pipeline on Intel platforms. -This guide covers two deployment methods: +## Table of contents - [🚀 1. Quick Start with Docker Compose](#-1-quick-start-with-docker-compose): The recommended method for a fast and easy setup. - [🚀 2. Manual Step-by-Step Deployment (Advanced)](#-2-manual-step-by-step-deployment-advanced): For users who want to build and run each container individually. diff --git a/comps/third_parties/funasr/src/Dockerfile b/comps/third_parties/funasr/src/Dockerfile index c0239dc925..158aa96063 100644 --- a/comps/third_parties/funasr/src/Dockerfile +++ b/comps/third_parties/funasr/src/Dockerfile @@ -18,8 +18,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends --fix-missing \ COPY --chown=user:user comps /home/user/comps -RUN pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu && \ - pip install -r /home/user/comps/third_parties/funasr/src/requirements-cpu.txt +ARG uvpip='uv pip install --system --no-cache-dir' +RUN pip install --no-cache-dir --upgrade pip setuptools uv && \ + $uvpip torch torchaudio --index-url https://download.pytorch.org/whl/cpu ; \ + $uvpip -r /home/user/comps/third_parties/funasr/src/requirements-cpu.txt + ENV PYTHONPATH=$PYTHONPATH:/home/user USER user diff --git a/comps/third_parties/funasr/src/requirements-cpu.txt b/comps/third_parties/funasr/src/requirements-cpu.txt index 86222eb53f..dd0c630b59 100644 --- a/comps/third_parties/funasr/src/requirements-cpu.txt +++ b/comps/third_parties/funasr/src/requirements-cpu.txt @@ -1,15 +1,491 @@ -aiohttp -datasets -docarray[full] -fastapi -funasr -mcp -opentelemetry-api -opentelemetry-exporter-otlp -opentelemetry-sdk -prometheus-fastapi-instrumentator +# This file was autogenerated by uv via the following command: +# uv pip compile --index-strategy unsafe-best-match ./comps/third_parties/funasr/src/requirements.in --universal -o ./comps/third_parties/funasr/src/requirements-cpu.txt +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.15 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # fsspec +aiosignal==1.4.0 + # via aiohttp +aliyun-python-sdk-core==2.16.0 + # via + # aliyun-python-sdk-kms + # oss2 +aliyun-python-sdk-kms==2.16.5 + # via oss2 +annotated-types==0.7.0 + # via pydantic +antlr4-python3-runtime==4.9.3 + # via + # hydra-core + # omegaconf +anyio==4.10.0 + # via + # httpx + # mcp + # sse-starlette + # starlette +attrs==25.3.0 + # via + # aiohttp + # jsonschema + # referencing +audioop-lts==0.2.2 ; python_full_version >= '3.13' + # via + # standard-aifc + # standard-sunau +audioread==3.0.1 + # via librosa +av==15.0.0 + # via docarray +certifi==2025.8.3 + # via + # httpcore + # httpx + # requests +cffi==1.17.1 + # via + # cryptography + # soundfile +charset-normalizer==3.4.3 + # via + # requests + # trimesh +click==8.2.1 + # via uvicorn +colorama==0.4.6 ; sys_platform == 'win32' + # via + # click + # colorlog + # tqdm +colorlog==6.9.0 + # via trimesh +crcmod==1.7 + # via oss2 +cryptography==45.0.6 + # via aliyun-python-sdk-core +datasets==4.0.0 + # via -r ./comps/third_parties/funasr/src/requirements.in +decorator==5.2.1 + # via librosa +dill==0.3.8 + # via + # datasets + # multiprocess +docarray==0.41.0 + # via -r ./comps/third_parties/funasr/src/requirements.in +editdistance==0.8.1 + # via funasr +embreex==2.17.7.post6 ; platform_machine == 'x86_64' + # via trimesh +fastapi==0.116.1 + # via -r ./comps/third_parties/funasr/src/requirements.in +filelock==3.19.1 + # via + # datasets + # huggingface-hub + # modelscope +frozenlist==1.7.0 + # via + # aiohttp + # aiosignal +fsspec==2025.3.0 + # via + # datasets + # huggingface-hub +funasr==1.2.7 + # via -r ./comps/third_parties/funasr/src/requirements.in +googleapis-common-protos==1.70.0 + # via + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http +grpcio==1.74.0 + # via opentelemetry-exporter-otlp-proto-grpc +h11==0.16.0 + # via + # httpcore + # uvicorn +hf-xet==1.1.9 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' + # via huggingface-hub +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via + # mcp + # trimesh +httpx-sse==0.4.1 + # via mcp +huggingface-hub==0.34.4 + # via datasets +hydra-core==1.3.2 + # via funasr +idna==3.10 + # via + # anyio + # httpx + # requests + # yarl +importlib-metadata==8.7.0 + # via opentelemetry-api +jaconv==0.4.0 + # via funasr +jamo==0.4.1 + # via funasr +jax==0.5.3 ; python_full_version >= '3.13' + # via docarray +jax==0.7.1 ; python_full_version < '3.13' + # via docarray +jaxlib==0.5.3 ; python_full_version >= '3.13' + # via jax +jaxlib==0.7.1 ; python_full_version < '3.13' + # via jax +jieba==0.42.1 + # via funasr +jmespath==0.10.0 + # via aliyun-python-sdk-core +joblib==1.5.2 + # via + # librosa + # pynndescent + # scikit-learn +jsonschema==4.25.1 + # via + # mcp + # trimesh +jsonschema-specifications==2025.4.1 + # via jsonschema +kaldiio==2.18.1 + # via funasr +lazy-loader==0.4 + # via librosa +librosa==0.11.0 + # via funasr +llvmlite==0.44.0 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # numba + # pynndescent +lxml==6.0.1 + # via trimesh +lz4==4.4.4 + # via docarray +manifold3d==3.2.1 + # via trimesh +mapbox-earcut==1.0.3 + # via trimesh +markdown-it-py==4.0.0 + # via rich +mcp==1.10.1 + # via -r ./comps/third_parties/funasr/src/requirements.in +mdurl==0.1.2 + # via markdown-it-py +ml-dtypes==0.4.1 ; python_full_version >= '3.13' + # via + # jax + # jaxlib +ml-dtypes==0.5.3 ; python_full_version < '3.13' + # via + # jax + # jaxlib +modelscope==1.29.1 + # via funasr +msgpack==1.1.1 + # via librosa +multidict==6.6.4 + # via + # aiohttp + # yarl +multiprocess==0.70.16 + # via datasets +mypy-extensions==1.1.0 + # via typing-inspect +networkx==3.5 + # via trimesh +numba==0.61.2 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # librosa + # pynndescent + # umap-learn +numpy==1.26.4 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # datasets + # docarray + # embreex + # jax + # jaxlib + # kaldiio + # librosa + # manifold3d + # mapbox-earcut + # ml-dtypes + # numba + # pandas + # pycollada + # pytorch-wpe + # scikit-learn + # scipy + # shapely + # soundfile + # soxr + # tensorboardx + # torch-complex + # trimesh + # umap-learn + # vhacdx +omegaconf==2.3.0 + # via hydra-core +opentelemetry-api==1.36.0 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http + # opentelemetry-sdk + # opentelemetry-semantic-conventions +opentelemetry-exporter-otlp==1.36.0 + # via -r ./comps/third_parties/funasr/src/requirements.in +opentelemetry-exporter-otlp-proto-common==1.36.0 + # via + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http +opentelemetry-exporter-otlp-proto-grpc==1.36.0 + # via opentelemetry-exporter-otlp +opentelemetry-exporter-otlp-proto-http==1.36.0 + # via opentelemetry-exporter-otlp +opentelemetry-proto==1.36.0 + # via + # opentelemetry-exporter-otlp-proto-common + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http +opentelemetry-sdk==1.36.0 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http +opentelemetry-semantic-conventions==0.57b0 + # via opentelemetry-sdk +opt-einsum==3.4.0 + # via jax +orjson==3.11.3 + # via docarray +oss2==2.19.1 + # via funasr +packaging==25.0 + # via + # datasets + # huggingface-hub + # hydra-core + # lazy-loader + # pooch + # tensorboardx + # torch-complex +pandas==2.3.2 + # via + # datasets + # docarray +pillow==11.3.0 + # via + # docarray + # trimesh +platformdirs==4.4.0 + # via pooch +pooch==1.8.2 + # via librosa +prometheus-client==0.22.1 + # via prometheus-fastapi-instrumentator +prometheus-fastapi-instrumentator==7.1.0 + # via -r ./comps/third_parties/funasr/src/requirements.in +propcache==0.3.2 + # via + # aiohttp + # yarl +protobuf==6.32.0 + # via + # docarray + # googleapis-common-protos + # opentelemetry-proto + # tensorboardx +pyarrow==21.0.0 + # via datasets +pycollada==0.9.2 + # via trimesh +pycparser==2.22 + # via cffi +pycryptodome==3.23.0 + # via oss2 pydantic==2.7.2 -pydub -python-multipart -shortuuid -uvicorn \ No newline at end of file + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # docarray + # fastapi + # mcp + # pydantic-settings +pydantic-core==2.18.3 + # via pydantic +pydantic-settings==2.10.1 + # via mcp +pydub==0.25.1 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # docarray +pygments==2.19.2 + # via rich +pynndescent==0.5.13 + # via umap-learn +python-dateutil==2.9.0.post0 + # via + # pandas + # pycollada +python-dotenv==1.1.1 + # via pydantic-settings +python-multipart==0.0.20 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # mcp +pytorch-wpe==0.0.1 + # via funasr +pytz==2025.2 + # via pandas +pyyaml==6.0.2 + # via + # datasets + # funasr + # huggingface-hub + # omegaconf +referencing==0.36.2 + # via + # jsonschema + # jsonschema-specifications +requests==2.32.5 + # via + # datasets + # funasr + # huggingface-hub + # modelscope + # opentelemetry-exporter-otlp-proto-http + # oss2 + # pooch +rich==14.1.0 + # via docarray +rpds-py==0.27.1 + # via + # jsonschema + # referencing +rtree==1.4.1 + # via trimesh +scikit-learn==1.7.1 + # via + # librosa + # pynndescent + # umap-learn +scipy==1.16.1 + # via + # funasr + # jax + # jaxlib + # librosa + # pynndescent + # scikit-learn + # trimesh + # umap-learn +sentencepiece==0.2.1 + # via funasr +setuptools==80.9.0 + # via modelscope +shapely==2.1.1 + # via trimesh +shortuuid==1.0.13 + # via -r ./comps/third_parties/funasr/src/requirements.in +six==1.17.0 + # via + # oss2 + # python-dateutil +sniffio==1.3.1 + # via anyio +soundfile==0.13.1 + # via + # funasr + # librosa +soxr==0.5.0.post1 + # via librosa +sse-starlette==3.0.2 + # via mcp +standard-aifc==3.13.0 ; python_full_version >= '3.13' + # via librosa +standard-chunk==3.13.0 ; python_full_version >= '3.13' + # via standard-aifc +standard-sunau==3.13.0 ; python_full_version >= '3.13' + # via librosa +starlette==0.47.3 + # via + # fastapi + # mcp + # prometheus-fastapi-instrumentator +svg-path==7.0 + # via trimesh +tensorboardx==2.6.4 + # via funasr +threadpoolctl==3.6.0 + # via scikit-learn +torch-complex==0.4.4 + # via funasr +tqdm==4.67.1 + # via + # datasets + # funasr + # huggingface-hub + # modelscope + # umap-learn +trimesh==4.7.4 + # via docarray +types-pillow==10.2.0.20240822 + # via docarray +types-requests==2.32.4.20250809 + # via docarray +typing-extensions==4.15.0 + # via + # aiosignal + # anyio + # fastapi + # huggingface-hub + # librosa + # opentelemetry-api + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-exporter-otlp-proto-http + # opentelemetry-sdk + # opentelemetry-semantic-conventions + # pydantic + # pydantic-core + # referencing + # starlette + # typing-inspect + # typing-inspection +typing-inspect==0.9.0 + # via docarray +typing-inspection==0.4.1 + # via pydantic-settings +tzdata==2025.2 + # via pandas +umap-learn==0.5.9.post2 + # via funasr +urllib3==2.5.0 + # via + # modelscope + # requests + # types-requests +uvicorn==0.35.0 + # via + # -r ./comps/third_parties/funasr/src/requirements.in + # mcp +vhacdx==0.0.8.post2 + # via trimesh +xxhash==3.5.0 + # via + # datasets + # trimesh +yarl==1.20.1 + # via aiohttp +zipp==3.23.0 + # via importlib-metadata diff --git a/comps/third_parties/funasr/src/requirements.in b/comps/third_parties/funasr/src/requirements.in new file mode 100644 index 0000000000..7bc6a9030e --- /dev/null +++ b/comps/third_parties/funasr/src/requirements.in @@ -0,0 +1,18 @@ +aiohttp +datasets +docarray[full] +fastapi +funasr==1.2.7 +llvmlite==0.44.0 +mcp +numba==0.61.2 +numpy==1.26.4 +opentelemetry-api +opentelemetry-exporter-otlp +opentelemetry-sdk +prometheus-fastapi-instrumentator +pydantic==2.7.2 +pydub +python-multipart +shortuuid +uvicorn \ No newline at end of file diff --git a/tests/asr/test_asr_funasr_paraformer.sh b/tests/asr/test_asr_funasr_paraformer.sh index 761b96768c..68adaeb1c8 100644 --- a/tests/asr/test_asr_funasr_paraformer.sh +++ b/tests/asr/test_asr_funasr_paraformer.sh @@ -7,7 +7,7 @@ set -x WORKPATH=$(dirname "$PWD") ip_address=$(hostname -I | awk '{print $1}') export TAG=comps -export FUNASR_PARAFORMER_PORT=10100 +export FUNASR_PARAFORMER_PORT=10102 export ASR_PORT=10101 cd $WORKPATH From 1a74d65538c4aaa53ee86f633ef8b968fffdd9e6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 08:49:10 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- comps/asr/src/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/comps/asr/src/README.md b/comps/asr/src/README.md index bd5c1841ac..99d68afbbd 100644 --- a/comps/asr/src/README.md +++ b/comps/asr/src/README.md @@ -18,9 +18,9 @@ ASR (Audio-Speech-Recognition) microservice helps users convert speech to text. For detailed, step-by-step instructions on how to deploy the ASR microservice using Docker Compose on different Intel platforms, please refer to the deployment guide. The guide contains all necessary steps, including building images, configuring the environment, and running the service. -| Platform | Deployment Method | Link | -| ----------------- | ----------------- | ---------------------------------------------------------- | -| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](./README_whisper.md) | +| Platform | Deployment Method | Link | +| ----------------- | ----------------- | ------------------------------------------ | +| Intel Xeon/Gaudi2 | Docker Compose | [Deployment Guide](./README_whisper.md) | | Intel Core | Docker Compose | [Deployment Guide](./README_paraformer.md) | ## Validated Configurations From 3e1c95943ff3316c0a78effe611149b2187d8834 Mon Sep 17 00:00:00 2001 From: llin60 Date: Mon, 1 Sep 2025 16:35:18 +0800 Subject: [PATCH 5/5] add funasr-paraformer dockerfile in github workflow --- .github/workflows/docker/compose/third_parties-compose.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docker/compose/third_parties-compose.yaml b/.github/workflows/docker/compose/third_parties-compose.yaml index 7085a19fd6..f6e555d42e 100644 --- a/.github/workflows/docker/compose/third_parties-compose.yaml +++ b/.github/workflows/docker/compose/third_parties-compose.yaml @@ -117,3 +117,7 @@ services: build: dockerfile: comps/third_parties/sglang/src/Dockerfile image: ${REGISTRY:-opea}/sglang:${TAG:-latest} + funasr-paraformer: + build: + dockerfile: comps/third_parties/funasr/src/Dockerfile + image: ${REGISTRY:-opea}/funasr-paraformer:${TAG:-latest}