vbach_lite_ui / app.py
noblebarkrr's picture
Update app.py
e883a21 verified
import gradio as gr
import os
import asyncio
import shutil
from datetime import datetime
import urllib.request
import zipfile
import gdown
import requests
import logging
# Настройка логирования
logging.basicConfig(level=logging.INFO)
# Константы
f0_min = 50
f0_max = 1100
rvc_models_dir = './models'
input_folder = './input'
output_folder = './output'
# Создание необходимых директорий
os.makedirs(rvc_models_dir, exist_ok=True)
os.makedirs(input_folder, exist_ok=True)
os.makedirs(output_folder, exist_ok=True)
# Общие функции
async def run_command_async(command):
"""Асинхронный запуск команд."""
process = await asyncio.create_subprocess_shell(
command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
logging.error(f"Error: {stderr.decode()}")
return stdout.decode()
def get_models_list():
"""Получение списка моделей."""
models = []
if os.path.exists(rvc_models_dir):
models = [d for d in os.listdir(rvc_models_dir) if os.path.isdir(os.path.join(rvc_models_dir, d))]
return models
# Функции для первой вкладки
def process_uploaded_files(files):
"""Обработка загруженных файлов."""
if os.path.exists(input_folder):
shutil.rmtree(input_folder)
os.makedirs(input_folder, exist_ok=True)
for file in files:
shutil.copy(file.name, input_folder)
return f"Uploaded {len(files)} files to {input_folder}"
async def convert_voice(
voicemodel_name,
pitch_vocal,
method_pitch,
hop_length,
index_rate,
filter_radius,
rms,
protect,
output_format
):
"""Конвертация голоса."""
current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
output_ai_vocals_folder = os.path.join(output_folder, current_time)
os.makedirs(output_ai_vocals_folder, exist_ok=True)
output_test = {
"mp3": "-ab 320k",
"wav": "-c:a pcm_s32le",
"flac": "-c:a flac -af aformat=s16"
}[output_format]
for filename in os.listdir(input_folder):
if filename.endswith(("wav", "mp3", "flac")):
input_path = os.path.join(input_folder, filename)
base_name = os.path.splitext(filename)[0]
output_filename = f"mono_{base_name}_{current_time}_{method_pitch}_{pitch_vocal}.{output_format}"
output_path = os.path.join(output_ai_vocals_folder, output_filename)
# Выполнение команды RVC
await run_command_async(
f"python3 -m rvc.cli.rvc_cli -i \"{input_path}\" -m \"{voicemodel_name}\" -p {pitch_vocal} "
f"-ir {index_rate} -fr {filter_radius} -rms {rms} -f0 \"{method_pitch}\" "
f"-hop {hop_length} -pro {protect} -f0min {f0_min} -f0max {f0_max} -f \"wav\""
)
# Конвертация в нужный формат
await run_command_async(
f"ffmpeg -y -i ./output/Voice_Converted.wav "
f"-vn -ar 44100 -ac 1 {output_test} \"{output_path}\""
)
return [os.path.join(output_ai_vocals_folder, f) for f in os.listdir(output_ai_vocals_folder) if f.endswith(output_format)]
# Функции для второй вкладки
def extract_zip(extraction_folder, zip_name):
"""Распаковка архива."""
os.makedirs(extraction_folder, exist_ok=True)
with zipfile.ZipFile(zip_name, 'r') as zip_ref:
zip_ref.extractall(extraction_folder)
os.remove(zip_name)
model_file = next((f for f in os.listdir(extraction_folder) if f.endswith('.pth')), None)
index_file = next((f for f in os.listdir(extraction_folder) if f.endswith('.index')), None)
if model_file:
os.rename(os.path.join(extraction_folder, model_file),
os.path.join(extraction_folder, model_file))
if index_file:
os.rename(os.path.join(extraction_folder, index_file),
os.path.join(extraction_folder, index_file))
async def download_model(url, dir_name):
"""Скачивание модели."""
try:
zip_path = os.path.join(rvc_models_dir, f"{dir_name}.zip")
extraction_path = os.path.join(rvc_models_dir, dir_name)
if os.path.exists(extraction_path):
return f"Error: Directory {dir_name} already exists!"
if 'drive.google.com' in url:
file_id = url.split("file/d/")[1].split("/")[0] if "file/d/" in url else url.split("id=")[1].split("&")[0]
gdown.download(id=file_id, output=zip_path, quiet=False)
elif 'huggingface.co' in url:
urllib.request.urlretrieve(url, zip_path)
elif 'pixeldrain.com' in url:
file_id = url.split("pixeldrain.com/u/")[1]
response = requests.get(f"https://pixeldrain.com/api/file/{file_id}")
with open(zip_path, 'wb') as f:
f.write(response.content)
extract_zip(extraction_path, zip_path)
return f"Model {dir_name} successfully installed!"
except Exception as e:
return f"Error: {str(e)}"
# Создание интерфейса
with gr.Blocks() as demo:
gr.Markdown("# VBach Lite WEBUI")
with gr.Tabs():
# Первая вкладка
with gr.TabItem("Замена вокала"):
with gr.Row():
with gr.Column():
file_input = gr.File(file_count="multiple", label="Загрузить один или несколько файлов")
upload_status = gr.Textbox(label="Статус загрузки")
file_input.upload(
fn=process_uploaded_files,
inputs=file_input,
outputs=upload_status
)
with gr.Accordion("Настройки RVC:", open=True):
voicemodel_name = gr.Dropdown(
choices=get_models_list(),
label="Имя модели",
value="senko" if "senko" in get_models_list() else None
)
refresh_btn = gr.Button("Обновить")
pitch_vocal = gr.Slider(-48, 48, value=0, step=12, label="Высота тона")
method_pitch = gr.Dropdown(
["fcpe", "rmvpe+", "mangio-crepe"],
value="rmvpe+",
label="Метод извлечения тона"
)
hop_length = gr.Slider(0, 255, value=73, step=1, label="Длина шага для mangio-crepe")
index_rate = gr.Slider(0, 1, value=1, step=0.05, label="ИИ-акцент")
filter_radius = gr.Slider(0, 7, value=7, step=1, label="Радиус фильтра")
rms = gr.Slider(0, 1, value=0, step=0.1, label="Нормализация")
protect = gr.Slider(0, 0.5, value=0.35, step=0.05, label="Защита согласных")
output_format = gr.Dropdown(
["flac", "wav", "mp3"],
value="mp3",
label="Формат вывода"
)
convert_btn = gr.Button("Преобразовать!", variant="primary")
with gr.Column():
output_files = gr.Files(label="Аудио с преобразованным вокалом")
# Обработчики
refresh_btn.click(
fn=lambda: gr.update(choices=get_models_list()),
outputs=voicemodel_name
)
convert_btn.click(
fn=convert_voice,
inputs=[
voicemodel_name,
pitch_vocal,
method_pitch,
hop_length,
index_rate,
filter_radius,
rms,
protect,
output_format
],
outputs=output_files
)
# Вторая вкладка
with gr.TabItem("Скачать модель"):
with gr.Row():
with gr.Column():
gr.Markdown("## Здесь можно скачать модель по ссылке на архив с нею")
url_input = gr.Textbox(
label="Ссылка на архив с моделью",
placeholder="хаггингфейс.ко/модель.zip"
)
dir_name_input = gr.Textbox(
label="Имя модели",
placeholder="Имя модели"
)
download_btn = gr.Button("Скачать модель", variant="primary")
install_status = gr.Textbox(label="Статус скачивания модели")
download_btn.click(
fn=download_model,
inputs=[url_input, dir_name_input],
outputs=install_status
)
with gr.Column():
gr.Markdown("## Проверить список моделей")
model_list = gr.Textbox(
value="\n".join(get_models_list()),
lines=10,
label="Установленные модели"
)
refresh_models_btn = gr.Button("Обновить")
refresh_models_btn.click(
fn=lambda: gr.update(value="\n".join(get_models_list())),
outputs=model_list
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)