मैं अपने Xamarin.Forms ऐप से अपने बैकएंड (.net कोर 2.2) में ऑडियो स्ट्रीमिंग लागू करने का प्रयास कर रहा हूं। तब मेरा बैकएंड एज़्योर कॉग्निटिव एपीआई को ऑडियो में आवाज को ट्रांसक्रिप्ट करने के लिए कॉल करेगा और ट्रांसक्रिप्टेड टेक्स्ट के साथ एक स्ट्रिंग वापस करेगा।

जब उपयोगकर्ता बोल रहा हो (जब वह बोलना समाप्त करता है तब नहीं) ट्रांसक्रिप्शन को टेक्स्ट बॉक्स घटक में किया जाना चाहिए और दिखाया जाना चाहिए।

ऑडियो रिकॉर्ड करने और इसे स्ट्रीम में डालने के लिए मैं नैट रिकार्ड के प्लगइन.ऑडियो रिकॉर्डर का उपयोग कर रहा हूं (https:/ /github.com/NateRickard/Plugin.AudioRecorder) और यह अच्छी तरह से काम करता है। मूल रूप से, यह उपयोगकर्ता के बोलते समय ऑडियो के साथ एक स्ट्रीम भरता है और इसे एक फ़ाइल में सहेजता है।

नैट रिकार्ड में एज़्योर कॉग्निटिव सर्विस स्पीचटोटेक्स्ट (https://github.com/NateRickard का उपयोग करके एक और प्लगइन भी है। /Xamarin.Cognitive.Speech)। यह आवाज को पकड़ने के लिए Plugin.AudioRecorder का उपयोग करता है और फिर टेक्स्ट को प्रतिक्रिया के रूप में प्राप्त करने के लिए Azure को ट्रांसक्रिप्शन का अनुरोध करने के लिए एक HttpClient का उपयोग करता है। यह समाधान Xamarin.Forms ऐप में सभी काम करता है और मुझे निम्नलिखित चाहिए:

    1. अनुरोध स्ट्रीम को सीधे Azure को भेजने के बजाय मेरे बैकएंड पर भेजें।
    1. मेरे बैकएंड से Azure को अनुरोध भेजें।
    1. Azure प्रतिक्रिया प्राप्त करें और इसे मेरे Xamarin.Forms ऐप पर वापस भेजें।

दूसरे और तीसरे चरण Xamarin.Cognitive.Speech प्लगइन में लागू किए गए समान हैं। मैं पहले चरण में फंस गया हूं जब मुझे अपने बैकएंड में http अनुरोध को संभालना है। Xamarin.Cognitive.Speech प्लगइन में लागू के रूप में इसमें एक PushStreamContent के साथ एक HttpRequestMessage भेजना, मैंने इसे नीला करने के बजाय इसे अपने बैकएंड पर भेजने के लिए यूआरएल बदल दिया है।

जब मैं ऐप चलाता हूं तो मुझे एक 415 स्थिति कोड (असमर्थित मीडिया प्रकार त्रुटि) मिलता है।

PushStreamContent कैसे बनाया जाता है, इसका नमूना कोड यहां दिया गया है (Xamarin.Cognitive.Speech प्लगइन से कोड):

        HttpContent PopulateRequestContent (Stream audioStream, int? channelCount = null, int? sampleRate = null, int? bitsPerSample = null, Task recordingTask = null, int streamReadDelay = 30)
        {
            const int audioDataWaitInterval = 100; //ms
            const int maxReadRetries = 10; //times

            return new PushStreamContent (async (outputStream, httpContext, transportContext) =>
            {
                try
                {
                    byte [] buffer = null;
                    int bytesRead = 0;
                    int readRetryCount = 0;

                    if (audioStream.CanRead)
                    {
                        var totalWait = 0;

                        //wait up to (audioDataWaitInterval * maxReadRetries) for some data to populate
                        while (audioStream.Length < ChunkSize && totalWait < audioDataWaitInterval * maxReadRetries)
                        {
                            Debug.WriteLine ("No audio data detected, waiting 100 MS");
                            await Task.Delay (audioDataWaitInterval);
                            totalWait += audioDataWaitInterval;
                        }

                        if (channelCount.HasValue && sampleRate.HasValue && bitsPerSample.HasValue)
                        {
                            //write a wav/riff header to the stream
                            outputStream.WriteWaveHeader (channelCount.Value, sampleRate.Value, bitsPerSample.Value);
                        }

                        //read 1024 (BufferSize) (max) raw bytes from the input audio stream
                        buffer = new byte [checked((uint) Math.Min (ChunkSize, (int) audioStream.Length))];

                        //probably a better way to do this... but if the caller has passed a Task in for us to determine the end of recording, we'll use that to see if it's ongoing
                        //  Otherwise, we'll always assume that the Stream is being populated and we'll fall back to using delays to attempt to wait for the end of stream
                        var tcs = new TaskCompletionSource<bool> ();
                        var waitTask = recordingTask ?? tcs.Task;

                        // loop while the stream is being populated... attempt to read <buffer.Length> bytes per loop, and see if we should keep checking, either via Task or read retries (when 0 bytes read)
                        while (audioStream.CanRead &&
                              ((bytesRead = await audioStream.ReadAsync (buffer, 0, buffer.Length)) != 0 || !waitTask.Wait (streamReadDelay)))
                        {
                            if (bytesRead > 0)
                            {
                                readRetryCount = -1;

                                //write the bytes to the output stream
                                await outputStream.WriteAsync (buffer, 0, bytesRead);
                            }

                            readRetryCount++;

                            //again, only using read retry timeouts if we don't have a Task
                            if (recordingTask == null && readRetryCount >= maxReadRetries)
                            {
                                tcs.SetResult (true);
                            }
                        }

                        await outputStream.FlushAsync ();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine (ex);
                    throw;
                }
                finally
                {
                    //must close/dispose output stream to notify that content is done
                    outputStream.Close ();
                }
            }, new MediaTypeHeaderValue (Constants.MimeTypes.WavAudio));
        }

परीक्षण उद्देश्यों के लिए मैं PushContentStream बनाने के लिए एक अतिभारित विधि का उपयोग कर रहा हूँ:
HttpContent PopulateRequestContent (string audioFilePath){...} लेकिन, जैसा कि प्लगइन में है, उपरोक्त का उपयोग किया जाएगा।

मेरे बैकएंड को भेजा गया अनुरोध यहां दिया गया है (Xamarin.Cognitive.Speech प्लगइन से कोड मेरे बैकएंड URL को सेट करने के लिए संशोधित है। मैं अनुरोध बनाने के लिए विधि मापदंडों का उपयोग नहीं करता):

        async Task<string> SendRequest (Func<HttpRequestMessage> requestFactory, Func<HttpContent> contentFactory)
        {
            try
            {
                HttpRequestMessage httpRequest = new HttpRequestMessage(new HttpMethod("POST"), "http://localhost:5000/api/test/v1/speechtotext");

                httpRequest.Headers.TransferEncodingChunked = true;
                httpRequest.Headers.Accept.ParseAdd(Constants.MimeTypes.Json);
                httpRequest.Headers.Accept.ParseAdd(Constants.MimeTypes.Xml);
                httpRequest.Version = HttpVersion.Version11;
                httpRequest.Content = PopulateRequestContent("/storage/emulated/0/Download/audioFile.wav");

                var response = await client.SendAsync(httpRequest, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false);

                if (response != null)
                {
                    // Do stuff
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine ("Error in sendRequest: {0}", ex);
                throw;
            }

            throw new Exception ("SendRequest: Unable to send successful request - unknown error or null response received");
        }

मेरे नियंत्रक वर्ग में मेरा वांछित बैकएंड एंडपॉइंट यहां दिया गया है:

        /// <summary>
        /// Receives stream content from request and calls service to send Azure SpeechToText request.
        /// </summary>
        /// <response code="200"> Ok. Returns transcribed text.</response>
        /// <response code="500">Internal Server Error. The search process ended with error.</response>       
        [HttpPost]
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [Route("/api/test/v1/speechtotext")]
        public async Task<HttpResponseMessage> SpeechToText(HttpRequestMessage requestMessage)
        {
            // TODO: Get request, change URL to azure one and send it (have to see if so easy is possible).
            // OR
            // TODO: Get request, get PushStreamContent from it, build a new request, set the PushStreamContent as HttpContent and send it to azure


            // TODO: Receive azure response and send it back to Xamarin.Forms app.
        }

अधिक सटीक होने के लिए, मैं केवल यह जानना चाहता हूं कि HttpRequestMessage कैसे प्राप्त करें और इससे PushStreamContent प्राप्त करें।

किसी भी मदद की सराहना की जाएगी, अग्रिम धन्यवाद!

0
mgp3952 17 फरवरी 2020, 12:28

1 उत्तर

सबसे बढ़िया उत्तर

निम्न कोड का उपयोग करें अनुरोध में फ़ाइल प्राप्त करें

var httpRequest = HttpContext.Current.Request;
var postedFile =httpRequest.Files[0];
0
Ali 18 फरवरी 2020, 06:46