Нет ответа на запрос HTTP Get в WebAPI в .NET 4.5 при использовании SpeechSynthesis для преобразования текста в речь

Я пытаюсь настроить простой веб-сервис с помощью WebAPI. Вот что у меня есть для кода:

public class SpeakController : ApiController
    {
        //
        // api/speak

        public HttpResponseMessage Get(String textToConvert, String outputFile, string gender, string age = "Adult")
        {
            VoiceGender voiceGender = (VoiceGender)Enum.Parse(typeof(VoiceGender), gender);
            VoiceAge voiceAge = (VoiceAge)Enum.Parse(typeof(VoiceAge), age);

            using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
            {
                synthesizer.SelectVoiceByHints(voiceGender, voiceAge);
                synthesizer.SetOutputToWaveFile(outputFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
                synthesizer.Speak(textToConvert);
            }

            return Request.CreateResponse(HttpStatusCode.OK, new Response { HttpStatusCode = (int)HttpStatusCode.OK, Message = "Payload Accepted." });
        }
    }

Код довольно прост и ни в коем случае не готов к работе. Но в своих тестах я заметил, что при любом запросе к контроллеру происходит следующее:

  • WAV-файл успешно сгенерирован
  • во время отладки я вижу возврат элемента управления и выход из метода
  • однако мой браузер просто продолжает вращаться, и я никогда не получаю ответа от сервера

Я попробовал то же самое с Postman (клиент REST для Chrome) и получил тот же результат. Хотя я действительно хочу, чтобы это был блокирующий вызов, в интересах попробовать другие вещи я изменил synthesizer.Speak на synthesizer.SpeakAsync и столкнулся с той же проблемой.

Однако, когда я тестирую фрагменты по отдельности, как показано ниже, код работает так, как ожидалось.

Тестирование вызова WebAPI с закомментированным разделом речи:

public class SpeakController : ApiController
{
    //
    // api/speak

    public HttpResponseMessage Get(String textToConvert, String outputFile, string gender, string age = "Adult")
    {
        VoiceGender voiceGender = (VoiceGender)Enum.Parse(typeof(VoiceGender), gender);
        VoiceAge voiceAge = (VoiceAge)Enum.Parse(typeof(VoiceAge), age);

        //using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
        //{
        //  synthesizer.SelectVoiceByHints(voiceGender, voiceAge);
        //  synthesizer.SetOutputToWaveFile(outputFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
        //  synthesizer.Speak(textToConvert);
        //}

        return Request.CreateResponse(HttpStatusCode.OK, new Response { HttpStatusCode = (int)HttpStatusCode.OK, Message = "Payload Accepted." });
    }
}

Отдельное тестирование речи в консольном приложении:

static string usageInfo = "Invalid or no input arguments!"
    + "\n\nUsage: initiatives \"text to speak\" c:\\path\\to\\generate.wav gender"
    + "\nGender:\n\tMale or \n\tFemale"
    + "\n";

static void Main(string[] args)
{
    if (args.Length != 3)
    {
        Console.WriteLine(usageInfo);
    }
    else
    {
        ConvertStringToSpeechWav(args[0], args[1], (VoiceGender)Enum.Parse(typeof(VoiceGender), args[2]));
    }

    Console.WriteLine("Press any key to continue...");
    Console.ReadLine();
}

static void ConvertStringToSpeechWav(String textToConvert, String pathToCreateWavFile, VoiceGender gender, VoiceAge age = VoiceAge.Adult)
{
    using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
    {
        synthesizer.SelectVoiceByHints(gender, age);
        synthesizer.SetOutputToWaveFile(pathToCreateWavFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
        synthesizer.Speak(textToConvert);
    }
}

WebAPI и SpeechSynthesis, похоже, плохо сочетаются друг с другом. Любая помощь в выяснении этого будет принята с благодарностью.

Спасибо!


person k427h1c    schedule 23.02.2013    source источник
comment
В каком месте находится ваш pathToCreateWavFile (локальный диск, сеть, какой формат пути), в частности, есть ли у вашего пула приложений для IIS разрешение на запись в эту папку?   -  person Mark Jones    schedule 24.02.2013
comment
Поскольку я тестирую это на своей машине для разработки, путь локальный. В частности, `C:\temp`. И да, я не думаю, что это проблема с разрешением, потому что WAV успешно сгенерирован. Что бы это ни стоило, Visual Studio 2012 поставляется с IISExpress.   -  person k427h1c    schedule 24.02.2013
comment
Хорошо, очевидно, что если файл полностью сгенерирован, это не проблема - просто подумал, что нужно проверить :-)   -  person Mark Jones    schedule 24.02.2013


Ответы (1)


Я понятия не имею, почему это происходит, но запуск вашего SpeechSynthesizer в отдельном потоке, кажется, помогает (несовместимая модель потоков?). Вот как я делал это в прошлом.

На основе: сверхбыстрого преобразования текста в речь (WAV -› MP3) в ASP.NET MVC

public dynamic Post(dynamic req)
{
    try 
    {
        string phrase = req["phrase"].Value;

        var stream = new MemoryStream();
        var t = new System.Threading.Thread(() =>
            {
                using (var synth = new SpeechSynthesizer())
                {
                    synth.SetOutputToWaveStream(stream);
                    synth.Speak(phrase);
                    synth.SetOutputToNull();
                }
            });

        t.Start();
        t.Join();

        stream.Position = 0;

        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StreamContent(stream);

        resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        resp.Content.Headers.ContentDisposition.FileName = "phrase.wav";

        return resp;
    }
    catch
    {
        return new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }
}
person Curtis Badke    schedule 18.11.2013
comment
Обычно лучше копировать соответствующую информацию в свой пост, а не просто размещать ссылку. В случае, если ссылка умрет, ваша информация не исчезнет. Затем вы можете поместить его в лучший контекст для ответа, чтобы улучшить его качество. - person crthompson; 19.11.2013
comment
Спасибо за ссылку! Ответ Наримана в обновлении № 2 полностью работает для меня. - person k427h1c; 02.07.2014