I have two scripts ones a uvicorn server made from converting a gradio webui and the other is for inferencing into the uvicorn server via c#. I want you to make adjustments to both if needed to make a progress bar for the progress of the split on the c# side. Return full code.

'Uvicorn Server'
import os
import json
import shutil
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import uvicorn
import torch

import logging

from audio_separator.separator import Separator

# ---- Constants setup (same as your Gradio defaults) ----
now_dir = os.getcwd()
config_file = os.path.join(now_dir, "assets", "config.json")
models_dir = "./models"
out_dir = "./outputs"
output_format_choices = [
    'wav','flac','mp3','ogg','opus','m4a','aiff','ac3'
]

device = "cuda" if torch.cuda.is_available() else "cpu"
use_autocast = device == "cuda"

app = FastAPI(title="UVR5 VR Arch Separation API")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Ensure output directory exists
os.makedirs(out_dir, exist_ok=True)

# Pydantic model for JSON request (multipart preferred for file upload)
class SeparateRequest(BaseModel):
    model: str
    output_format: str
    window_size: int
    aggression: int
    tta: bool
    post_process: bool
    post_process_threshold: float
    high_end_process: bool
    batch_size: int
    normalization_threshold: float
    amplification_threshold: float
    single_stem: Optional[str] = ""

# Utility function to validate model path
def get_model_path(model_name: str):
    path = os.path.join(models_dir, model_name)
    if not os.path.isfile(path):
        raise HTTPException(status_code=404, detail=f"Model '{model_name}' not found.")
    return path

@app.post("/separate/")
async def separate_audio(
    audio: UploadFile = File(...),
    model: str = Form(...),
    output_format: str = Form(...),
    window_size: int = Form(...),
    aggression: int = Form(...),
    tta: bool = Form(...),
    post_process: bool = Form(...),
    post_process_threshold: float = Form(...),
    high_end_process: bool = Form(...),
    batch_size: int = Form(...),
    normalization_threshold: float = Form(...),
    amplification_threshold: float = Form(...),
    single_stem: str = Form("")
):
    """
    Endpoint to perform audio separation.

    Return value: JSON with paths to separated stems files.
    """
    # Validate output format
    if output_format not in output_format_choices:
        raise HTTPException(status_code=400, detail=f"Unsupported output format '{output_format}'.")

    # Validate model
    model_path = get_model_path(model)

    # Save uploaded audio file temporarily
    audio_temp_path = os.path.join(out_dir, f"input_{audio.filename}")
    try:
        with open(audio_temp_path, "wb") as f:
            f.write(await audio.read())
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to save input audio: {e}")

    try:
        separator = Separator(
            log_level=logging.WARNING,
            model_file_dir=models_dir,
            output_dir=out_dir,
            output_format=output_format,
            use_autocast=use_autocast,
            normalization_threshold=normalization_threshold,
            amplification_threshold=amplification_threshold,
            output_single_stem=single_stem,
            vr_params={
                "batch_size": batch_size,
                "window_size": window_size,
                "aggression": aggression,
                "enable_tta": tta,
                "enable_post_process": post_process,
                "post_process_threshold": post_process_threshold,
                "high_end_process": high_end_process,
            }
        )

        separator.load_model(model_filename=model)

        separation = separator.separate(audio_temp_path)

        if len(separation) == 0:
            raise RuntimeError("Separation returned empty output list.")

        # Compose response with file URLs or file paths
        # serve files directly by endpoint (or just return path)
        # Here, we just return file paths (relative to out_dir)
        stems_response = {}

        # If output_single_stem is set, separator returns one stem, else list
        if single_stem.strip():
            # Return a single stem as "stem1"
            stem_path = separation[0]
            stem_filename = os.path.basename(stem_path)
            stems_response["stem1"] = f"/files/{stem_filename}"
        else:
            # Normally two stems
            for idx, path in enumerate(separation[:2], 1):
                stem_filename = os.path.basename(path)
                stems_response[f"stem{idx}"] = f"/files/{stem_filename}"

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Separation failed: {str(e)}")
    finally:
        # Cleanup uploaded file
        if os.path.exists(audio_temp_path):
            try:
                os.remove(audio_temp_path)
            except:
                pass

    return {"result": stems_response}

@app.get("/files/{filename}")
async def get_file(filename: str):
    """
    Serve the separated audio files.
    """
    file_path = os.path.join(out_dir, filename)
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found.")
    return FileResponse(file_path, filename=filename)

if __name__ == '__main__':
    # Run server on port 8403
    uvicorn.run(app, host='0.0.0.0', port=8403)

'C# Side'
private async void button3_Click(object sender, EventArgs e)
{
    string outputFolder = @"C:\AI\UVR5_UI\outputs";

    SharedPath = Path.Combine(
        DatasetHome,
        Dataset_List.SelectedItem.ToString(),
        Speaker_List.SelectedItem.ToString(),
        Voice_List.SelectedItem.ToString());

    Text = SharedPath;
    string stem1Path = string.Empty;
    string stem2Path = string.Empty;

    using var client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:8403");

    using var form = new MultipartFormDataContent();

    // Add the audio file
    var audioBytes = await File.ReadAllBytesAsync(SharedPath);
    var fileContent = new ByteArrayContent(audioBytes);
    fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("audio/wav");
    form.Add(fileContent, "audio", Path.GetFileName(SharedPath));

    // Add other form fields
    form.Add(new StringContent("4_HP-Vocal-UVR.pth"), "model");
    form.Add(new StringContent("wav"), "output_format");
    form.Add(new StringContent("320"), "window_size");
    form.Add(new StringContent("23"), "aggression");
    form.Add(new StringContent("false"), "tta");
    form.Add(new StringContent("false"), "post_process");
    form.Add(new StringContent("0.2"), "post_process_threshold");
    form.Add(new StringContent("true"), "high_end_process");
    form.Add(new StringContent("2"), "batch_size");
    form.Add(new StringContent("0.5"), "normalization_threshold");
    form.Add(new StringContent("0.0"), "amplification_threshold");
    form.Add(new StringContent(""), "single_stem");

    var response = await client.PostAsync("/separate/", form);

    var jsonResponse = await response.Content.ReadAsStringAsync();

    if (!response.IsSuccessStatusCode)
    {
        throw new Exception($"Request failed with status {response.StatusCode}: {jsonResponse}");
    }

    // Parse JSON response to extract stem URLs
    using var jsonDoc = System.Text.Json.JsonDocument.Parse(jsonResponse);
    var root = jsonDoc.RootElement;

    if (root.TryGetProperty("result", out var resultElement))
    {
        if (resultElement.TryGetProperty("stem1", out var stem1Element))
            stem1Path = stem1Element.GetString();

        if (resultElement.TryGetProperty("stem2", out var stem2Element))
            stem2Path = stem2Element.GetString();
    }

    string outputFile = Path.Combine(outputFolder, stem1Path.Replace(@"/files/", string.Empty));

    File.Delete(SharedPath);
    File.Copy(outputFile,SharedPath);
    }
}