'C# Errors'
{"detail":[{"type":"model_attributes_type","loc":["body","request"],"msg":"Input should be a valid dictionary or object to extract fields from","input":"{\"model_choice\":\"Zyphra/Zonos-v0.1-transformer\",\"text\":\"testing hello.\",\"language\":\"en-us\",\"emotions\":[0.5,0.1,0.0,0.0,0.0,0.0,0.0,0.0],\"vq_single\":0.78,\"fmax\":24000.0,\"pitch_std\":45.0,\"speaking_rate\":15.0,\"dnsmos_ovrl\":4.0,\"speaker_noised\":false,\"cfg_scale\":2.0,\"min_p\":0.15,\"seed\":1575522834,\"randomize_seed\":true,\"unconditional_keys\":[\"emotion\"]}"}]}

'Uvicorn Server Code Converted from Gradio App by AI'
import torch
import torchaudio
from fastapi import FastAPI, UploadFile, File
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List
import os

# Importing your custom model and utilities
from zonos.model import Zonos, DEFAULT_BACKBONE_CLS as ZonosBackbone
from zonos.conditioning import make_cond_dict, supported_language_codes
from zonos.utils import DEFAULT_DEVICE as device

app = FastAPI()

# CORS Middleware for frontend access (optional)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

CURRENT_MODEL_TYPE = None
CURRENT_MODEL = None

SPEAKER_EMBEDDING = None
SPEAKER_AUDIO_PATH = None


class AudioGenerationRequest(BaseModel):
    model_choice: str
    text: str
    language: str
    emotions: List[float]
    vq_single: float
    fmax: float
    pitch_std: float
    speaking_rate: float
    dnsmos_ovrl: float
    speaker_noised: bool
    cfg_scale: float
    min_p: float
    seed: int
    randomize_seed: bool
    unconditional_keys: List[str]


def load_model_if_needed(model_choice: str):
    global CURRENT_MODEL_TYPE, CURRENT_MODEL
    if CURRENT_MODEL_TYPE != model_choice:
        if CURRENT_MODEL is not None:
            del CURRENT_MODEL
            torch.cuda.empty_cache()
        print(f"Loading {model_choice} model...")
        CURRENT_MODEL = Zonos.from_pretrained(model_choice, device=device)
        CURRENT_MODEL.requires_grad_(False).eval()
        CURRENT_MODEL_TYPE = model_choice
        print(f"{model_choice} model loaded successfully!")
    return CURRENT_MODEL


@app.post("/generate-audio/")
async def generate_audio(
    request: AudioGenerationRequest,
    speaker_audio: UploadFile = File(None),
    prefix_audio: UploadFile = File(None)
):
    selected_model = load_model_if_needed(request.model_choice)

    global SPEAKER_EMBEDDING, SPEAKER_AUDIO_PATH
    
    # Handle speaker audio
    if speaker_audio:
        wav, sr = torchaudio.load(speaker_audio.file)
        SPEAKER_EMBEDDING = selected_model.make_speaker_embedding(wav, sr).to(device, dtype=torch.bfloat16)
        SPEAKER_AUDIO_PATH = speaker_audio.filename

    # Handle prefix audio
    audio_prefix_codes = None
    if prefix_audio:
        wav_prefix, sr_prefix = torchaudio.load(prefix_audio.file)
        wav_prefix = wav_prefix.mean(0, keepdim=True)
        wav_prefix = selected_model.autoencoder.preprocess(wav_prefix, sr_prefix).to(device, dtype=torch.float32)
        audio_prefix_codes = selected_model.autoencoder.encode(wav_prefix.unsqueeze(0))

    emotion_tensor = torch.tensor(request.emotions, device=device)
    vq_tensor = torch.tensor([request.vq_single] * 8, device=device).unsqueeze(0)

    cond_dict = make_cond_dict(
        text=request.text,
        language=request.language,
        speaker=SPEAKER_EMBEDDING,
        emotion=emotion_tensor,
        vqscore_8=vq_tensor,
        fmax=request.fmax,
        pitch_std=request.pitch_std,
        speaking_rate=request.speaking_rate,
        dnsmos_ovrl=request.dnsmos_ovrl,
        speaker_noised=request.speaker_noised,
        device=device,
        unconditional_keys=request.unconditional_keys,
    )
    conditioning = selected_model.prepare_conditioning(cond_dict)

    # Generate audio
    codes = selected_model.generate(
        prefix_conditioning=conditioning,
        audio_prefix_codes=audio_prefix_codes,
        max_new_tokens=86 * 30,
        cfg_scale=request.cfg_scale,
        batch_size=1,
        sampling_params=dict(min_p=request.min_p),
    )

    wav_out = selected_model.autoencoder.decode(codes).cpu().detach()
    sr_out = selected_model.autoencoder.sampling_rate

    if wav_out.dim() == 2 and wav_out.size(0) > 1:
        wav_out = wav_out[0:1, :]

    output_path = "output/generated_audio.wav"
    torchaudio.save(output_path, wav_out.unsqueeze(0), sr_out)

    return JSONResponse(content={"audio_filepath": output_path})


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

'C# Class used to inference with the uvicorn server'
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

public class LocosTTS
{
    private readonly string url;

    public LocosTTS(string url)
    {
        this.url = url;
    }

    public async Task<(bool success, string resultWav)> GenerateAudio(
        string modelChoice,
        string text,
        string language,
        List<float> emotions,
        float vqSingle,
        float fmax,
        float pitchStd,
        float speakingRate,
        float dnsmosOvrl,
        bool speakerNoised,
        float cfgScale,
        float minP,
        int seed = 0,
        bool randomizeSeed = false,
        List<string> unconditionalKeys = null,
        byte[] speakerAudio = null,
        byte[] prefixAudio = null)
    {
        using (var client = new HttpClient())
        {
            var formContent = new MultipartFormDataContent();

            // Adding audio file parts if they are provided
            if (speakerAudio != null)
            {
                var speakerContent = new ByteArrayContent(speakerAudio);
                speakerContent.Headers.ContentType = MediaTypeHeaderValue.Parse("audio/wav");
                formContent.Add(speakerContent, "speaker_audio", "speaker_audio.wav");
            }

            if (prefixAudio != null)
            {
                var prefixContent = new ByteArrayContent(prefixAudio);
                prefixContent.Headers.ContentType = MediaTypeHeaderValue.Parse("audio/wav");
                formContent.Add(prefixContent, "prefix_audio", "prefix_audio.wav");
            }

            // Prepare the JSON object
            var jsonBody = new
            {
                model_choice = modelChoice,
                text,
                language,
                emotions,
                vq_single = vqSingle,  // Ensure these match what is expected
                fmax,
                pitch_std = pitchStd,
                speaking_rate = speakingRate,
                dnsmos_ovrl = dnsmosOvrl,
                speaker_noised = speakerNoised,
                cfg_scale = cfgScale,
                min_p = minP,
                seed,
                randomize_seed = randomizeSeed,
                unconditional_keys = unconditionalKeys
            };

            // Serialize the object to JSON
            var jsonString = JsonConvert.SerializeObject(jsonBody);
            var jsonContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
            // Adding the JSON to form data
            formContent.Add(jsonContent, "request");

            // Send the request
            var response = await client.PostAsync(url, formContent);

            if (response.IsSuccessStatusCode)
            {
                var responseData = await response.Content.ReadAsStringAsync();
                dynamic result = JsonConvert.DeserializeObject(responseData);
                return (true, result.audio_filepath); // Return the audio file path from the response
            }
            else
            {
                var errorMessage = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"Error: {errorMessage}");
                Clipboard.SetText( errorMessage );
                return (false, errorMessage);
            }
        }
    }
}

'C# task to inference with the class'
public async Task GimmieLocoz(string message)
{
    // Ensure the message ends with a terminal punctuation mark
    if (!message.EndsWith("?") && !message.EndsWith(".") && !message.EndsWith("!"))
    {
        message += ".";
    }

    // Load the reference voice audio file if necessary
    byte[] referenceVoiceBytes = File.ReadAllBytes(RefAudioFile); // Replace with actual path
    byte[] prefixAudioBytes = File.ReadAllBytes(@"H:\Hot\Pookie\Poo\poo\api\zonos.git\app\assets\silence_100ms.wav"); // Load a prefix audio file

    // Prepare input data
    var emotions = new List<float> { 0.5f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };

    // Make sure you reference the correct URL with a trailing slash
    var audioGenerator = new LocosTTS("http://localhost:8000/generate-audio/");

    int seed = new Random().Next(); // Generate a random seed
    bool randomizeSeed = true; // Specify if you want to randomize the seed

    var (success, resultWav) = await audioGenerator.GenerateAudio(
        modelChoice: "Zyphra/Zonos-v0.1-transformer",
        text: message,
        language: "en-us",
        emotions: emotions,
        vqSingle: 0.78f, // Ensure it matches what FastAPI expects
        fmax: 24000f,
        pitchStd: 45f,
        speakingRate: 15f,
        dnsmosOvrl: 4f,
        speakerNoised: false,
        cfgScale: 2f,
        minP: 0.15f,
        seed: seed,
        randomizeSeed: randomizeSeed, // Ensure it matches what FastAPI expects
        unconditionalKeys: new List<string> { "emotion" },
        speakerAudio: referenceVoiceBytes, // Send reference voice audio
        prefixAudio: prefixAudioBytes // Send prefix audio if available
    );

    if (success)
    {
        // Notify the user about the generated audio file path
        MessageBox.Show($"Generated audio file path: {resultWav}");
    }
    else
    {
        // Notify the user about the failure
        MessageBox.Show($"Failed to generate audio: {resultWav}");
    }
}

'please correct them all where you see fit also here is the original gradio code:'
import torch
import torchaudio
import gradio as gr
from os import getenv

from zonos.model import Zonos, DEFAULT_BACKBONE_CLS as ZonosBackbone
from zonos.conditioning import make_cond_dict, supported_language_codes
from zonos.utils import DEFAULT_DEVICE as device

CURRENT_MODEL_TYPE = None
CURRENT_MODEL = None

SPEAKER_EMBEDDING = None
SPEAKER_AUDIO_PATH = None


def load_model_if_needed(model_choice: str):
    global CURRENT_MODEL_TYPE, CURRENT_MODEL
    if CURRENT_MODEL_TYPE != model_choice:
        if CURRENT_MODEL is not None:
            del CURRENT_MODEL
            torch.cuda.empty_cache()
        print(f"Loading {model_choice} model...")
        CURRENT_MODEL = Zonos.from_pretrained(model_choice, device=device)
        CURRENT_MODEL.requires_grad_(False).eval()
        CURRENT_MODEL_TYPE = model_choice
        print(f"{model_choice} model loaded successfully!")
    return CURRENT_MODEL


def update_ui(model_choice):
    """
    Dynamically show/hide UI elements based on the model's conditioners.
    We do NOT display 'language_id' or 'ctc_loss' even if they exist in the model.
    """
    model = load_model_if_needed(model_choice)
    cond_names = [c.name for c in model.prefix_conditioner.conditioners]
    print("Conditioners in this model:", cond_names)

    text_update = gr.update(visible=("espeak" in cond_names))
    language_update = gr.update(visible=("espeak" in cond_names))
    speaker_audio_update = gr.update(visible=("speaker" in cond_names))
    prefix_audio_update = gr.update(visible=True)
    emotion1_update = gr.update(visible=("emotion" in cond_names))
    emotion2_update = gr.update(visible=("emotion" in cond_names))
    emotion3_update = gr.update(visible=("emotion" in cond_names))
    emotion4_update = gr.update(visible=("emotion" in cond_names))
    emotion5_update = gr.update(visible=("emotion" in cond_names))
    emotion6_update = gr.update(visible=("emotion" in cond_names))
    emotion7_update = gr.update(visible=("emotion" in cond_names))
    emotion8_update = gr.update(visible=("emotion" in cond_names))
    vq_single_slider_update = gr.update(visible=("vqscore_8" in cond_names))
    fmax_slider_update = gr.update(visible=("fmax" in cond_names))
    pitch_std_slider_update = gr.update(visible=("pitch_std" in cond_names))
    speaking_rate_slider_update = gr.update(visible=("speaking_rate" in cond_names))
    dnsmos_slider_update = gr.update(visible=("dnsmos_ovrl" in cond_names))
    speaker_noised_checkbox_update = gr.update(visible=("speaker_noised" in cond_names))
    unconditional_keys_update = gr.update(
        choices=[name for name in cond_names if name not in ("espeak", "language_id")]
    )

    return (
        text_update,
        language_update,
        speaker_audio_update,
        prefix_audio_update,
        emotion1_update,
        emotion2_update,
        emotion3_update,
        emotion4_update,
        emotion5_update,
        emotion6_update,
        emotion7_update,
        emotion8_update,
        vq_single_slider_update,
        fmax_slider_update,
        pitch_std_slider_update,
        speaking_rate_slider_update,
        dnsmos_slider_update,
        speaker_noised_checkbox_update,
        unconditional_keys_update,
    )


def generate_audio(
    model_choice,
    text,
    language,
    speaker_audio,
    prefix_audio,
    e1,
    e2,
    e3,
    e4,
    e5,
    e6,
    e7,
    e8,
    vq_single,
    fmax,
    pitch_std,
    speaking_rate,
    dnsmos_ovrl,
    speaker_noised,
    cfg_scale,
    min_p,
    seed,
    randomize_seed,
    unconditional_keys,
    progress=gr.Progress(),
):
    """
    Generates audio based on the provided UI parameters.
    We do NOT use language_id or ctc_loss even if the model has them.
    """
    selected_model = load_model_if_needed(model_choice)

    speaker_noised_bool = bool(speaker_noised)
    fmax = float(fmax)
    pitch_std = float(pitch_std)
    speaking_rate = float(speaking_rate)
    dnsmos_ovrl = float(dnsmos_ovrl)
    cfg_scale = float(cfg_scale)
    min_p = float(min_p)
    seed = int(seed)
    max_new_tokens = 86 * 30

    # This is a bit ew, but works for now.
    global SPEAKER_AUDIO_PATH, SPEAKER_EMBEDDING

    if randomize_seed:
        seed = torch.randint(0, 2**32 - 1, (1,)).item()
    torch.manual_seed(seed)

    if speaker_audio is not None and "speaker" not in unconditional_keys:
        if speaker_audio != SPEAKER_AUDIO_PATH:
            print("Recomputed speaker embedding")
            wav, sr = torchaudio.load(speaker_audio)
            SPEAKER_EMBEDDING = selected_model.make_speaker_embedding(wav, sr)
            SPEAKER_EMBEDDING = SPEAKER_EMBEDDING.to(device, dtype=torch.bfloat16)
            SPEAKER_AUDIO_PATH = speaker_audio

    audio_prefix_codes = None
    if prefix_audio is not None:
        wav_prefix, sr_prefix = torchaudio.load(prefix_audio)
        wav_prefix = wav_prefix.mean(0, keepdim=True)
        wav_prefix = selected_model.autoencoder.preprocess(wav_prefix, sr_prefix)
        wav_prefix = wav_prefix.to(device, dtype=torch.float32)
        audio_prefix_codes = selected_model.autoencoder.encode(wav_prefix.unsqueeze(0))

    emotion_tensor = torch.tensor(list(map(float, [e1, e2, e3, e4, e5, e6, e7, e8])), device=device)

    vq_val = float(vq_single)
    vq_tensor = torch.tensor([vq_val] * 8, device=device).unsqueeze(0)

    cond_dict = make_cond_dict(
        text=text,
        language=language,
        speaker=SPEAKER_EMBEDDING,
        emotion=emotion_tensor,
        vqscore_8=vq_tensor,
        fmax=fmax,
        pitch_std=pitch_std,
        speaking_rate=speaking_rate,
        dnsmos_ovrl=dnsmos_ovrl,
        speaker_noised=speaker_noised_bool,
        device=device,
        unconditional_keys=unconditional_keys,
    )
    conditioning = selected_model.prepare_conditioning(cond_dict)

    estimated_generation_duration = 30 * len(text) / 400
    estimated_total_steps = int(estimated_generation_duration * 86)

    def update_progress(_frame: torch.Tensor, step: int, _total_steps: int) -> bool:
        progress((step, estimated_total_steps))
        return True

    codes = selected_model.generate(
        prefix_conditioning=conditioning,
        audio_prefix_codes=audio_prefix_codes,
        max_new_tokens=max_new_tokens,
        cfg_scale=cfg_scale,
        batch_size=1,
        sampling_params=dict(min_p=min_p),
        callback=update_progress,
    )

    wav_out = selected_model.autoencoder.decode(codes).cpu().detach()
    sr_out = selected_model.autoencoder.sampling_rate
    if wav_out.dim() == 2 and wav_out.size(0) > 1:
        wav_out = wav_out[0:1, :]
    return (sr_out, wav_out.squeeze().numpy()), seed


def build_interface():
    supported_models = []
    if "transformer" in ZonosBackbone.supported_architectures:
        supported_models.append("Zyphra/Zonos-v0.1-transformer")

    if "hybrid" in ZonosBackbone.supported_architectures:
        supported_models.append("Zyphra/Zonos-v0.1-hybrid")
    else:
        print(
            "| The current ZonosBackbone does not support the hybrid architecture, meaning only the transformer model will be available in the model selector.\n"
            "| This probably means the mamba-ssm library has not been installed."
        )

    with gr.Blocks() as demo:
        with gr.Row():
            with gr.Column():
                model_choice = gr.Dropdown(
                    choices=supported_models,
                    value=supported_models[0],
                    label="Zonos Model Type",
                    info="Select the model variant to use.",
                )
                text = gr.Textbox(
                    label="Text to Synthesize",
                    value="Zonos uses eSpeak for text to phoneme conversion!",
                    lines=4,
                    max_length=500,  # approximately
                )
                language = gr.Dropdown(
                    choices=supported_language_codes,
                    value="en-us",
                    label="Language Code",
                    info="Select a language code.",
                )
            prefix_audio = gr.Audio(
                value="assets/silence_100ms.wav",
                label="Optional Prefix Audio (continue from this audio)",
                type="filepath",
            )
            with gr.Column():
                speaker_audio = gr.Audio(
                    label="Optional Speaker Audio (for cloning)",
                    type="filepath",
                )
                speaker_noised_checkbox = gr.Checkbox(label="Denoise Speaker?", value=False)

        with gr.Row():
            with gr.Column():
                gr.Markdown("## Conditioning Parameters")
                dnsmos_slider = gr.Slider(1.0, 5.0, value=4.0, step=0.1, label="DNSMOS Overall")
                fmax_slider = gr.Slider(0, 24000, value=24000, step=1, label="Fmax (Hz)")
                vq_single_slider = gr.Slider(0.5, 0.8, 0.78, 0.01, label="VQ Score")
                pitch_std_slider = gr.Slider(0.0, 300.0, value=45.0, step=1, label="Pitch Std")
                speaking_rate_slider = gr.Slider(5.0, 30.0, value=15.0, step=0.5, label="Speaking Rate")

            with gr.Column():
                gr.Markdown("## Generation Parameters")
                cfg_scale_slider = gr.Slider(1.0, 5.0, 2.0, 0.1, label="CFG Scale")
                min_p_slider = gr.Slider(0.0, 1.0, 0.15, 0.01, label="Min P")
                seed_number = gr.Number(label="Seed", value=420, precision=0)
                randomize_seed_toggle = gr.Checkbox(label="Randomize Seed (before generation)", value=True)

        with gr.Accordion("Advanced Parameters", open=False):
            gr.Markdown(
                "### Unconditional Toggles\n"
                "Checking a box will make the model ignore the corresponding conditioning value and make it unconditional.\n"
                'Practically this means the given conditioning feature will be unconstrained and "filled in automatically".'
            )
            with gr.Row():
                unconditional_keys = gr.CheckboxGroup(
                    [
                        "speaker",
                        "emotion",
                        "vqscore_8",
                        "fmax",
                        "pitch_std",
                        "speaking_rate",
                        "dnsmos_ovrl",
                        "speaker_noised",
                    ],
                    value=["emotion"],
                    label="Unconditional Keys",
                )

            gr.Markdown(
                "### Emotion Sliders\n"
                "Warning: The way these sliders work is not intuitive and may require some trial and error to get the desired effect.\n"
                "Certain configurations can cause the model to become unstable. Setting emotion to unconditional may help."
            )
            with gr.Row():
                emotion1 = gr.Slider(0.0, 1.0, 1.0, 0.05, label="Happiness")
                emotion2 = gr.Slider(0.0, 1.0, 0.05, 0.05, label="Sadness")
                emotion3 = gr.Slider(0.0, 1.0, 0.05, 0.05, label="Disgust")
                emotion4 = gr.Slider(0.0, 1.0, 0.05, 0.05, label="Fear")
            with gr.Row():
                emotion5 = gr.Slider(0.0, 1.0, 0.05, 0.05, label="Surprise")
                emotion6 = gr.Slider(0.0, 1.0, 0.05, 0.05, label="Anger")
                emotion7 = gr.Slider(0.0, 1.0, 0.1, 0.05, label="Other")
                emotion8 = gr.Slider(0.0, 1.0, 0.2, 0.05, label="Neutral")

        with gr.Column():
            generate_button = gr.Button("Generate Audio")
            output_audio = gr.Audio(label="Generated Audio", type="numpy", autoplay=True)

        model_choice.change(
            fn=update_ui,
            inputs=[model_choice],
            outputs=[
                text,
                language,
                speaker_audio,
                prefix_audio,
                emotion1,
                emotion2,
                emotion3,
                emotion4,
                emotion5,
                emotion6,
                emotion7,
                emotion8,
                vq_single_slider,
                fmax_slider,
                pitch_std_slider,
                speaking_rate_slider,
                dnsmos_slider,
                speaker_noised_checkbox,
                unconditional_keys,
            ],
        )

        # On page load, trigger the same UI refresh
        demo.load(
            fn=update_ui,
            inputs=[model_choice],
            outputs=[
                text,
                language,
                speaker_audio,
                prefix_audio,
                emotion1,
                emotion2,
                emotion3,
                emotion4,
                emotion5,
                emotion6,
                emotion7,
                emotion8,
                vq_single_slider,
                fmax_slider,
                pitch_std_slider,
                speaking_rate_slider,
                dnsmos_slider,
                speaker_noised_checkbox,
                unconditional_keys,
            ],
        )

        # Generate audio on button click
        generate_button.click(
            fn=generate_audio,
            inputs=[
                model_choice,
                text,
                language,
                speaker_audio,
                prefix_audio,
                emotion1,
                emotion2,
                emotion3,
                emotion4,
                emotion5,
                emotion6,
                emotion7,
                emotion8,
                vq_single_slider,
                fmax_slider,
                pitch_std_slider,
                speaking_rate_slider,
                dnsmos_slider,
                speaker_noised_checkbox,
                cfg_scale_slider,
                min_p_slider,
                seed_number,
                randomize_seed_toggle,
                unconditional_keys,
            ],
            outputs=[output_audio, seed_number],
        )

    return demo


if __name__ == "__main__":
    demo = build_interface()
    share = getenv("GRADIO_SHARE", "False").lower() in ("true", "1", "t")
    server_name = getenv("SERVER_NAME", "0.0.0.0")
    demo.launch(server_name=server_name, share=share)