添加性能监控

This commit is contained in:
Downupanddownup 2024-04-26 13:25:02 +08:00
parent 1da23aa259
commit 2880e3a6f8
10 changed files with 202 additions and 57 deletions

View File

@ -0,0 +1,71 @@
import time
from Ref_Audio_Selector.config_param.log_config import p_logger
import Ref_Audio_Selector.config_param.config_params as params
def timeit_decorator(func):
"""
装饰器用于计算被装饰函数的执行时间
参数:
func (function): 要计时的函数
返回:
function: 包含计时功能的新函数
"""
def wrapper(*args, **kwargs):
if params.time_log_print_type != 'file':
return func(*args, **kwargs)
start_time = time.perf_counter() # 使用 perf_counter 获取高精度计时起点
func_result = func(*args, **kwargs) # 执行原函数
end_time = time.perf_counter() # 获取计时终点
elapsed_time = end_time - start_time # 计算执行耗时
# 记录日志内容
log_message = f"{func.__name__} 执行耗时: {elapsed_time:.6f}"
p_logger.info(log_message)
return func_result
return wrapper
def time_monitor(func):
"""
返回结果追加时间
"""
def wrapper(*args, **kwargs):
start_time = time.perf_counter() # 使用 perf_counter 获取高精度计时起点
func_result = func(*args, **kwargs) # 执行原函数
end_time = time.perf_counter() # 获取计时终点
elapsed_time = end_time - start_time # 计算执行耗时
return elapsed_time, func_result
return wrapper
# 使用装饰器
@timeit_decorator
def example_function(n):
time.sleep(n) # 假设这是需要计时的函数,这里模拟耗时操作
return n * 2
def example_function2(n):
time.sleep(n) # 假设这是需要计时的函数,这里模拟耗时操作
return n * 2
if __name__ == "__main__":
# 调用经过装饰的函数
# result = example_function(2)
print(time_monitor(example_function2)(2))

View File

@ -1,6 +1,10 @@
# config.ini # config.ini
[Base] [Base]
# 函数时间消耗日志打印类型 file 打印到文件; close 关闭
time_log_print_type = file
# 函数时间消耗日志保存目录路径
time_log_print_dir = Ref_Audio_Selector/log/performance
# 参考音频目录 # 参考音频目录
reference_audio_dir = refer_audio reference_audio_dir = refer_audio

View File

@ -3,6 +3,10 @@ import Ref_Audio_Selector.config_param.config_manager as config_manager
config = config_manager.get_config() config = config_manager.get_config()
# [Base] # [Base]
# 函数时间消耗日志打印类型 file 打印到文件; close 关闭
time_log_print_type = config.get_base('time_log_print_type')
# 函数时间消耗日志保存目录路径
time_log_print_dir = config.get_base('time_log_print_dir')
# 参考音频目录 # 参考音频目录
reference_audio_dir = config.get_base('reference_audio_dir') reference_audio_dir = config.get_base('reference_audio_dir')

View File

@ -0,0 +1,39 @@
import logging
import datetime
import Ref_Audio_Selector.config_param.config_params as params
def setup_logging():
# 获取当前日期,用于文件名和日志内容
current_date = datetime.datetime.now().strftime('%Y-%m-%d')
# 创建一个用于常规日志的处理器
general_handler = logging.FileHandler('general.log', mode='a', encoding='utf-8')
general_handler.setLevel(logging.INFO)
general_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
general_handler.setFormatter(general_formatter)
# 创建一个专用于性能监控日志的处理器
performance_handler = logging.FileHandler(
f"{params.time_log_print_dir}/{current_date}.log", mode='a', encoding='utf-8')
performance_handler.setLevel(logging.INFO)
performance_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
performance_handler.setFormatter(performance_formatter)
# 配置一个常规的logger
general_logger = logging.getLogger('general')
general_logger.setLevel(logging.INFO)
general_logger.addHandler(general_handler)
# 配置一个专门用于性能监控的logger
performance_logger = logging.getLogger('performance')
performance_logger.setLevel(logging.INFO)
performance_logger.addHandler(performance_handler)
# 配置根logger以防万一
logging.basicConfig(level=logging.WARNING, handlers=[general_handler])
return general_logger, performance_logger
logger, p_logger = setup_logging()

View File

@ -9,6 +9,8 @@ import Ref_Audio_Selector.tool.audio_config as audio_config
import Ref_Audio_Selector.tool.delete_inference_with_ref as delete_inference_with_ref import Ref_Audio_Selector.tool.delete_inference_with_ref as delete_inference_with_ref
import Ref_Audio_Selector.common.common as common import Ref_Audio_Selector.common.common as common
import Ref_Audio_Selector.config_param.config_params as params import Ref_Audio_Selector.config_param.config_params as params
import Ref_Audio_Selector.common.time_util as time_util
from Ref_Audio_Selector.config_param.log_config import logger
from tools.i18n.i18n import I18nAuto from tools.i18n.i18n import I18nAuto
from config import python_exec, is_half from config import python_exec, is_half
from tools import my_utils from tools import my_utils
@ -16,11 +18,11 @@ from tools.asr.config import asr_dict
from subprocess import Popen from subprocess import Popen
i18n = I18nAuto() i18n = I18nAuto()
rw_param = params.config_manager.get_rw_param()
p_similarity = None p_similarity = None
p_asr = None p_asr = None
p_text_similarity = None p_text_similarity = None
rw_param = params.config_manager.get_rw_param()
# 校验基础信息 # 校验基础信息
@ -50,10 +52,13 @@ def convert_from_list(text_work_space_dir, text_role, text_list_input):
ref_audio_all = os.path.join(base_role_dir, ref_audio_all = os.path.join(base_role_dir,
params.list_to_convert_reference_audio_dir) params.list_to_convert_reference_audio_dir)
text_convert_from_list_info = f"转换成功:生成目录{ref_audio_all}"
time_consuming, _ = time_util.time_monitor(audio_similarity.convert_from_list)(text_list_input, ref_audio_all)
text_convert_from_list_info = f"耗时:{time_consuming:0.1f}秒;转换成功:生成目录{ref_audio_all}"
text_sample_dir = ref_audio_all text_sample_dir = ref_audio_all
audio_similarity.convert_from_list(text_list_input, ref_audio_all) # audio_similarity.convert_from_list(text_list_input, ref_audio_all)
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_convert_from_list_info = f"发生异常:{e}" text_convert_from_list_info = f"发生异常:{e}"
@ -113,10 +118,17 @@ def sample(text_work_space_dir, text_role, text_sample_dir, text_base_voice_path
raise Exception("每段随机抽样个数不能为空") raise Exception("每段随机抽样个数不能为空")
ref_audio_dir = os.path.join(base_role_dir, params.reference_audio_dir) ref_audio_dir = os.path.join(base_role_dir, params.reference_audio_dir)
text_sample_info = f"抽样成功:生成目录{ref_audio_dir}"
similarity_list, _, _ = start_similarity_analysis(base_role_dir, text_sample_dir, time_consuming, similarity_list, _, _ = (
text_base_voice_path, checkbox_similarity_output) time_util.time_monitor(start_similarity_analysis)(base_role_dir,
text_sample_dir,
text_base_voice_path,
checkbox_similarity_output))
text_sample_info = f"耗时:{time_consuming:0.1f}秒;抽样成功:生成目录{ref_audio_dir}"
# similarity_list, _, _ = start_similarity_analysis(base_role_dir, text_sample_dir,
# text_base_voice_path, checkbox_similarity_output)
if similarity_list is None: if similarity_list is None:
raise Exception("相似度分析失败") raise Exception("相似度分析失败")
@ -136,9 +148,9 @@ def sample(text_work_space_dir, text_role, text_sample_dir, text_base_voice_path
# 根据参考音频和测试文本,执行批量推理 # 根据参考音频和测试文本,执行批量推理
def model_inference(text_work_space_dir, text_role, text_model_inference_voice_dir, text_url, def model_inference(text_work_space_dir, text_role, text_model_inference_voice_dir, text_url,
text_text, text_ref_path, text_ref_text, text_emotion, text_text, text_ref_path, text_ref_text, text_emotion,
text_test_content): text_test_content_dir):
text_work_space_dir, text_model_inference_voice_dir, text_test_content \ text_work_space_dir, text_model_inference_voice_dir, text_test_content_dir \
= common.batch_clean_paths([text_work_space_dir, text_model_inference_voice_dir, text_test_content]) = common.batch_clean_paths([text_work_space_dir, text_model_inference_voice_dir, text_test_content_dir])
inference_dir = None inference_dir = None
text_asr_audio_dir = None text_asr_audio_dir = None
@ -151,7 +163,7 @@ def model_inference(text_work_space_dir, text_role, text_model_inference_voice_d
raise Exception("推理服务请求地址不能为空") raise Exception("推理服务请求地址不能为空")
if text_text is None or text_text == '': if text_text is None or text_text == '':
raise Exception("文本参数名不能为空") raise Exception("文本参数名不能为空")
if text_test_content is None or text_test_content == '': if text_test_content_dir is None or text_test_content_dir == '':
raise Exception("待推理文本路径不能为空") raise Exception("待推理文本路径不能为空")
if (text_ref_path is None or text_ref_path == '') and (text_ref_text is None or text_ref_text == '') and ( if (text_ref_path is None or text_ref_path == '') and (text_ref_text is None or text_ref_text == '') and (
text_emotion is None or text_emotion == ''): text_emotion is None or text_emotion == ''):
@ -160,18 +172,24 @@ def model_inference(text_work_space_dir, text_role, text_model_inference_voice_d
inference_dir = os.path.join(base_role_dir, params.inference_audio_dir) inference_dir = os.path.join(base_role_dir, params.inference_audio_dir)
text_asr_audio_dir = os.path.join(inference_dir, text_asr_audio_dir = os.path.join(inference_dir,
params.inference_audio_text_aggregation_dir) params.inference_audio_text_aggregation_dir)
text_model_inference_info = f"推理成功:生成目录{inference_dir}"
url_composer = audio_inference.URLComposer(text_url, text_emotion, text_text, text_ref_path, text_ref_text) url_composer = audio_inference.URLComposer(text_url, text_emotion, text_text, text_ref_path, text_ref_text)
url_composer.is_valid() url_composer.is_valid()
text_list = common.read_text_file_to_list(text_test_content) text_list = common.read_text_file_to_list(text_test_content_dir)
if text_list is None or len(text_list) == 0: if text_list is None or len(text_list) == 0:
raise Exception("待推理文本内容不能为空") raise Exception("待推理文本内容不能为空")
ref_audio_manager = common.RefAudioListManager(text_model_inference_voice_dir) ref_audio_manager = common.RefAudioListManager(text_model_inference_voice_dir)
if len(ref_audio_manager.get_audio_list()) == 0: if len(ref_audio_manager.get_audio_list()) == 0:
raise Exception("待推理的参考音频不能为空") raise Exception("待推理的参考音频不能为空")
audio_inference.generate_audio_files(url_composer, text_list, ref_audio_manager.get_ref_audio_list(),
inference_dir) time_consuming, _ = time_util.time_monitor(audio_inference.generate_audio_files)(url_composer, text_list,
ref_audio_manager.get_ref_audio_list(),
inference_dir)
text_model_inference_info = f"耗时:{time_consuming:0.1f}秒;推理成功:生成目录{inference_dir}"
# audio_inference.generate_audio_files(url_composer, text_list, ref_audio_manager.get_ref_audio_list(),
# inference_dir)
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_model_inference_info = f"发生异常:{e}" text_model_inference_info = f"发生异常:{e}"
@ -198,10 +216,15 @@ def asr(text_work_space_dir, text_role, text_asr_audio_dir, dropdown_asr_model,
raise Exception("asr模型大小不能为空") raise Exception("asr模型大小不能为空")
if dropdown_asr_lang is None or dropdown_asr_lang == '': if dropdown_asr_lang is None or dropdown_asr_lang == '':
raise Exception("asr语言不能为空") raise Exception("asr语言不能为空")
asr_file = open_asr(text_asr_audio_dir, base_role_dir, dropdown_asr_model, dropdown_asr_size,
dropdown_asr_lang) time_consuming, asr_file = time_util.time_monitor(open_asr)(text_asr_audio_dir, base_role_dir,
dropdown_asr_model, dropdown_asr_size,
dropdown_asr_lang)
# asr_file = open_asr(text_asr_audio_dir, base_role_dir, dropdown_asr_model, dropdown_asr_size,
# dropdown_asr_lang)
text_text_similarity_analysis_path = asr_file text_text_similarity_analysis_path = asr_file
text_asr_info = f"asr成功生成文件{asr_file}" text_asr_info = f"耗时:{time_consuming:0.1f}秒;asr成功生成文件{asr_file}"
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_asr_info = f"发生异常:{e}" text_asr_info = f"发生异常:{e}"
@ -253,8 +276,13 @@ def text_similarity_analysis(text_work_space_dir, text_role,
if text_text_similarity_analysis_path is None or text_text_similarity_analysis_path == '': if text_text_similarity_analysis_path is None or text_text_similarity_analysis_path == '':
raise Exception("asr生成的文件路径不能为空请先完成上一步操作") raise Exception("asr生成的文件路径不能为空请先完成上一步操作")
similarity_dir = os.path.join(base_role_dir, params.text_similarity_output_dir) similarity_dir = os.path.join(base_role_dir, params.text_similarity_output_dir)
text_text_similarity_analysis_info = f"相似度分析成功:生成目录{similarity_dir}"
open_text_similarity_analysis(text_text_similarity_analysis_path, similarity_dir) time_consuming, _ = time_util.time_monitor(open_text_similarity_analysis)(text_text_similarity_analysis_path,
similarity_dir)
text_text_similarity_analysis_info = f"耗时:{time_consuming:0.1f}秒;相似度分析成功:生成目录{similarity_dir}"
# open_text_similarity_analysis(text_text_similarity_analysis_path, similarity_dir)
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_text_similarity_analysis_info = f"发生异常:{e}" text_text_similarity_analysis_info = f"发生异常:{e}"
@ -293,13 +321,18 @@ def similarity_audio_output(text_work_space_dir, text_role, text_base_audio_path
raise Exception("基准音频路径不能为空") raise Exception("基准音频路径不能为空")
if text_compare_audio_dir is None or text_compare_audio_dir == '': if text_compare_audio_dir is None or text_compare_audio_dir == '':
raise Exception("待分析的音频所在目录不能为空") raise Exception("待分析的音频所在目录不能为空")
similarity_list, similarity_file, similarity_file_dir = start_similarity_analysis(
base_role_dir, text_compare_audio_dir, text_base_audio_path, True) time_consuming, similarity_list, similarity_file, similarity_file_dir \
= time_util.time_monitor(start_similarity_analysis)(base_role_dir,
text_compare_audio_dir, text_base_audio_path, True)
# similarity_list, similarity_file, similarity_file_dir = start_similarity_analysis(
# base_role_dir, text_compare_audio_dir, text_base_audio_path, True)
if similarity_list is None: if similarity_list is None:
raise Exception("相似度分析失败") raise Exception("相似度分析失败")
text_similarity_audio_output_info = f'相似度分析成功:生成目录{similarity_file_dir},文件{similarity_file}' text_similarity_audio_output_info = f'耗时:{time_consuming:0.1f}秒;相似度分析成功:生成目录{similarity_file_dir},文件{similarity_file}'
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
@ -320,9 +353,13 @@ def sync_ref_audio(text_work_space_dir, text_role, text_sync_ref_audio_dir,
raise Exception("参考音频目录不能为空") raise Exception("参考音频目录不能为空")
if text_sync_inference_audio_dir is None or text_sync_inference_audio_dir == '': if text_sync_inference_audio_dir is None or text_sync_inference_audio_dir == '':
raise Exception("推理生成的音频目录不能为空") raise Exception("推理生成的音频目录不能为空")
delete_text_wav_num, delete_emotion_dir_num = delete_inference_with_ref.sync_ref_audio(text_sync_ref_audio_dir, time_consuming, delete_text_wav_num, delete_emotion_dir_num \
text_sync_inference_audio_dir) = time_util.time_monitor(delete_inference_with_ref.sync_ref_audio)(text_sync_ref_audio_dir,
text_sync_ref_audio_info = f"推理音频目录{text_sync_inference_audio_dir}text目录删除了{delete_text_wav_num}个参考音频emotion目录下删除了{delete_emotion_dir_num}个目录" text_sync_inference_audio_dir)
# delete_text_wav_num, delete_emotion_dir_num = delete_inference_with_ref.sync_ref_audio(
# text_sync_ref_audio_dir, text_sync_inference_audio_dir)
text_sync_ref_audio_info = (f"耗时:{time_consuming:0.1f}秒;推理音频目录{text_sync_inference_audio_dir}下,"
f"text目录删除了{delete_text_wav_num}个参考音频emotion目录下删除了{delete_emotion_dir_num}个目录")
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_sync_ref_audio_info = f"发生异常:{e}" text_sync_ref_audio_info = f"发生异常:{e}"
@ -343,10 +380,17 @@ def create_config(text_work_space_dir, text_role, text_template, text_sync_ref_a
if text_sync_ref_audio_dir2 is None or text_sync_ref_audio_dir2 == '': if text_sync_ref_audio_dir2 is None or text_sync_ref_audio_dir2 == '':
raise Exception("参考音频目录不能为空") raise Exception("参考音频目录不能为空")
config_file = os.path.join(base_role_dir, f'{params.reference_audio_config_filename}.json') config_file = os.path.join(base_role_dir, f'{params.reference_audio_config_filename}.json')
text_create_config_info = f"配置生成成功:生成文件{config_file}"
ref_audio_manager = common.RefAudioListManager(text_sync_ref_audio_dir2) ref_audio_manager = common.RefAudioListManager(text_sync_ref_audio_dir2)
audio_config.generate_audio_config(base_role_dir, text_template, ref_audio_manager.get_ref_audio_list(),
config_file) time_consuming, _ = time_util.time_monitor(audio_config.generate_audio_config)(base_role_dir, text_template,
ref_audio_manager.get_ref_audio_list(),
config_file)
# audio_config.generate_audio_config(base_role_dir, text_template, ref_audio_manager.get_ref_audio_list(),
# config_file)
text_create_config_info = f"耗时:{time_consuming:0.1f}秒;配置生成成功:生成文件{config_file}"
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
text_create_config_info = f"发生异常:{e}" text_create_config_info = f"发生异常:{e}"
@ -514,7 +558,8 @@ with gr.Blocks() as app:
button_model_inference.click(model_inference, button_model_inference.click(model_inference,
[text_work_space_dir, text_role, text_model_inference_voice_dir, text_url, [text_work_space_dir, text_role, text_model_inference_voice_dir, text_url,
text_text, text_ref_path, text_ref_text, text_emotion, text_text, text_ref_path, text_ref_text, text_emotion,
text_test_content], [text_model_inference_info, text_asr_audio_dir, text_sync_inference_audio_dir]) text_test_content],
[text_model_inference_info, text_asr_audio_dir, text_sync_inference_audio_dir])
app.launch( app.launch(
server_port=9423, server_port=9423,

View File

@ -4,6 +4,7 @@ import argparse
import os import os
import traceback import traceback
import Ref_Audio_Selector.config_param.config_params as params import Ref_Audio_Selector.config_param.config_params as params
from Ref_Audio_Selector.common.time_util import timeit_decorator
from tqdm import tqdm from tqdm import tqdm
from funasr import AutoModel from funasr import AutoModel
@ -34,30 +35,7 @@ def only_asr(input_file):
return text return text
def execute_asr(input_folder, output_folder, model_size, language): @timeit_decorator
input_file_names = os.listdir(input_folder)
input_file_names.sort()
output = []
output_file_name = os.path.basename(input_folder)
for name in tqdm(input_file_names):
try:
text = model.generate(input="%s/%s" % (input_folder, name))[0]["text"]
output.append(f"{input_folder}/{name}|{output_file_name}|{language.upper()}|{text}")
except:
print(traceback.format_exc())
output_folder = output_folder or "output/asr_opt"
os.makedirs(output_folder, exist_ok=True)
output_file_path = os.path.abspath(f'{output_folder}/{output_file_name}.list')
with open(output_file_path, "w", encoding="utf-8") as f:
f.write("\n".join(output))
print(f"ASR 任务完成->标注文件路径: {output_file_path}\n")
return output_file_path
def execute_asr_multi_level_dir(input_folder, output_folder, model_size, language): def execute_asr_multi_level_dir(input_folder, output_folder, model_size, language):
output = [] output = []
output_file_name = os.path.basename(input_folder) output_file_name = os.path.basename(input_folder)

View File

@ -2,6 +2,7 @@ import os
import requests import requests
import itertools import itertools
import Ref_Audio_Selector.config_param.config_params as params import Ref_Audio_Selector.config_param.config_params as params
from Ref_Audio_Selector.common.time_util import timeit_decorator
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse, quote from urllib.parse import urlparse, parse_qs, urlencode, urlunparse, quote
@ -72,6 +73,7 @@ def safe_encode_query_params(original_url):
return encoded_url return encoded_url
@timeit_decorator
def generate_audio_files(url_composer, text_list, emotion_list, output_dir_path): def generate_audio_files(url_composer, text_list, emotion_list, output_dir_path):
# Ensure the output directory exists # Ensure the output directory exists
output_dir = os.path.abspath(output_dir_path) output_dir = os.path.abspath(output_dir_path)

View File

@ -6,11 +6,9 @@ import librosa
def check_audio_duration(path, min_duration=3, max_duration=10): def check_audio_duration(path, min_duration=3, max_duration=10):
try: try:
# 加载音频文件
audio, sample_rate = librosa.load(path)
# 计算音频的时长(单位:秒) # 直接计算音频文件的时长(单位:秒)
duration = librosa.get_duration(y=audio, sr=sample_rate) duration = librosa.get_duration(filename=path)
# 判断时长是否在3s至10s之间 # 判断时长是否在3s至10s之间
if min_duration <= duration <= max_duration: if min_duration <= duration <= max_duration:

View File

@ -1,5 +1,6 @@
import argparse import argparse
import os import os
from Ref_Audio_Selector.common.time_util import timeit_decorator
from modelscope.pipelines import pipeline from modelscope.pipelines import pipeline
@ -10,6 +11,7 @@ sv_pipeline = pipeline(
) )
@timeit_decorator
def compare_audio_and_generate_report(reference_audio_path, comparison_dir_path, output_file_path): def compare_audio_and_generate_report(reference_audio_path, comparison_dir_path, output_file_path):
# Step 1: 获取比较音频目录下所有音频文件的路径 # Step 1: 获取比较音频目录下所有音频文件的路径
comparison_audio_paths = [os.path.join(comparison_dir_path, f) for f in os.listdir(comparison_dir_path) if comparison_audio_paths = [os.path.join(comparison_dir_path, f) for f in os.listdir(comparison_dir_path) if

View File

@ -2,6 +2,7 @@ import os
import argparse import argparse
from collections import defaultdict from collections import defaultdict
from operator import itemgetter from operator import itemgetter
from Ref_Audio_Selector.common.time_util import timeit_decorator
import Ref_Audio_Selector.tool.text_comparison.text_comparison as text_comparison import Ref_Audio_Selector.tool.text_comparison.text_comparison as text_comparison
import Ref_Audio_Selector.config_param.config_params as params import Ref_Audio_Selector.config_param.config_params as params
import Ref_Audio_Selector.common.common as common import Ref_Audio_Selector.common.common as common
@ -88,6 +89,7 @@ def format_list_to_text(data_list, output_filename):
output_file.write(formatted_line) output_file.write(formatted_line)
@timeit_decorator
def process(asr_file_path, output_dir, similarity_enlarge_boundary): def process(asr_file_path, output_dir, similarity_enlarge_boundary):
# 检查输出目录是否存在,如果不存在则创建 # 检查输出目录是否存在,如果不存在则创建
if not os.path.exists(output_dir): if not os.path.exists(output_dir):