himanago

Azure・C#などのMS系技術やLINE関連技術など、好きな技術について書くブログ

【GitHub Codespaces + LINE OpenAPI + azd】最新の機能をサポートした C# SDK で LINE Bot 開発が始められるテンプレートを改良しました

昨年末、アドベントカレンダー記事用に実験的に「GitHub Codespaces + LINE OpenAPI による C# での LINE Bot 開発がすぐ始められるテンプレート」を作っていました。 himanago.hatenablog.com

明日このハンズオンイベントをやるので(準備がギリギリすぎる)

linedevelopercommunity.connpass.com

ここで使えるように以前の課題を克服してある程度使えるように改良してみました!

今回作ったテンプレートリポジトリ

こちら。使い方は README に簡単に書きました。

最新の LINE Messaging API の機能をサポートした SDK で開発が始められます。

github.com

改善点

Azure Developer CLI (azd) & Bicep 対応

今回一番やりたかったことですが、最初に azd up すれば一発でオウム返ししてくれる LINE Bot のバックエンド(Azure Functions)が Azure 上にデプロイされます!

LINE のチャネルアクセストークンも azd up 実行時のパラメータとして受け取って、Key Vault に格納するように組んでいるので、使い勝手もよいかと思います。

.NET 8 isolated → .NET 6 in-process への変更

以前作ったものでは .NET 8 isolated になってしまっていました。

Azure Functions の .NET 8 isolated のコードはいままでの書き方とだいぶ違っていたりして作りにくい感じだったのですが、今回は .NET 6 in-process に変更1。だいぶ作りやすくなったかと思います。

もうすぐ .NET 8 in-process が出るとのことなので、そちらが出たらアップグレードしようと思います。

関数コードの改良

DI で MessagingApiApi をもらってくるようにしたので、関数のクラスのコードがちょっとすっきりできたかなと思います。

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using LineOpenApi.MessagingApi.Api;
using LineOpenApi.MessagingApi.Model;
using LineOpenApi.Webhook.Model;
using System.Collections.Generic;

namespace LineBotFunctions;
public class WebhookEndpoint
{
    private IMessagingApiApiAsync Api { get; }

    public WebhookEndpoint(IMessagingApiApiAsync api)
    {
        Api = api;
    }

    [FunctionName("WebhookEndpoint")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# webhook endpoint function processed a request.");

        try
        {
            var body = await new StreamReader(req.Body).ReadToEndAsync();
            var callbackRequest = JsonConvert.DeserializeObject<CallbackRequest>(body);

            foreach (var ev in callbackRequest.Events)
            {
                // echo when receive text message
                if (ev is MessageEvent messageEvent && messageEvent.Message is TextMessageContent textMessageContent)
                {
                    var replyMessageRequest = new ReplyMessageRequest(messageEvent.ReplyToken, new List<Message>
                    {
                        new TextMessage(textMessageContent.Text)
                        {
                            Type = "text"
                        }
                    });
                    await Api.ReplyMessageAsync(replyMessageRequest);
                }
            }
        }
        catch (Exception e)
        {
            log.LogError($"Error: {e.Message}");
            log.LogError($"Error: {e.StackTrace}");
        }
        
        return new OkObjectResult("OK");
    }
}

Webhook で受け取る JSON のデシリアライズがうまくいかない件の対応&最新化対応

以前の記事にも書いたのですが、不要な行が OpenAPI Generator で生成した SDK の一部ファイルに含まれています。

そこで、シェルスクリプトでその行を一気に削除するようにしました。

この処理は SDK の生成とあわせてひとつのファイルにまとめ、再実行により常に最新のものにアップデートできるようにしています。

if [ -d "./sdk" ]; then
    rm -rf ./sdk
fi

npx @openapitools/openapi-generator-cli generate -i https://raw.githubusercontent.com/line/line-openapi/main/messaging-api.yml -o sdk -g csharp --additional-properties=netCoreProjectFile=true,targetFramework=netstandard2.1,library=httpclient,packageName=LineOpenApi.MessagingApi

npx @openapitools/openapi-generator-cli generate -i https://raw.githubusercontent.com/line/line-openapi/main/webhook.yml -o sdk -g csharp --additional-properties=netCoreProjectFile=true,targetFramework=netstandard2.1,library=httpclient,packageName=LineOpenApi.Webhook

find ./sdk/src/LineOpenApi.Webhook/Model/ -type f | while read file; do
    if ! grep -q ": IEquatable<" "$file"; then
        sed -i '/\[JsonConverter(typeof(JsonSubtypes), "Type")\]/d' "$file"
    fi
done

まとめ

まだオウム返ししか試せてないですが、明日のハンズオンでやりたい機能なども検証しつつハンズオン用のテンプレートも作っていこうと思います。

今回のテンプレートはハンズオンでもわりと使いやすいと思うので、今後ハンズオンする際に活用していきたいなと思います。


  1. .NET 6 に落とした際、OpenAPI Generator で生成したコードで使用している RestSharp でビルドエラーになったので、生成コマンドのオプションでこのライブラリを使わないように指定して回避しました。

【Azure Functions】Durable Entity を使った「リプライトークンリレー」で LINE Bot の返信処理を拡張する

はじめに

LINE Bot では、無料で使うことのできる返信(Reply API)を効果的に使うことが求められます。

今回は、その返信をより柔軟に・効果的に拡張するアイディアを紹介します。

リプライトークンの有効期限が長くなった

ここ数年で LINE Messaging API による Bot 開発も大きく変わっていている点の一つに、リプライトークンの有効期限が大幅に延長されたことが挙げられます。

Messaging API では、Webhook で受信したメッセージに返信する際の Reply API では、受信メッセージに含まれるリプライトークンを使用する必要があります。

このトークンは従来は有効期限が短く、30 秒ほどで使えなくなってしまっており、時間のかかる処理では使えなかったほか、サーバーレスで組む際などにコールドスタートに悩まされることもあったかと思います。

これが現在では、ドキュメントを見ると

Webhookを受信してから1分以内に使用する必要があります。1分を超える場合の使用については、動作は保証されません。

という記載になっており、実は数分はトークンが有効のままでいてくれるため、ある程度時間のかかる処理でも、終わってから返信をする余裕ができました。

参考:Messaging APIリファレンス | LINE Developers

返信の入れ違いの問題

一方で、時間のかかる処理を通常の返信で対応しようとすると新しい課題も浮上してきます。

処理中にユーザーから新たに別のメッセージが送られてしまうと、返信が入れ違ってしまいます。

時間のかかる処理を連続でリクエストされてしまっては、サーバー側の負荷も気になるところですし、ものによってはおかしな動作をする可能性もあると思います。

そこで、返信の入れ違いを防ぐために、時間のかかる処理中の場合は新たなリクエストを受け付けないようにトークンをうまく使って返信をコントロールしてみる方法を考えてみます。

Durable Entity を利用したトークン管理

今回考えたのは、Durable Entity をトークンストアとして活用し、時間のかかる処理に対するリプライトークンをいったんストアし、それをリレーして引き継ぎながら時間のかかる処理を返信したかどうかを管理する方法です。

まず Durable Entity についてですが、これは Azure Functions の拡張機能である Durable Functions の 1 機能で、状態を保持するための仕組みです。

「エンティティ ID」という値をキーにエンティティを作成し、そのエンティティ内に状態を保持しておくことができます。

learn.microsoft.com

処理の流れ

今回やりたいのはこういう流れです。

「猫の絵を描いて」というリクエストに対する処理が終わるまで、別のリクエストは受け付けず、「待ってね」と返します。

Durable Entity を用いて、これを実現します。

全体像はこんな感じ。

通常のフローとしては、① 時間のかかる処理の依頼メッセージを受け取った Webhook エンドポイントの関数は、② 依頼したLINEユーザーの LINE ユーザー ID をエンティティ ID(エンティティの識別子)として起動し、そこにリプライトークンをセットします。

その後 Webhook エンドポイントは ③ 外部の時間のかかる処理本体を呼び出します。単純に外部 API をコールするほか、人への作業・承認依頼や、何かデバイスなどに指示を出すような IoT シナリオが想定されます。

時間のかかる処理が終わったら、そこから ④ 返信用関数をコールしてもらいます。

その返信用関数から、処理を依頼している LINE ユーザー ID のエンティティを確認し、⑤ 保存されているリプライトークンを取得し、エンティティ内からリプライトークンを削除します。

このような動きを実現するために、③ → ④ の経路で処理を依頼している LINE ユーザー ID の情報は引き渡していく必要があります。

最後に、⑥ ⑤ で取得したリプライトークンで結果を返信すれば完了です。

これを基本の流れとするのですが、時間のかかる処理完了前に次の依頼メッセージを送ってしまった時の対策フローは以下です。

処理が完了する前に新たに ① 時間のかかる処理の依頼メッセージを送った場合、② すでに同じLINEユーザーIDのエンティティが存在し、かつ未使用のリプライトークンを持っていれば「処理中」と判断し、③ エンティティにセットされていたリプライトークンを受け取ります。

次に ④ ①で受け取った新しいリプライトークンを代わりにエンティティにセットしておきます。(リプライトークンを入れ替える「リレー」を行っています)

最後に ⑤ セットされていたリプライトークンで、処理中である旨の返信を行う、という流れです。

この方法により、時間のかかる処理の完了 / 未完了をエンティティがリプライトークンを持っているかどうかで判断できます。

さらに、処理中に再リクエストした際にリプライトークンを入れ替えて処理中である旨の返信をすることで、リプライトークンの有効期限を実質的に伸ばす副次的なメリットも得られます。

まとめ

この方法を使えば、時間のかかる処理に対して、返信の入れ違いを防ぎながら、リプライトークンの有効期限を有効に使うことができます。

この仕組みを実装し、ちょっとした便利ツールを開発して使っているので、次回はサンプルコードも交えてその実例の紹介もしたいと思います。

ハンズオンイベントやります

3/28(木) の夜にオンラインでハンズオンイベントをやります!

linedevelopercommunity.connpass.com

今回紹介した「リプライトークンリレー」の動きも実際に体験できるので、気になった方はぜひ!

GitHub Codespaces + LINE OpenAPI による C# での LINE Bot 開発がすぐ始められるテンプレートを作ってみた

はじめに

この記事は 「LINE DC Advent Calendar 2023」 19日目の記事です。

Azure には Azure OpenAI Service があり、LINE Pay Bot からも使いたい、そして Azure では C# での開発が何かと便利。

Azure と C# で LINE Bot 開発したくなるのは必然です。

そこで今回は LINE OpenAPI を使って、C# による開発を便利にできないか?ということをちょっと趣向を変えつつ考えてみました。

LINE OpenAPI は、LINE DC のアドカレ4日目の記事でも取り上げられてます。

qiita.com

以前は C# で LINE Bot を開発するときは、コミュニティ SDK を使っていましたが、現在は最新化されておらず…

LINE OpenAPI を使って SDK を最新化するのもよいのですが、最近 GitHub Codespaces を使っていてすごく便利だなと感じているので、今回はそれと絡めて、Codespace の開発環境を立ち上げたときに最新の SDK がその場で自動生成され、すぐに Bot 開発が始められるテンプレートを作る、ということをやってみました。

やりたいこと

GitHub Codespaces にはテンプレート機能というのがあります。

DevContainer に使いたい環境を定義し、あらかじめ用意しておきたいファイルとセットで GitHub にテンプレートリポジトリとして公開しておけば、それを Codespace から開くことができます。

好きな開発環境を展開できるのでとても便利です。

docs.github.com

これを使って、

  • Azure Functions の開発環境(CLIVS Code 拡張機能など)
  • LINE OpenAPI 定義をもとに生成された C# SDK
  • オウム返しをする LINE Bot のサンプル関数クラス

がセットになった環境をすぐ開けるようにおぜん立てします。

C# SDK の生成は、openapi-generator-cli を使用します。

github.com

作ったもの

ということで作ってみたのですが、後述する理由から正直そこまでの実用性のあるものにはなってません。。

github.com

このテンプレートから Codespace を起動すると、起動後に openapi-generator-cli が走り、最新の LINE OpenAPI 定義に基づいて LINE Bot 開発に必要な C# のプロジェクト群が sdk フォルダに作られます。

必要な拡張機能や Azure Functions Core Tools なども最初から入るようにしています。

DevContainer の定義

postCreateCommand のところで、openapi-generator-cli を使って LINE OpenAPI の定義を基にした C# コードを生成するコマンドを書いています。

生成している定義はとりあえず最低限、messaging-api.ymlwebhook.yml です。

{
    "name": "LINE OpenAPI C# Azure Functions Starter",
    "image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bullseye",
    "features": {
        "ghcr.io/devcontainers/features/dotnet:2": {
            "version": "6.0"
        },
        "ghcr.io/devcontainers/features/java:1": {
            "installMaven": true,
            "version": "latest",
            "jdkDistro": "ms",
            "gradleVersion": "latest",
            "mavenVersion": "latest",
            "antVersion": "latest"
        }
    },

    "postCreateCommand": "npm install @openapitools/openapi-generator-cli -g && npm install -g azure-functions-core-tools@4 && npx @openapitools/openapi-generator-cli generate -i https://raw.githubusercontent.com/line/line-openapi/main/messaging-api.yml -o sdk -g csharp --additional-properties=netCoreProjectFile=true,targetFramework=netstandard2.1,packageName=LineOpenApi.MessagingApi && npx @openapitools/openapi-generator-cli generate -i https://raw.githubusercontent.com/line/line-openapi/main/webhook.yml -o sdk -g csharp --additional-properties=netCoreProjectFile=true,targetFramework=netstandard2.1,packageName=LineOpenApi.Webhook",
    "customizations": {
        "codespaces": {
            "openFiles": ["LineBotFunctions/ReplyFunction.cs"]
        },
        "vscode": {
            "extensions": [
                "ms-azuretools.vscode-azurefunctions",
                "ms-dotnettools.csdevkit"
            ]
        }
    }
}

生成される LINE OpenAPI のコード

自動生成で下記のようなものが作られています。

それっぽいクラス群がコマンド一発で生成されるのはとても気持ちいいですね。

オウム返し用サンプル関数

生成されるコードにあわせて、こんなかんじになりました。

Event オブジェクトを取りまわして分岐させていくところは自分で書かないといけないので、ここはちゃんと作られた SDK には当然劣りますね。

あと、これは仕方ないのですが MessagingApiApi というのがなんともいえない感じです。

[Function("ReplyFunction")]
public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
    try
    {
        var body = await new StreamReader(req.Body).ReadToEndAsync();
        var callbackRequest = JsonConvert.DeserializeObject<CallbackRequest>(body);

        var api = new MessagingApiApi(new Configuration
        {
            AccessToken = Environment.GetEnvironmentVariable("ChannelAccessToken"),
            BasePath = "https://api.line.me"
        });

        foreach (var ev in callbackRequest.Events)
        {
            if (ev is MessageEvent messageEvent && messageEvent.Message is TextMessageContent textMessageContent)
            {
                var replyMessageRequest = new ReplyMessageRequest(messageEvent.ReplyToken, new List<Message>
                {
                    new TextMessage(textMessageContent.Text)
                    {
                        Type = "text"
                    }
                });
                await api.ReplyMessageAsync(replyMessageRequest);
            }
        }
    }
    catch (Exception e)
    {
        _logger.LogError($"Error: {e.Message}");
        _logger.LogError($"Error: {e.StackTrace}");
    }
    
    return req.CreateResponse(HttpStatusCode.OK);
}

困りごと

Webhook で受け取る JSON のデシリアライズC# オブジェクトへの変換)がうまくいかない

今回最もハマったところなのですが、

if (ev is MessageEvent messageEvent && messageEvent.Message is TextMessageContent textMessageContent)

でやっている分岐がうまく動かない、というものでした。

実は生成されたコードでは、MessageEventEvent を継承し、TextMessageContentMessageContent を継承しています。

LINE Messaging API ではさまざまなイベントやメッセージタイプがありますが、それをポリモーフィズムで表現しています。

それぞれのクラス定義では、以下のように継承の親子関係を JSON からデシリアライズする際にわかるように指定がされています。

Event クラスでは、「Type"message" だったら MessageEvent として扱う」などの指定が存在するサブタイプの数だけ指定されています。

    [DataContract(Name = "Event")]
    [JsonConverter(typeof(JsonSubtypes), "Type")]
    [JsonSubtypes.KnownSubType(typeof(AccountLinkEvent), "accountLink")]
    [JsonSubtypes.KnownSubType(typeof(ActivatedEvent), "activated")]
    [JsonSubtypes.KnownSubType(typeof(BeaconEvent), "beacon")]
    [JsonSubtypes.KnownSubType(typeof(BotResumedEvent), "botResumed")]
    [JsonSubtypes.KnownSubType(typeof(BotSuspendedEvent), "botSuspended")]
    [JsonSubtypes.KnownSubType(typeof(DeactivatedEvent), "deactivated")]
    [JsonSubtypes.KnownSubType(typeof(FollowEvent), "follow")]
    [JsonSubtypes.KnownSubType(typeof(JoinEvent), "join")]
    [JsonSubtypes.KnownSubType(typeof(LeaveEvent), "leave")]
    [JsonSubtypes.KnownSubType(typeof(MemberJoinedEvent), "memberJoined")]
    [JsonSubtypes.KnownSubType(typeof(MemberLeftEvent), "memberLeft")]
    [JsonSubtypes.KnownSubType(typeof(MessageEvent), "message")]
    [JsonSubtypes.KnownSubType(typeof(ModuleEvent), "module")]
    [JsonSubtypes.KnownSubType(typeof(PostbackEvent), "postback")]
    [JsonSubtypes.KnownSubType(typeof(ThingsEvent), "things")]
    [JsonSubtypes.KnownSubType(typeof(UnfollowEvent), "unfollow")]
    [JsonSubtypes.KnownSubType(typeof(UnsendEvent), "unsend")]
    [JsonSubtypes.KnownSubType(typeof(VideoPlayCompleteEvent), "videoPlayComplete")]
    public partial class Event : IEquatable<Event>, IValidatableObject
    {

サブタイプである MessageEvent クラスはこのように定義されています。

    [DataContract(Name = "MessageEvent")]
    [JsonConverter(typeof(JsonSubtypes), "Type")]
    public partial class MessageEvent : Event, IEquatable<MessageEvent>, IValidatableObject
    {

これらの設定により、JSON データの中身を見てそれがどのサブタイプにデシリアライズされるべきか見てくれる動きは、「JsonSubTypes」というライブラリによって実現する機能です。

しかし、どういうわけかこれが効かず、MessageEvent になってほしいのに基底クラスの Event としてデシリアライズされてしまうという現象が起きてしまいました。

なんやかんや試行錯誤したり ChatGPT に聞いたりしていたら、解決。

どうやらサブタイプ側の記述が不要だったようです。

解決策

サブタイプのクラスについている [JsonConverter(typeof(JsonSubtypes), "Type")] を消す or コメントアウトします。

    [DataContract(Name = "MessageEvent")]
    // ↓↓↓これを消す↓↓↓
    // [JsonConverter(typeof(JsonSubtypes), "Type")]
    public partial class MessageEvent : Event, IEquatable<MessageEvent>, IValidatableObject
    {

この記述が悪さをして、うまくサブタイプでデシリアライズしてくれなかったようです。(OpenAPI Generator の不具合なのか…??)

これを、Webhook プロジェクト内の Model 内のすべてのサブタイプに対して行う必要がありますが、サンプルのオウム返しを動かすだけなら

  • sdk/src/LineOpenApi.Webhook/Model/MessageEvent.cs
  • sdk/src/LineOpenApi.Webhook/Model/TextMessageContent.cs

だけで大丈夫です。

コメントアウトしたら、無事に動くようになりました。

まとめ

今回は実験的試みでしたが、OpenAPI Generator の癖なども実感することができたので得たものはあったかなというところです。

公式の OpenAPIの活用によるSDK開発の進化:LINE APIの進化の軌跡 の記事でも紹介されていますが、公式の SDK は、GitHub Actions を用いて自動生成やスクリプト実行によって最新状態を保っているようです。公式 SDK の各リポジトリを見るとその仕組みが垣間見れます。

今回はまったく異なるアプローチでの実験でしたが、やはり実用性を考えれば、公式 SDK 同様のアプローチで SDK を作ってあげるのがスマートですね。

Azure のハンズオン記事紹介(サーバーレス / ChatGPT)&今年度振り返り

はじめに

今年度もそろそろ終わりですが、今年ハンズオンを作成してあまり宣伝していなかったので、こちらに書いておきます。

Azure サーバーレスをササっと体験するハンズオン

github.com

Gitpod 上でサクッとサーバーレスなアプリを構築して Azure の便利さを体験するハンズオンです。

Bicep と GitHub Actions を使って Azure サーバーレステクノロジーを組み合わせた開発を高速で体験します。

README 記載の手順に沿って作業すると、以下のテクノロジーを使用した簡易掲示板アプリがデプロイされます。

  • Azure Static Web Apps
  • Azure Functions
  • Azure Cosmos DB
  • Azure SignalR Service

環境も Gitpod 対応なので、ローカルの開発環境の準備は不要です。

ChatGPT と話せる LINE Bot を Logic Apps テンプレートで超爆速開発

zenn.dev

話題の ChatGPT API と話せる LINE Bot を爆速で開発するハンズオンです。

以前公開した Azure Logic Apps 用の LINE Bot テンプレートを利用して、Logic App ・LINE 間の接続部分の手順を省略しています。

ささっと LINE から ChatGPT が使えるようになるので ChatGPT に興味がある方も、ノーコード・ローコードでの LINE Bot 開発に興味がある方にもおすすめです。

もっと便利にする続編も書いていますので、こちらも近日公開予定です。

今年度の振り返り

今年度は Azure Container Apps について大きなカンファレンスで登壇することができました。

LINE Developers Community REV UP 2022」という LINE 関連開発者向けカンファレンス、「ServerlessDays Tokyo 2022 Virtual」というサーバレス開発者向けのカンファレンスです。

REV UP 2022 のほうは実行委員までやらせていただき、とてもよい経験になりました。来年度(今年)も楽しみです。

資料・動画

Container Apps と LINE API の連携・活用アイディアについて解説しています。

資料

REV UP版 www.docswell.com

ServerlessDays版 www.docswell.com

動画

REV UP版 www.youtube.com

ServerlessDays版 www.youtube.com

おわりに

MVP の審査の活動報告のタイミングだったので、年度末ということもあり振り返ってみました。

来年度は少し活動の幅を広げてみたいなと思ってます。引き続き、よろしくお願いいたします。

Microsoft MVP を再受賞しました。

おかげさまで、今年も Microsoft MVP を再受賞することができました。

カテゴリは変わらず Microsoft Azure です。

ツイートでも書いた通り、初めてちゃんとした審査での再受賞です。

2019 年 11 月の初受賞だったので 2020 年 7 月の更新はスルー、2021 年 7 月は基本審査なしでの再受賞。今回、MVP として活動していた期間を初めて評価いただいたかたちです。

この先やりたいこともいろいろ出てきているところではありますが、楽しんでやっていこうと思います!

そして明日は、以下イベントでお話しします。

linedevelopercommunity.connpass.com

こちらのイベントにも引き続き Microsoft MVP 兼 LINE API Expert として参加できることになり、一安心です(笑)

【小ネタ】Azure Cognitive Service for Language の質問応答の回答を "ねこ" っぽくする

はじめに

2022年2月22日、にゃんにゃんにゃんで 2 が 6 個ということで、今日はかなりの「ねこの日」でした。

ちょうど自社内でチャットボットの話をする機会もあったので、Azure のナレッジベースのサービスを使って "ねこ" っぽいチャットボットを作りました。

技術的にはだいぶしょーもないやり方ですが、備忘的に記録しておきます。

手順

ナレッジベースを作る

ふつうに URL などからナレッジベースを作ります。

「Manage sources」から、適当な FAQ ページの URL を追加します。

f:id:himanago:20220222233324p:plain

一般的な日本語の FAQ ページからとれば、だいたい「ですます調」で回答が作成されるかと思います。

f:id:himanago:20220222230818p:plain

次に、雑談対応のためにおしゃべり(Chitchat)を追加します。

あとからねこっぽくするわけですが、その変換がしやすいので、ここであえて Professional を選択します。

f:id:himanago:20220222230734p:plain

猫語に変換

このやり方が、まじでしょーもないです。

ナレッジベースを Excel にエクスポートします。

f:id:himanago:20220222230840p:plain

エクスポートした Excel ファイルを開き、で回答の列を選択肢、以下の順で文字列置換します。

  1. 「よ。」→「。」
  2. 「ね。」→「。」
  3. 「。」→「にゃ。」

※ 1 と 2 は主におしゃべりの「~ですよ。」「~ですね。」をいったん「~です。」に統一する目的

f:id:himanago:20220222231024p:plain

こうすると、おしゃべり部分含めて語尾が違和感なく「にゃ。」になり、ちょっと丁寧なねこの口調(?)になります。

f:id:himanago:20220222231157p:plain

この Excel ファイルを上書き保存して、Language Studio にインポート。

f:id:himanago:20220222231215p:plain

ナレッジベースが、語尾が「にゃ。」になった回答で上書きされます。

動かしてみる

ちゃんとねこっぽいですね。

f:id:himanago:20220222231626p:plain

おしゃべりの部分も「早くお休みになれるといいですね。」→「早くお休みになれるといいですにゃ。」になっており、違和感なくねこです。

f:id:himanago:20220222233846p:plain

Azure Bot Service を使って Teams / LINE / Alexa 等に公開したい場合は以下の記事などを参照ください。

Azure Cognitive Service for Language + Azure Bot Service で超簡単にチャットボット作成①~ナレッジベースの作成&Webチャットの公開 - himanago

Azure Cognitive Service for Language + Azure Bot Service で超簡単にチャットボット作成②~Microsoft Teamsへの簡易接続 - himanago

Azure Cognitive Service for Language + Azure Bot Service で超簡単にチャットボット作成③~LINE Botとしての公開 - himanago

Azure Cognitive Service for Language + Azure Bot Service で超簡単にチャットボット作成④~Alexa スキルとしての公開 - himanago

まとめ

語尾を変えるくらいなら Excel でばばっとやってしまうのが早いこともありますね。

Language Studio の質問応答、Excel 形式でエクスポート・インポートできるのは地味に便利でした。

【Update】GitHub のボタンから 1 クリックでデプロイできる LINE Bot のオウム返しバックエンド用 Azure Logic Apps フロー

以前公開した、1 クリックで LINE Bot 用の Logic Apps フローをデプロイできる ARM テンプレートですが、オウム返しのフローを更新しました。

himanago.hatenablog.com

テンプレートはこちらのリポジトリから。

github.com

README のところにボタンがあるので、ここからデプロイして即オウム返しの LINE Bot が完成します。

f:id:himanago:20220222221712p:plain

「Deploy to Azure」ボタンを押して Azure にサインイン後、

  • サブスクリプション
  • リソースグループ
  • リージョン
  • Logic App 名
  • LINE Messaging API のチャネル ID
  • LINE Messaging API のチャネルシークレット

を入力すると選んだサブスクリプション、リソースグループにデプロイされます。

今回のアップデート内容

200 の応答を即返すようにしつつ、全体的にフローをみなしました。

f:id:himanago:20220222222353p:plain

これまではユーザーから送られたテキスト内容をそのまま返信するオウム返しとして、テキストメッセージのみに対応していましたが、今回からメッセージ種別の分岐をスイッチで追加し、スタンプが送られた場合は固定のスタンプを返すようにしています。

f:id:himanago:20220222223709p:plain

他のメッセージ種別の分岐を追加するのも容易になったと思います。

また、メッセージイベントのみに反応させるための制御(条件)も追加しているので、必要に応じてその他のイベント(フォローイベントなど)の処理も追加しやすくなったと思います。

こういった分岐が最初からあると、本格的な LINE Bot を作る足掛かりになると思うので、ぜひ使ってみてほしいと思います。