あんパン

こしあん派

ChatGPTのWork with Appsを利用してXcodeでiOSアプリを作った雑感

ここ1年くらい睡眠用ASMR動画を流しながら寝ているのだが、つい先日、妻がロック画面に表示された動画の名前を音読する事件が発生したので、再発防止策として簡素なプレイヤーを自作して動画名を隠そうという気持ちになった。最近ChatGPTがXcode上で使えるようになったという情報を見たので実際に試してみた。

当該の記事はこれで、要はChatGPTのネイティブアプリを入れておくと、Work with Appsのショートカットを押したときになんかいい感じにアプリと連携してくれるよ、というもの。Xcodeだけじゃなく他のアプリケーション(iTerm2とかNotionとか)とも連携してくれるっぽい。

help.openai.com

以下雑感。

  • Xcodeと連携すると、Xcode上の最前面で表示している1ファイルだけをChatGPTに送信して、応答に含まれている差分を1ボタンで適用できるようだった
  • Clineみたいなものを想像しているとだいぶ期待外れだと思う
    • Plan/Actみたいなモードはないので「まず計画を示してください」みたいなプロンプトを無限に入力することになる
      • 無計画に実行するとだいたい気持ちとズレたものが出てきがちなので計画を洗練させる、みたいなのは一緒な気がする
    • 編集してほしいファイル以外を渡すと発狂する
      • VideoListView.swiftを渡すつもりがContentView.swiftを渡してしまうとContentViewの中にVideoListViewを作り始める、みたいなことが発生する
      • 適切なファイルを渡すためにも、どのファイルをどう編集するのか、お伺いをたてる必要がある
    • clinerulesみたいなものは存在しないので、新規に開く都度文脈を手書きすることになる
      • ペライチのドキュメントを用意して最初に手で読み込ませればよさそうではある
    • ファイルシステムを操作できない
      • 読み込みすらできないので、まず文脈を伝えるために1ファイルずつ送信してこれを覚えてくださいみたいなプロンプトを入力していた
      • 当然書き込みもできないので新規にファイルを作ってあげて、そのファイルを渡して…… みたいなことが発生する
    • 差分の適用が1ボタンでできるのは便利
      • Auto Approve的なやつもある
  • 簡単かつある程度定型的なものであれば意外とシュッとできる、気がする
    • とはいえプロンプトを結構な量入力しないとまともに動作しないので、熟達した人間が利用するものではないイメージ
      • マジの初心者が調べながら書くよりは速い、くらいだと思う
    • コード書くのだるいな、というときには有用かもしれない
  • つまるところ、裏側は普通のChatGPTであって、そこにソースコードを投げてやりとりできる、くらいの機能があるだけ
    • やりとりのログもChatGPT上に保存される
      • だらだらやっていると前のやつから消えていく? ような気がする
      • これって通常のChatGPTもこうなのかな、あんまり長くやりとりすることなかったので分かってない
    • 課金プランもChatGPT Plusで利用できるので、費用が定額なのは魅力的ではある
  • そうこうしているうちにWWDCでApple Intelligenceのいい感じグッズが発表されそうな予感はする

自己紹介用のアイコンキーホルダーを自作する

カンファレンスやら勉強会やらの懇親会でSNSのアカウント情報を交換するのはよくあることだと思う。大抵の場合はTwitterのプロフィール画面を見せてアカウント名を手打ちすることになる。もう一歩進んだ形だとQRコードを用意しておいて読んでもらったり、より高級な形だとプレーリーカードを作ったりするのだと思う。

prairie.cards

自分もプレーリーカードを作ろうかと考えていたところ、写真を封入して推し活キーホルダーを作れるハメパチという製品を発見した。

www.daioshop.jp

これにアイコンの写真とNFCシールを封入すれば同じことができそうだ。カード型だと毎回取り出す必要があるが、キーホルダー型なら名札にひっかけておけるし、アイコンで認識されていたら声もかけてもらいやすいのでは? と思い作ってみることにした。実際に購入したのは以下のふたつ。探せばより小ロットから購入できるところもある。

正方形のものでもサイズ違いがいくつか用意されているが、33mm四方くらいだとあまり主張も激しくなく丁度よいのではないかと思う。

作る手順もそんなに難しくない。まず入れたい写真を印刷する。L版サイズにアイコンと自分のWebサイトのQRコードを配置する。Adobeのフォトプランに加入しているのでPhotoshopを利用したが、Canvaなどでも作れるはず。これを近くのコンビニで印刷してきた。

印刷物とハメパチとNFCタグ

これをカットし、NFCシールと一緒にハメパチに封入する。表面はアイコン、裏面はQRコードにすることで、NFCリーダーがない端末でも読めるようにしている。

2枚の写真の間にNFCシールを仕込む

NFCタグへの書き込みはNFC Toolsというアプリを使った。タグの書き込みでは割と鉄板なアプリという印象。Android版もある。

NFC Tools

NFC Tools

  • wakdev
  • ユーティリティ
  • 無料
apps.apple.com

これでWebサイトに飛べるように設定すればひととおりの準備は完了。実際にiPhone 16, iPhone 16 Pro Max, Pixel 7で読めることを確認した。

iPhone 16 Pro Maxで読みとる図。これくらいのサイズ感になる

これからカンファレンスなどに参加する際は、名札にこれをひっかけて過ごしたい。インターネットの人々をSNSのアイコンで認識していることが多いので、真似してくれる人が増えると嬉しい。

GLSLで背景を描ける時計を作った

どういうことか分からないと思うので動画を用意した。色が薄すぎて見ても分からないかもしれない。

GLSLで背景を描ける時計

自室は電波時計の電波が入りづらく常に時計が狂っているという問題があり、大変困るのでNTPで調整してくれる時計がほしかった。ついでに自室の温度とか湿度とかいろいろ情報を表示してくれるとうれしい。そういう感じならいろいろ表示してくれるWebページを作ってモニタで表示したらいいじゃん、背景が画像なのもつまらないしフラグメントシェーダーで描けたらいいじゃんと思ったのが始まり。AliExpressで縦長モニタを手に入れて、Raspberry Piから映像を出力することにした。完成したリポジトリはこれ。

github.com

主な機能は……

  • 時計を表示できる
  • 背景をGLSLで描ける
    • 厳密にはフラグメントシェーダのみ対応
  • GLSLをWeb経由で編集できる
  • 任意のWebページからHTMLを読み込んできて表示できる

といったもの。

Viteでサーバを起動しており、fragファイルを編集するとHMRで反映してくれる。Dockerでcode-serverを起動しておけばWebブラウザでVS Codeが立ち上がって直接fragファイルを編集できる。

ブラウザからフラグメントシェーダーを編集できる

自分自身めちゃくちゃフラグメントシェーダーを書けますという感じでもないのでChatGPTに依頼しながらちょいちょいいろんなパターンを試している。デスクに置くものの見た目を手軽にカスタムできるのは面白い。

そのほか、いろいろ情報を表示したくなるだろうと思って、外からHTMLを取得してきてそのまま埋め込むだけの機能を作っておいた。本当はiframeとかでやるべきなんだろうけど、どうせ自分で作ったAPIサーバしか叩かないでしょと思ってこのへんは雑。自分はHonoで以下のようなサーバをローカルに立てて、SwitchBot APIから取得した気温湿度・CO2濃度をHTML片にして返している。

gist.github.com

Reactの知識がClass Componentを作っていた時代で止まっていたので最近のものに触れられてよかった(といってもべつに目新しいAPIを触っているわけではない)。あとHonoも初めて触ったけど、こういう手軽なサーバをシュッと立てられて便利だった。

自分の他に使いたい人いないでしょと思っているので、systemdのunitファイルまわりの話題とかRaspberry Piで起動時にキオスクモードでブラウザを表示する話題とか、READMEに書いていないことがいろいろある。丁度これを作っている時期にRaspberry PiのWaylandコンポジタがlabwcに変更になって*1、マウスカーソルを隠せないとかいろいろな問題が発生している。このあたりは追い追いどこかにメモしていきたい。というかこれを作ったのももう2ヶ月くらい前のことだし、ネタは溜め込まずにさっさと放出していきたい。

iOSのヘルスケアアプリに記録された情報をMackerelに送信する

これは はてなエンジニア Advent Calendar 2024 24日目の記事です。

こんにちは、 id:masawada です。30代に突入して早一年、だんだんと健康が気になり始めています。エンジニアたるもの無闇にアクションを取る前にまずは計測、ということでiOSにプリインストールされているヘルスケアアプリの情報をMackerelに送信して傾向を眺められるようにしてみます。

(注意: 株式会社はてなはPHRサービス事業協会に加入している法人ではありません。この記事は健康に関するデータをMackerelに記録することを公式に推奨するものではありません。あくまで個人利用・自己責任の範囲で参考にしてください)

iOSにはショートカットというアプリもプリインストールされています。ショートカットでは「アクション」と呼ばれるブロックを積み重ねることでワークフローを構築することができます。「アクション」にはヘルスケア情報を取得するものや特定のURLにHTTPリクエストを送るものなども用意されているので、これらを組み合わせればMackerelに値を送信できます。

Apple Watchを着用している場合、心拍数や歩数などのメトリックがヘルスケアアプリに自動で記録されます。また、ヘルスケアアプリと連携するサードパーティアプリを利用している場合は、それらに記録されたメトリックも自動で吸い出して集約してくれます。たとえば自分はオムロン製の血圧計、体重計、体温計を利用しており、OMRON Connectというアプリを経由してヘルスケアアプリにメトリックを集約しています。今回は心拍数を送信する例をご紹介します。


ショートカットアプリを実際に触る前に、まずはMackerelにどう値を送信するか確認しておきましょう。今回はサービスメトリックとして情報を保存することにします。

mackerel.io

Mackerelで事前にServiceを作成して、curlで以下のようなリクエストを送ると値を投稿することができます。

curl -H 'Content-Type: application/json' \
     -H 'X-Api-Key: <apiKey>' \
     'https://api.mackerelio.com/api/v0/services/<serviceName>/tsdb' \
     -d '[{ "name": "heart_rate.count", "time": 1734966000, "value": 80 }]'

ヘルスケアのメトリックを取得し、それをJSON形式に加工してこのURLにPOSTするのが今回のゴールです。というわけで、まずはヘルスケアのメトリックを取得します。

ショートカットアプリを開いて新規にショートカットを作成し「ヘルスケアサンプルを検索」アクションを配置しましょう。「クイックルック」アクションを接続することで取得した値を表示することができ、デバッグに便利です。Mackerelのサービスメトリックは最大で過去24時間分の値を記録できるので、検索する範囲は過去1日として心拍数を取得してみます。一旦情報を取得できていることだけを確かめたいので1件だけ取得することにします。

これを実行すると結果が表示されます。

酒を飲んだ後だったので心拍数がやけに高いですね。これだけで不健康さがよく分かります。

値を取得できることは分かったので、これを加工してJSONにしましょう。「各項目を繰り返す」というアクションを利用すると、いわゆるmap的な処理を実現することができます。これを配置して入力の引数を「ヘルスケアサンプル」に指定します。繰り返しの中に「ヘルスケアサンプルの詳細を取得」アクションをふたつ配置し、「繰り返し項目」から「開始日」「値」をそれぞれ取得します。「テキスト」アクションを配置すると、開始日と値を変数として埋め込んだテキストをフォーマットできます。テキストの内容として {"name": "hr.count", "time": 開始日, "value": 値} を設定することで、JSONを生成します。

この結果も「クイックルック」アクションで見てみましょう。

それっぽいJSONが表示されました。現段階では、mapした結果のitemがひとつずつ表示されています。また、timeの値がepoch秒になっていません。このままではリクエストボディとして利用できないので修正していきます。

まず結果を結合して配列にします。「テキストを結合」アクションを繰り返しの終了の後に配置し、繰り返しの結果をカンマで結合します。さらに、結合してできた文字列を「テキスト」アクションに埋め込んで [] で囲います。

次に時刻をepoch秒に変換します。繰り返し項目から開始日を取得するアクションの次に「端数を処理」アクションを接続します。数値計算系アクションの引数に日付を入れるとepoch秒(小数部5桁の精度)にキャストされる仕組みを利用しています。四捨五入と表示されますが、常に切り捨てるモードを選ぶことができます。後続の「テキスト」アクション内の「開始日」を「端数処理済の数値」に置き換えましょう。これでepoch秒を挿入することができます。

ここまででMackerelに送信するJSONを生成することができました。うまく構成できていれば以下のようになるはずです。見やすいように直近の3件をサンプリングしていますが、実際に送信する際はヘルスケアサンプルを取得するアクションの項目数を制限するチェックを外しています。

ここからは生成した値をMackerelに送信します。HTTPリクエストには「URLの内容を取得」アクションを利用します。このアクションを最後に接続しましょう。サービスメトリック投稿APIはPOSTでリクエストを送るので、方法(HTTPメソッド)はPOSTです。送信するのはJSONですが、「本文を要求」をJSONにすると値を送ることができません。サービスメトリック投稿APIでは、トップレベルが配列形式のJSONがリクエストボディとして要求されています。しかし「URLの内容を取得」アクションでJSONを送信しようとするとトップレベルが辞書形式のリクエストになります。これを回避するため「本文を要求」は「ファイル」に変更し、引数として生成したJSONのテキストを選択します。また、ヘッダとして Content-Typeapplication/json に、 X-Api-Key をMackerelから取得したAPIキーにそれぞれ設定します。これらを済ませると以下のような形になっているはずです。

試しにこれで実際にどういうリクエストが送られるのか確認してみましょう。nc コマンド*1でHTTPリクエストを待ち受けて様子を眺めてみます。

$ ( echo "HTTP/1.0 200 OK"; echo; echo "it works!" ) | nc -l -p 8080
POST / HTTP/1.1
Host: 192.168.0.56:8080
Content-Type: application/json
Connection: keep-alive
X-Api-Key: dummy_api_key
Accept: */*
Accept-Language: ja
Content-Length: 172
Accept-Encoding: gzip, deflate
User-Agent: BackgroundShortcutRunner/3218.0.9 CFNetwork/1568.300.101 Darwin/24.2.0

[{ "name": "hr.count", "time": 1734964612, "value": 141 },{ "name": "hr.count", "time": 1734964603, "value": 140 },{ "name": "hr.count", "time": 1734964598, "value": 139 }]

実際にMackerelに送信したい内容と同等のリクエストになっていることが確認できますね。ということで、あとはURLをMackerel APIのものに置き換えれば完成です。実際に投稿すると以下のようなグラフを眺められるようになるかと思います。

心拍の落ち着いているタイミングを見るに、昨日は5時過ぎに寝て10時ちょっと前に起きているのがよくわかります。来年はこういったメトリクスを駆使して健康になれるようなアクションを取っていきたいですね。

明日の担当は id:yujiorama さんです。

*1:GNU版とBSD版でオプションが違うので注意してください。ここで利用しているのはGNU版です

YAPC::Hakodate 2024にスタッフとして参加した

2024/10/5に開催された YAPC::Hakodate 2024 にコアスタッフとして参加していたので、ややいまさらながら個人の感想などを書いておく。ブログを書くまでがYAPCです。

yapcjapan.org


JPA理事の id:papix さん繋がりで YAPC::Kyoto 2023 ではコアスタッフをしていて YAPC::Hiroshima 2024 でもと思っていたのだけど、ちょうどたてこんでいる時期だったためやむなく断念。ひととおり終わって余裕がでてきたので YAPC::Hakodate 2024 ではスタッフをやらせてくださいとpapixさんにお伝えして参加することになった。ちなみに何故忙しかったというと以下の仕事をしていたから。

masawada.hatenablog.jp

準備面で担当したのは参加者向けの名札の監修と、学生旅費支援に参加する学生さんとのやりとり。名札のデザイン自体は id:mazco さんにお願いしていて、自分は名札に配置する要素だったり文言だったりを考える係だった。大吉祥寺.pmに参加した際に名札のおもてなしがめちゃいいな〜と思っていて、YAPCでもこういう名札ができるといいなと考えていたので自ら買って出たのだった。

最低限必要な要素を運営内でヒアリングして、あとは完全に自由にやらせてもらった。いま見返すと表面についてはほぼ初稿のままで細かい調整が入っているくらいで、 id:mazco さんに助けられまくっている。

検討段階の名札(初稿)

入稿した名札

裏面はいろいろな変遷を経て決定稿に落ち着いた。QRコードからヘルプページに飛べたり、ベストスピーカー賞のフォームに飛べたりという感じ。実は当日向けのヘルプページを作る試みも今回が初めてで、このコンテンツも自分が担当していた。ヘルプページについてはいろいろ反省事項もあるので今後に役立てたい。

もちろん名札以外にも、前夜祭や当日の運営スタッフとしてもいろいろと動いていた。なりゆきで裏方の裏方みたいな動きをしていたので、発表をあんまり見られなかったり参加されていた方々との交流が少なめだったりという感じでこちらもやや反省。発表については後日公開されるであろうYouTubeでの配信を見つつ、次回は余裕をもった動き方をしたい。しかし反省といいつつ、こういうわちゃわちゃした感じが文化祭っぽくて楽しくはあるのだよなあ。


個人的に参加した中で一番よかったことは @deckeye さんと初めてリアルでお会いできたことだと思う。というのも、@deckeyeさんはTwitterでほぼ最初期にフォローしていただいた方なのだった。おそらく1人目か2人目くらいじゃないだろうか? 自分がTwitterアカウントを作ったのは中学の卒業式を終えた直後の2009年3月21日なので、実に丸15年越し。今回 YAPC::Hakodate 2024 の特別企画に登壇されるという話を運営内で聞いてからずっとご挨拶したかったので、お声がけできて本当によかった。今後ともよろしくお願いします。

一方最大の後悔は観光を一切せずに函館を脱出してしまったこと。2年前に妻と函館旅行をしていたこともあり、余市とかにも行きたいしシュッと札幌まで移動してしまうか〜と考えていたのだけど、2日間動き回った反動なのか札幌のホテルで夕方まで寝てしまいなにもできずに破滅。こんなことなら函館に残ってもうちょっといろいろ食べ歩いたらよかった。また近いうちに遊びにいけたらいいな。

と思っていたら、これを書いているいま、妻が社員旅行で函館にいます。なぜ。