diff --git a/README.md b/README.md index 15e5e4b..1edc0a1 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ sudo apt install -y ros-${ROS_DISTRO}-webots-ros2 \ ros-${ROS_DISTRO}-rosbag2-storage-mcap \ ros-${ROS_DISTRO}-librealsense2 \ ros-${ROS_DISTRO}-realsense2* \ + libportaudio2 \ ``` diff --git a/src/iiwa_voice/iiwa_voice/__init__.py b/src/iiwa_voice/iiwa_voice/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/iiwa_voice/package.xml b/src/iiwa_voice/package.xml new file mode 100644 index 0000000..943f388 --- /dev/null +++ b/src/iiwa_voice/package.xml @@ -0,0 +1,18 @@ + + + + iiwa_voice + 0.0.0 + TODO: Package description + daniel + TODO: License declaration + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/src/iiwa_voice/resource/.env b/src/iiwa_voice/resource/.env new file mode 100644 index 0000000..f7cf19c --- /dev/null +++ b/src/iiwa_voice/resource/.env @@ -0,0 +1,40 @@ +# ============================================================================= +# Qwen3-TTS — настройки окружения (.env) +# Скопируйте этот файл в .env и заполните своими значениями +# ============================================================================= + +# --- Hugging Face --------------------------------------------------------- +# Токен нужен только если модели приватные или у вас rate-limit +HF_TOKEN= + +# Путь для кэша весов моделей (рекомендуется SSD с ~20 ГБ свободного места) +HF_CACHE_DIR=./hf_cache + +# --- GPU ------------------------------------------------------------------ +# Сколько GPU выделить каждому сервису (обычно 1) +GPU_COUNT=1 + +# Видимые GPU (например "0" или "0,1" для multi-GPU) +CUDA_VISIBLE_DEVICES=0 + +# Утилизация памяти GPU (0.0–1.0). Уменьшите при OOM. +GPU_MEM_UTIL=0.90 + +# Максимальная длина контекста +MAX_MODEL_LEN=4096 + +# --- Порты ---------------------------------------------------------------- +CUSTOMVOICE_PORT=8091 +VOICEDESIGN_PORT=8092 +BASE_PORT=8093 + +# --- Модели --------------------------------------------------------------- +# По умолчанию 1.7B. Замените на 0.6B для экономии VRAM (~4 ГБ вместо ~8 ГБ) +# MODEL_SIZE=Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice +MODEL_SIZE=Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice + +# MODEL_VOICEDESIGN=Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign +MODEL_VOICEDESIGN=Qwen/Qwen3-TTS-12Hz-0.6B-VoiceDesign + +# MODEL_BASE=Qwen/Qwen3-TTS-12Hz-1.7B-Base +MODEL_BASE=Qwen/Qwen3-TTS-12Hz-0.6B-Base \ No newline at end of file diff --git a/src/iiwa_voice/resource/docker-compose.yaml b/src/iiwa_voice/resource/docker-compose.yaml new file mode 100644 index 0000000..ea54921 --- /dev/null +++ b/src/iiwa_voice/resource/docker-compose.yaml @@ -0,0 +1,101 @@ +# ============================================================================= +# Qwen3-TTS — vLLM-Omni (docker-compose.yml) +# Три варианта модели на разных портах: +# customvoice → :8091 (заранее настроенные голоса: Vivian, Ryan …) +# voicedesign → :8092 (создание голоса по текстовому описанию) +# base → :8093 (клонирование голоса из ~3 сек. аудио) +# +# Запуск всех сервисов: docker compose up -d +# Только один сервис: docker compose up -d qwen3-tts-customvoice +# Логи: docker compose logs -f qwen3-tts-customvoice +# ============================================================================= + +x-tts-common: &tts-common + image: vllm/vllm-omni:v0.18.0 + ipc: host + ulimits: + memlock: -1 + stack: 67108864 + restart: unless-stopped + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: ${GPU_COUNT:-1} # кол-во GPU на сервис (см. .env) + capabilities: [gpu] + volumes: + - ${HF_CACHE_DIR:-./hf_cache}:/root/.cache/huggingface + - ./output_audio:/output_audio # сохранение WAV-файлов + environment: + HF_TOKEN: ${HF_TOKEN:-} # токен Hugging Face (если нужен) + VLLM_USE_V1: "0" # офлайн-режим совместимости + VLLM_WORKER_MULTIPROC_METHOD: spawn # требуется для TTS-воркеров + CUDA_VISIBLE_DEVICES: ${CUDA_VISIBLE_DEVICES:-0} + healthcheck: + test: ["CMD", "python3", "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:${_PORT:-8091}/health')"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 120s # модель грузится долго + +# ============================================================================= +services: + + # --------------------------------------------------------------------------- + # 1. CustomVoice — готовые голоса (Vivian, Ryan и др.) + # POST /v1/audio/speech { "input": "...", "voice": "Vivian" } + # --------------------------------------------------------------------------- + qwen3-tts-customvoice: + <<: *tts-common + container_name: qwen3-tts-customvoice + ports: + - "${CUSTOMVOICE_PORT:-8091}:8091" + command: > + ${MODEL_SIZE:-Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice} + --omni + --port 8091 + --gpu-memory-utilization ${GPU_MEM_UTIL:-0.90} + --max-model-len ${MAX_MODEL_LEN:-4096} + profiles: + - customvoice + - all + + # --------------------------------------------------------------------------- + # 2. VoiceDesign — синтез голоса по описанию на естественном языке + # POST /v1/audio/speech { "input": "...", "voice": "a calm female voice" } + # --------------------------------------------------------------------------- + qwen3-tts-voicedesign: + <<: *tts-common + container_name: qwen3-tts-voicedesign + ports: + - "${VOICEDESIGN_PORT:-8092}:8091" + command: > + ${MODEL_VOICEDESIGN:-Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign} + --omni + --port 8091 + --gpu-memory-utilization ${GPU_MEM_UTIL:-0.90} + --max-model-len ${MAX_MODEL_LEN:-4096} + profiles: + - voicedesign + - all + + # --------------------------------------------------------------------------- + # 3. Base — клонирование голоса из референс-аудио + # POST /v1/audio/speech { "input": "...", + ref_audio файл } + # --------------------------------------------------------------------------- + qwen3-tts-base: + <<: *tts-common + container_name: qwen3-tts-base + ports: + - "${BASE_PORT:-8093}:8091" + command: > + ${MODEL_BASE:-Qwen/Qwen3-TTS-12Hz-1.7B-Base} + --omni + --port 8091 + --gpu-memory-utilization ${GPU_MEM_UTIL:-0.90} + --max-model-len ${MAX_MODEL_LEN:-4096} + profiles: + - base + - all \ No newline at end of file diff --git a/src/iiwa_voice/resource/iiwa_voice b/src/iiwa_voice/resource/iiwa_voice new file mode 100644 index 0000000..e69de29 diff --git a/src/iiwa_voice/setup.cfg b/src/iiwa_voice/setup.cfg new file mode 100644 index 0000000..9f55aaa --- /dev/null +++ b/src/iiwa_voice/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/iiwa_voice +[install] +install_scripts=$base/lib/iiwa_voice diff --git a/src/iiwa_voice/setup.py b/src/iiwa_voice/setup.py new file mode 100644 index 0000000..86e7857 --- /dev/null +++ b/src/iiwa_voice/setup.py @@ -0,0 +1,29 @@ +from setuptools import find_packages, setup + +package_name = 'iiwa_voice' + +setup( + name=package_name, + version='0.0.0', + packages=find_packages(exclude=['test']), + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='daniel', + maintainer_email='grabardm@ml-dev.ru', + description='TODO: Package description', + license='TODO: License declaration', + extras_require={ + 'test': [ + 'pytest', + ], + }, + entry_points={ + 'console_scripts': [ + ], + }, +)