ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

红色警戒2心灵终结[语音转文本][笔记] 达摩语音识别本地+处理wav 笔记 20260307

红色警戒2心灵终结[语音转文本][笔记] 达摩语音识别本地+处理wav 笔记 20260307 为了将群友发的红色警戒2心灵终结 全阵营 EVA命令与征服中的辅助计算机EVA让洛天依复刻必须先检索一眼丁真 鉴定为 焚风怎么读 骇然 难绷 666没什么部署记录 只有代码托管语音生成自己学习VITS-GPT调用API生成echo off chcp 65001 nul ::自己改路径 使用绝对路径最简单最直接 这里使用CPU推理 cd C:\Users\Administrator\Downloads\GPT-SoVITS-v2pro-20250604 .\runtime\python api.py -a 0.0.0.0 -d cpu -s SoVITS_weights_v2/luotianyi_e16_s432.pth -p 3752 -g GPT_weights_v2/luotianyi-e50.ckpt -dr 怎么还是这张图捏能不能换一张呀.wav -dt 怎么还是这张图捏能不能换一张呀 -dl zh pause# -*- coding: utf-8 -*- VITS 批量语音生成脚本 功能读取 txt.txt逐行生成语音并保存 import requests import os import time from datetime import datetime # 配置项 # VITS 服务地址 (与 web.py 中的 TTS_URL 保持一致) TTS_URL http://localhost:3752/ # 输入文本文件 INPUT_FILE txt.txt # 输出音频保存目录 OUTPUT_DIR batch_output # 语言设置 (参考 web.py 默认为 zh) LANGUAGE zh # def batch_generate(): # 1. 检查文件是否存在 if not os.path.exists(INPUT_FILE): print(f[错误] 未找到文件: {INPUT_FILE}) print([提示] 请在当前目录下创建 txt.txt 并放入要生成的文本。) return # 2. 创建输出目录 if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) print(f[信息] 已创建输出目录: {OUTPUT_DIR}) # 3. 读取文本 with open(INPUT_FILE, r, encodingutf-8) as f: lines [line.strip() for line in f.readlines() if line.strip()] total len(lines) print(f[开始] 共读取到 {total} 行文本准备开始生成...\n) success_count 0 fail_count 0 # 4. 逐行处理 for index, text in enumerate(lines): print(f[{index1}/{total}] 正在处理: {text}) try: # 发送请求 (与 web.py 的 generate_tts 逻辑一致) payload { text: text, text_language: LANGUAGE } start_time time.time() response requests.post(TTS_URL, jsonpayload, timeout60) if response.status_code 200: # 生成文件名: 序号_时间戳.wav timestamp datetime.now().strftime(%H%M%S) filename f{index1:03d}_{timestamp}.wav save_path os.path.join(OUTPUT_DIR, filename) # 保存音频 with open(save_path, wb) as audio_file: audio_file.write(response.content) duration time.time() - start_time print(f - 成功! 已保存: {filename} (耗时 {duration:.2f}s)) success_count 1 else: print(f - 失败! 服务返回状态码: {response.status_code}) fail_count 1 except requests.exceptions.ConnectionError: print( - [严重错误] 无法连接到 VITS 服务请确保 web.py 或 VITS 服务已启动。) break except Exception as e: print(f - 发生异常: {e}) fail_count 1 print(f\n[完成] 处理结束。成功: {success_count}, 失败: {fail_count}) print(f[输出] 音频文件已保存在文件夹: {os.path.abspath(OUTPUT_DIR)}) if __name__ __main__: batch_generate()这里只是开始处理音频了语音识别#!/usr/bin/env python3 # -*- coding: utf-8 -*- 红警2 EVA语音识别批处理脚本 功能自动下载语音识别模型 - 自动遍历根目录和子文件夹中的wav文件 - 按文件夹输出识别结果为txt import os import sys import warnings from pathlib import Path from funasr import AutoModel from collections import defaultdict # 屏蔽 jieba 的 pkg_resources 警告 warnings.filterwarnings(ignore, categoryDeprecationWarning, modulejieba) # 配置区域 # 文件夹名称中文映射可选 FOLDER_NAME_MAP { soviet: 苏联, allied: 盟军, yuri: 厄普西隆, german: 焚风, } # def get_all_wav_files(): 自动获取根目录和所有子文件夹下的wav文件按文件夹分组 wav_by_folder defaultdict(list) # 扫描当前目录下的所有wav文件包括子文件夹 for wav_path in Path(.).rglob(*.wav): # 获取父文件夹路径 parent wav_path.parent # 判断是根目录还是子文件夹 if parent Path(.): folder_key 根目录 else: folder_key str(parent) wav_by_folder[folder_key].append(wav_path) # 同时检查大写扩展名 .WAV for wav_path in Path(.).rglob(*.WAV): parent wav_path.parent if parent Path(.): folder_key 根目录 else: folder_key str(parent) wav_by_folder[folder_key].append(wav_path) return wav_by_folder def process_audio_files(): 主处理函数 print(f\n{*60}) print(f模型类型: 英文 Paraformer) print(f扫描范围: 根目录及所有子文件夹) print(f{*60}\n) # 初始化英文模型首次运行会自动下载 print(正在加载英文模型首次运行需要下载请耐心等待...) try: model AutoModel( modelparaformer-en, # 只下载英文模型 vad_modelfsmn-vad, punc_modelct-punc ) print(模型加载完成\n) except Exception as e: print(f模型加载失败: {str(e)}) print(请检查网络连接或尝试手动下载模型) sys.exit(1) # 获取所有wav文件按文件夹分组 wav_by_folder get_all_wav_files() if not wav_by_folder: print(f警告没有找到任何wav文件) return total_files sum(len(files) for files in wav_by_folder.values()) print(f找到 {total_files} 个wav文件分布在 {len(wav_by_folder)} 个文件夹\n) # 显示检测到的文件夹 print(检测到的文件夹) for folder in sorted(wav_by_folder.keys()): print(f - {folder}: {len(wav_by_folder[folder])} 个文件) print() # 按文件夹处理 total_success 0 total_failed 0 for folder_name, wav_files in sorted(wav_by_folder.items()): print(f\n{*60}) print(f正在处理文件夹: {folder_name}) print(f文件数量: {len(wav_files)}) print(f{*60}\n) # 确定输出txt文件名 if folder_name 根目录: folder_key 根目录 output_name 根目录 else: folder_key Path(folder_name).name output_name FOLDER_NAME_MAP.get(folder_key, folder_key) txt_filename f{output_name}.txt results [] success_count 0 failed_files [] for idx, wav_path in enumerate(wav_files, 1): print(f [{idx}/{len(wav_files)}] 正在处理: {wav_path.name}) try: # 识别音频 res model.generate(inputstr(wav_path), batch_size_s300) # 提取文本 if res and len(res) 0: text res[0].get(text, ) results.append({ filename: wav_path.name, filepath: str(wav_path), text: text }) print(f ✓ 识别成功) print(f 文本: {text[:60]}{... if len(text) 60 else }\n) success_count 1 else: print(f ✗ 识别失败未返回结果\n) failed_files.append(wav_path.name) except Exception as e: print(f ✗ 处理出错: {str(e)}\n) failed_files.append(wav_path.name) # 保存该文件夹的txt with open(txt_filename, w, encodingutf-8) as f: f.write(f文件夹: {folder_name}\n) f.write(f识别时间: {__import__(datetime).datetime.now().strftime(%Y-%m-%d %H:%M:%S)}\n) f.write(f成功: {success_count} 个 | 失败: {len(failed_files)} 个\n) f.write(f{*60}\n\n) for item in results: f.write(f【{item[filename]}】\n) if item[filepath] ! item[filename]: # 如果不是根目录显示相对路径 f.write(f路径: {item[filepath]}\n) f.write(f{item[text]}\n\n) print(f 已保存到: {txt_filename}) print(f 成功: {success_count} 个 | 失败: {len(failed_files)} 个) total_success success_count total_failed len(failed_files) # 输出总结 print(f\n{*60}) print(f全部处理完成) print(f总成功: {total_success} 个文件) print(f总失败: {total_failed} 个文件) print(f输出位置: 根目录) print(f{*60}\n) if __name__ __main__: print( ╔══════════════════════════════════════════════════════════╗ ║ 红警2 EVA 语音识别批处理工具 v3.0 ║ ║ 基于达摩院 FunASR Paraformer 英文模型 ║ ║ 自动扫描根目录和子文件夹按文件夹输出txt ║ ╚══════════════════════════════════════════════════════════╝ ) # 运行主函数 process_audio_files()处理文件语音文件夹→打包→解包import os import json from datetime import datetime from pydub import AudioSegment # 配置 WAV_FOLDER wav OUTPUT_MP3 output.mp3 JSON_FILE audio_info.json NEW_WAV_FOLDER newwav2 def format_time(ms): 毫秒转 分:秒.毫秒 seconds ms / 1000 minutes int(seconds // 60) secs seconds % 60 return f{minutes}:{secs:.2f} def get_sorted_wav_files(): 获取并排序wav文件按cfoe013, cfoe015, cfoe016顺序 if not os.path.exists(WAV_FOLDER): print(f错误{WAV_FOLDER} 文件夹不存在) return [] wav_files [f for f in os.listdir(WAV_FOLDER) if f.lower().endswith(.wav)] wav_files.sort() # 按文件名排序 return wav_files def merge_wav_to_mp3(): 合并所有wav为一个mp3 wav_files get_sorted_wav_files() if not wav_files: print(没有找到wav文件) return print(f找到 {len(wav_files)} 个wav文件:) for f in wav_files: print(f - {f}) combined AudioSegment.empty() audio_info { merge_time: datetime.now().isoformat(), source_folder: WAV_FOLDER, output_file: OUTPUT_MP3, files: [] } current_pos 0 # 当前位置毫秒 for i, wav_file in enumerate(wav_files, 1): file_path os.path.join(WAV_FOLDER, wav_file) try: audio AudioSegment.from_wav(file_path) duration len(audio) start_time current_pos end_time current_pos duration audio_info[files].append({ index: i, original_name: wav_file, start_ms: start_time, end_ms: end_time, start_time: format_time(start_time), end_time: format_time(end_time), duration: format_time(duration), duration_ms: duration }) combined audio current_pos end_time print(f[{i}/{len(wav_files)}] {wav_file} - {format_time(duration)}) except Exception as e: print(f错误无法处理 {wav_file}: {e}) # 导出mp3 combined.export(OUTPUT_MP3, formatmp3, bitrate192k) # 保存json with open(JSON_FILE, w, encodingutf-8) as f: json.dump(audio_info, f, ensure_asciiFalse, indent2) print(f\n✓ 合并完成!) print(f 输出: {OUTPUT_MP3}) print(f 总时长: {format_time(len(combined))}) print(f 记录文件: {JSON_FILE}) def split_mp3_to_wav(mp3_path): 根据json拆分mp3为wav if not os.path.exists(JSON_FILE): print(f错误{JSON_FILE} 不存在请先执行合并操作) return if not os.path.exists(mp3_path): print(f错误{mp3_path} 不存在) return # 创建输出文件夹 os.makedirs(NEW_WAV_FOLDER, exist_okTrue) # 读取json with open(JSON_FILE, r, encodingutf-8) as f: audio_info json.load(f) print(f加载mp3: {mp3_path}) audio AudioSegment.from_mp3(mp3_path) print(f\n开始拆分 {len(audio_info[files])} 个文件:) for file_info in audio_info[files]: start_ms file_info[start_ms] end_ms file_info[end_ms] original_name file_info[original_name] # 切片 segment audio[start_ms:end_ms] # 导出 output_path os.path.join(NEW_WAV_FOLDER, original_name) segment.export(output_path, formatwav) print(f {original_name} ({file_info[duration]})) print(f\n✓ 拆分完成! 输出文件夹: {NEW_WAV_FOLDER}) def main(): print( * 50) print( 音频合并/拆分工具) print( * 50) print( [1] 合并 - wav文件夹 - mp3) print( [2] 拆分 - mp3 - newwav2文件夹) print( * 50) choice input(请选择 (1/2): ).strip() if choice 1: print(\n 执行合并操作) merge_wav_to_mp3() elif choice 2: print(\n 执行拆分操作) mp3_path input(请输入mp3路径: ).strip() # 如果用户直接输入文件名自动补全路径 if not os.path.exists(mp3_path) and os.path.exists(os.path.join(., mp3_path)): mp3_path os.path.join(., mp3_path) split_mp3_to_wav(mp3_path) else: print(无效选择请输入 1 或 2) input(\n按回车键退出...) if __name__ __main__: main()处理文件名称import os import re import shutil # 配置 SOURCE_FOLDER wav # 现有的wav文件夹 TEMPLATE_FOLDER template # 指定文件夹文件名模板 OUTPUT_FOLDER newwav # 输出文件夹 def extract_number(filename): 从文件名提取编号如 cfoe013.wav - 13 match re.search(r(\d), filename) return int(match.group(1)) if match else 0 def get_sorted_files(folder, ext.wav): 获取排序后的文件列表 if not os.path.exists(folder): return [] files [f for f in os.listdir(folder) if f.lower().endswith(ext)] files.sort() # 按文件名排序 return files def main(): print( * 50) print( WAV文件重命名工具) print( * 50) # 检查文件夹 if not os.path.exists(SOURCE_FOLDER): print(f错误{SOURCE_FOLDER} 文件夹不存在) input(按回车键退出...) return if not os.path.exists(TEMPLATE_FOLDER): print(f错误{TEMPLATE_FOLDER} 文件夹不存在) input(按回车键退出...) return # 获取文件列表 source_files get_sorted_files(SOURCE_FOLDER) template_files get_sorted_files(TEMPLATE_FOLDER) if not source_files: print(f错误{SOURCE_FOLDER} 中没有wav文件) return if not template_files: print(f错误{TEMPLATE_FOLDER} 中没有wav文件) return # 按编号排序模板文件 template_files_sorted sorted(template_files, keyextract_number) print(f\n源文件夹 ({SOURCE_FOLDER}): {len(source_files)} 个文件) print(f模板文件夹 ({TEMPLATE_FOLDER}): {len(template_files_sorted)} 个文件) # 显示映射关系 print(\n映射关系) print(- * 50) pairs [] for i, (src, tmpl) in enumerate(zip(source_files, template_files_sorted)): new_name tmpl pairs.append((src, new_name)) print(f {src} - {new_name}) if len(source_files) len(template_files_sorted): print(f\n⚠ 源文件多了 {len(source_files) - len(template_files_sorted)} 个无法全部重命名) elif len(template_files_sorted) len(source_files): print(f\n⚠ 模板文件多了 {len(template_files_sorted) - len(source_files)} 个部分模板不会使用) # 确认执行 print(- * 50) confirm input(\n确认执行: ).strip().lower() if confirm ! y: print(已取消) return # 创建输出文件夹 os.makedirs(OUTPUT_FOLDER, exist_okTrue) # 执行重命名复制文件 success_count 0 for src, new_name in pairs: src_path os.path.join(SOURCE_FOLDER, src) dst_path os.path.join(OUTPUT_FOLDER, new_name) try: shutil.copy2(src_path, dst_path) success_count 1 print(f ✓ {src} - {new_name}) except Exception as e: print(f ✗ {src}: {e}) print(f\n完成成功 {success_count} 个输出到 {OUTPUT_FOLDER}) input(\n按回车键退出...) if __name__ __main__: main()处理文件格式# 原代码问题RA2_SAMPLE_RATE 22050 → 样本2是 32000 Hz import os import re import soundfile as sf import numpy as np from pydub import AudioSegment from pydub.silence import detect_nonsilent # 配置参数 SOURCE_FOLDER audio_source OUTPUT_FOLDER newwav # 修正匹配样本2的格式参数 RA2_SAMPLE_RATE 32000 # 改为 32000 Hz原为22050 RA2_CHANNELS 1 # 静音检测参数 SILENCE_THRESHOLD -50 MIN_SILENCE_LEN 100 def get_wav_files(folder): 获取文件夹中按数字顺序排列的wav文件 wav_files [] for filename in os.listdir(folder): if filename.lower().endswith(.wav): match re.search(r(\d), filename) if match: num int(match.group(1)) wav_files.append((num, os.path.join(folder, filename))) wav_files.sort(keylambda x: x[0]) return [(path, os.path.basename(path)) for _, path in wav_files] def analyze_wav_file(wav_path): 分析WAV文件并打印详细信息 try: info sf.info(wav_path) audio_data, sr sf.read(wav_path) file_size os.path.getsize(wav_path) duration info.duration frames info.frames channels info.channels sample_rate info.samplerate subtype info.subtype if duration 0: bit_rate (file_size * 8) / duration / 1000 else: bit_rate 0 if audio_data.ndim 1: data_min, data_max float(np.min(audio_data)), float(np.max(audio_data)) data_shape f({frames},) else: data_min, data_max float(np.min(audio_data)), float(np.max(audio_data)) data_shape f({frames}, {channels}) print( * 70) print(f正在解析WAV文件: {os.path.basename(wav_path)}) print( * 70) print(f1. 采样率: {sample_rate} Hz) print(f2. 声道数: {channels}) print(f - 说明: 1单声道, 2立体声, 2多声道) print(f3. 音频时长: {duration:.2f} 秒) print(f4. 总帧数: {frames}) print(f5. 格式类型: {info.format}) print(f6. 编码方式: {subtype}) print(f7. 采样宽度: {info.subtype_info if hasattr(info, subtype_info) else subtype}) print(f8. 总文件大小: {file_size} 字节 ({file_size/1024:.2f} KB)) print(f9. 比特率: 约 {bit_rate:.1f} kbps) print() print(10. 音频数据验证:) print(f - 加载成功数据形状: {data_shape}) print(f - 数据范围: {data_min:.6f} ~ {data_max:.6f}) print() print( * 70) return True except Exception as e: print(f解析失败: {e}) return False def process_wav_file(wav_path): 处理单个wav文件返回去除头尾静音后的AudioSegment try: audio_data, sr sf.read(wav_path) if audio_data.dtype np.float64 or audio_data.dtype np.float32: audio_data (audio_data * 32767).astype(np.int16) else: audio_data audio_data.astype(np.int16) channels 1 if audio_data.ndim 1 else audio_data.shape[1] audio AudioSegment( audio_data.tobytes(), frame_ratesr, sample_width2, channelschannels ) except Exception as e: print(f读取文件失败 {wav_path}: {e}) return None if len(audio) 0: return None nonsilent_ranges detect_nonsilent( audio, min_silence_lenMIN_SILENCE_LEN, silence_threshSILENCE_THRESHOLD, seek_step10 ) if not nonsilent_ranges: return None start_index nonsilent_ranges[0][0] end_index nonsilent_ranges[-1][1] trimmed audio[start_index:end_index] orig_len len(audio) / 1000 new_len len(trimmed) / 1000 print(f处理结果: 去除静音 {orig_len:.2f}s - {new_len:.2f}s) return trimmed def convert_to_ra2_format(audio): 转换为样本2格式 (32000 Hz, PCM_16, 单声道) if audio.frame_rate ! RA2_SAMPLE_RATE: audio audio.set_frame_rate(RA2_SAMPLE_RATE) if audio.channels ! RA2_CHANNELS: audio audio.set_channels(RA2_CHANNELS) return audio def process_folder(folder_path, output_folder_name): 处理一个文件夹的所有语音文件 folder_name os.path.basename(folder_path) output_dir os.path.join(OUTPUT_FOLDER, output_folder_name) print(f\n{*70}) print(f处理文件夹: {folder_name}) print(f输出目录: {output_dir}) os.makedirs(output_dir, exist_okTrue) wav_files get_wav_files(folder_path) if not wav_files: print(f没有找到wav文件) return False print(f找到 {len(wav_files)} 个wav文件) processed_count 0 for i, (wav_path, wav_name) in enumerate(wav_files, 1): print(f\n[{i}/{len(wav_files)}]) analyze_wav_file(wav_path) audio_segment process_wav_file(wav_path) if audio_segment is None: continue audio_segment convert_to_ra2_format(audio_segment) output_path os.path.join(output_dir, wav_name) # 导出 PCM_16 格式与样本2一致 try: audio_segment.export(output_path, formatwav, parameters[-acodec, pcm_s16le]) print(f导出成功 (PCM_16, 32000 Hz): {wav_name}) processed_count 1 except Exception as e: print(f导出失败 {wav_name}: {e}) print(f\n完成: {processed_count}/{len(wav_files)} 个文件) return processed_count 0 def main(): print( * 70) print(音频处理工具 - 输出格式: PCM_16, 32000 Hz, 单声道) print( * 70) if not os.path.exists(SOURCE_FOLDER): print(f错误: 源文件夹不存在: {SOURCE_FOLDER}) return os.makedirs(OUTPUT_FOLDER, exist_okTrue) folders [] for item in os.listdir(SOURCE_FOLDER): item_path os.path.join(SOURCE_FOLDER, item) if os.path.isdir(item_path): has_wav any(f.lower().endswith(.wav) for f in os.listdir(item_path)) if has_wav: folders.append((item, item_path)) if not folders: print(没有找到包含wav文件的文件夹) return print(f发现 {len(folders)} 个文件夹) for folder_name, folder_path in folders: process_folder(folder_path, folder_name) print(\n * 70) print(f处理完成输出目录: {os.path.abspath(OUTPUT_FOLDER)}) print( * 70) if __name__ __main__: main()可选 修改文件名称 需要修改对应INI (wav根目录下)import os import sys def batch_rename_wav(directory, prefix_map): 批量重命名 WAV 文件根据前缀映射表添加新前缀。 print(f--- 正在扫描目录: {directory} ---) # 检查目录是否存在 if not os.path.exists(directory): print(f[错误] 目录不存在: {directory}) return # 获取目录下所有文件 files os.listdir(directory) wav_files [f for f in files if f.lower().endswith(.wav)] print(f找到 {len(wav_files)} 个 WAV 文件:) for f in wav_files: print(f - {f}) rename_count 0 for filename in wav_files: # 获取文件完整路径 old_path os.path.join(directory, filename) # 确保是文件 if os.path.isfile(old_path): # 分离文件名和扩展名 name_part, ext_part os.path.splitext(filename) # 遍历映射表检查是否需要重命名 for old_prefix, new_prefix in prefix_map.items(): # 如果文件名以指定前缀开头不区分大小写 if name_part.lower().startswith(old_prefix.lower()): # 构建新文件名 # 例如cyur001 - ltycyur 001 new_name_part new_prefix name_part[len(old_prefix):] new_filename new_name_part ext_part # 构建新路径 new_path os.path.join(directory, new_filename) # 安全检查如果新文件名已存在跳过防止覆盖 if os.path.exists(new_path): print(f[跳过] 文件已存在无法重命名: {filename} - {new_filename}) continue try: # 执行重命名 os.rename(old_path, new_path) print(f[成功] {filename} - {new_filename}) rename_count 1 except OSError as e: print(f[失败] 重命名出错 {filename}: {e}) # 匹配到一个前缀后跳出内循环避免重复处理 break print(f--- 处理完成共重命名 {rename_count} 个文件 ---) if __name__ __main__: # # 配置区域 (根据你的需求修改这里) # # 1. 设置目标文件夹路径 (默认为脚本所在目录) target_dir os.path.dirname(os.path.abspath(__file__)) # 2. 设置重命名规则 (旧前缀 : 新前缀) # 这里包含了你要求的四个前缀 rename_rules { cyur: ltycyur, # 尤里阵营 cfoe: ltycfoe, # 焚风阵营 ceva: ltyceva, # 盟军阵营 csof: ltycsof, # 苏军阵营 } # # 执行 # print(即将开始批量重命名...) print(f目标目录: {target_dir}) print(f重命名规则: {rename_rules}) # 修复后的输入行 confirm input(\n确认执行吗(输入 y 继续): ) if confirm.lower() y: batch_rename_wav(target_dir, rename_rules) else: print(操作已取消。)
返回列表