3行まとめ
- Apple Watchのランニングデータを半自動でスプレッドシートに集約する仕組みをChatGPTで作りました
- ChatGPTプラグインとGAS(Google Apps Script)連携で、データ分析や練習メニューを相談をしています
- Looker Studioでの可視化や、ChatGPTのDeep Research機能も活用しています
背景: Apple Watchでのランニング記録と課題
前提として現在、自分はApple Watchを使ってランニングの記録をしています。ランニング後にApple WatchやiPhoneでその日のワークアウトの様子を確認できる機能があり、何分走ったか、何キロ走ったか、心拍数はいくつかなどの情報を見ることができます。しかし、個々のワークアウトの情報は確認できますが、例えばBIツールのようなダッシュボード形式でリッチに表示されるわけではありません。
- ジョグの練習のみに絞り込む
- 走行距離が10km以上のワークアウトに絞り込む
といったフィルタリングや高度な集計はできません。一括でエクスポートすることも可能ですが、日々の変化を確認したい場合に、毎回エクスポートしてどこかにインポートするという手動作業は非常に面倒です。
やりたいこと: ChatGPTによるランニングデータ管理の自動化と活用
そのため、そういった作業や可視化を簡単にできるようにしたいと考えました。また、それを可能にした上で、以下のようなことをChatGPTに相談したいと考えました。
- 最近の練習結果を見て、テンポ走をした際に、前回のテンポ走と比較して今回のテンポ走にはどのような特徴があったか
- 直近で2週間後にレースがある場合に、最近の練習状況を踏まえながらこの2週間でどのような練習メニューを組み立てるのが良いか
本エントリでは、ChatGPTをゴリゴリに使い倒した上で、これらを実現させる方法について紹介します。
実際にやったこと
Apple Watchからのデータ抽出とtsv出力
まず一つ目の取り組みとして、Apple Watchからのランニングアクティビティのスクリーンショットを受け取り、そこから日付やワークアウトなどを考慮した上で、tsv形式で出力するというワークフローを構築しています。tsv形式だと、スプレッドシートへの入力がコピペだけで完結するので、スマホでも手間がかかりません。
画像は毎回iPhoneに表示されるスクリーンショットなので、形式はかなり固定されています。そのため、これくらいのinstructionでも、ほぼ間違いなく処理できるかなと思います。
ダッシュボード化する際に、ワークアウトの時間がTime型(例: 23:59:59
)だとうまく処理できないことがあったため、以下の処理を実装しています。
- 秒単位のint型に置き換える処理
- 平均ペースや心拍数ゾーンなどから練習タイプを自動で判定する機能
- 例: ジョグなのか、ペース走なのか、インターバル走なのか
- コメントも同時に出力する機能
これをスプレッドシートにコピペします。ChatGPTのプラグインを使えば、スプレッドシートへの出力も比較的簡単に自動化できます。しかし、内容が正しいかどうかまだChatGPTを私が完全に信頼しきれていないため、一度人手で入力内容が正しそうかを確認するという工程を入れています。
こうしてデータを蓄積していくと、以下のようなスプレッドシートができあがります。この形式になっていると、自分が好きなように分析もしやすいですね。
ちなみにこのシートはスプレッドシートのテーブル機能を使って作るのがオススメです。テーブル機能は列毎に型の制約を設けることができるため、ChatGPTの解析が万が一間違えた場合にも素早く気付けます。
データ抽出に使っている実際のinstructionも以下に書いておくので、真似したい人は使ってみてください(プロジェクトの機能を使うのがオススメです)。データ型の定義と自分用の練習タイプを定義するのがミソです。ちなみに、過去の自分の練習タイムなどを提示した上で、ChatGPTと相談しながら自分用の練習タイプを決定しました。
データ抽出の実際のinstruction(クリックで開きます)
Apple Watchからランニングのアクティビティに関する画像が添付されます。画像から以下のカラムをtsvとして出力してください(型も考慮してください)。 - 日付: datetime - 日付の「年」は質問している日の年を当てはめてください - ランニングの開始時刻も考慮してください - ワークアウト時間: number - 秒数に変換してください - 距離(km): number - アクティブカロリー: number - 合計カロリー: number - 上昇した高度: number - 平均仕事量(W): number - 平均ケイデンス(SPM): number - 平均ペース: number - 秒数に変換してください - 平均心拍数: number - 練習タイプ: string - 今回の練習結果を見た上で、後述する練習タイプを1つだけ選んでください - コメント: string - 画像以外に文字列が入力されることがあります - その情報はこのカラムにまとめましょう - 口語や音声認識の結果が入ってくる場合があるので、最低限の修正をしましょう - 改行は含まないように修正して、一行にしましょう --- - 各カラムにはダブルクオートを付与して、validなtsvとして出力してください - ユーザーがワンクリックでクリップボードにコピーしやすい形式で出力してください - ヘッダーの出力は省略してください - 該当する項目がない場合は空文字を出力してください - 出力した末尾に[ランニング練習ノート](https://docs.google.com/spreadsheets/d/XXX_YYY_ZZZ)へのリンクも記載しておいてください - ユーザーがノートに転記する際に使います ## 練習タイプの定義 | 練習タイプ | 目的 | 距離の目安 | ペースの目安 | 備考 | |----------------|------------------------------------------------------------|------------------------------------------------|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ジョグ | 有酸素の基礎づくり、コンディション維持、疲労回復 | 2〜8km程度<br>(疲労度に応じて調整) | 1kmあたり6分30秒〜8分程度<br>(会話ができるゆったりペース) | 疲労回復がメインの場合は、短めの距離(例:3km程度)+さらにゆっくりとしたペースを心がけましょう。疲れが少ない日は距離を少し増やしてもOKです。心肺への負担が軽く、フォームを確認するのにも適した練習です。 | | ロング走 | 持久力強化、脂肪燃焼 | 10〜20km程度<br>(ハーフ程度まで) | 1kmあたり7〜8分程度<br>(非常に余裕のあるスピード) | ロングスロー(LSD)の略。タイムを気にせず長時間かけて走ることで、心肺機能・脚づくりや脂肪燃焼を狙います。1回の練習で90分〜120分程度を目安に、こまめに給水してください。あくまで「長くゆっくり」なので、ペースはジョグよりもさらに遅くて問題ありません。 | | ペース走 | 一定ペースの維持、ペース感覚向上 | 5〜12km程度 | 目標レースペース前後<br>(例:1kmあたり6分00秒〜6分20秒) | レース本番でキロ6分前後を目指す場合、そのペースをできるだけ長く保つ練習です。呼吸がやや苦しい程度の強度を最後まで維持し、ペース配分の感覚を鍛えます。距離は徐々に伸ばしながら慣れていくと良いでしょう。 | | テンポ走 | スピード持久力の向上、閾値強化 | 3〜6km程度 | ややきついペース<br>(例:1kmあたり5分30秒〜5分50秒) | 20〜30分ほど、乳酸が溜まり始める一歩手前のペースで維持します。会話はほぼできない程度の強度で、呼吸は苦しくなるけれど無酸素領域に入らないギリギリを狙います。乳酸耐性を上げ、レースペースを楽に感じられる効果があります。 | | インターバル走 | 速度向上、心肺機能の強化(VO₂max向上) | (高速走区間の合計)3〜5km程度<br>例:400m×10本など | インターバル区間はかなり速いペース<br>(例:1km5分を切るスピード) | 高速ダッシュとゆっくりジョグ(もしくは完全休息)を繰り返す高負荷トレーニングです。トラックや目安となる距離を決めて取り組み、各本の合間でしっかり心拍を落とします。スピードの底上げと心肺機能向上に効果的ですが負荷が高いので、週1回程度を目安にしてください。 | | ビルドアップ走 | 負荷耐性向上、後半の粘り強化 | 6〜12km程度 | 徐々に加速する走り<br>(序盤はジョグペース→終盤はレースペース近く) | 序盤は1kmあたり7分前後とかなり余裕を持ったペースから入り、2〜3kmごとに少しずつ上げて、最終的に1kmあたり6分前後で走り切るイメージです。後半に負荷が高まることでレース終盤の粘り強さを養います。練習後の達成感も高く、ペース配分力を鍛えられる効果的な方法です。 | | レース | 記録更新・現状の走力確認 | 5km、10km、ハーフなど | できるだけ速いペース<br>(10km53分の場合:1km約5分20秒) | 文字通り本番のレースやタイムトライアル(TT)です。練習で培った力を最大限発揮し、自己ベスト更新や実力のチェックを行います。特に大会ではアドレナリン効果で練習以上の力を出せる場合も。TTなら定期的に設定して走力を可視化する目安としましょう。 |
ChatGPTによるデータ分析と練習メニュー作成
データ分析しやすい形にようやくできたので、ここからはお楽しみの時間です。こうしておくことで、ChatGPTに例えば「ランニングの練習をしてきたので、APIからデータを取得して最新のデータを見てください」のように指示すると、ChatGPTのプラグインがGASを通じてスプレッドシートのデータを取得し、データを確認してくれます。
最新のデータだけでなく、100件程度のデータも問題なく取得し、コンテキストに含めてくれるので、以下のような確認が可能です。
- 前回のテンポ走との比較
- この1ヶ月間の累計走行距離
- 先月と比較してどの程度頑張れているか
こういったことがiPhoneのChatGPTから聞けるので、ランニングの帰りにジムでストレッチをしながらだったり、晩御飯を食べながらこういったことを分析できます。これは非常に便利です。
また、練習メニューの組み立てが特に便利です。例えば、以下のような制約を伝えた上で、それに合致し、かつ走行距離なども考慮したメニューを提案してくれます*1。
- 4月20日に淀川のマラソン大会に出場するので、1週間前くらいはテーパリングで疲労を抜く期間を設けたい
- この日は東京出張のため練習できるかわからない
- 土日は時間が取れるので長めの練習を入れたい
- 休養日を入れるなら平日にしてほしい
自分で毎日メニューを組んでいる人もいると思いますが、私のように趣味でランニングをしているような人間がそこまでスケジュールを厳密に管理するかというと、そうでもないでしょう。そういった人にはこのようにチャットで気軽に相談しながら、練習メニューを考えられるのはかなり便利だと思います。
Looker Studioダッシュボードによる可視化
また、スプレッドシートに綺麗なデータがあるので、ダッシュボード化も簡単です。ChatGPTに毎回聞くのも便利ではあるのですが、定期的に見たいものについてはダッシュボード化して見るのが早いですからね。
実際に以下のようなダッシュボードを作っています。時系列での練習状況の推移や、練習タイプでの絞り込み、目標である月間100~150kmのラインを越えられそうか?あたりを可視化しています。「最近はジョグ多めでやりつつ、週1程度でテンポ走を取り入れることができていそう」というのが例えば分かりますね。
その他の活用: Deep Research
ランニングの練習を積み重ねていくと、自分のランニングの練習結果以外にもランニング以外のことを知りたくなることがよくあります。例えば以下のようなことです。
- テンポ走やインターバル走など様々な練習方法があるが、現在の自分の走力を考えると具体的にはどれくらいのペースになるのか?
- 自分のような市民ランナーがハーフマラソンを走る際、平均や中央値はどれくらいなのか
- 年代別だとどうなのか?
- ランニングシューズの交換時期
- 何キロくらいで交換するのがいいのか?
- 現在使っているシューズを踏まえ、自分のような初心者や練習量だとどういったシューズを選ぶのがいいか?
- 一足を履き潰すのではなく複数シューズをローテーションするのがいいのか?
- 練習とレースで使い分けた場合の効果はどれくらいあるのか?
学生時代から長距離をやっていて、周りにこのようなことを聞ける人がいる場合は、特にこのような情報を調べる必要はないのかもしれません。しかし、社会人になってから、あるいは最近ランニングを始めたような人は、このような情報はよくわからないという状況だと思います。そういった際に、ChatGPT Deep Researchが網羅的に調べてくれるのは非常に役立っています。情報を鵜呑みにするのは良くないという点はありますが、率直に言って、Google検索などで自分で調べても、どの情報が信頼できるかという判断基準がそもそもわからないという状況だったりするので、そういった点での取っ掛かりとしても、詳細な調査のようなものは非常に有用かと考えています*2。
また、ChatGPTは最近メモリ機能が備わるようになり、過去にした質問や私に関する背景なども考慮した上で回答してくれえることもあるので、最近は暇があれば色々ChatGPTに質問しまくる日々を送っています。
補足
他ツールとの比較とChatGPTプラグインの利点
最近では、ClineやCopilot Agentのようなもので、MCP(Model Context Protocol)を通じてデータのやり取りをする方法があるかと思います。かなり工夫すれば携帯からも可能かもしれませんが、通常はPCを開かないと操作できず、現状はMCPを利用できないと思います。
また「ChatGPTはGoogle Driveの連携があるから、プラグインを自作する必要はないのでは?」と疑問に思う人もいるでしょう。残念なことに執筆時点ではGoogle Driveの連携はChatGPTのWeb UIからしか選択できず、出先のiPhoneからGoogle Drive連携を使いスプレッドシートを読み込むことはできません。
しかし、ChatGPTのプラグインを使えば、PCの前にいなくても本当に自分専用のトレーナーがいるかのように活用できます。例えば、食事中にiPhoneだけでスケジュールの確認が可能です。また、「今日の練習強度に合わせたストレッチメニューを教えて」と尋ねれば、すぐに回答を得られます。
パートナルトレーナー化するための仕組み(コード付き)
では、具体的なやり方について説明しましょう。携帯からChatGPTを使う場合、前述したようにスプレッドシートを直接参照させることは難しいです。そのため、ChatGPTのプラグインを使ってスプレッドシートのデータを参照させます。ChatGPTのプラグインは外部リソースをHTTP経由で呼び出して情報を取得することができます。アクセスさせるためのエンドポイントをGAS(Google Apps Script)で待ち受けさせ、ChatGPTがそこに問い合わせることで、自分のワークアウト情報を取得してくれるという仕組みになっています。
GASの作成方法に関する情報は多く出回っているので、特に難しいことはないですし、以下の実際のGASコードもChatGPTに書いてもらいました。管理やDeployはclaspでやるのがよいでしょう。
GASの実際のコード(クリックで開きます)
function doGet(e) { try { // ① スプレッドシートを取得 const ss = SpreadsheetApp.openById("スプレッドシートのID"); const sheet = ss.getSheetByName("シート名"); // ② シートの内容を2次元配列で取得 const range = sheet.getDataRange(); const values = range.getValues(); // [ [見出し1, 見出し2, ...], [row1col1, row1col2, ...], ... ] // ③ JSONに変換するロジック (見出し行をキーにする例) const headers = values[0]; const dataRows = values.slice(1); // 1行目はヘッダ const data = dataRows.map(row => { let obj = {}; headers.forEach((header, i) => { obj[header] = row[i]; }); return obj; }); // ④ JSONレスポンスを返す return ContentService .createTextOutput(JSON.stringify({ status: "ok", data })) .setMimeType(ContentService.MimeType.JSON); } catch (err) { // エラー時 const errorMessage = { status: "error", message: err.toString() }; return ContentService .createTextOutput(JSON.stringify(errorMessage)) .setMimeType(ContentService.MimeType.JSON); } }
このエンドポイントに対して、心配な方はもちろん認証などを挟むことも可能ですが、自分のランニング結果は特に誰かに見られて困るものではないため、現在のところは認証なしで運用しています。必要な人は認証を挟むようにしましょう。
今度はGASで立てたエンドポイントに対してアクセスするChatGPTのプラグインを作っていきます。やり方は詳しく書いてくださっている方がいます。実際に私が作ったプラグインの設定を以下に載せておきます。
ChatGPTプラグインの設定(クリックで開きます)
指示
:
## 一般的な注意点 - 日本語で返答します - APIからのJSONのレスポンスの日付はUTCで返ってきているので、JSTに変換してください - ユーザーが特に興味があるのは以下のカラムです、特に指示がなければこれらのカラムを優先的に出力しましょう - 日付 - ワークアウト時間 - 距離 - 平均ケイデンス - 平均ペース - 平均心拍数 - 練習タイプ - コメント - 以下のカラムは「秒」が単位になっていますが、ユーザーに見せるときは`HH:mm:ss`のフォーマットで書いてください - `ワークアウト時間(秒)`, `平均ペース` - 例: 315 => 05:15 - データを集約する際は以下のことに気を付けましょう - 一日に複数回のワークアウトを行なうことがあります - `ワークアウト時間(秒)`については秒のまま足し合わせ、`HH:mm:ss`のフォーマットに直してから出力してください - 平均ペースは一日の中で最も走行距離が長かったワークアウトのものを`HH:mm:ss`のフォーマットで表示してください - 距離は合計距離を出してください - 平均心拍数は一日の中で最も走行距離が長かったワークアウトのもの表示してください - トレーニーを伸ばすために、誠心誠意褒めましょう - ペースや距離、トレーニーが話したことなど、主観的 / 客観的な立場からトレーニーを褒めましょう - 褒めるとトレーニーは次のトレーニングへの活力になります - 事務的ではない、寄り沿った褒め方が推奨されます
会話のきっかけ:
ランニングの練習してきたから、APIからデータを取得して、最新データを見てください
ランニングの練習してきたから、APIからデータを取得してください。直近7件の練習を確認した上で、最新の練習結果についてコメントをください
知識
:
## トレーニーのプロフィール - 2024/10からランニングを始めた初心者です - 月間100~150kmを目標に走っています - 週末は長めに時間を確保できるため、練習は休みたくありません - 練習を入れるならば平日に入れたいです - パーソナルベストは以下の通り - 10km: 53:22 - ハーフマラソン: 2:13:40 - フルマラソンには興味がありません ## 直近のランニングの練習予定 - 4/9(水)~4/10(木)は出張であり、長距離の練習はできない - 4/20(日)がハーフマラソン本番であり、一週間前からは練習量を落として疲労を抜きたい ## 練習タイプの定義 | 練習タイプ | 目的 | 距離の目安 | ペースの目安 | 備考 | |----------------|------------------------------------------------------------|------------------------------------------------|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ジョグ | 有酸素の基礎づくり、コンディション維持、疲労回復 | 2〜8km程度<br>(疲労度に応じて調整) | 1kmあたり6分30秒〜8分程度<br>(会話ができるゆったりペース) | 疲労回復がメインの場合は、短めの距離(例:3km程度)+さらにゆっくりとしたペースを心がけましょう。疲れが少ない日は距離を少し増やしてもOKです。心肺への負担が軽く、フォームを確認するのにも適した練習です。 | | ロング走 | 持久力強化、脂肪燃焼 | 10〜20km程度<br>(ハーフ程度まで) | 1kmあたり7〜8分程度<br>(非常に余裕のあるスピード) | ロングスロー(LSD)の略。タイムを気にせず長時間かけて走ることで、心肺機能・脚づくりや脂肪燃焼を狙います。1回の練習で90分〜120分程度を目安に、こまめに給水してください。あくまで「長くゆっくり」なので、ペースはジョグよりもさらに遅くて問題ありません。 | | ペース走 | 一定ペースの維持、ペース感覚向上 | 5〜12km程度 | 目標レースペース前後<br>(例:1kmあたり6分00秒〜6分20秒) | レース本番でキロ6分前後を目指す場合、そのペースをできるだけ長く保つ練習です。呼吸がやや苦しい程度の強度を最後まで維持し、ペース配分の感覚を鍛えます。距離は徐々に伸ばしながら慣れていくと良いでしょう。 | | テンポ走 | スピード持久力の向上、閾値強化 | 3〜6km程度 | ややきついペース<br>(例:1kmあたり5分30秒〜5分50秒) | 20〜30分ほど、乳酸が溜まり始める一歩手前のペースで維持します。会話はほぼできない程度の強度で、呼吸は苦しくなるけれど無酸素領域に入らないギリギリを狙います。乳酸耐性を上げ、レースペースを楽に感じられる効果があります。 | | インターバル走 | 速度向上、心肺機能の強化(VO₂max向上) | (高速走区間の合計)3〜5km程度<br>例:400m×10本など | インターバル区間はかなり速いペース<br>(例:1km5分を切るスピード) | 高速ダッシュとゆっくりジョグ(もしくは完全休息)を繰り返す高負荷トレーニングです。トラックや目安となる距離を決めて取り組み、各本の合間でしっかり心拍を落とします。スピードの底上げと心肺機能向上に効果的ですが負荷が高いので、週1回程度を目安にしてください。 | | ビルドアップ走 | 負荷耐性向上、後半の粘り強化 | 6〜12km程度 | 徐々に加速する走り<br>(序盤はジョグペース→終盤はレースペース近く) | 序盤は1kmあたり7分前後とかなり余裕を持ったペースから入り、2〜3kmごとに少しずつ上げて、最終的に1kmあたり6分前後で走り切るイメージです。後半に負荷が高まることでレース終盤の粘り強さを養います。練習後の達成感も高く、ペース配分力を鍛えられる効果的な方法です。 | | レース | 記録更新・現状の走力確認 | 5km、10km、ハーフなど | できるだけ速いペース<br>(10km53分の場合:1km約5分20秒) | 文字通り本番のレースやタイムトライアル(TT)です。練習で培った力を最大限発揮し、自己ベスト更新や実力のチェックを行います。特に大会ではアドレナリン効果で練習以上の力を出せる場合も。TTなら定期的に設定して走力を可視化する目安としましょう。 |
アクション
:
openapi: 3.1.0 info: title: GAS Sheets API version: "1.0" servers: - url: https://script.google.com paths: /macros/s/XXX_YYY_ZZZ/exec: get: operationId: getData summary: Get spreadsheet data description: Returns JSON from the published Google Apps Script responses: "200": description: Successful response content: application/json: schema: type: object properties: status: type: string data: type: array items: type: object properties: 日付: type: string format: date-time description: "ワークアウト日付" example: "2024-10-06T07:34:00.000Z" ワークアウト時間(秒): type: integer description: "ワークアウトの継続時間(秒)" example: 3263 距離(km): type: number description: "走行距離(km)" example: 5.51 アクティブカロリー: type: integer description: "アクティブカロリー(kcal)" example: 282 合計カロリー: type: integer description: "ワークアウトで消費した合計カロリー(kcal)" example: 348 上昇した高度: oneOf: - type: number - type: string description: "獲得標高(メートル)または空文字" example: 17 平均仕事量(W): type: integer description: "平均仕事量(W)" example: 100 平均ケイデンス(SPM): type: integer description: "平均ケイデンス(steps per minute)" example: 160 平均ペース: type: integer description: "平均ペース(1kmあたりの秒数)" example: 592 平均心拍数: type: integer description: "平均心拍数(bpm)" example: 134 練習タイプ: type: string description: "ジョグやロング走" example: ジョグ コメント: type: string description: "その日のランニングのコメント" example: 今日もよく頑張りました!
まとめ
今回は、Apple WatchのランニングデータをChatGPTと連携させて、パーソナルトレーナーのように活用する方法について紹介しました。
データの自動集約から、分析、練習メニューの相談、さらには関連情報の調査まで、ChatGPTはランニングライフをより豊かに、効率的にしてくれる可能性を秘めていると感じています。
設定も比較的簡単なので、興味のある方はぜひ試してみてください。