diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 00000000..b957ee2e --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,46 @@ +name: Docker Image CI + +on: + push: + tags: + - 'v*.*.*' # 只在以 v 开头的标签推送时触发,例如 v1.0.0 + +jobs: + release: + name: Release Docker image + runs-on: ubuntu-latest + permissions: + packages: write + contents: write + id-token: write + issues: write + + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.TOKEN }} + + - name: Extract version from tag + id: get_version + run: | + echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Build and push Docker image + id: build_push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ghcr.io/${{ github.repository }}:${{ env.VERSION }} + ghcr.io/${{ github.repository }}:latest + platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile b/Dockerfile index 94e9b763..c343476b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,11 @@ # 第一阶段:前端构建 -FROM ccr.ccs.tencentyun.com/kalicyh/node:18-alpine AS frontend-builder + +FROM kalicyh/node:v18-alpine AS frontend-builder WORKDIR /app/ZhiKongTaiWeb +# RUN corepack enable && yarn config set registry https://registry.npmmirror.com + COPY ZhiKongTaiWeb/package.json ZhiKongTaiWeb/yarn.lock ./ RUN yarn install --frozen-lockfile @@ -11,7 +14,8 @@ COPY ZhiKongTaiWeb . RUN yarn build # 第二阶段:构建 Python 依赖 -FROM ccr.ccs.tencentyun.com/kalicyh/poetry:v3.10_xiaozhi AS builder + +FROM kalicyh/poetry:v3.10_xiaozhi AS builder WORKDIR /app diff --git a/core/providers/tts/base.py b/core/providers/tts/base.py index 54438f31..84737608 100644 --- a/core/providers/tts/base.py +++ b/core/providers/tts/base.py @@ -2,7 +2,7 @@ import asyncio from config.logger import setup_logging import os import numpy as np -import opuslib +import opuslib_next from pydub import AudioSegment from abc import ABC, abstractmethod @@ -58,7 +58,7 @@ class TTSProviderBase(ABC): raw_data = audio.raw_data # 初始化Opus编码器 - encoder = opuslib.Encoder(16000, 1, opuslib.APPLICATION_AUDIO) + encoder = opuslib_next.Encoder(16000, 1, opuslib_next.APPLICATION_AUDIO) # 编码参数 frame_duration = 60 # 60ms per frame diff --git a/core/utils/asr.py b/core/utils/asr.py index 1c23fe55..ab1c35c4 100644 --- a/core/utils/asr.py +++ b/core/utils/asr.py @@ -1,18 +1,36 @@ import time import wave import os +import sys +import io from abc import ABC, abstractmethod from config.logger import setup_logging from typing import Optional, Tuple, List import uuid -import opuslib +import opuslib_next from funasr import AutoModel from funasr.utils.postprocess_utils import rich_transcription_postprocess TAG = __name__ logger = setup_logging() +# 捕获标准输出 +class CaptureOutput: + def __enter__(self): + self._output = io.StringIO() + self._original_stdout = sys.stdout + sys.stdout = self._output + + def __exit__(self, exc_type, exc_value, traceback): + sys.stdout = self._original_stdout + self.output = self._output.getvalue() + self._output.close() + + # 将捕获到的内容通过 logger 输出 + if self.output: + logger.bind(tag=TAG).info(self.output.strip()) + class ASR(ABC): @abstractmethod def save_audio_to_file(self, opus_data: List[bytes], session_id: str) -> str: @@ -33,28 +51,28 @@ class FunASR(ASR): # 确保输出目录存在 os.makedirs(self.output_dir, exist_ok=True) - - self.model = AutoModel( - model=self.model_dir, - vad_kwargs={"max_single_segment_time": 30000}, - disable_update=True, - hub="hf" - # device="cuda:0", # 启用GPU加速 - ) + with CaptureOutput(): + self.model = AutoModel( + model=self.model_dir, + vad_kwargs={"max_single_segment_time": 30000}, + disable_update=True, + hub="hf" + # device="cuda:0", # 启用GPU加速 + ) def save_audio_to_file(self, opus_data: List[bytes], session_id: str) -> str: """将Opus音频数据解码并保存为WAV文件""" file_name = f"asr_{session_id}_{uuid.uuid4()}.wav" file_path = os.path.join(self.output_dir, file_name) - decoder = opuslib.Decoder(16000, 1) # 16kHz, 单声道 + decoder = opuslib_next.Decoder(16000, 1) # 16kHz, 单声道 pcm_data = [] for opus_packet in opus_data: try: pcm_frame = decoder.decode(opus_packet, 960) # 960 samples = 60ms pcm_data.append(pcm_frame) - except opuslib.OpusError as e: + except opuslib_next.OpusError as e: logger.bind(tag=TAG).error(f"Opus解码错误: {e}", exc_info=True) with wave.open(file_path, "wb") as wf: diff --git a/core/utils/vad.py b/core/utils/vad.py index 05e11eb5..ef782281 100644 --- a/core/utils/vad.py +++ b/core/utils/vad.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod from config.logger import setup_logging -import opuslib +import opuslib_next import time import numpy as np import torch @@ -24,7 +24,7 @@ class SileroVAD(VAD): force_reload=False) (get_speech_timestamps, _, _, _, _) = self.utils - self.decoder = opuslib.Decoder(16000, 1) + self.decoder = opuslib_next.Decoder(16000, 1) self.vad_threshold = config.get("threshold") self.silence_threshold_ms = config.get("min_silence_duration_ms") @@ -59,7 +59,7 @@ class SileroVAD(VAD): conn.client_have_voice_last_time = time.time() * 1000 return client_have_voice - except opuslib.OpusError as e: + except opuslib_next.OpusError as e: logger.bind(tag=TAG).info(f"解码错误: {e}") except Exception as e: logger.bind(tag=TAG).error(f"Error processing audio packet: {e}") diff --git a/docker-compose.yml b/docker-compose.yml index 58e8417a..26aa64e8 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: xiaozhi-esp32-server: - image: ccr.ccs.tencentyun.com/kalicyh/esp32-ai-server:latest + image: ghcr.io/kalicyh/xiaozhi-esp32-server:latest container_name: xiaozhi-esp32-server restart: always #security_opt: diff --git a/docs/Deployment-silm.md b/docs/Deployment-silm.md index b0f54e47..404106ef 100644 --- a/docs/Deployment-silm.md +++ b/docs/Deployment-silm.md @@ -105,7 +105,7 @@ docker run -it --name xiaozhi-env --restart always --security-opt seccomp:unconf -p 8000:8000 \ -p 8002:8002 \ -v ./:/app \ - ccr.ccs.tencentyun.com/kalicyh/poetry:v3.10_latest + kalicyh/poetry:v3.10_latest ``` 然后就和正常开发一样了 diff --git a/docs/Deployment.md b/docs/Deployment.md index 0dff72a8..a0f75e41 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -1,3 +1,4 @@ + # 本地源码运行 ## 1.安装基础环境 diff --git a/poetry.lock b/poetry.lock index 3d5366d8..8e2114ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2202,14 +2202,15 @@ datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] realtime = ["websockets (>=13,<15)"] [[package]] -name = "opuslib" -version = "3.0.1" +name = "opuslib-next" +version = "1.1.2" description = "Python bindings to the libopus, IETF low-delay audio codec" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "opuslib-3.0.1.tar.gz", hash = "sha256:2cb045e5b03e7fc50dfefe431e3404dddddbd8f5961c10c51e32dfb69a044c97"}, + {file = "opuslib_next-1.1.2-py2.py3-none-any.whl", hash = "sha256:adc432290ed721febff19dc0deb3b0cdbe846e80cd79fec742a7d47d960f13ed"}, + {file = "opuslib_next-1.1.2.tar.gz", hash = "sha256:d44a63c69783ab3ccaf349d46a1e37741eb620d6391461a18f95ac1b538e6796"}, ] [[package]] @@ -3731,4 +3732,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.1" python-versions = "^3.10.16" -content-hash = "a4198be98d482e4393ef98f074b2c62c59786c8ef679adc2285473d1b9eb7d92" +content-hash = "9d724dd1cc50a7a6a42f0b5d8a81ad788332939ffc6a3ba12537106567f4ebe7" diff --git a/pyproject.toml b/pyproject.toml index eb5a9718..2ee2fc14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ pyyml = "0.0.2" torch = "2.2.2" silero-vad = "5.1.2" websockets = "14.2" -opuslib = "3.0.1" numpy = "1.26.4" pydub = "0.25.1" funasr = "1.2.3" @@ -26,6 +25,7 @@ ormsgpack = "1.7.0" ruamel-yaml = "0.18.10" setuptools = "^75.8.0" loguru = "^0.7.3" +opuslib-next = "^1.1.2" [build-system] diff --git a/requirements.txt b/requirements.txt index 46636a22..be566306 100755 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ pyyml==0.0.2 torch==2.2.2 silero_vad==5.1.2 websockets==14.2 -opuslib==3.0.1 +opuslib_next==1.1.2 numpy==1.26.4 pydub==0.25.1 funasr==1.2.3