2.5時間でAzureのバックエンドを使用するWP8、Win8、Androidの音声ショッピングリストのプロトタイプ

11月9日から11日まで、Windows 8 Hackathon RUWOWZAPPが開催されました。最初に参加者として登録した後、専門家としてイベントに参加できたことを光栄に思います。 専門家として、私は多くの素晴らしい人々と彼らのプロジェクトを知るようになります。 とても面白かったので、彼は夜でもアドバイスを続け、4-5時間は睡眠のために残りました。 私は、人々のポジティブでエネルギー、そして作成したいという欲求に非常に感染していたため、自分の小さなプロトタイプアプリケーション、つまり音声認識をサポートするショッピングリストを作成することに抵抗できませんでした。

数時間のうちに、WP、Win8、Androidのクライアントでアプリケーションのアイデアを示す機能的なプロトタイプを作成することができました。



このような粗いプロトタイプを使用したアプリケーションコンペティションには参加したくありませんでしたが、数時間でやったことを見せたかったのです。







このアプリケーションはハッカソンの参加者の間で大きな関心を呼びました。実際、これは私が十分な時間を持っていなかった質問に対するすべての答えを含む約束された記事です。



コードをすぐに見たい人は、 ここからソースをダウンロードできます

そして残りは猫にお願いします。



このビデオとは対照的に、私はパフォーマンス中に急いでいて、アンドロイドバージョンを起動することができませんでした。 主な関心は音声認識の発生方法にあると予想していましたが、他のすべてにはあまり関心がありませんでしたが、次の30分で、数十人の人々がプロジェクトについてさまざまな質問をしました。たとえば、同期の発生方法、分析の発生方法コマンド、アンドロイド用の書き方、サーバー部分の作成内容など。 当時、私は誰にもプロジェクトの出所を示す機会がなかったことをおandびします。実際、この記事では、私が尋ねられたすべての質問に対する答えを約束しました。



アプリケーションのアイデア。



実際、最初はついに最終的にWP8で音声認識を試してみたかったのですが、これは開発者が利用できるようになりました。 そして、私は特にロシア語と友達になるような決断をしたかったのです。

次の一連のコマンドに決めました。



[製品]を購入 -製品をリストに追加

購入[製品] -「購入」チェックマークのインストール

[製品]を削除 -リストから製品を削除します

リストを削除 - リストをクリアします

価格[製品] [価格] -価格の設定

[製品]店舗内[店舗] -製品を購入できる店舗の表示



6時間で3つのプラットフォームでこのようなアプリケーションを作成できると考えました。先を見て、予想よりも時間が短く、最初の4チームしかなかったと言います。



音声認識。 -1時間。



WP8は英語でも非常にうまく機能し、私のアクセントでも認識します。 しかし、ロシア語の認識機能は非常に限られていることが判明しました。 ロシア語の場合、WP8は事前定義された辞書のみを認識します。 私は約30分間それを殺しました。

本当にそれをロシア語にしたかったのですが、すでに音声認識サービスの使用経験があったので、しばらくの間商用音声認識エンジンを台無しにすることにしました。 しかし、私が最後に彼らと仕事をして以来、何も変わっておらず、実際、誰も自動トライアルや有料期間を経験していません。 そして、マネージャーとすべてのサービスと通信する必要があるため、デモのためにGoogleからの音声認識を台無しにすることにしました。 Google音声認識エンジンの使用条件を具体的に検索しましたが、見つかりませんでしたが、どこかで商業目的に使用できないことを見たことを思い出しました(間違っているかもしれませんが)。 優れたC#ソースコードの記事提供してくれたYakhnevに感謝します 。 音声認識用のAPIを使用して、デスクトッププロジェクトからWebプロジェクトを作成するのにたった10分しかかかりませんでした。 しかし、アプリケーションにはファイルをディスクに保存する機能がなく、メモリ内で認識をやり直す時間がなかったため、Azureの無料のWebロールを放棄する必要がありました。 幸いなことに、Azureにいくつかの仮想マシンを既にデプロイしていたため、プロジェクトを作り直してサーバーにアップロードしても問題はありませんでした。 その結果、 voice.akhmed.ru / recognize.ashxアクセスポイントで認識サービスを取得しました。POST要求でWAVファイルを送信し、出力でテキストを取得します。



WP7の申し込み-30分



ほとんどの場合、WP7のアプリケーションにかかっていました。 しかし、このプラットフォームがテストの場であり、開発中にコードを絶えず変更したからです。



音声認識サービスを提起した後、デバイスでの音声認識に関する質問がありました。

機能的なプロトタイプであったため、不要なもの、ユーザー認証、ボタンクリック処理、ダウンロードインジケーター、再送信、エラー処理(アプリケーションが定期的にクラッシュする可能性がある)、データベースへの保存、wavファイルなどをすべて廃棄することにしました。

アプリケーションはAndroidにも移植する必要があるため、MVVMを使用せずにプロトタイプを作成することにしました。そのため、ひどいコードの混乱が発生しました。



WP8専用のアプリケーションを作成する必要がなくなったため、WP7でバージョンを作成することにしました。これにより、追加の利点が得られました。プロトタイプはどのWPデバイスでも動作します。 マイクの録音はWP7でかなり重要な作業ですが、音声をWAVファイルに簡単に録音できるWPExtensionsライブラリを既に持っていました。 AppBarで、彼は手でリストにレコードを追加するためのダミーボタンを1つ追加し、マイク付きのボタンを追加しました。最初に押すと録音を開始し、もう一度押すと録音をサーバーに送信して結果を処理しました。



private bool isRecording = false; private readonly MicrophoneWrapper microphone = new MicrophoneWrapper(); private void ApplicationBarRecordIconButton_Click(object sender, System.EventArgs e) { if (!isRecording) { microphone.Record(); PageTitle.Text= "..."; } else if (isRecording) { microphone.Stop(); var wav = microphone.GetWavContent(); Send(wav); PageTitle.Text = defaultHeader; } isRecording = !isRecording; }
      
      







送信方法も非常に簡単で、サーバーに応答を送信し、受信した応答を処理します



 private void Send(byte[] wav) { var client = new HttpWebClient(); client.Post("http://voice.akhmed.ru/recognize.ashx", wav, (result) => Dispatcher.BeginInvoke(() => ParseString(result))); } private void ParseString(string result) { logicLayer.Parse(result); RefreshView(); }
      
      







コマンドの分析の実行方法、テキスト分析に使用するライブラリの種類、「buy」や「and」などの余分な単語のフィルタリング方法については、多くの質問がありました。 もちろん、このリリースでは、形態素解析と構文解析を使用してはるかに有能な決定を下す必要がありますが、今ではコードは見苦しくなります。 最初の単語をコマンドとして使用し、すべての単語を2文字にフィルター処理します。



 public void Parse(string voiceText) { var words = voiceText.Split(new[]{' '}, StringSplitOptions.RemoveEmptyEntries); if(words.Length>1) { var command = words.First(); if(command.Equals("")) { Add(words.Skip(1)); IncrementUpdate(); } if(command.StartsWith("")) { SetBoughtStatusTrue(words.Skip(1)); IncrementUpdate(); } if (command.Equals("") || command.Equals("")) { if (words[1].Equals("")) { shopList.ShopItems.Clear(); } else { RemoveShopListItems(words.Skip(1)); } IncrementUpdate(); } } }
      
      







アプリケーションバックエンド-20分



他のデバイスとの同期を確保するために、サーバー部分を作成する必要がありました。 もちろん、このようなバックエンドは、AzureでWebロールとしてホストするための理想的な候補ですが、プロトタイプの場合、音声認識と同じAzureの仮想マシンに配置できます。 私たちの時間は非常に限られているため、スタジオはクライアント上でプロキシを迅速に生成できるため、SOAPサービスを作成することは理にかなっています。

また、このサービスは不名誉になりやすいです。 クライアントからサーバーに転送した買い物リストが1つあります(クライアントの場合は、プロキシで生成されます)。



 public class ShopList { public ShopList() { ShopItems=new List<ShopItem>(); } public List<ShopItem> ShopItems { get; set; } public int Version { get; set; } } public class ShopItem { public string Name { get; set; } public decimal Price { get; set; } public char Valute { get; set; } public bool IsBought { get; set; } }
      
      







正直に言うと、PriceとValuteの2つのフィールドは、私はそれらを使用することができなかったので、不要ですが、コードを「そのまま」引用しています。

リストの保存と取得も非常に簡単です。



 public class GroceryService : System.Web.Services.WebService { private LogicLayer logicLayer = new LogicLayer(); [WebMethod] public ShopList GetVersion() { return logicLayer.GetShopList(); } [WebMethod] public void UploadVersion(ShopList request) { logicLayer.Update(request); } }
      
      







もちろん、リリースはリストの完全な更新ではなく、変更されたデータの部分的な更新である必要がありますが、プロトタイプの場合はそうなります。

データベースの現在の値を維持しながら、これはデータベースを持たないプロトタイプであるため、ロジックは非常に簡単に不名誉になります。 正直なところ、そのような論理には意味がありませんでしたが、「現状のまま」引用しています。 メソッド名は失敗しましたが、変更されませんでした。



 public class LogicLayer { private static ShopList shopList = new ShopList(); public ShopList GetShopList() { return shopList; } internal void Update(ShopList newshopList) { shopList = newshopList; } }
      
      





最終的に、私はvoicegrocery.akhmed.ru/GroceryService.asmxでこのサービスを調達しました

質問は、更新を顧客に提供する方法ですか? もちろん、PushNotificationによるものです。 しかし、その実装には多くの時間がかかる可能性があり、それはわずかであり、クライアントから5秒で要求を出しました。



 DispatcherTimer dispathcerTimer = new DispatcherTimer(); dispathcerTimer.Interval = TimeSpan.FromSeconds(5); dispathcerTimer.Tick += dispathcerTimer_Tick; dispathcerTimer.Start();
      
      







クライアントとの間で更新を行うロジックは非常に単純です。

1.現在のバージョンがサーバーから受信したバージョンよりも小さい場合、現在のリストはサーバーのリストに置き換えられます。

2.クライアントで何らかの変更が発生した場合、バージョンが1増加してサーバーに送信されます。



 void dispathcerTimer_Tick(object sender, System.EventArgs e) { var client = new ServiceReference1.GroceryServiceSoapClient(); client.GetVersionCompleted += client_GetVersionCompleted; client.GetVersionAsync(); } void client_GetVersionCompleted(object sender, ServiceReference1.GetVersionCompletedEventArgs e) { if (e.Result.Version > logicLayer.GetVersion()) { logicLayer.UpdateShopList(e.Result); RefreshView(); } } private void IncrementUpdate() { var shopListItem = new ShopList() { Version = shopList.Version + 1, ShopItems = shopList.ShopItems }; var client = new ServiceReference1.GroceryServiceSoapClient(); client.UploadVersionAsync(shopListItem); }
      
      







Windows 8への移植-10分。



アプリケーションをWin8に移植するのは非常に簡単でした。 クライアントに音声認識を実装しなかったため、一方向の同期が行われました。 XAMLは実質的に変更なしでコピーされたため、サーバーへの送信コードを少し修正する必要がありました。 少し簡単になりました-一つの方法で



 async void dispathcerTimer_Tick(object sender, object e) { var client = new ServiceReference1.GroceryServiceSoapClient(); var result = await client.GetVersionAsync(); if (result.Body.GetVersionResult.Version > logicLayer.GetVersion()) { logicLayer.UpdateShopList(result.Body.GetVersionResult); RefreshView(); } }
      
      







Androidへのアプリケーションの移植-15分。





モノラルプラットフォームが大好きです。 コードは事実上変更されておらず、UIを微調整するために残っています。 Androidではプレゼンテーションがはるかに難しいので、カスタムアダプターの作成にあまり時間をかけず、5分後にロールバックし、角かっこで囲まれた単純なテキストリストを作成しました。



 void client_GetVersionCompleted(object sender, ru.akhmed.voicegrocery.GetVersionCompletedEventArgs e) { try { list.Clear(); var result = e.Result.ShopItems; foreach (var item in result) { var checkBox = item.IsBought ? "( X ) " : "( ) "; list.Add(checkBox + item.Name); } this.RunOnUiThread(() => { this.ListAdapter = new ArrayAdapter<string>(this, Resource.Layout.ListItem, list); ((BaseAdapter)this.ListAdapter).NotifyDataSetChanged(); }); } catch (Exception) { } }
      
      







iOSへの移植-なし



もちろん、iOSに移植することを考えていましたが、ホーム開発で使用しているiデバイスとハックイントッシュがないため、このようなイベントで表示するのは間違っており、このアイデアを延期するのに時間がかかりませんでした。 特に私とラップトップ上で私はハッキントッシュを持っていませんでした



まとめ



WP8プラットフォームの機能の調査に費やした40分を考慮しない場合、サーバーへのアップロードのコストと小さなバグ修正を考慮して、わずか2時間以内に、アプリケーションの主要なアイデアを示す本格的なプロトタイプが実装され、それを捨てて本格的な実装に進むことは残念です。

もちろん、コードは非常に汚く、最適ではなく、多数の欠陥と未完成の機能がありました。 しかし、機能的なプロトタイプが必要なのは「紙のスケッチ」を作成するためだけです。ドラフトでは、顧客/上司に最終製品を提示します。



All Articles