'The Task'
I need you to make me a Unity Editor script that allows me to change all these params

'Params List'
- string _url.
- string _text.
- string _apiKey.
- string _format.
- chunkLength.
- maxNewTokens.
- topP.
- temperature.
- repetitionPenalty.
- seed.
- referenceTexts.
- referenceAudios.
- outputFilePath.

'Extra Task Info'
I need you to make the editor script be able to show a logo and under that all the settings for the params and a Generate button as well as a Boot OAS1M button.

'Example of generation button (this is not unity code just an example)'
public async Task GimmieFish(string xmessage, bool PreviewMode)
{
    // Load voice file
    byte[] referenceVoiceBytes;
    try
    {
        referenceVoiceBytes = await File.ReadAllBytesAsync(Reference_Voice).ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Error reading voice file: {ex.Message}");
        return;
    }

    var referenceTexts = new List<string> { Reference_Text };

    var client = new TTSClient(
        url: "http://127.0.0.1:8032/v1/tts",
        text: xmessage,
        apiKey: "YOUR_API_KEY",
        referenceTexts: referenceTexts,
        referenceAudios: new List<byte[]> { referenceVoiceBytes },
        chunkLength: Chunk_Length,
        topP: Top_P,
        temperature: Temperature,
        seed: GenerateRandomSeed(),
        maxNewTokens: Max_Tokens,
        repetitionPenalty: Repetition_Penalty
    );

    var (success, message) = await client.SendRequestAndSaveAudioAsync().ConfigureAwait(false);

    if (!success)
    {
        MessageBox.Show($"TTS Error: {message}");
        return;
    }

    audioFilePath = message;
    duration = GetWaveFileDuration(audioFilePath);

    // --- Fix starts here ---
    int selectedIndex = 0;

    // Safely get SelectedIndex from comboBoxOutputDevices
    if (comboBoxOutputDevices.InvokeRequired)
    {
        selectedIndex = (int)comboBoxOutputDevices.Invoke(new Func<int>(() => comboBoxOutputDevices.SelectedIndex));
    }
    else
    {
        selectedIndex = comboBoxOutputDevices.SelectedIndex;
    }

    // Assign OutDev based on PreviewMode and selected index
    OutDev = PreviewMode
        ? Previews.SelectedIndex
        : (selectedIndex >= 0 ? selectedIndex : 0);
    // --- Fix ends here ---
}

'Example of Boot Button (this is not unity code just an example)'
private void sTARTToolStripMenuItem_Click(object sender, EventArgs e)
{
    string command = "cd ~/fish-speech && conda activate fish-speech && python -m tools.api_server --listen 0.0.0.0:8032 --llama-checkpoint-path \"checkpoints/openaudio-s1-mini\" --decoder-checkpoint-path \"checkpoints/openaudio-s1-mini/codec.pth\" --decoder-config-name modded_dac_vq --compile";

    ProcessStartInfo psi = new ProcessStartInfo
    {
        FileName = "wt.exe",
        Arguments = $"wsl -e bash -li -c \"{command}\"",
        UseShellExecute = true
    };

    try
    {
        Process.Start(psi);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Failed to launch WSL command: " + ex.Message);
    }
}


'the main class'
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

public class TTSClient
{
    private readonly string _url;
    private readonly string _text;
    private readonly string _apiKey;
    private readonly string _format;
    private readonly int _chunkLength;
    private readonly int _maxNewTokens;
    private readonly float _topP;
    private readonly float _temperature;
    private readonly float _repetitionPenalty;
    private readonly int? _seed;
    private readonly List<string> _referenceTexts;
    private readonly List<byte[]> _referenceAudios;
    private readonly string _outputFilePath;

    [Serializable]
    private class ReferenceObject
    {
        public string text;
        public string audio;
    }

    [Serializable]
    private class RequestData
    {
        public string text;
        public List<ReferenceObject> references;
        public bool normalize;
        public string format;
        public int max_new_tokens;
        public int chunk_length;
        public float top_p;
        public float repetition_penalty;
        public float temperature;
        public bool streaming;
        public string use_memory_cache;
        public int seed;
    }

    public TTSClient(
        string url,
        string text,
        string apiKey,
        List<string> referenceTexts,
        List<byte[]> referenceAudios,
        string format = "wav",
        int chunkLength = 0,
        float topP = 0.9f,
        float temperature = 0.9f,
        int? seed = 0,
        int maxNewTokens = 0,
        float repetitionPenalty = 1.1f,
        string outputFilePath = null)
    {
        _url = url ?? throw new ArgumentNullException(nameof(url));
        _text = text ?? throw new ArgumentNullException(nameof(text));
        _apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey));
        _referenceTexts = referenceTexts ?? throw new ArgumentNullException(nameof(referenceTexts));
        _referenceAudios = referenceAudios ?? throw new ArgumentNullException(nameof(referenceAudios));
        _format = format;
        _chunkLength = chunkLength;
        _topP = topP;
        _temperature = temperature;
        _seed = seed;
        _maxNewTokens = maxNewTokens;
        _repetitionPenalty = repetitionPenalty;

        // Default output file path if none specified (Unity persistentDataPath)
        _outputFilePath = outputFilePath ?? System.IO.Path.Combine(Application.persistentDataPath, $"output.{_format}");
    }

    /// <summary>
    /// Sends the TTS request and saves the audio file.
    /// </summary>
    /// <returns>Tuple indicating success and message or saved file path.</returns>
    public async Task<(bool success, string message)> SendRequestAndSaveAudioAsync()
    {
        try
        {
            var requestData = new RequestData
            {
                text = _text,
                references = CreateReferenceObjects(),
                normalize = true,
                format = _format,
                max_new_tokens = _maxNewTokens,
                chunk_length = _chunkLength,
                top_p = _topP,
                repetition_penalty = _repetitionPenalty,
                temperature = _temperature,
                streaming = false,
                use_memory_cache = "on",
                seed = _seed ?? 0
            };

            string json = JsonUtility.ToJson(requestData);

            using UnityWebRequest uwr = new UnityWebRequest(_url, "POST");
            byte[] jsonToSend = Encoding.UTF8.GetBytes(json);
            uwr.uploadHandler = new UploadHandlerRaw(jsonToSend);
            uwr.downloadHandler = new DownloadHandlerBuffer();
            uwr.SetRequestHeader("Content-Type", "application/json");
            uwr.SetRequestHeader("Authorization", $"Bearer {_apiKey}");

            var operation = uwr.SendWebRequest();

#if UNITY_2020_1_OR_NEWER
            while (!operation.isDone)
                await Task.Yield();
#else
            // Fallback for older versions - NOT recommended, but kept for compatibility
            await Task.Run(() =>
            {
                while (!operation.isDone) { }
            });
#endif

            if (uwr.result != UnityWebRequest.Result.Success)
            {
                string errorMsg = uwr.error;
                if (!string.IsNullOrEmpty(uwr.downloadHandler.text))
                    errorMsg += " - " + uwr.downloadHandler.text;
                return (false, $"Request failed: {errorMsg}");
            }

            byte[] audioData = uwr.downloadHandler.data;

            try
            {
                System.IO.File.WriteAllBytes(_outputFilePath, audioData);
                return (true, _outputFilePath);
            }
            catch (Exception ex)
            {
                return (false, $"Failed to save audio: {ex.Message}");
            }
        }
        catch (Exception ex)
        {
            return (false, $"Exception during request: {ex.Message}");
        }
    }

    private List<ReferenceObject> CreateReferenceObjects()
    {
        int count = Math.Min(_referenceTexts.Count, _referenceAudios.Count);
        var refs = new List<ReferenceObject>(count);

        for (int i = 0; i < count; i++)
        {
            string base64Audio = _referenceAudios[i] != null && _referenceAudios[i].Length > 0
                ? Convert.ToBase64String(_referenceAudios[i])
                : null;
            refs.Add(new ReferenceObject
            {
                text = _referenceTexts[i],
                audio = base64Audio
            });
        }

        return refs;
    }
}

'End notes'
Please provide entire scripts and save tokens by not explaining anything.