質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C#

    7147questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • REST

    137questions

    REST(Representational State Transfer)はwebアプリケーションの構築スタイルの一種です。HTTP GET/POSTによってリクエストを送信し、レスポンスはXMLで返されます。SOAPのようなRPCの構築と比べるとサーバからクライアントを分離することが出来る為、人気です。

  • Watson

    28questions

    Watsonは、IBMが開発した質問応答・意思決定支援を行うシステムです。人口知能と言われることもあるが、IBMは自然言語処理と機械学習を用いて人間の意思決定を支援するコグニティブコンピューティングプラットホームと呼んでいます。

Watson の speech to text を HTTP REST で呼び出す方法

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,918

rhas

score 2

前提・実現したいこと

【IBM Watson音声認識のAPI呼び出し】
IBM Watson の HTTP REST API で speech to text の recognize を呼び出したいです。
呼び出す部分の処理はC#で書いてます。
sessionの作成はできていて、Responseは正常に返ってきました。
(以下のURLにsession_idが入った状態で返ってきました。)
"recognize": "https://stream.watsonplatform.net/speech-to-text/api/v1/sessions/<session_id>"
を使用してAPI呼び出しをしています。

Watson の Speech to text を REST API で呼び出すときに必要なヘッダやパラメータ、音声データの渡し方等ご指摘いただきたいです。

発生している問題・エラーメッセージ

リモートサーバーがエラーを返しました:(401) 許可されていません

該当のソースコード

String url = "https://stream.watsonplatform.net/speech-to-text/api/v1/sessions/<session_id>";

Dictionary<string, object> param = new Dictionary<string, object>();

// byte[] data  
param.Add("data", new FileParameter(data, "","audio/ogg;codec=opus"));

HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
CreateRequestHeaders(wr, m_username, m_passwrd, "POST", null);
wr.Proxy = GetWebProxy();
wr.ContentLength = size;

using (Stream rs = wr.GetRequestStream())
{
    rs.Write(data, 0, size);
    rs.Close();
}

HttpWebResponse wres;
try
{
    wres = wr.GetResponse() as HttpWebResponse;
}
catch (WebException webEx)
{
    Loggers.Output.Error(webEx.ToString());
}

試したこと

リクエストに必要なヘッダやパラメータに過不足があるのではないかと思い、色々と試しましたが、状況は変わりませんでした。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

+1

Watsonさわったことなくて興味があったので回答しようと試したのですが、...
オチから言うと
「WebSocketでやってもうた...Sessionの方を質問していたのか...」です。

Sessionでのやり方は試していないので回答にはなりませんが、
WebSocketはドキュメント通りやれば素直にできたので参考程度に書いておくと....

C#のClientWebSocketクラスを使ってます。
Basic認証でtoken取得(本家ドキュメントのここらへん)をして、
socketをConnectionを開く→
openのメッセージを投げる("action": "start","content-type": *, "continuous": true, "interim_results": trueあたり。***は投げるデータのタイプを...)→
あとは音声を投げれば(本家ドキュメントのここあたり)簡単にテキストが取得できました。

WebSocketクラスでもできるとは思いますが、私の興味のままに..使ったことのないClientWebSocketでやってます....)

参考程度にコードを。。。(雑実装な点は触れずに頂けると...)
マイク使って音とるほど興味はなかったので、音声データ(wavファイル)のパスを指定して音声を送信→Consoleにテキストを表示するものです。

Consoleのアプリ作って以下のクラスをnewして、wavファイルのパスを指定してSendAudioFileAsyncメソッドを呼べば、コンソールにテキストが表示されます。

using Newtonsoft.Json;
using System;
using System.IO;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WatsonDemo
{
    public class SpeechToText
    {
        #region variables

        private const string Password = "*****passwordを入力****";
        private const string UserName = "******usernameを入力******";

        private const string JajpModelString = "ja-JP_BroadbandModel";
        private const string SpeechToTextEndpoint = @"wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-token={0}&model={1}";

        private static readonly Uri AuthEndpointUri = new Uri(@"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api");

        private static readonly ArraySegment<byte> OpenMessage = new ArraySegment<byte>(Encoding.UTF8.GetBytes("{\"action\": \"start\", \"content-type\": \"audio/wav\", \"continuous\" : true, \"interim_results\": true}"));
        private static readonly ArraySegment<byte> CloseMessage = new ArraySegment<byte>(Encoding.UTF8.GetBytes("{\"action\": \"stop\"}"));

        #endregion

        //classをnewしてこのメソッド呼べば動きます。
        //今回は、音声データ(wav)のファイルパスを指定する想定で書いてます。
        public async Task SendAudioFileAsync(string filePath)
        {
            var token = await GetAuthTokenAsync(UserName, Password);
            var uri = GetUri(token, JajpModelString);

            var socket = new ClientWebSocket();
            // socket open
            await socket.ConnectAsync(uri, CancellationToken.None);
            // open message send
            await Task.WhenAll(socket.SendAsync(OpenMessage, WebSocketMessageType.Text, true, CancellationToken.None), HandleCallback(socket));
            // send audio
            await Task.WhenAll(SendAudioToWatson(socket, filePath), HandleCallback(socket));

            await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None);

        }

        private static async Task SendAudioToWatson(ClientWebSocket client, string filePath)
        {
            using (var fileStream = File.OpenRead(filePath))
            {
                var bytes = new byte[1024];
                while (fileStream.Read(bytes, 0, bytes.Length) > 0)
                {
                    await client.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Binary, true, CancellationToken.None);
                }
                await client.SendAsync(CloseMessage, WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }


        private static async Task HandleCallback(ClientWebSocket socket)
        {
            var buffer = new byte[1024];
            while (true)
            {
                var segment = new ArraySegment<byte>(buffer);
                var result = await socket.ReceiveAsync(segment, CancellationToken.None);

                if (result.MessageType == WebSocketMessageType.Close) return;

                var count = result.Count;
                while (!result.EndOfMessage)
                {
                    if (count >= buffer.Length)
                    {
                        await socket.CloseAsync(WebSocketCloseStatus.InvalidPayloadData, "count >= buffer.Length!!!!!", CancellationToken.None);
                        return;
                    }

                    segment = new ArraySegment<byte>(buffer, count, buffer.Length - count);
                    result = await socket.ReceiveAsync(segment, CancellationToken.None);
                    count += result.Count;
                }

                var message = Encoding.UTF8.GetString(buffer, 0, count);
                // logging
                Console.WriteLine(message);

                if (IsDelimeter(message)) return;
            }


        }

        private static bool IsDelimeter(string json) => JsonConvert.DeserializeObject<dynamic>(json).state == "listening";

        private static async Task<string> GetAuthTokenAsync(string user, string pass)
        {
            var credential = Encoding.UTF8.GetBytes($"{user}:{pass}");
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(credential));
                var response = await client.GetAsync(AuthEndpointUri);

                return await response.Content.ReadAsStringAsync();
            }
        }

        private static Uri GetUri(string token, string model) => new Uri(string.Format(SpeechToTextEndpoint, token, model));
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/25 08:29

    websocket では send でバイナリデータを送信するのですね・・・!
    REST ではリクエストボディに音声データを含めればいいかと思ってるのですが、いまだうまくいかず。。
    もう少し検討してみます。
    ご回答ありがとうございました!

    キャンセル

  • 2017/01/25 09:00 編集

    音声データを扱う場合、大きなデータまたはリアルタイムに一定時間データを送信し続けることが想定されるため、socketを使うのが現時点ではベターという世の中の流れです。そのため、音声系のサービスはwssを提供してることが多く、素直にそれを使うのがプラクティスとしてベターだと思います。
    また、C#的な話をさせていただくと、有名な流れではありますがWebRequestは機能的にDeadなので...HttpClient使って非同期処理を行った方がよいかと思います。(...と余計な情報ばかり提供してしまっていますね....すいません)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    7147questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • REST

    137questions

    REST(Representational State Transfer)はwebアプリケーションの構築スタイルの一種です。HTTP GET/POSTによってリクエストを送信し、レスポンスはXMLで返されます。SOAPのようなRPCの構築と比べるとサーバからクライアントを分離することが出来る為、人気です。

  • Watson

    28questions

    Watsonは、IBMが開発した質問応答・意思決定支援を行うシステムです。人口知能と言われることもあるが、IBMは自然言語処理と機械学習を用いて人間の意思決定を支援するコグニティブコンピューティングプラットホームと呼んでいます。