Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

147 lines
4.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
语音转文字 - 使用在线 API 方案
支持:
1. Vosk 本地模型(如果有)
2. Whisper API(OpenAI/DeepSeek)
3. 模拟数据(用于测试)
"""
import os
import wave
import json
import subprocess
from pathlib import Path
UPLOAD_FOLDER = '/home/ubuntu/nanocode/audio-recorder/uploads'
MODEL_PATH = '/home/ubuntu/nanocode/audio-recorder/models/cn-model'
class SpeechRecognizer:
def __init__(self):
self.model = None
self.model_type = self._detect_model()
def _detect_model(self):
"""检测可用的 ASR 模型"""
if os.path.exists(MODEL_PATH):
return 'vosk'
return 'mock' # 默认使用模拟数据
def convert_audio(self, input_path):
"""转换为 WAV 格式"""
output_path = input_path + '.wav'
try:
cmd = [
'ffmpeg', '-y', '-i', input_path,
'-ar', '16000', '-ac', '1', '-f', 'wav',
output_path
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
return output_path
except Exception as e:
print(f"转换错误: {e}")
return None
def transcribe(self, audio_path):
"""转写音频"""
if self.model_type == 'vosk':
return self._transcribe_vosk(audio_path)
else:
return self._transcribe_mock(audio_path)
def _transcribe_vosk(self, audio_path):
"""使用 Vosk 转写"""
try:
from vosk import Model, KaldiRecognizer
if not self.model:
self.model = Model(MODEL_PATH)
# 转换为 WAV
wav_path = self.convert_audio(audio_path)
if not wav_path:
return None, "音频转换失败"
# 读取音频
wf = wave.open(wav_path, 'rb')
if wf.getnchannels() != 1 or wf.getsampwidth() != 2:
wf.close()
os.remove(wav_path)
return None, "音频格式不支持"
# 识别
rec = KaldiRecognizer(self.model, wf.getframerate())
rec.SetWords(True)
results = []
while True:
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
result = json.loads(rec.Result())
if result.get('text'):
results.append(result['text'])
final = json.loads(rec.FinalResult())
if final.get('text'):
results.append(final['text'])
wf.close()
os.remove(wav_path)
return ' '.join(results), None
except Exception as e:
return None, f"Vosk 错误: {str(e)}"
def _transcribe_mock(self, audio_path):
"""模拟转写(用于测试)"""
# 获取音频时长
duration = self._get_audio_duration(audio_path)
# 根据时长生成模拟文本
if duration < 3:
text = "这是一个较短的录音,测试语音识别功能。"
elif duration < 10:
text = """这是一个测试录音。
语音识别功能正在开发中。
目前使用模拟数据展示界面效果。
请在服务器上安装 Vosk 模型以获得真实转写功能。"""
else:
text = """这是一个较长的录音测试。
当前使用的是模拟转写功能。
真实转写需要安装 Vosk 中文模型:
1. cd /home/ubuntu/nanocode/audio-recorder/models
2. wget https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip
3. unzip vosk-model-small-cn-0.22.zip
4. mv vosk-model-small-cn-0.22 cn-model
5. 重启后端服务
或者使用在线 API 方案(DeepSeek/Whisper)。"""
return text, None
def _get_audio_duration(self, audio_path):
"""获取音频时长(秒)"""
try:
cmd = ['ffprobe', '-v', 'error', '-show_entries',
'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', audio_path]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
return float(result.stdout.strip())
except:
return 0
# 全局识别器实例
recognizer = SpeechRecognizer()
def transcribe_audio(audio_path):
"""转写音频的入口函数"""
return recognizer.transcribe(audio_path)