Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile.redhat
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ RUN rm -f /usr/lib64/cmake/OpenSSL/OpenSSLConfig.cmake
# hadolint ignore=SC2046
RUN bazel build --jobs=$JOBS ${debug_bazel_flags} ${minitrace_flags} //src:ovms $(if [ "$OPTIMIZE_BUILDING_TESTS" == "1" ] ; then echo -n //src:ovms_test; fi)

# espeak-ng is built as a separate step, independent of the OVMS binary.
# Set ESPEAK=0 to skip the espeak build.
ARG ESPEAK=1
# hadolint ignore=DL3059
RUN if [ "$ESPEAK" == "1" ]; then bazel build --jobs=$JOBS ${debug_bazel_flags} //third_party:espeak_ng //third_party:espeak_ng_data; fi

# Tests execution
COPY ci/check_coverage.bat /ovms/
ARG CHECK_COVERAGE=0
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ ARG OPTIMIZE_BUILDING_TESTS=0
# hadolint ignore=SC2046
RUN if [ "$FUZZER_BUILD" == "0" ]; then bazel build --jobs=$JOBS ${debug_bazel_flags} ${minitrace_flags} //src:ovms $(if [ "${OPTIMIZE_BUILDING_TESTS}" == "1" ] ; then echo -n //src:ovms_test; fi); fi;

# espeak-ng is built as a separate step, independent of the OVMS binary.
# Set ESPEAK=0 to skip the espeak build.
ARG ESPEAK=1
# hadolint ignore=DL3059
RUN if [ "$ESPEAK" == "1" ]; then bazel build --jobs=$JOBS ${debug_bazel_flags} //third_party:espeak_ng //third_party:espeak_ng_data; fi

ARG RUN_TESTS=0
RUN if [ "$RUN_TESTS" == "1" ] ; then mkdir -p demos/common/export_models/ && mv export_model.py demos/common/export_models/ && ./prepare_llm_models.sh /ovms/src/test/llm_testing docker && ./run_unit_tests.sh ; fi

Expand Down
12 changes: 4 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,8 @@ else ifeq ($(findstring redhat,$(BASE_OS)),redhat)
else
$(error BASE_OS must be either ubuntu or redhat)
endif
ifeq ($(ESPEAK),1)
ESPEAK_PARAMS = " --//:espeak=on"
else
ESPEAK_PARAMS = " --//:espeak=off"
endif
CAPI_FLAGS = "--strip=$(STRIP)"$(BAZEL_DEBUG_BUILD_FLAGS)" --config=mp_off_py_off"$(OV_TRACING_PARAMS)$(TARGET_DISTRO_PARAMS)$(ESPEAK_PARAMS)
BAZEL_DEBUG_FLAGS="--strip=$(STRIP)"$(BAZEL_DEBUG_BUILD_FLAGS)$(DISABLE_PARAMS)$(FUZZER_BUILD_PARAMS)$(OV_TRACING_PARAMS)$(TARGET_DISTRO_PARAMS)$(ESPEAK_PARAMS)$(REPO_ENV)
CAPI_FLAGS = "--strip=$(STRIP)"$(BAZEL_DEBUG_BUILD_FLAGS)" --config=mp_off_py_off"$(OV_TRACING_PARAMS)$(TARGET_DISTRO_PARAMS)
BAZEL_DEBUG_FLAGS="--strip=$(STRIP)"$(BAZEL_DEBUG_BUILD_FLAGS)$(DISABLE_PARAMS)$(FUZZER_BUILD_PARAMS)$(OV_TRACING_PARAMS)$(TARGET_DISTRO_PARAMS)$(REPO_ENV)

# Option to Override release image.
# Release image OS *must have* glibc version >= glibc version on BASE_OS:
Expand Down Expand Up @@ -249,7 +244,8 @@ BUILD_ARGS = --build-arg http_proxy=$(HTTP_PROXY)\
--build-arg JOBS=$(JOBS)\
--build-arg CAPI_FLAGS=$(CAPI_FLAGS)\
--build-arg VERBOSE_LOGS=$(VERBOSE_LOGS)\
--build-arg KONFLUX=$(KONFLUX)
--build-arg KONFLUX=$(KONFLUX)\
--build-arg ESPEAK=$(ESPEAK)


.PHONY: default docker_build \
Expand Down
3 changes: 1 addition & 2 deletions common_settings.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@mediapipe//mediapipe/framework:more_selects.bzl", "more_selects")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load("//:distro.bzl", "distro_flag", "espeak_flag")
load("//:distro.bzl", "distro_flag")

# cc_library rule wrapper that will accept the same arguments but if user will not provide
# copts, linkopts, local_defines it will set them to the defaults
Expand Down Expand Up @@ -58,7 +58,6 @@ def ovms_cc_library(**kwargs):

def create_config_settings():
distro_flag()
espeak_flag()
native.config_setting(
name = "disable_mediapipe",
define_values = {
Expand Down
1 change: 1 addition & 0 deletions create_package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ESPEAK_DATA_SRC=$(find /ovms/bazel-out/k8-*/bin/external/espeak_ng -type d -name
if [ -n "$ESPEAK_DATA_SRC" ] && [ -d "$ESPEAK_DATA_SRC" ] ; then
mkdir -p /ovms_release/share
cp -rL "$ESPEAK_DATA_SRC" /ovms_release/share/ ;
chmod -R u+w /ovms_release/share/espeak-ng-data 2>/dev/null || true ;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add also a note in building from src doc with info that espeek is optional and can be delete from the package if not needed. explain the consequences - which language is supported without it

fi
# Resolve the packaged eSpeak shared object dynamically so version bumps
# do not require touching this script.
Expand Down
175 changes: 62 additions & 113 deletions demos/audio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,116 +8,80 @@ Check supported [Speech Recognition Models](https://openvinotoolkit.github.io/op

## Prerequisites

**OVMS version 2025.4** This demo require version 2025.4 or nightly release.

**Model preparation**: Python 3.10 or higher with pip
**OVMS version 2026.3** This demo require version 2026.3 or nightly release.

**Model Server deployment**: Installed Docker Engine or OVMS binary package according to the [baremetal deployment guide](../../docs/deploying_server_baremetal.md)

**Client**: curl or Python for using OpenAI client package

## Speech generation
### Prepare speaker embeddings
When generating speech you can use default speaker voice or you can prepare your own speaker embedding file. Here you can see how to do it with downloaded file from online repository, but you can try with your own speech recording as well:
```console
pip install -r https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/audio/requirements.txt
mkdir audio_samples
curl --create-dirs "https://www.voiptroubleshooter.com/open_speech/american/OSR_us_000_0032_8k.wav" -o audio_samples/audio.wav
curl --create-dirs https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/audio/create_speaker_embedding.py -o models/speakers/create_speaker_embedding.py
python models/speakers/create_speaker_embedding.py audio_samples/audio.wav models/speakers/voice1.bin
```

Kokoro is the primary example in this demo, but SpeechT5 remains supported for existing deployments.
### Model preparation
Supported models should use the topology of [microsoft/speecht5_tts](https://huggingface.co/microsoft/speecht5_tts) which needs to be converted to IR format before using in OVMS.

Specific OVMS pull mode example for models requiring conversion is described in the [Ovms pull mode](../../docs/pull_hf_models.md#pulling-models-outside-openvino-organization)

Or you can use the python export_model.py script described below.

Here, the original Text to Speech model will be converted to IR format and optionally quantized.
That ensures faster initialization time, better performance and lower memory consumption.
Execution parameters will be defined inside the `graph.pbtxt` file.

Download export script, install it's dependencies and create directory for the models:
```console
curl https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/common/export_models/export_model.py -o export_model.py
pip install -r https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/common/export_models/requirements.txt
mkdir models
```

Run `export_model.py` script to download and quantize the model:

> **Note:** The users in China need to set environment variable HF_ENDPOINT="https://hf-mirror.com" before running the export script to connect to the HF Hub.
> **Note:** Exporting `microsoft/speecht5_tts` model requires Python 3.10

**CPU**
```console
python export_model.py text2speech --source_model microsoft/speecht5_tts --weight-format fp16 --model_name microsoft/speecht5_tts --config_file_path models/config.json --model_repository_path models --overwrite_models --vocoder microsoft/speecht5_hifigan --speaker_name voice1 --speaker_path models/speakers/voice1.bin
```
This demo uses a pre-exported OpenVINO IR model [luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS](https://huggingface.co/luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS) available on HuggingFace.
The model can be pulled directly by OVMS without any conversion step.

> **Note:** Change the `--weight-format` to quantize the model to `int8` precision to reduce memory consumption and improve performance.
> **Note:** `speaker_name` and `speaker_path` may be omitted if the default model voice is sufficient
> **Note:** The users in China need to set environment variable HF_ENDPOINT="https://hf-mirror.com" before starting OVMS to connect to the HF Hub.
> **Note:** Kokoro voices are loaded from the `voices/` directory in the model repository and can be selected per request with the `voice` field.

The default configuration should work in most cases but the parameters can be tuned via `export_model.py` script arguments. Run the script with `--help` argument to check available parameters and see the [T2s calculator documentation](../../docs/speech_generation/reference.md) to learn more about configuration options and limitations.
See the [T2s calculator documentation](../../docs/speech_generation/reference.md) to learn more about configuration options and limitations.

### Deployment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be included option for deployment on GPU and NPU


:::{dropdown} **Deploying with Docker**

**CPU**

Running this command starts the container with CPU only target device:
Running this command starts the container with CPU target device:
```bash
mkdir -p models
docker run -d -u $(id -u):$(id -g) --rm -p 8000:8000 -v $(pwd)/models:/models:rw openvino/model_server:latest --rest_port 8000 --model_path /models/microsoft/speecht5_tts --model_name microsoft/speecht5_tts
mkdir models
docker run -d -u $(id -u):$(id -g) --rm -p 8000:8000 -v $(pwd)/models:/models:rw openvino/model_server:latest --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path /models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device CPU --task text2speech
```

**Deploying on Bare Metal**
**GPU**

```bat
In case you want to use GPU device, add extra docker parameters `--device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1)` and use the GPU image:
```bash
mkdir models

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on windows it's better to use c:\models

ovms --rest_port 8000 --model_path models/microsoft/speecht5_tts --model_name microsoft/speecht5_tts
docker run -d -u $(id -u):$(id -g) --rm -p 8000:8000 --device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1) -v $(pwd)/models:/models:rw openvino/model_server:latest-gpu --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path /models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device GPU --task text2speech
```

### Request Generation

:::{dropdown} **Unary call with curl with default voice**

**NPU**

In case you want to use NPU device, add extra docker parameters `--device /dev/accel --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1)` and use the GPU image:
```bash
curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"microsoft/speecht5_tts\", \"input\": \"The quick brown fox jumped over the lazy dog\"}" -o speech.wav
mkdir models
docker run -d -u $(id -u):$(id -g) --rm -p 8000:8000 --device /dev/accel --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1) -v $(pwd)/models:/models:rw openvino/model_server:latest-gpu --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path /models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device NPU --task text2speech
```
:::

:::{dropdown} **Unary call with OpenAI python library with default voice**

```python
from pathlib import Path
from openai import OpenAI

prompt = "The quick brown fox jumped over the lazy dog"
filename = "speech.wav"
url="http://localhost:8000/v3"


speech_file_path = Path(__file__).parent / "speech.wav"
client = OpenAI(base_url=url, api_key="not_used")
:::{dropdown} **Deploying on Bare Metal**

with client.audio.speech.with_streaming_response.create(
model="microsoft/speecht5_tts",
voice=None,
input=prompt
) as response:
response.stream_to_file(speech_file_path)
**CPU**
```bat
mkdir c:\models
ovms --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path c:\models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device CPU
```

**GPU**
```bat
mkdir c:\models
ovms --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path c:\models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device GPU
```

print("Generation finished")
**NPU**
```bat
mkdir c:\models
ovms --rest_port 8000 --source_model luis-castillo/Kokoro-82M-OpenVINO-FP16-OVMS --model_repository_path c:\models --model_name Kokoro-82M-OpenVINO-FP16-OVMS --target_device NPU
```
:::

### Request Generation

:::{dropdown} **Unary call with curl**


```bash
curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"microsoft/speecht5_tts\", \"voice\":\"voice1\", \"input\": \"The quick brown fox jumped over the lazy dog\"}" -o speech.wav
curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"Kokoro-82M-OpenVINO-FP16-OVMS\", \"voice\": \"af_alloy\", \"input\": \"The quick brown fox jumped over the lazy dog\"}" -o speech.wav
```
:::

Expand All @@ -136,8 +100,8 @@ speech_file_path = Path(__file__).parent / "speech.wav"
client = OpenAI(base_url=url, api_key="not_used")

with client.audio.speech.with_streaming_response.create(
model="microsoft/speecht5_tts",
voice="voice1",
model="Kokoro-82M-OpenVINO-FP16-OVMS",
voice="af_alloy",
input=prompt
) as response:
response.stream_to_file(speech_file_path)
Expand All @@ -152,20 +116,25 @@ Play speech.wav file to check generated speech.
## Benchmarking speech generation
An asynchronous benchmarking client can be used to access the model server performance with various load conditions. Below are execution examples captured on Intel(R) Core(TM) Ultra 7 258V.

> **Note:** `RTFx` (Real-Time Factor, inverted) is calculated as `generated_audio_duration / generation_time`.
> Values greater than `1.0x` mean faster-than-real-time generation, while values below `1.0x` mean slower-than-real-time.

```console
pip install -r https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/benchmark/v3/requirements.txt
curl https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/main/demos/benchmark/v3/benchmark.py -o benchmark.py
python benchmark.py --api_url http://localhost:8000/v3/audio/speech --model microsoft/speecht5_tts --batch_size 1 --limit 100 --request_rate inf --backend text2speech --dataset edinburghcstr/ami --hf-subset ihm --tokenizer openai/whisper-large-v3-turbo --trust-remote-code True
Number of documents: 100
100%|████████████████████████████████████████████████████████████████████████████████| 100/100 [01:58<00:00, 1.19s/it]
Tokens: 1802
Success rate: 100.0%. (100/100)
Throughput - Tokens per second: 15.2
Mean latency: 63653.98 ms
Median latency: 66736.83 ms
Average document length: 18.02 tokens
pip install -r https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/mkulakow/kokoro_improvements/demos/benchmark/v3/requirements.txt
curl https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/mkulakow/kokoro_improvements/demos/benchmark/v3/benchmark.py -o benchmark.py
python benchmark.py --api_url http://localhost:8000/v3/audio/speech --model Kokoro-82M-OpenVINO-FP16-OVMS --batch_size 1 --limit 100 --request_rate inf --backend text2speech --dataset edinburghcstr/ami --hf-subset ihm --voice af_alloy
Number of documents: 1000
Comment on lines +123 to +126
100%|█████████████████████████████████████████████████████████████████████████████████| 1000/1000 [15:53<00:00, 1.05it/s]
Success rate: 100.0%. (1000/1000)
Mean latency: 742.48 ms
Median latency: 662.10 ms
Mean RTFx: 5.091x
Median RTFx: 5.173x
```

> **Note:** `RTFx` (Real-Time Factor, inverted) is calculated as `generated_audio_duration / generation_time`.
> Values greater than `1.0x` mean faster-than-real-time generation, while values below `1.0x` mean slower-than-real-time.

## Transcription
### Model preparation
Many variances of Whisper models can be deployed in a single command by using pre-configured models from [OpenVINO HuggingFace organization](https://huggingface.co/collections/OpenVINO/speech-to-text) and used both for translations and transcriptions endpoints.
Expand Down Expand Up @@ -235,7 +204,7 @@ ovms --rest_port 8000 --model_path /models/openai/whisper-large-v3-turbo --model
The default configuration should work in most cases but the parameters can be tuned via `export_model.py` script arguments. Run the script with `--help` argument to check available parameters and see the [s2t calculator documentation](../../docs/speech_recognition/reference.md) to learn more about configuration options and limitations.

### Request Generation
Transcript file that was previously generated with audio/speech endpoint.
Transcribe the speech.wav file generated in the [Speech generation](#speech-generation) section.

> **Note:** Streaming responses are supported for `audio/transcriptions`. `audio/translations` does not support streaming.

Expand Down Expand Up @@ -360,33 +329,13 @@ Average document length: 10.948 tokens
```

## Translation
To test translations endpoint we first need to prepare audio file with speech in language other than English, e.g. Spanish. To generate such sample we will use finetuned version of microsoft/speecht5_tts model.

**Deploying with Docker**
To test the translations endpoint we first need to prepare an audio file with speech in a language other than English, e.g. Spanish. To generate such a sample, follow the [Speech generation](#speech-generation) section to deploy Kokoro and then run:

```bash
mkdir -p models

python export_model.py text2speech --source_model Sandiago21/speecht5_finetuned_facebook_voxpopuli_spanish --weight-format fp16 --model_name speecht5_tts_spanish --config_file_path models/config.json --model_repository_path models --overwrite_models --vocoder microsoft/speecht5_hifigan

docker run -d -u $(id -u):$(id -g) --rm -p 8000:8000 -v $(pwd)/models:/models:rw openvino/model_server:latest --rest_port 8000 --model_path /models/speecht5_tts_spanish --model_name speecht5_tts_spanish

curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"speecht5_tts_spanish\", \"input\": \"Madrid es la capital de España\"}" -o speech_spanish.wav
```

**Deploying on Bare Metal**

```bat
mkdir models

python export_model.py text2speech --source_model Sandiago21/speecht5_finetuned_facebook_voxpopuli_spanish --weight-format fp16 --model_name speecht5_tts_spanish --config_file_path models/config.json --model_repository_path models --overwrite_models --vocoder microsoft/speecht5_hifigan

ovms --rest_port 8000 --model_path models/speecht5_tts_spanish --model_name speecht5_tts_spanish

curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"speecht5_tts_spanish\", \"input\": \"Madrid es la capital de España\"}" -o speech_spanish.wav
```console
curl http://localhost:8000/v3/audio/speech -H "Content-Type: application/json" -d "{\"model\": \"Kokoro-82M-OpenVINO-FP16-OVMS\", \"voice\": \"em_alex\", \"input\": \"Madrid es la capital de España\"}" -o speech_spanish.wav
```

### Model preparation
### Deployment
Whisper models can be deployed in a single command by using pre-configured models from [OpenVINO HuggingFace organization](https://huggingface.co/collections/OpenVINO/speech-to-text) and used both for translations and transcriptions endpoints.
Here is an example of OpenVINO/whisper-large-v3-fp16-ov deployment:

Expand Down Expand Up @@ -427,7 +376,7 @@ ovms --rest_port 8000 --source_model OpenVINO/whisper-large-v3-fp16-ov --model_r
:::

### Request Generation
Transcript and translate file that was previously generated with audio/speech endpoint.
Translate the speech_spanish.wav file generated above.

:::{dropdown} **Unary call with cURL**

Expand Down
Loading