はじめに
Power Apps Advent Calendar 2024 12月16日分。今回はPower Apps
でJSON
ファイルをデータソースにしたモダンなチャットアプリを作っていきたいと思います。
デザインは下記のようなPower Apps キャンバス アプリ
です。
画面デザインがそれらしいですね。HTML 文字列
を活用しています。
またHTML 文字列
の格納先は、高さが伸縮可能なギャラリー コントロール
です。
Chat Screen (画面)
└── conMainScreen (垂直コンテナー)
└── conChatLayout (水平コンテナー)
├── conChatListSidebar (垂直コンテナー)
│ ├── conUserProfileHeader (水平コンテナー)
│ │ ├── imgUserProfile (画像)
│ │ └── lblUserName (ラベル)
│ ├── conNewChatHeader (水平コンテナー)
│ │ ├── icoNewChat (アイコン)
│ │ └── lblicoNewChat (ラベル)
│ └── galChatList (Gallery)
│ ├── lblCreatedTime (ラベル)
│ ├── txtAvatar (テキスト入力)
│ └── lblChatTitle (Label)
└── conChatMain (垂直コンテナー)
├── conChatHeader (水平コンテナー)
│ ├── icoChatHeader (画像)
│ └── lblChatHeader (ラベル)
├── galMessages (高さが伸縮可能なギャラリー)
│ └── htmlMessageContent (Html 文字列)
└── conMessageInput (水平コンテナー)
├── inpMessageText (テキスト入力)
└── btnSendMessage (ボタン)
モダン コントロールは、ボタン コントロール
のみ利用しています。
今回のポイントはJSON
ファイルのコンテンツの書き込み、読み込みによるデータのやり取りになります。
Power Automate
をつかった手法です。
-
Power Apps
では、ParseJSON 関数 -
Power Automate
ではファイル コンテンツの取得、ファイルの作成、ファイルの更新
上記を活用します。順番に見ていきます。
レイアウト作成案のコツ
最近の私のレイアウト案の進め方ですが、AIファーストで案出しを進めています。
Copilot
、ChatGPT
やClaude
どれも非常に優秀です。
その中でもClaude
はArtifacts機能があり、視覚的にアプリのレイアウトを提案してくれます。
レイアウトに自信がない方や、どのような形で作成するか迷った際には、こういった進め方もあるんだな、くらいに見ていただければ幸いです。
JSONファイル活用におけるデータ戦略
今回はチャットの履歴をJSON
ファイルそのものに格納します。内容は都度Power Automate
で読み込む進め方です。
図解すると下記のようになります
あらためて必要な項目に目を向けてみます。
下記のような項目を挙げて進めてみることにします。
-
MessageID
: 参照用に設けるGUID列 -
LastMessageText
: 最後に投稿されたメッセージ -
LastMessageTime
: 最後に投稿された日時 -
LastSender
: 最後に投稿したユーザー名 -
MessageCount
: メッセージ数 -
CreatedBy
: チャットを作成したユーザー名 -
CreatedTime
: 作成日時 -
UpdatedTime
: 更新日時 -
Subject
: 会話タイトル-
MessageIndex
: メッセージの順番 -
SenderMailAddress
: 送信元のメールアドレス -
SenderName
: 送信元のユーザー -
TimeStamp
: 送信日時
-
上記のうち、第一階層であるLastMessageText
~ Subject
までは、SharePoint ドキュメント ライブラリ
の機能を活用し、メタデータとして列を設けます。
CreatedTime
やUpdatedTime
はシステム列と内容がかぶりますが、メタデータとして今回は追加します。
列名 | データ型 |
---|---|
MessageID | 1 行テキスト |
LastMessageText | 1 行テキスト |
LastMessageTime | 日付と時刻 |
LastSender | 1 行テキスト |
MessageCount | 数値 |
CreatedBy | 1 行テキスト |
CreatedTime | 日付と時刻 |
UpdatedTime | 日付と時刻 |
Subject | 1 行テキスト |
そして、このメタデータが付記されたJSON
ファイルに、下記の値を追加していきます。
{
"Log": [
{
"MessageIndex": "メッセージの順番",
"SenderMailAddress": "送信元のメールアドレス",
"SenderName": "送信元のユーザー",
"TimeStamp": "送信日時"
},
{
"MessageIndex": "メッセージの順番",
"SenderMailAddress": "送信元のメールアドレス",
"SenderName": "送信元のユーザー",
"TimeStamp": "送信日時"
} // 末尾に値を追加していくイメージ
]
}
海外のMVPのYouTubeを見ているとParseJSON 関数を使った大規模データ対応を見かけます。
それであれば、書き込み先そのものがJSON
でいいのでは🧐という思想に基づいて作成しています。
アプリの機能
それではPower Apps
の解説にうつります。このアプリのサイドパネルには、以下の項目が表示しています。
- 自分自身の名前
- チャットの履歴
- チャット相手との詳細なやり取り
複数のチャットの履歴は、SharePoint
のドキュメント ライブラリ
をデータソースにします。
ここのJSON ファイル
が表示されるイメージです。
このギャラリー コントロールがクリックされた際に、JSON
ファイル コンテンツを読み込む処理を走らせます。
// ローカル変数に一意の値であるMessageIDを保持する
UpdateContext({locMessageID: ThisItem.MessageID});
// JSONファイルコンテンツをパースしてテーブルに変換する
ClearCollect(
colChat,
ForAll(
Table(ParseJSON('get-json-content'.Run(locMessageID).response).Log) As Result,
{
MessageIndex: Value(Result.Value.MessageIndex),
MessageText: Text(Result.Value.MessageText),
SenderName: Text(Result.Value.SenderName),
TimeStamp: DateTimeValue(Result.Value.TimeStamp)
}
)
);
チャットの内容
メッセージボックス、つまりチャット内容のやり取りについては、以下の関数を使用して、HTML文字列
で表現します。
With(
{
avatarStyle: "width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px;",
messageWrapperBase: "max-width: 70%; margin-bottom: 16px; display: flex; gap: 8px;",
messageBubbleBase: "padding: 8px 12px; border-radius: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.1);",
nameStyle: "font-size: 12px; color: #666666; margin-bottom: 4px;",
timeStyle: "font-size: 11px; color: #666666; text-align: right;"
},
Switch(
Mod(ThisItem.MessageIndex, 2),
0,
$"<div style='{messageWrapperBase} margin-right: auto;'>
<div style='{avatarStyle} background-color: #e0e0e0;'>
{Left(ThisItem.SenderName, 2)}
</div>
<div>
<div style='{nameStyle}'>{ThisItem.SenderName}</div>
<div style='{messageBubbleBase} background-color: #ffffff;'>
<div style='margin-bottom: 4px;'>{ThisItem.MessageText}</div>
<div style='{timeStyle}'>{ThisItem.TimeStamp}</div>
</div>
</div>
</div>",
1,
$"<div style='{messageWrapperBase} margin-left: auto; flex-direction: row-reverse;'>
<div style='{avatarStyle} background-color: #128C7E; color: white;'>Me</div>
<div>
<div style='{nameStyle} text-align: right;'>自分</div>
<div style='{messageBubbleBase} background-color: #dcf8c6;'>
<div style='margin-bottom: 4px;'>{ThisItem.MessageText}</div>
<div style='{timeStyle}'>{ThisItem.TimeStamp}</div>
</div>
</div>
</div>"
)
)
登場する関数は、下記の三つです。
これらを組み合わせ、HTML文字列を用いた高さの自動調整機能や伸縮可能なギャラリーを活用することで、動的なデザインを実現されます。
まったくローコードではないですね。AI
の力を借りないと作成できません。
なぜHTML文字列
を採用しているのか、理由はコントロール数が抑えられることにあります。
Power Apps キャンバスアプリ
に設定できるコントロール数には限りがあります。
デザインにこだわればこだわるほど、コントロール数は増加傾向にあり、自分のやりたいことと離れる可能性があります。
AI黎明期の今、Copilot in Edge
でも上記のような関数は提案してくださいます。
ぜひ活用を検討してみてください。
チャットの投稿パネル
チャットの投稿用にテキスト入力
と送信用のボタン
を設けます。
こちらに後述するPower Automate
のフローを追加します。
// コレクションのアイテムの数で、処理を分ける
If(
CountRows(colChat) = 0,
// 初回投稿
ClearCollect(
colChat,
{
MessageIndex: 1,
SenderName: Office365ユーザー.MyProfileV2().displayName,
MessageText: inpMessageText.Text,
TimeStamp: Now()
}
);
Collect(
colChat,
{
MessageIndex: (CountRows(colChat) + 1),
SenderName: "AI Builder",
MessageText: 'AI Reply'.Predict(inpMessageText.Text).Text,
TimeStamp: Now()
}
);
// AI Builderのカスタムプロンプトでタイトルを作成する
UpdateContext({locAiResponse: 'Custom-prompt-response'.Predict(inpMessageText.Text).StructuredOutput});
,
// 初回投稿ではないときは、自分の投稿とAI Replyの値を設定する
Collect(
colChat,
{
MessageIndex: (CountRows(colChat) + 1),
SenderName: Office365ユーザー.MyProfileV2().displayName,
MessageText: inpMessageText.Text,
TimeStamp: Now()
}
);
Collect(
colChat,
{
MessageIndex: (CountRows(colChat) + 1),
SenderName: "AI Builder",
MessageText: 'AI Reply'.Predict(inpMessageText.Text).Text,
TimeStamp: Now()
}
);
);
// 初回の投稿と最後の投稿をWith関数に格納
With(
{
FirstPost: First(colChat),
LastPost: Last(colChat)
},
// JSON文字列用にオブジェクトを設定
UpdateContext(
{
spMetaData: {
MessageID: Coalesce(
locMessageID,
Text(GUID())
),
LastMessageText: LastPost.MessageText,
LastMessageTime: LastPost.TimeStamp,
LastSender: LastPost.SenderName,
MessageCount: CountRows(colChat),
CreateBy: FirstPost.SenderName,
CreatedTime: FirstPost.TimeStamp,
UpdatedTime: LastPost.TimeStamp,
Subject: Coalesce(
locAiResponse.response,
galChatList.Selected.Subject
)
}
}
)
);
// Power Automateを実施、初回データ作成時用にMessageIdを戻す
UpdateContext(
{
locMessageID: 'post-json-chat'.Run(
JSON(spMetaData),
JSON(
{Log: Table(colChat)},
JSONFormat.Compact
)
).messageid
}
);
// テキスト入力をクリアする
Reset(inpMessageText);
// Filter関数で引数に設定しているギャラリーコントロール 最新化用の値
UpdateContext({locFilter: false});
UpdateContext({locFilter: true});
後述しますが、JSON ファイルの中身は、Power Apps
から都度設定し、Power Automateに送る流れです。
JSON 関数を使って、チャットのやり取りを構造化された文字列に変換しましょう。
JSON ファイルにユーザーを表すプロパティを用意しています。ユーザー列に該当するSenderMailAddress
とSenderName
を文字列に設定しているのは、プロフィールの画像データなど不要な列を含めてしまうことを避けるためです。
AI Builderの活用
この関数の中でAI Builder
を利用しています。
まずチャットの返信はAIReplyで実施しています。
GPT
による返答の恩恵が受けられます。
単純に応答を返すだけの関数ですね。
またチャットの要約、タイトルを設定するためにカスタム プロンプト
を利用します。
AI ハブから簡単にJSONで構造化された応答を返すことが可能です。
プロンプト ビルダーを使用して JSON で GPT の出力形式を定義します。
下記はチャットを開始するときの文言です。内容から会話の内容を決定し、20文字ほどの一文に要約してください。また要約した内容からチャットのアイコンを作成します。16進法で文字色と背景色を提案してください。
- 文章は一文でまとめてください
- 体言止めを用いてください
- 句読点は出力に含めないでください
### チャット
{引数のチャット}
引数は右上の画面から設定します。
テキストだけではなく、画像
やデータソース
の利用も可能です。
出力はJSON
を指定して
下記のように加工しやすい形に変換します。
戻り値が構造的になるため、非常に便利です。
こちらの詳細はMicrosoft learnに譲らせてください。
ここからPower Automate
の解説といきたいところですが・・・
ここまでで結構長くなってしまいました。
Power Automateは次回投稿に内容を譲ることにします。
お楽しみに!