Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a REST api service with fastapi for simple inferencing. #1614

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from

Conversation

w4hns1nn
Copy link

PR type

  • New feature REST API.

Description

Added a REST service with fastapi. By starting the server with "python rvc_fastapy.py" the REST service is launched under localhost:8080. The API is well documented and easy to use.

Screenshot

rvc_rest

fumiama
fumiama previously approved these changes Dec 20, 2023
@fumiama fumiama enabled auto-merge (squash) December 20, 2023 05:44
@fumiama fumiama changed the base branch from v2.1 to dev December 26, 2023 15:19
@fumiama fumiama added the enhancement ✨功能增强 label Dec 26, 2023
@Kamikadashi
Copy link

This significantly speeds up the inference process compared to the currently available API.

@fumiama
Copy link
Member

fumiama commented Dec 28, 2023

This significantly speeds up the inference process compared to the currently available API.

I agree with you. Need @RVC-Boss to decide whether merge or not.

@iotgopher
Copy link

this would be a great addition - please @RVC-Boss can you help merging?

@joshlatham
Copy link

Hi, I have cloned this solution to test it out but I am not able to successfully process using the api. No matter what I put as the value for input_path or input_file, I am getting "detail": "infer() missing 1 required positional argument: 'input'" or {"detail":[{"loc":["body","input_file"],"msg":"field required","type":"value_error.missing"}]}. I've tried both the endpoints local and non local.

@w4hns1nn
Copy link
Author

Hey, I already made some changes there to improve and added also pure rest inference points without local paths, what works even better. I did not know how ho update the pull request with git though

@Kamikadashi
Copy link

Hey, I already made some changes there to improve and added also pure rest inference points without local paths, what works even better. I did not know how ho update the pull request with git though

The last changes I see are dated three weeks ago. Did you make any other changes?

@iotgopher
Copy link

@w4hns1nn maybe you can create a new PR?

@Kamikadashi
Copy link

Kamikadashi commented Jan 11, 2024

Hi, I have cloned this solution to test it out but I am not able to successfully process using the api. No matter what I put as the value for input_path or input_file, I am getting "detail": "infer() missing 1 required positional argument: 'input'" or {"detail":[{"loc":["body","input_file"],"msg":"field required","type":"value_error.missing"}]}. I've tried both the endpoints local and non local.

def send_request(file_path):
    
    url = "http://localhost:8001/voice2voice"
    params = {
        "model_name": "Emilia.pth",
        "index_path": "None",
        "f0up_key": -1,
        "f0method": "rmvpe",
        "index_rate": 0.66,
        "device": "cuda",
        "is_half": "False",
        "filter_radius": 3,
        "resample_sr": 0,
        "rms_mix_rate": 0.25,
        "protect": 0.33
    }
    with open(file_path, "rb") as f:
        files = {"input_file": f}
        response = session.post(url, files=files, params=params, stream=True)
    print(f"Status code: {response.status_code}")

    # Save the response as a .wav file in the same directory as the script
    dir_path = os.path.dirname(os.path.realpath(__file__))
    output_file_path = os.path.join(dir_path, "output.wav")
    with open(output_file_path, "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

    return output_file_path

or

def send_request(file_data):
    url = "http://localhost:8001/voice2voice"
    params = {
        "model_name": "Emilia.pth",
        "index_path": "None",
        "f0up_key": -1,
        "f0method": "rmvpe",
        "index_rate": 0.66,
        "device": "cuda",
        "is_half": "False",
        "filter_radius": 3,
        "resample_sr": 0,
        "rms_mix_rate": 0.25,
        "protect": 0.33
    }
    files = {"input_file": file_data}
    response = session.post(url, files=files, params=params, stream=True)

    # Return the response content as a byte stream
    response_content = response.content

    return response_content

@fumiama
Copy link
Member

fumiama commented Jan 11, 2024

Hey, I already made some changes there to improve and added also pure rest inference points without local paths, what works even better. I did not know how ho update the pull request with git though

Just edit your fork https://github.com/w4hns1nn/Retrieval-based-Voice-Conversion-FastAPI/tree/main and it will update to this PR automatically.

@fumiama fumiama disabled auto-merge January 11, 2024 13:34
Copy link

@markyfsun markyfsun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please also add a response_format param?


# call the infer function
try:
wf = infer(**kwargs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a response_format parameter here to decide whether to response in wav or mp3 format?
Like this:

def infer(
        input: Union[str, bytes],  # filepath or raw bytes
        model_name: str,
        response_format: str = 'wav',  # new parameter for specifying the output format
        index_path: str = None,
        f0up_key: int = 0,
        f0method: str = "crepe",
        index_rate: float = 0.66,
        device: str = None,
        is_half: bool = False,
        filter_radius: int = 3,
        resample_sr: int = 0,
        rms_mix_rate: float = 1,
        protect: float = 0.33,
        **kwargs
    ):
    if response_format.lower() not in ['wav', 'mp3', 'flac', 'ogg', 'aac']:
        raise ValueError(f"Unsupported response_format: {response_format}. Supported formats: wav, mp3, flac, ogg, aac")
    model_name = model_name.replace(".pth", "")

    if index_path is None:
        index_path = os.path.join("logs", model_name, f"added_IVF1254_Flat_nprobe_1_{model_name}_v2.index")
        if not os.path.exists(index_path):
            index_path = None
            # raise ValueError(f"autinferred index_path {index_path} does not exist. Please provide a valid index_path")

    vc = model_cache.load_model(model_name, device=device, is_half=is_half)

    _, wav_opt = vc.vc_single(
        sid=0,
        input_audio_path=input,
        f0_up_key=f0up_key,
        f0_file=None,
        f0_method=f0method,
        file_index=index_path,
        file_index2=None,
        index_rate=index_rate,
        filter_radius=filter_radius,
        resample_sr=resample_sr,
        rms_mix_rate=rms_mix_rate,
        protect=protect
    )

    # using virtual file to be able to return it as response
    wf = BytesIO()

    # Check if the desired response format is valid and supported


    # Save the output in the desired format
    sf.write(wf, wav_opt[1], wav_opt[0], format=response_format.upper())

    # Make sure to seek the beginning of the BytesIO object before returning it
    wf.seek(0)

    return wf

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is from OpenAI TTS API, which allows user to decide response format

@Tps-F Tps-F mentioned this pull request Jan 13, 2024
if index_path is None:
index_path = os.path.join("logs", model_name, f"added_IVF1254_Flat_nprobe_1_{model_name}_v2.index")
if not os.path.exists(index_path):
raise ValueError(f"autinferred index_path {index_path} does not exist. Please provide a valid index_path")
Copy link

@markyfsun markyfsun Jan 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some models do not come with index files. If fails to find index_path, how about leaving it to None instead of raising an Exception?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current version works without an index file just fine, just set "index_path": "None"

@w4hns1nn
Copy link
Author

w4hns1nn commented Feb 2, 2024

Could you please also add a response_format param?

I will do, in a few weeks

@Tps-F
Copy link
Member

Tps-F commented Feb 4, 2024

API is under development in this repository.
https://github.com/RVC-Project/Retrieval-based-Voice-Conversion

@fumiama fumiama changed the base branch from v2.2 to dev March 1, 2024 09:30
@fumiama fumiama dismissed their stale review March 1, 2024 09:30

The base branch was changed.

@fumiama fumiama deleted the branch RVC-Project:dev March 1, 2024 09:39
@fumiama fumiama closed this Mar 1, 2024
@iielse
Copy link

iielse commented Mar 13, 2024

Sorry, I'm new to using git. REST api service with fastapi This function has not been merged into the main or dev branch at present, right? Because I have not seen the existence of the rvc_fastapi.py file on main or dev.

@fumiama
Copy link
Member

fumiama commented Mar 13, 2024

Yes, it is closed by a mistake. I will re-open it.

@fumiama fumiama reopened this Mar 13, 2024
@iielse
Copy link

iielse commented Mar 14, 2024

Today I performed a request test on the function of this code and it works normally.

--> END POST (1286684-byte body)
<-- 200 OK http://localhost:8001/voice2voice?model_name=qiqi-jp.pth&index_path=log%2Fadded_IVF985_Flat_nprobe_1_qiqi-jp_v2.index&f0up_key=0&f0method=rmvpe&index_rate=1.0&device=cuda%3A0&is_half=false&filter_radius=3&resample_sr=0&rms_mix_rate=1&protect=0.33 (643ms)
date: Thu, 14 Mar 2024 06:41:40 GMT
server: uvicorn
content-disposition: attachment; filename=rvc.wav
content-type: audio/wav
Transfer-Encoding: chunked

<-- END HTTP (binary 641324-byte body omitted)
File saved successfully! D:\audioApiOut.wav
cost time: 4152ms

@Kamikadashi
Copy link

It’s baffling to me that this hasn’t been merged into the main branch after all this time. Without this API, RVC is literally unusable for my use case, and I doubt I’m the only one.

@Kamikadashi Kamikadashi mentioned this pull request Mar 15, 2024
@ouarrtaha
Copy link

i was playing with this branch, it was useful, but didn't u take in consideration concurrency, how we can deal with multiple requests, if u have multiple simultaneous requests will significally slow down inference time, can we do something like batching...?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement ✨功能增强
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet