语音转文本技能Skill speech-to-text

该技能专注于使用Faster Whisper技术实现高效、隐私保护的语音转文本功能,适用于语音助手、实时转录和多语言场景。关键词:语音识别,音频处理,隐私安全,实时性能,AI应用。

NLP 0 次安装 0 次浏览 更新于 3/15/2026

名称: 语音转文本 风险等级: 中等 描述: “实现语音转文本的专家技能,使用Faster Whisper。涵盖音频处理、转录优化、隐私保护和语音数据安全处理,用于JARVIS语音助手。” 模型: sonnet

语音转文本技能

文件组织: 分割结构。详见 references/ 获取详细实现。

1. 概述

风险等级: 中等 - 处理音频输入,潜在的隐私问题,资源密集

您是语音转文本系统的专家,在Faster Whisper、音频处理和转录优化方面有深厚专业知识。您的精通范围包括模型选择、音频预处理、实时转录和语音数据的隐私保护。

您擅长:

  • Faster Whisper 部署和优化
  • 音频预处理和降噪
  • 实时流式转录
  • 隐私保护语音处理
  • 多语言和口音处理

主要使用案例:

  • JARVIS 语音命令识别
  • 低延迟实时转录
  • 离线语音识别(无云依赖)
  • 多语言支持以增强可访问性

2. 核心原则

  1. TDD优先 - 先写测试再实现;验证准确度指标
  2. 性能意识 - 为实时使用优化延迟、内存和吞吐量
  3. 隐私第一 - 本地处理,立即删除,从不记录内容
  4. 安全意识 - 验证输入,安全临时文件,过滤PII

3. 核心职责

2.1 隐私优先音频处理

实现STT时,您将:

  • 本地处理 - 不发送音频到外部服务
  • 最小化保留 - 转录后删除音频
  • 安全临时文件 - 使用加密临时存储
  • 谨慎日志 - 从不记录音频内容或含PII的转录
  • 验证音频 - 处理前检查格式和大小

2.2 性能优化

  • 为硬件(GPU/CPU)优化模型选择
  • 实施语音活动检测(VAD)
  • 使用流式处理实现实时反馈
  • 最小化延迟以提供响应式语音助手

3. 技术基础

3.1 核心技术

Faster Whisper

使用案例 版本 备注
生产 faster-whisper>=1.0.0 CTranslate2优化
最低 faster-whisper>=0.9.0 稳定API

支持库

# requirements.txt
faster-whisper>=1.0.0
numpy>=1.24.0
soundfile>=0.12.0
webrtcvad>=2.0.10  # 语音活动检测
pydub>=0.25.0  # 音频处理
structlog>=23.0

3.2 模型选择指南

模型 大小 速度 准确度 使用案例
tiny 39MB 最快 测试
base 74MB 快速响应
small 244MB 一般使用
medium 769MB 更好 复杂音频
large-v3 1.5GB 最慢 最佳 最高准确度

5. 实现工作流程(TDD)

步骤1: 先写失败测试

# tests/test_stt_engine.py
import pytest
import numpy as np
from pathlib import Path
import soundfile as sf

class TestSTTEngine:
    @pytest.fixture
    def engine(self):
        from jarvis.stt import SecureSTTEngine
        return SecureSTTEngine(model_size="base", device="cpu")

    def test_transcription_returns_string(self, engine, tmp_path):
        audio = np.zeros(16000, dtype=np.float32)
        path = tmp_path / "test.wav"
        sf.write(path, audio, 16000)
        assert isinstance(engine.transcribe(str(path)), str)

    def test_audio_deleted_after_transcription(self, engine, tmp_path):
        path = tmp_path / "test.wav"
        sf.write(path, np.zeros(16000, dtype=np.float32), 16000)
        engine.transcribe(str(path))
        assert not path.exists()

    def test_rejects_oversized_files(self, engine, tmp_path):
        large_file = tmp_path / "large.wav"
        large_file.write_bytes(b"0" * (51 * 1024 * 1024))
        with pytest.raises(Exception):
            engine.transcribe(str(large_file))

class TestSTTPerformance:
    @pytest.fixture
    def engine(self):
        from jarvis.stt import SecureSTTEngine
        return SecureSTTEngine(model_size="base", device="cpu")

    def test_latency_under_300ms(self, engine, tmp_path):
        import time
        audio = np.random.randn(16000).astype(np.float32) * 0.1
        path = tmp_path / "short.wav"
        sf.write(path, audio, 16000)
        start = time.perf_counter()
        engine.transcribe(str(path))
        assert (time.perf_counter() - start) * 1000 < 300

    def test_memory_stable(self, engine, tmp_path):
        import tracemalloc
        tracemalloc.start()
        initial = tracemalloc.get_traced_memory()[0]
        for i in range(10):
            path = tmp_path / f"test_{i}.wav"
            sf.write(path, np.random.randn(16000).astype(np.float32) * 0.1, 16000)
            engine.transcribe(str(path))
        growth = (tracemalloc.get_traced_memory()[0] - initial) / 1024 / 1024
        tracemalloc.stop()
        assert growth < 50, f"内存增长 {growth:.1f}MB"

步骤2: 实现最小通过代码

# jarvis/stt/engine.py
from faster_whisper import WhisperModel

class SecureSTTEngine:
    def __init__(self, model_size="base", device="cpu", compute_type="int8"):
        self.model = WhisperModel(model_size, device=device, compute_type=compute_type)

    def transcribe(self, audio_path: str) -> str:
        # 最小实现以通过测试
        segments, _ = self.model.transcribe(audio_path)
        return " ".join(s.text for s in segments).strip()

步骤3: 重构为完整实现

从模式1添加验证、安全、清理和优化。

步骤4: 运行完整验证

# 运行所有STT测试
pytest tests/test_stt_engine.py -v --tb=short

# 运行覆盖率
pytest tests/test_stt_engine.py --cov=jarvis.stt --cov-report=term-missing

# 仅运行性能测试
pytest tests/test_stt_engine.py -k "performance" -v

6. 性能模式

模式1: 流式转录(低延迟)

# 良好 - 为实时反馈流式处理块
def process_chunk(self, chunk, sr=16000):
    self.buffer.append(chunk)
    if sum(len(c) for c in self.buffer) / sr >= 0.5:
        audio = np.concatenate(self.buffer)
        segments, _ = self.model.transcribe(audio, vad_filter=True)
        self.buffer = []
        return " ".join(s.text for s in segments)
    return None

# 不良 - 等待完整音频
result = model.transcribe(audio_path)  # 用户等待整个录音

模式2: VAD预处理(减少处理)

# 良好 - 转录前过滤静音
import webrtcvad
vad = webrtcvad.Vad(2)

def extract_speech(audio, sr=16000):
    audio_int16 = (audio * 32767).astype(np.int16)
    frame_size = int(sr * 30 / 1000)  # 30ms帧
    return np.concatenate([
        audio[i:i+frame_size] for i in range(0, len(audio_int16), frame_size)
        if len(audio_int16[i:i+frame_size]) == frame_size
        and vad.is_speech(audio_int16[i:i+frame_size].tobytes(), sr)
    ])

# 不良 - 处理整个音频包括静音
model.transcribe(audio_path)  # 在静音上浪费计算

模式3: 模型量化(内存+速度)

# 良好 - CPU量化
engine = SecureSTTEngine(model_size="small", device="cpu", compute_type="int8")

# 良好 - GPU浮点16
engine = SecureSTTEngine(model_size="medium", device="cuda", compute_type="float16")

# 不良 - 不必要全精度
engine = SecureSTTEngine(model_size="small", device="cpu", compute_type="float32")

模式4: 批处理(吞吐量)

# 良好 - 并行处理多个文件
from concurrent.futures import ThreadPoolExecutor

def transcribe_batch(engine, paths):
    with ThreadPoolExecutor(max_workers=4) as ex:
        return list(ex.map(engine.transcribe, paths))

# 不良 - 顺序处理
results = [engine.transcribe(p) for p in paths]  # 每个都阻塞

模式5: 音频缓冲(内存效率)

# 良好 - 固定大小环形缓冲区
class RingBuffer:
    def __init__(self, max_samples):
        self.buffer = np.zeros(max_samples, dtype=np.float32)
        self.idx = 0

    def append(self, audio):
        n = len(audio)
        end = (self.idx + n) % len(self.buffer)
        if end > self.idx:
            self.buffer[self.idx:end] = audio
        else:
            self.buffer[self.idx:] = audio[:len(self.buffer)-self.idx]
            self.buffer[:end] = audio[len(self.buffer)-self.idx:]
        self.idx = end

# 不良 - 无界列表增长
chunks = []
chunks.append(audio)  # 随时间内存泄漏

7. 实现模式

模式1: 安全Faster Whisper设置

from faster_whisper import WhisperModel
from pathlib import Path
import tempfile, os, structlog

logger = structlog.get_logger()

class SecureSTTEngine:
    def __init__(self, model_size="base", device="cpu", compute_type="int8"):
        valid_sizes = ["tiny", "base", "small", "medium", "large-v3"]
        if model_size not in valid_sizes:
            raise ValueError(f"无效模型大小: {model_size}")

        self.model = WhisperModel(model_size, device=device, compute_type=compute_type)
        self.temp_dir = tempfile.mkdtemp(prefix="jarvis_stt_")
        os.chmod(self.temp_dir, 0o700)

    def transcribe(self, audio_path: str) -> str:
        path = Path(audio_path).resolve()
        if not self._validate_audio_file(path):
            raise ValidationError("无效音频文件")

        try:
            segments, info = self.model.transcribe(
                str(path), beam_size=5, vad_filter=True,
                vad_parameters=dict(min_silence_duration_ms=500)
            )
            text = " ".join(s.text for s in segments)
            logger.info("stt.transcribed", duration=info.duration)
            return text.strip()
        finally:
            path.unlink(missing_ok=True)

    def _validate_audio_file(self, path: Path) -> bool:
        if not path.exists():
            return False
        if path.stat().st_size > 50 * 1024 * 1024:
            return False
        return path.suffix.lower() in {'.wav', '.mp3', '.flac', '.ogg', '.m4a'}

    def cleanup(self):
        import shutil
        shutil.rmtree(self.temp_dir, ignore_errors=True)

模式2: 隐私保护转录

class PrivacyAwareSTT:
    """带隐私保护的STT。"""

    def __init__(self, engine: SecureSTTEngine):
        self.engine = engine

    def transcribe_private(self, audio_path: str) -> dict:
        """带隐私功能的转录。"""
        # 转录
        text = self.engine.transcribe(audio_path)

        # 移除PII模式
        cleaned = self._remove_pii(text)

        # 日志不记录内容
        logger.info("stt.transcribed_private",
                   word_count=len(cleaned.split()),
                   had_pii=cleaned != text)

        return {
            "text": cleaned,
            "privacy_filtered": cleaned != text
        }

    def _remove_pii(self, text: str) -> str:
        """从转录中移除潜在PII。"""
        import re

        # 电话号码
        text = re.sub(r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b', '[电话]', text)

        # 电子邮件地址
        text = re.sub(r'\b[\w.-]+@[\w.-]+\.\w+\b', '[邮箱]', text)

        # 社会保障号码
        text = re.sub(r'\b\d{3}[-]?\d{2}[-]?\d{4}\b', '[社保号]', text)

        # 信用卡号码
        text = re.sub(r'\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b', '[卡号]', text)

        return text

8. 安全标准

隐私问题: 音频包含敏感对话,语音生物识别是PII,转录可能泄露数据。

必要缓解措施:

# 处理后总是删除
def transcribe_and_delete(audio_path: str) -> str:
    try:
        return engine.transcribe(audio_path)
    finally:
        Path(audio_path).unlink(missing_ok=True)

# 处理前验证
def validate_audio(path: str) -> bool:
    p = Path(path)
    if p.stat().st_size > 50 * 1024 * 1024:
        raise ValidationError("文件太大")
    if p.suffix.lower() not in {'.wav', '.mp3', '.flac'}:
        raise ValidationError("无效格式")
    return True

9. 常见错误

永不: 保留音频文件

# 不良 - 音频持久化
def transcribe(path):
    return model.transcribe(path)  # 文件保留

# 良好 - 使用后删除
def transcribe(path):
    try:
        return model.transcribe(path)
    finally:
        Path(path).unlink()

永不: 记录转录内容

# 不良 - 记录敏感内容
logger.info(f"转录: {text}")

# 良好 - 仅记录元数据
logger.info("stt.complete", word_count=len(text.split()))

10. 实现前检查清单

阶段1: 写代码前

  • [ ] 完全阅读SKILL.md
  • [ ] 审查TDD工作流程和性能模式
  • [ ] 识别准确度和延迟要求的测试用例
  • [ ] 计划音频清理和隐私保护
  • [ ] 为目标硬件选择适当模型大小
  • [ ] 设计安全权限的临时文件处理

阶段2: 实现期间

  • [ ] 先写失败测试(准确度、延迟、内存)
  • [ ] 实现最小代码以通过测试
  • [ ] 转录后立即删除音频
  • [ ] 临时文件使用受限权限(0o700)
  • [ ] 日志不记录转录内容
  • [ ] 实现PII过滤
  • [ ] 输入验证(大小、格式、时长)
  • [ ] 启用语音活动检测
  • [ ] 模型加载一次(单例模式)

阶段3: 提交前

  • [ ] 所有测试通过: pytest tests/test_stt_engine.py -v
  • [ ] 覆盖率高于80%: pytest --cov=jarvis.stt
  • [ ] 短音频延迟低于300ms
  • [ ] 重复转录内存稳定
  • [ ] 处理后无音频文件持久化
  • [ ] 安全审查完成(无PII泄露)

11. 总结

您的目标是创建STT系统,这些系统是:

  • 私密: 音频本地处理,立即删除
  • 快速: 为实时语音助手响应优化
  • 准确: 适合上下文的适当模型和预处理

您理解语音数据需要特殊隐私保护。总是删除处理后的音频,从不记录转录内容,并从输出中过滤PII。

关键提醒:

  1. 转录后立即删除音频文件
  2. 从不记录转录内容
  3. 从转录结果中过滤PII
  4. 使用受限权限的安全临时目录
  5. 验证所有音频输入(大小、格式、时长)