これは GMOペパボディレクター Advent Calendar 2024 5日の記事です。
日々のちょっとしたデータの保存先として、Google スプレッドシートを利用することはあると思う。しかし、保存するだけ保存して、活用しない・見なくなることもよく起こる。
この記事では、Google スプレッドシートのデータを Dify で分析し、その結果を週に1回Slackに通知する仕組みを簡易に作ってみたので紹介する。
構成
今回は、活動量や体重、食事内容などを記録したGoogle スプレッドシートのデータを対象とする。
データの蓄積先が Google スプレッドシートであること、定期的に自動実行したかったことから、Google Apps Script を用いて以下のような構成で実行した。
Google Apps Script が Google スプレッドシートからデータを取得し、Dify にそのデータを送り、Dify で分析結果を生成し、 Google Apps Script が受け取り、Slack に通知を行う。Google Apps Script のトリガーを日時単位で設定することで、定期的な通知を行うようにしている。
※ 上図で別記事となっているところは以下
設定方法
1. Dify の設定
Dify はデータを受け取り、分析を行う役割をする。下図のようなシンプルな構成にしている。開始ブロックで3種類のデータを受け取り、LLMブロックで分析を生成し、終了ブロックでその結果を出力している。
LLMブロックのプロンプトは以下のようにした。今回、プロンプトの改善は色々試さなかったが、もっと適切な分析結果が得られる書き方がありそう。
あなたは優秀な栄養士です。以下のデータを用いて、以下の観点から分析を行ってください。
# データ
- {#health_data}は、体重、体脂肪などの健康に関するデータと歩数や消費カロリーなどの運動量に関するデータです。
- {#nutrition_data}は、摂取した栄養素に関するデータです。
- {#foods_data} は、今週1週間で摂取した食品とその栄養素です。
# 分析の観点
先週1週間に比べて、今週1週間で大きく変わった項目はあるか、あるならどのように変わったのか、その要因は何か。特に、以下の観点で分析してください。
- 体重および体脂肪の変化に対して、取得した栄養素がどのように影響しているか、さらにその栄養素はどの食品が影響しているか。
- 体重および体脂肪の変化に対して、運動量は影響しているか。
# 結果の出力条件
分析結果は以下のフォーマットで出力してください。
1. *大きな変化があった項目*
・{項目名}: {変化量}({先週の値}→{今週の値})
※ 2〜3項目程度にとどめてください
2. *考察*
※ 影響を与えた食品についても触れてください
3. *結論*
※ 変化とその背景をまとめ、どのように改善すべきかを簡潔にまとめてください
2. Slack の設定
https://api.slack.com/quickstart を参照して、今回必要な部分のみ設定した。
- Slack App の作成(1. Creating an app参照)
https://api.slack.com/apps より、アプリ名を入力し、ワークスペースを選択
- スコープの設定(2. Requesting scopes参照)
左のメニューから OAuth & Permissions を選択し、Scopes で chat:write を設定
- Slack App のインストール(3. Installing and authorizing the app参照)
左のメニューから Install App を選択し、App をインストールする - Slackの通知先のチャンネルに App を招待する
3. Google Apps Script の設定
- 環境変数の設定 スクリプトに直接書きたくない機密情報はプロパティサービスに登録する。 プロジェクトの設定 > スクリプト プロパティ と進み、key-valueのペアで設定する。
2. スクリプトの作成
function main() {
const data = fetchData();
const analysisResult = postToDifyAPI(data);
postMessageToSlack(analysisResult);
}
function fetchData() {
const sheets = [
{ name: 'health', id: 'health_spreadsheet_id', range: 'A1:N4' }, //各データを保存しているスプレッドシートのIDとセル範囲を指定する
{ name: 'foods', id: 'foods_spreadsheet_id', range: 'A1:Z10' },
{ name: 'nutrition', id: 'nutrition_spreadsheet_id', range: 'A1:Z4' }
];
const data = {};
sheets.forEach(sheetInfo => {
try {
const { id, name, range } = sheetInfo;
const spreadsheet = SpreadsheetApp.openById(id);
const sheet = spreadsheet.getSheetByName(name);
if (!sheet) {
throw new Error(`Sheet "${name}" not found in spreadsheet ID: ${id}`);
}
const values = sheet.getRange(range).getValues();
data[name + '_data'] = JSON.stringify(values);
} catch (error) {
console.error(`Error fetching data for sheet "${sheetInfo.name}": ${error.message}`);
}
});
return data;
}
function postToDifyAPI(data) {
const apiKey = PropertiesService.getScriptProperties().getProperty('DIFY_API_KEY');
const url = 'https://api.dify.ai/v1/workflows/run';
const payload = {
'inputs': data,
'response_mode': 'blocking',
'user': 'GoogleAppsScript'
};
const response = makeApiRequest_(url, apiKey, payload);
return response.data.outputs.text;
}
function postMessageToSlack(message) {
const token = PropertiesService.getScriptProperties().getProperty('SLACK_BOT_TOKEN');
const channel_id = 'channek_id'; // 投稿するSlackのチャンネルIDを指定する
const url = 'https://slack.com/api/chat.postMessage';
const payload = {
'channel': channel_id,
'text': message
};
makeApiRequest_(url, token, payload);
}
function makeApiRequest_(url, token, payload) {
const options = {
method: 'POST',
contentType: 'application/json',
headers: {
Authorization: `Bearer ${token}`
},
payload: JSON.stringify(payload)
};
try {
const response = UrlFetchApp.fetch(url, options);
const responseText = response.getContentText();
if (response.getResponseCode() !== 200) {
throw new Error(`HTTP Error ${response.getResponseCode()}: ${responseText}`);
}
return JSON.parse(responseText);
} catch (error) {
console.error(error.message);
return { error: error.message };
}
}
- トリガーの設定 左のメニューからトリガーを選択し、任意の間隔でスクリプトが実行されるようにする
結果
Slack に以下のような形で通知されるようになった。
感想
Google スプレッドシートに保存している各種データに対して、色々と活用できる可能性がありそうだと感じた。一方で、分析のプロンプトはまだ改善の余地がある。今回は試行錯誤しなかったけど、精度を上げる工夫ができそう。