I have a uvicorn server converted from a gradio webui that I'm trying to inference with in c# but the uvr client is responding with "INFO:     127.0.0.1:61922 - "POST /separate/ HTTP/1.1" 404 Not Found"

'uvicorn app'
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)

'My C# Inference'
private async void button3_Click(object sender, EventArgs e)
{
    SharedPath = Path.Combine(
        DatasetHome,
        Dataset_List.SelectedItem.ToString(),
        Speaker_List.SelectedItem.ToString(),
        Voice_List.SelectedItem.ToString());

    Text = SharedPath;

    string wavPath = SharedPath;

    try
    {
        var (stem1, stem2) = await SeparatorClient.ProcessWaveFile(wavPath);
        Console.WriteLine($"Stem1 saved to: {stem1}");
        if (stem2 != null)
            MessageBox.Show($"Stem2 saved to: {stem2}");
        else
            Console.WriteLine("Only one stem returned by server.");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Processing failed: {ex.Message}");
    }
}