VoiceFixer / app.py
harp-dev's picture
Tidy the launch call and drop stray files
28eed4a verified
Raw History Blame Contribute Delete
4.1 kB
from __future__ import annotations
import gradio as gr
try:
import spaces
except ImportError: # 'spaces' is only provided by Hugging Face Spaces
import types as _types
def _gpu(*args, **kwargs):
if len(args) == 1 and callable(args[0]) and not kwargs:
return args[0]
def _decorator(func):
return func
return _decorator
spaces = _types.SimpleNamespace(GPU=_gpu)
from pyharp import *
import tempfile
from voicefixer import VoiceFixer
# Initialize VoiceFixer. It handles downloading checkpoints and setting device.
# The VoiceFixer class automatically detects and uses CUDA if available.
voicefixer_model = VoiceFixer()
model_card = ModelCard(
name="VoiceFixer",
description=(
"VoiceFixer aims to restore human speech regardless how serious its "
"degraded. It can handle noise, reverberation, low resolution "
"(2kHz~44.1kHz) and clipping (0.1-1.0 threshold) effect within one "
"model. The model is fixed-rate and mono, so the result is resampled "
"back to the input's rate and copied across its channels: the output "
"has the format it came in with, but no stereo image. Repository: "
"https://github.com/haoheliu/voicefixer Paper: "
"https://arxiv.org/abs/2109.13731"
),
author="Haohe Liu, Qiuqiang Kong, Qiao Tian, Yan Zhao, DeLiang Wang, Chuanzeng Huang, Yuxuan Wang",
tags=[Subcategory.RESTORATION, SampleRate(44100), Channels(1), 'speech'],
)
@spaces.GPU
def match_input_format(output_path: str, input_path: str) -> str:
"""
Rewrite an output file at the sample rate and channel count it came in with.
The models here are fixed-rate and mono, and hand the writing to vendored
upstream code, so the format is corrected afterwards rather than threaded
through inference. Duplicated channels are copies, not a recovered stereo
image; the model card says so.
Args:
output_path (str): File the model wrote. Overwritten in place.
input_path (str): File the request supplied.
Returns:
output_path (str): The same path, for use in a return statement.
"""
import librosa
import numpy as np
import soundfile
want = soundfile.info(input_path)
have = soundfile.info(output_path)
if have.samplerate == want.samplerate and have.channels == want.channels:
return output_path
data, rate = soundfile.read(output_path, always_2d=True)
if rate != want.samplerate:
data = librosa.resample(
data.T, orig_sr=rate, target_sr=want.samplerate
).T
if data.shape[1] == 1 and want.channels > 1:
data = np.tile(data, (1, want.channels))
elif data.shape[1] > 1 and want.channels == 1:
data = data.mean(axis=1, keepdims=True)
soundfile.write(output_path, data, want.samplerate)
return output_path
def process_fn(input_audio, mode):
output_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False).name
voicefixer_model.restore(input_audio, output_file, mode=int(mode))
return match_input_format(output_file, input_audio)
if __name__ == "__main__":
with gr.Blocks() as demo:
input_components = [
gr.Audio(type="filepath", label="Input Audio").harp_required(True).set_info("Upload an audio file to be processed by VoiceFixer."),
gr.Dropdown(choices=["0", "1", "2"], value="0", label="Processing Mode", info="Select the VoiceFixer processing mode:\n0: Original Model (suggested by default)\n1: Add preprocessing module (remove higher frequency)\n2: Train mode (might work sometimes on seriously degraded real speech)"),
]
output_components = [
gr.Audio(type="filepath", label="Fixed Audio").set_info("The enhanced audio output from VoiceFixer."),
]
build_endpoint(
model_card=model_card,
input_components=input_components,
output_components=output_components,
process_fn=process_fn,
)
demo.queue().launch(show_error=True, pwa=True)