语音转换文本
收藏回复举报
语音转换文本
新人帖
发表于2024-12-28 10:37:47
0 查看

#!/usr/bin/env python

coding: utf-8

import os from datetime import datetime from flask import Flask, request, jsonify import torchaudio import torchaudio.compliance.kaldi as kaldi from ais_bench.infer.interface import InferSession import numpy as np from pypinyin import lazy_pinyin # 导入 pypinyin

app = Flask(name)

class WeNetASR: def init(self, model_path, vocab_path): """初始化模型,加载词表""" self.vocabulary = self.load_vocab(vocab_path) self.model = InferSession(0, model_path) # 获取模型输入特征的最大长度 self.max_len = self.model.get_inputs()[0].shape[1]

def transcribe(self, wav_file):
    """执行模型推理,将录音文件转为文本。"""
    try:
        feats_pad, feats_lengths = self.preprocess(wav_file)
        output = self.model.infer([feats_pad, feats_lengths])
        txt = self.post_process(output)
        return txt
    except Exception as e:
        print(f"Error during transcription: {e}")
        return None

def preprocess(self, wav_file):
    """数据预处理"""
    waveform, sample_rate = torchaudio.load(wav_file)
    # 音频重采样,采样率16000
    waveform, sample_rate = self.resample(waveform, sample_rate, resample_rate=16000)
    # 计算fbank特征
    feature = self.compute_fbank(waveform, sample_rate)
    feats_lengths = np.array([feature.shape[0]]).astype(np.int32)
    # 对输入特征进行padding,使符合模型输入尺寸
    feats_pad = self.pad_sequence(feature, batch_first=True, padding_value=0, max_len=self.max_len)
    feats_pad = feats_pad.numpy().astype(np.float32)
    return feats_pad, feats_lengths

def post_process(self, output):
    """对模型推理结果进行后处理,根据贪心策略选择概率最大的token,去除重复字符和空白字符,得到最终文本。"""
    encoder_out_lens, probs_idx = output[1], output[4]
    token_idx_list = probs_idx[0, :, 0][:encoder_out_lens[0]]
    token_idx_list = self.remove_duplicates_and_blank(token_idx_list)
    text = ''.join(self.vocabulary[token_idx_list])
    return text

@staticmethod
def remove_duplicates_and_blank(token_idx_list):
    """去除重复字符和空白字符"""
    res = []
    cur = 0
    BLANK_ID = 0
    while cur < len(token_idx_list):
        if token_idx_list[cur] != BLANK_ID:
            res.append(token_idx_list[cur])
        prev = cur
        while cur < len(token_idx_list) and token_idx_list[cur] == token_idx_list[prev]:
            cur += 1
    return res

@staticmethod
def pad_sequence(seq_feature, batch_first=True, padding_value=0, max_len=966):
    """对输入特征进行padding,使符合模型输入尺寸"""
    feature_shape = seq_feature.shape
    feat_len = feature_shape[0]
    if feat_len > max_len:
        # 如果输入特征长度大于模型输入尺寸,则截断
        seq_feature = seq_feature[:max_len].unsqueeze(0)
        return seq_feature

    batch_size = 1
    trailing_dims = feature_shape[1:]
    if batch_first:
        out_dims = (batch_size, max_len) + trailing_dims
    else:
        out_dims = (max_len, batch_size) + trailing_dims

    out_tensor = seq_feature.data.new(*out_dims).fill_(padding_value)
    if batch_first:
        out_tensor[0, :feat_len, ...] = seq_feature
    else:
        out_tensor[:feat_len, 0, ...] = seq_feature
    return out_tensor

@staticmethod
def resample(waveform, sample_rate, resample_rate=16000):
    """音频重采样"""
    waveform = torchaudio.transforms.Resample(orig_freq=sample_rate, new_freq=resample_rate)(waveform)
    return waveform, resample_rate

@staticmethod
def compute_fbank(waveform, sample_rate, num_mel_bins=80, frame_length=25, frame_shift=10, dither=0.0):
    """提取filter bank音频特征"""
    AMPLIFY_FACTOR = 1 << 15
    waveform = waveform * AMPLIFY_FACTOR
    mat = kaldi.fbank(
        waveform,
        num_mel_bins=num_mel_bins,
        frame_length=frame_length,
        frame_shift=frame_shift,
        dither=dither,
        energy_floor=0.0,
        sample_frequency=sample_rate
    )
    return mat

@staticmethod
def load_vocab(txt_path):
    """加载词表"""
    vocabulary = []
    LEN_OF_VALID_FORMAT = 2
    try:
        with open(txt_path, 'r', encoding='utf-8') as fin:
            for line in fin:
                arr = line.strip().split()
                # 词表格式:token id
                if len(arr) != LEN_OF_VALID_FORMAT:
                    raise ValueError(f"Invalid line: {line}. Expect format: token id")
                vocabulary.append(arr[0])
        return np.array(vocabulary)
    except FileNotFoundError:
        print(f"Vocabulary file not found at: {txt_path}")
        return None
    except Exception as e:
        print(f"Error loading vocabulary: {e}")
        return None

def initialize_model(): &quot;&quot;&quot;初始化WeNetASR模型实例&quot;&quot;&quot; model_path = &quot;/home/HwHiAiUser/samples/notebooks/09-speech-recognition/offline_encoder.om&quot; vocab_path = &quot;/home/HwHiAiUser/samples/notebooks/09-speech-recognition/vocab.txt&quot;

if not os.path.exists(model_path) or not os.path.exists(vocab_path):
    print("Model or vocabulary file not found.")
    exit(1)

return WeNetASR(model_path, vocab_path)

在程序启动时就初始化模型

asr_model = initialize_model()

@app.route('/transcribe', methods=['POST']) def transcribe(): if 'file' not in request.files: return jsonify({&quot;error&quot;: &quot;No file part&quot;}), 400

file = request.files['file']

if file.filename == '':
    return jsonify({"error": "No selected file"}), 400

if file:
    # 创建临时文件保存上传的音频
    temp_filename = os.path.join("/tmp", file.filename)
    file.save(temp_filename)

    start_time = datetime.now()
    result = transcribe_audio(temp_filename)
    end_time = datetime.now()
    time_difference = (end_time - start_time).total_seconds()

    # 删除临时文件
    os.remove(temp_filename)

    if result:
        response = {
            "transcribed_text": result["transcribed_text"],
            "pinyin_text": result["pinyin_text"],
            "processing_time": f"{time_difference:.2f} seconds"
        }
        return jsonify(response), 200
    else:
        return jsonify({"error": "Failed to transcribe audio."}), 500

def transcribe_audio(wav_file): &quot;&quot;&quot;处理单个音频文件的转录请求&quot;&quot;&quot; txt = asr_model.transcribe(wav_file) if txt: # 将文本转换为带拼音的形式 pinyin_txt = ' '.join(lazy_pinyin(txt))

return {
        "transcribed_text": txt,
        "pinyin_text": pinyin_txt
    }
else:
    print("Failed to transcribe audio.")
    return None

if name == &quot;main&quot;: app.run(debug=False, host='0.0.0.0', port=9999)

**错误如下 **** [INFO] acl init success [INFO] open device 0 success [INFO] load model /home/HwHiAiUser/samples/notebooks/09-speech-recognition/offline_encoder.om success [INFO] create model description success

  • Serving Flask app 'main'
  • Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
  • Running on all addresses (0.0.0.0) Press CTRL+C to quit EE1001: The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] Solution: 1.Check the input parameter range of the function. 2.Check the function invocation relationship. TraceBack (most recent call last): ctx is NULL![FUNC:DevMalloc][FILE:api_impl.cc][LINE:1327] The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] alloc device memory failed, runtime result = 107002[FUNC:ReportCallError][FILE:log_inner.cpp][LINE:161] ctx is NULL![FUNC:GetDevErrMsg][FILE:api_impl.cc][LINE:4541] The argument is invalid.Reason: rtGetDevMsg execute failed, reason=[context pointer null]

[107002][Error code unknown] Malloc ptrData failed.[ERROR] MemoryHelper::MxbsMalloc failed device size:472960 ret:2 EE1001: The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] Solution: 1.Check the input parameter range of the function. 2.Check the function invocation relationship. TraceBack (most recent call last): ctx is NULL![FUNC:DevMalloc][FILE:api_impl.cc][LINE:1327] The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] alloc device memory failed, runtime result = 107002[FUNC:ReportCallError][FILE:log_inner.cpp][LINE:161] ctx is NULL![FUNC:GetDevErrMsg][FILE:api_impl.cc][LINE:4541] The argument is invalid.Reason: rtGetDevMsg execute failed, reason=[context pointer null]

EE1001: The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] Solution: 1.Check the input parameter range of the function. 2.Check the function invocation relationship. TraceBack (most recent call last): ctx is NULL![FUNC:DevMalloc][FILE:api_impl.cc][LINE:1327] The argument is invalid.Reason: rtMalloc execute failed, reason=[context pointer null] alloc device memory failed, runtime result = 107002[FUNC:ReportCallError][FILE:log_inner.cpp][LINE:161] ctx is NULL![FUNC:GetDevErrMsg][FILE:api_impl.cc][LINE:4541] The argument is invalid.Reason: rtGetDevMsg execute failed, reason=[context pointer null]

[107002][Error code unknown] Malloc ptrData failed.[ERROR] MemoryHelper::MxbsMalloc failed device size:4 ret:2 [ERROR] Check i:0 name:speech in size:2 needsize:472960 not match [ERROR] Check InVector failed ret:-1 Error during transcription: [-1][ACL: general failure] Failed to transcribe audio. 192.168.1.91 - - [28/Dec/2024 10:04:43] &quot;POST /transcribe HTTP/1.1&quot; 500 - [INFO] unload model success, model Id is 1

内容如下: total used free shared buff/cache available Mem: 7.4Gi 1.2Gi 4.6Gi 17Mi 1.6Gi 5.9Gi Swap: 8.0Gi 0B 8.0Gi

本帖最后由 匿名用户2024/12/30 16:56:32 编辑

我要发帖子