前回はエックスサーバーにMecabをインストールしてASP.Net Core で形態素解析の処理をおこないました。今回は他のページからでもこれを利用できるようにします。そのためにはこれをAPIとして公開します。そのあとJavaScriptを使って形態素解析をしてその結果を表示させます。
Contents
単純なWeb APIを作る
まずはASP.NET Coreでもっとも単純なWeb API を作るところからはじめます。
文字列をPostしたらそれをそのまま返すAPIを作ります。
まずApiクラスを定義します。
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
class Api { public static void Test(WebApplication app) { app.MapPost("/api-test", (TestRequestBody body) => { if (body.Sentence == null) { return Results.Ok(new TestResponse { Sentence = "", Result = $"エラー:Sentenceが設定されていません", }); } return Results.Ok(new TestResponse { Sentence = body.Sentence, Result = $"「{body.Sentence}」を返します", }); }); } // リクエストとレスポンス class TestRequestBody { public string Sentence { get; set; } } class TestResponse { public string Sentence { get; set; } public string Result { get; set; } } } |
Program.cs
1 2 3 4 |
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); Api.Test(app); app.Run(); |
実際に別のコンソールアプリケーションを作成して動作テストをしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System.Net.Http.Json; HttpClient client = new HttpClient(); HttpResponseMessage response = await client.PostAsJsonAsync( "http://localhost:5000/api-test", // 5000の部分は各自の適切な番号に変更する new RequestBody { Sentence = "APIのテストをする" } ); if (response.IsSuccessStatusCode) { // jsonテキストを取得する var json = await response.Content.ReadAsStringAsync(); Console.WriteLine(json); // Resultの部分だけ取得したいなら以下の方法で取得できる Response testResponse = await response.Content.ReadFromJsonAsync<Response>(); Console.WriteLine(testResponse.Result); } class RequestBody { public string Sentence { get; set; } } class Response { public string Sentence { get; set; } public string Result { get; set; } } |
Mecabで形態素解した結果を取得できるAPIを公開する
本番はここからです。Mecabで解析した結果を取得できるようにします。
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); Api.Mecab(app); app.Run(); class Api { static MeCabTagger? _mecab = null; public static void Mecab(WebApplication app) { app.MapPost("/mecab-api", (MecabRequestBody body) => { if (body.Sentence == null) { return Results.Ok(new MecabResponse { Sentence = "", Result = $"エラー:Sentenceが設定されていません", }); } if (_mecab == null) { // ローカルでテストするとき string path = "C:\\Program Files (x86)\\MeCab\\dic\\ipadic"; // サーバー上に公開するときはmecabをインストールしたパスを指定する path = "/home/<アカウント名>/opt/mecab/lib/mecab/dic/ipadic"; _mecab = MeCabTagger.Create(new MeCabParam { DicDir = path, }); } return Results.Ok(new MecabResponse { Sentence = body.Sentence, Result = _mecab.Parse(body.Sentence), }); }); } // リクエストとレスポンス class MecabRequestBody { public string Sentence { get; set; } } class MecabResponse { public string Sentence { get; set; } public string Result { get; set; } } } |
別のコンソールアプリケーションを作成して動作テストをしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using System.Net.Http.Json; HttpClient client = new HttpClient(); HttpResponseMessage response = await client.PostAsJsonAsync( "http://localhost:5000/mecab-api", new MecabRequestBody { Sentence = "スモモも桃も桃のうち" } ); if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); Console.WriteLine(json); } // リクエストとレスポンス class MecabRequestBody { public string Sentence { get; set; } } class MecabResponse { public string Sentence { get; set; } public string Result { get; set; } } |
実行結果
1 2 3 4 |
{ "sentence":"スモモも桃も桃のうち", "result":"スモモ\t名詞,一般,*,*,*,*,スモモ,スモモ,スモモ\r\nも\t助詞,係助詞,*,*,*,*, も,モ,モ\r\n桃\t名詞,一般,*,*,*,*,桃,モモ,モモ\r\nも\t助詞,係助詞,*,*,*,*,も,モ,モ\r\n桃\t名詞,一般,*,*,*,*,桃,モモ,モモ\r\nの\t助詞,連体化,*,*,*,*,の,ノ,ノ\r\nうち\t名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ\r\nEOS\r\n" } |
ところで上記はローカルで実験したときの結果です。サーバー上で実行すると改行は\r\nではなく\nになっています。
自作APIで形態素解析をする
これをweb上で使ってみましょう。
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Mecabで形態素解析(自作API)</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> #container { margin: 50px; width: 100%; max-width: 600px; } .button { width: 100px; margin-top: 20px; } td { border:1px solid #333; padding:5px; } </style> </head> <body> <div id = "container"> <p>Mecabと自作APIで形態素解析をおこないます。</p> <div><textarea id="text" rows="10" cols="50"></textarea></div> <div> <button type="button" class ="button" onclick="OnClick()">解析</button> <button type="button" class ="button" onclick="Clear()">クリア</button> </div> <div id="result"> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="app.js"></script> </body> </html> |
クロスオリジン要求を有効にする
ところでこのままでは処理はおこなわれません。
クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、http://localhost:5000/Mecab-Api にあるリモートリソースの読み込みは拒否されます
上のようなエラーが出ます。そこでこれを解決するためにクロスオリジン要求 (CORS) を有効にする処理をおこないます。
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy(name: "MecabOrigins", policy => { policy.WithOrigins("https://lets-csharp.com").AllowAnyHeader(); }); }); var app = builder.Build(); app.UseCors("MecabOrigins"); Api.Mecab(app); app.Run(); |
クライアントサイドにおける処理
[クリア]ボタンを押したらテキストエリアにある文字列をクリアするとともに表示されている形態素解析の結果を消去します。
1 2 3 4 |
function Clear(){ document.getElementById('text').value = ''; document.getElementById('result').innerText = ''; } |
[解析]ボタンを押したらテキストエリアにある文字列を取得して、これをJSONに変換してAPIのエンドポイントにPost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
function OnClick(){ let text = document.getElementById('text').value; let obj = { "sentence":text } var json_text = JSON.stringify(obj); jQuery.ajax({ type:"post", url:"http://localhost:5000/Mecab-Api", // POST送信先のURL data:json_text, // JSONデータ本体 contentType: 'application/json', // リクエストの Content-Type dataType: "json", // レスポンスをJSONとしてパースする success: function(data) { // 200 OK時 ShowResult(data.result); }, error: function() { // HTTPエラー時 alert("失敗:Server Error."); } }); } function ShowResult(result){ document.getElementById('result').innerText = ''; let words = result.split('\n'); let html = ''; html += '<table>'; html += `<tr>`; html += `<td>単語</td>`; html += `<td>原型</td>`; html += `<td>品詞名</td>`; html += `</tr>`; for(let i=0; i<words.length; i++){ let texts1 = words[i].split('\t'); if(texts1.length < 2) // 終わり continue; if(texts1[0] == '') // 改行 continue; console.log(texts1[1]); let texts2 = texts1[1].split(','); if (texts2.length < 7) // 原型が取得できない場合 continue; html += `<tr>`; html += `<td>${texts1[0]}</td>`; html += `<td>${texts2[6]}</td>`; html += `<td>${texts2[0]}</td>`; html += `</tr>`; } html += '</table>'; document.getElementById('result').innerHTML = html; } |