トップ
追記 RSS

ワタタツの日記


2025 年 10 月 28 日 (火)

PyCon JP 2025でコミュニティポスター発表をした

PyCon JP 2025のもう一人の副座長のNyohoです。

PyCon JP 2025で「すごい広島」を中心としたコミュニティポスターセッションに応募し、採択されました。そのポスターを制作の様子です。

ポスターの概要

発表したポスターのタイトルは、「Hyper-Local and Globally Connected: The “Sugoi Hiroshima” Model for Sustainable Python Communities (超ローカルかつグローバルに繋がる: 持続可能なPythonコミュニティのための「すごい広島」モデル)」でした。長いですね。

詳細は公式タイムテーブルをご参照ください。
https://2025.pycon.jp/timetable/talk/U8EJYT

できあがったポスターの全体像はこうです。

できたコミュニティポスター

ポスター制作プロセス

ポスター制作プロセスです。

誰がポスターを作るか

PyCon JP 2025の座長が「すごい広島 with Python」の主催でもあり、めちゃんこ忙しいので、せっかく広島でPyCon JPがあるのだから、誰かすごい広島のメンバでコミュニティポスター作ってくれないか、コアタイムに誰もいなくてもいいので、などと言っていましたが、誰も名乗りを上げませんでした。

とうとう、仕方がないので私が作るかなどと座長が口走っていたので、いやいや座長が作るぐらいならわしがダイビングキャッチ、と言って副座長のわしが奪いました。

初期段階: ロゴの手書きシルエット

昔から「すごい広島」にはロゴがあるのですが、雰囲気を変えてみようと思って、わしが手書きで適当にシルエットだけ描いてみました。これを3D化して、より印象的なビジュアルにしようと構想しました。

「すごい広島」の手書きのシルエット

AI画像生成への挑戦

これをNano Bananaに食べさせ、次のプロンプトで画像生成をお願いしました。

このロゴを用いて、20th century foxのロゴのように立体的な感じの3Dの構図の画像を作って下さい。フォトリアル。ロゴの部分は 20th century fox logoのような金ぴかではなく、ゴツゴツした岩のようにしてみてください。このロゴの画像がxy座標だとして、そのxy平面に垂直な方向にこのロゴの高さと同じ厚みを出して下さい。
下からサーチライトで照らす演出は付けて下さい。(たぶん20th century foxのにありますよね?)

生成自体は進みました。何度か試して次を得ました。

生成された画像1

生成された画像2

2つ目のテイストがいいなと思いました。ロゴがゴツゴツした岩のような質感になり、下からのサーチライト演出も加わりました。

奥行きの調整に苦戦

ただ、ここから問題が生じました。20th Century Foxのロゴのようなもっと深い奥行きを出したかったのですが、その指示が上手く伝わりませんでした。

試行錯誤した指示内容:

ロゴの岩の部分をもっと奥行きの長さを今の5倍ぐらいの長さに伸ばしてください。奥行きというのは元のロゴの画像のx,y平面に対して垂直な方向のことです。20th Century foxはかなり奥行きに伸びています。そして、ロゴの上側の表面が暗いので、もう少しふんわりライトを当てて下さい。ロゴだけに。すると後ろの夜空とのコントラストが出るはず。

伝わりませんでした。↓

伝わらない生成画像

さらに明確に、

岩のロゴの部分の奥行きの長さが変わっていません。5倍の幅があるようにしてください。画面に対して前後の方向です。

と指示しても伝わらず、間違った方向に伸びてしまいました。

伸ばす方向は、そっちではない↓

そっちではない

そこで最終手段として、ピンクで指示を画像に直接描き込みました。

「奥行き」が伝わらないのでピンクで指示を書いた。

「奥行き」が伝わらないのでピンクで指示を書きました。奥行きはこの方向です。

画像での明確な指示でやっと意図が理解されるかと思いきや、理解されませんでした。

諦めの境地

こちらの工夫の限界を感じたので、諦めて、生成した画像の横をinpaintingして奥行きを増やし、ポスター上部の画像を完成としました。時間も迫っていましたので!

その他の部分にギャグ: 棒グラフ

その他の部分について、少し紹介します。

「すごい広島」と「すごい広島 with Python」の実施回数の棒グラフを作りました。PyCon JPなのでわざわざmatplotlibで描きました。

変な棒グラフ

回数なので必ず1ずつ増えます。ただ、どのぐらいの時期から「with Python」が始まったのかについては一望にできるので、完全に無意味なグラフというわけではないものになりました。

ツッコミ

ちゃんと自分で突っ込みも入れておきました。

はいそこー! 回数を棒グラフにしない〜ww

セルフツッコミ

印刷

ポスタープリンタで印刷している様子を激写しました。Day 0です。

ポスタープリンタで印刷
ポスタープリンタで印刷
ポスタープリンタで印刷
ポスタープリンタで印刷

当日

当日は主催メンバーとしてあちこちに存在していたので、ポスターセッションのコアタイムすべてにはいられませんでしたが、コアタイムで説明するときに来てくださった方とは地域でコミュニティを維持することについていろいろな側面からお話ができてよかったです。

PyCon JP 2025でお会いできた皆様、ありがとうございました!


2025 年 10 月 27 日 (月)

PyCon JP 2025で「Pythonのピース」を集めるウェブアプリを作って運用した

[screenshot]

こんにちは。PyCon JP 2025のもう一人の副座長のNyohoです。

今年のPyCon JP 2025のテーマは「あつまれPythonのピース」でした。せっかくこんなエモーショナルなテーマですので、このテーマを仮想的に実現するような、参加者の皆さんが持ち寄った「Pythonのピース」を仮想的に集めるウェブアプリを作って会場で使っていただきました。

テーマの思い

「あつまれPythonのピース」というテーマには、Pythonの得意な使い方、愛用しているライブラリ、考え方、立場の違い(エキスパート・入門者・教育者・コミュニティ運営者など) といった、Pythonに関するさまざまな “ピース” を参加者が持ち寄って、集まり、それらの異なるピースがPyCon JPの会場で出会い、複雑にコミュニケーションが起こるというイメージの想いが込められています。

パズルのピースのように、それぞれの個性が噛み合って新しい何かが生まれる……そんなイメージを形にしたのが、今回のロゴです。エモーショナル!

テーマの思いのこもったロゴ

今回のロゴは、Pythonのロゴをモチーフにして、テーマに合わせてパズルピースになっています! しかも平面を無限に敷き詰められるようにデザインされています。すべて、デザイナの柳谷さんのアイディアです。

[平面充填できちゃうロゴ]

当初は、このロゴをアクリル製のピースにして、
そこに参加者が自分の“Pythonのピース”を書き込むという企画を考えていました。しかし、アクリルの制作はスケジュールやコストや使用法の面で難しく、実現を断念しました。

ところが、座長が「このロゴに込めた意味はまだ諦めていない」と言っていたのをわしが思い出し、その想いをオンラインで形にするために、このウェブアプリを作ることにしたのです。

ウェブアプリの仕組み

このウェブアプリは2つのサイトから成っています。

集める方

集める方のアプリでは、

  • 参加者が自分の“Pythonのピース”を入力できます。
  • 認証は不要で誰でも投稿できます。
  • いたずら防止のために管理者ページを設け、投稿内容を承認したら表示するアプリに出てくるようにしました。
  • 投稿があるとわしに通知が届き、承認されたものだけがAPI経由で表示する方で公開されます。
表示する方

表示する側は、アクリルにしたかったこのピースを、できるだけ美しい3DCGになるように心がけました。

公開APIを通じて表示する側ののサイトがピースの名前たちを取得し、3Dで表現された美しいクリスタルのようなピースに名前を刻んで表示します。

新しいピースが追加されると、画面上に上から降ってきて集まっていく―― そんな、ちょっとエモーショナルな演出にしています。

こんな感じです。

当日の様子

当日は、入力フォームのQRコードと説明書き印刷して、会場のあちこちに貼ったり、参加者に直接お伝えしたりしました。

説明書き

参加者の皆さんにも随時紹介し、表示する側の3DCGはメイン会場のスクリーンで幕間にループ再生してもらいました。ウェブアプリにしたことで、配信チームにループ再生してもらうことが容易になっています。たぶん。

入力があ(って承認され)るたんびに、ピースが一つ、また一つと画面の上から降り、増えていく様子がリアルタイムで見えて、とても印象的な光景になったと思います。

公式パーティー会場でもピースを表示し、最終的には2日間で約60個のピースが集まりました。さらに翌日のスプリントでも紹介し、合計80個以上のピースが集まりました。やった!

もう少し広報を強化したらもっと使っていただけたかもしれませんが、多くの方が参加してくださり、とても嬉しかったです。

感想

このアプリを通じて、みんなのPythonへの思いやピースがどんどん集まっていくというアイディアが、仮想的にでも形になっていく様子を見られたのは、とても感慨深い体験でした。PyCon JP 2025の「あつまれ Python のピース」というテーマが、まさにそのまま具現化できたと思います。楽しかったです。コナミ環

【後半】PyCon JP 2025「あつまれPythonのピース」技術構成

後半は、技術的な構成を書きます。

上の記事に出てきたウェブアプリの技術構成を簡単にメモいたします。

概要

PyCon JP 2025のテーマ「あつまれPythonのピース」を体現する、参加者からキーワードを収集し、3D空間で可視化するインタラクティブシステムを構築しました。システムは2つの独立したウェブアプリケーションで構成されています。

システム構成図
[参加者]
    ↓ 「Pythonのピースの名前」を投稿
[gathering-names-of-pieces-2025] (FastAPI)
    ↓ 承認されたキーワード
[collected-pieces-2025] (React Three Fiber)
    ↓ 3D可視化
[参加者が閲覧]

1. ピースの名前を集めたり管理するシステム (gathering-names-of-pieces-2025)

参加者から「あなたのPythonのピース」の名前を収集し、管理者が承認を行うシステムです。

技術スタック
  • Python
  • FastAPI
  • Jinja2
  • データベース: PostgreSQL (Supabase)
  • Docker
  • Google Cloud Run
  • Supabase
  • GitHub Actions

あつまる側のアプリは、せっかくなので、Next.js, ReactのようなJavaScriptのフレームワークを全く使わずに、Python、FastAPIで作ってみました。

また、クラウド的にSupabaseというウェブサービスがPostgreSQLを簡単に使えそうでしたので今回初めて使ってみました。

また、認証画面は自分だけですが、わざわざGoogle OAuthで認証するように作ってみました。

今回、pycon.jpのドメインで公開するためにCloud Runだけだとhttpsの証明書の名前が付けにくかったので、Cloud Runの前に、ロードバランサを入れました。これはPeacock氏のアドバイスです。

2. あつまったPythonのピースを3Dで可視化システム (collected-pieces-2025)

承認された「ピースの名前」を3D空間に「ピース」に書き込んで降らせ、物理演算でインタラクティブに表示するビジュアライゼーションシステムです。

技術スタック
  • フレームワーク: React 18 + TypeScript
  • ビルドツール: Vite
  • 3Dレンダリング: Three.js (React Three Fiber)
  • 物理エンジン: Rapier (@react-three/rapier)
  • 3Dユーティリティ: @react-three/drei
  • ホスティング: Cloudflare Pages

これはさすがにJavaScriptを使いました。

Three.jsとそのReactで使えるもの自体は使ったことがあったのですが、物理エンジンにRapierを使ったのが初めてでした。

こちらはViteで静的サイトとしてビルドし、CloudFlare Pagesにデプロイしました。

パフォーマンス最適化

数百の入力があることを想定して、パフォーマンスについても考慮していました。数百を超えている場合は、ピースの方を、丸みなど少し簡素化して、より滑らかに動くようにするというものです。

何も最適化しないと、500個ぐらいのピースでもうガクガクになりました。

アニメーション

一定の時間の操作がないと、自動的にアニメーションするようにしました。

ゆっくりカメラが周りを回り、ときどき一つのピースをランダムで選んでカメラに見せるというものです。カメラに見せ終わったら、ぽーんと中央に飛ばすようにしてみました。

まとめ

このプロジェクトでは、FastAPIとReact Three Fiberを組み合わせることで、参加者の皆さんの「Pythonのピース」を仮想的に、かつ、インタラクティブに3DCGでお見せすることを実現しました。

新しい技術も学べて面白かったです。コナミ環

Tags: PyConJP PyCon

2025 年 10 月 13 日 (月)

PyCon JP 2025で短いBGMを3曲作った

PyCon JP 2025を終えて。主催メンバーTシャツと名札

PyCon JP 2025のもう一人の副座長のNyohoです。今回のPyCon JP 2025で、カンファレンスのために短い曲を3曲作曲しました。経験者によるとPyCon JPで音楽が付いたのは初めてだそうです。

1. オープニング・ジングル

《↓SoundCloudの埋め込みとリンク》

今回、同じく副座長のPeacockさんが両日、朝のオープニング司会を担当することになりました。そこで、Peacockさんの登場時と、司会終わりに使えるジングルを作ろうと思い立ちました。

Peacockさんに好みの曲調を尋ねたところ、「クラシカルな感じ」とのことだったので、その方向で制作することにしました。インスピレーションを得るために考えていると、以前、Peacockさんに名前の由来を聞いたことを思い出しました。「なんでPeacockなんですか?」と。その由来とは、コダーイ・ゾルターンの有名な管弦楽曲《ハンガリ民謡『孔雀は飛んだ』による変奏曲》、通称《孔雀》でした。

ここからインスピレーションが湧き、コダーイの《孔雀》のテーマをモチーフにして、「PyCon JP two five」という歌詞を当てはめ、続けて「in Hiroshima」というメロディを作りました。

抜粋した楽譜

楽譜の抜粋

ちなみに、コダーイは没後70年経ってないのでこの変奏曲自体は勝手に改造できないんですが、コダーイがこの変奏曲に使った主題のハンガリ民謡はもっと昔から存在していたらしいので、著作権的にばっちりです!

シンセサイザ以外の生音は妻とわしです。

パート 演奏者
ソプラノ
アルト わし
テノール わし
バス わし
トランペット わし

高い声を妻に手伝ってもらったというわけです。

2. クロージング・ジングル

オープニングの終わりや、あわよくば各講演の終わりにも使えるよう、クロージング・ジングルも前日に急いで作りました。

《↓SoundCloudの埋め込みとリンク》

こちらは歌詞「PyCon JP」のみのシンプルな曲で、インスピレーションが湧くままに一気に作りました。これでオープニングの最初と最後を飾る曲が揃いました。

机に残されていたスケッチ

後日談ですが、すべての日程を終えて帰宅すると、机の上にこの曲のスケッチが残っていました。エモーショナル!

机の上に残されていたクロージング・ジングルのスケッチ

ライトニングトークと終了音楽として使用

当初は各セッションの登壇の最初と最後に使えたら、とも思ったのですが、設備・音響的な都合でそれは叶いませんでした。

ところが、思わぬ形でこの曲が活躍することになります。1日目と2日目の夕方に行われたライトニングトーク (LT) で、5分経過を知らせる「銅鑼」の音の代わりに、このジングルを使わせていただけることになったのです! LT司会者のヨナスさん、ありがとうございました。

ライトニングトークは、5分という制限時間内に発表するプレゼンテーションです。5分経過すると、銅鑼の音などで強制的に終了させられるのが醍醐味の一つ。今回は、その銅鑼の代わりにこのジングルを使わせていただきました。
しかも、タイムキーパーと音出しの役割もわし自身が担当させてもらいました。下手(しもて)袖でやっておりました。

癖になる

これは癖になりそうです。5分経過した瞬間に、プレゼンを強制終了させる、しかも自分の曲を流して止めるのは、なかなかの快感でした。

見事なタイムマネジメントで時間内に発表を終える方には「ちぇっ」と思いつつ(←失礼だねっ)、時間をオーバーしそうな方には「よしよし」と思いながら、思い切って音楽を流しました。

3. 西本座長 登場曲

一番大きな会場であるフェニックスホールでは、袖で音楽の操作をする担当がいれば音を出せるとのことだったので、オープニングで先の2曲を使うことにしました。

前日のリハーサルで座長の西本さんが登壇するパートを確認したところ、フェニックスホールのステージがこれまでのPyCon JPの会場と比べて非常に広く、下手(しもて)から上手(かみて)の演台まで移動するのに時間がかかり「間が持たない」ことが判明しました。

そこで急遽、西本座長の登場曲を作ることに。1日目の朝になんとか突貫工事で完成させました。

それがこちらです。

《↓SoundCloudの埋め込みとリンク》

手拍子をいただけた

この曲はアップテンポで楽しい雰囲気にしました。オープニングで流したところ、なんと参加者の皆さんから自然と手拍子が沸き起こったのです! 作曲した本人としても本当に嬉しかったし、改めて音楽の力のすごさを実感し、感動しました。

まとめ

というわけで、合計3曲が誕生しました。短い曲作りと聞いていただくこと、楽しかったです。来年のPyCon JPも広島の同じ会場で開催されます。できたらまた音楽制作や音響担当として関われたら嬉しいなあと思います。コナミ環。


2022 年 12 月 30 日 (金)

Linuxカーネルの関数の書き方が変わっていたので対応した

LinuxカーネルのPCI関係のモジュールに使っていた関数の書き方が変わっていたので対応しました。

具体的には次のAPIが無くなっていました。

  • pci_alloc_consistent
  • pci_free_consistent
  • pci_set_dma_mask

遅くとも Linux 6.1.0 にはもうありませんでした。実際にはもう少し前から無くなっていたようです。以前までは pci-dma-compat.h に入っていたようです。

Christophe JAILLETさんの Remove usage of the deprecated "pci-dma-compat.h" API という投稿によるととっくにdeprecatedだったようです。を見ます。ここにいくつかのドライバのパッチもあたっているので、どう書き換えればいいのかわかりました。

書き換え方

関数の名前は、

  • pci_alloc_consistent は dma_alloc_coherent に
  • pci_free_consistent は dma_free_coherent に
  • pci_set_dma_mask は dma_set_mask_and_coherent に

それぞれ変更します。

次に、どの関数も、第1引数を p とすると &p->dev に変更します。

dma_alloc_coherent だけは、第4引数として GFP_KERNEL を追加します。

成功

以上でコンパイルも通りました。カーネルにロードして少し使ってみたところ正常に動いているようでした。

Tags: Linux

2022 年 12 月 9 日 (金)

consult.el の非同期コマンドの仕組み

このエントリはEmacsのAdvent Calendar 2022の9日目用です。

以前の記事「はてなブックマーク用のconsultコマンドを作っている」で書いた consult-hatena-bookmark を改良するにあたり、今年夏から秋にかけて、(自分としては)かなり consult.el のコードを読みました。

そのコードリーディングの中で、consult.el が非同期な候補の読み込みをどうやっているのか、だいぶわかったのでご紹介します。

公式で非同期で読んでいる consult コマンドのまねをしたい

公式で用意されている consult コマンドの中で、候補を非同期で読んでいるタイプのものは次などがあります。

  • consult-grep
  • consult-ripgrep
  • consult-man
  • consult-find

コマンドを実行してからプロンプトを表示しながら、入力するたびに、検索的なことが非同期に実行されて、その結果を受けとりながら、インクリメンタルに候補を表示します。

はてなブックマークの検索でも、同様の非同期検索体験が実現できるととても快適になると思うので、どうしても非同期に読み込む方法を理解して実装したかったです。 (2021年の初期バージョンでは、同期的に検索して結果を表示していました)

これらの非同期な consult コマンドは全部 consult--async-command を使っていました。これが鍵です。

consult--async-command

consult.el は基本的に consult--read 関数に候補のリストを渡して使います。

静的な候補を絞り込みたい場合は、候補のリストをそのまま consult--read の第1引数に渡します。

一方、非同期に候補のリストがどんどん更新されるようにしたいときのために consult--async-command マクロが用意されています。

consult--async-command を使えば作れそう……と思ったのですが、これは、さらに consult--command-builder なる、(UNIX的な意味での)コマンドのビルダを渡して、またさらに consult--async-process で非同期に(そのコマンドの)プロセスを起動するという使い方をされています。

今使いたいはてなブックマークの検索はweb APIであって、ローカルのコマンドではないので、これではだめです。(前回の初期バージョンでは w3m コマンドを使ってブックマーク検索結果を取得していたので、この外部コマンドを使う方法でいけたかも知れませんが、もう w3m ではログインできなくなったのでweb APIにしました。) (UNIX的な意味での外部コマンドの結果を consult.el で絞り込みたい非同期 consult コマンドを作る場合は、そのまま consult--async-command を使えばできると思います。)

consult--async-command みたいなのの web API を叩く版を作る!

というわけで consult--async-command の中身のコードちゃんと読んで、外部コマンドを叩こうとしているところを、必要な処理に置き換えることにしました。

というわけでコードリーディングはまだまだ続きます。

つまり consult--async-command の中身です。ここが今回わしが 一番面白さを感じたところ です。

コードは https://github.com/minad/consult/blob/93091590b2a2029bcecce3fa355f8857a8775836/consult.el#L2169-L2184 です。

thread-first から始まって、(consult--async-sink)(consult--async-refresh-timer)、終わりの方では (consult--async-throttle)(consult--async-split) などと、consult--async-系の単独の関数がどんどん並んでいます。

thread-first マクロは、「前の結果(出力)を次の関数の第1引数に入れる」ことを繰り返して1本のスレッドのようにつなげていく書き方ができるマクロです。ちなみに thread は英語の単語で、糸という意味です。

「次の関数」は第1引数を省略した形で書いておきます。そこだけ見ると不完全なように思えますが、thread-first の中ではその書き方でいいわけです。オードリーの春日が「春日のここ、空いてますよ。」と言うような感じです。(「春日のここ」が第1引数ではなく、最終引数になったバージョンの thread-last マクロもあります。)

ヘルプに載っている例がわかりやすいです。

(thread-first
  5
  (+ 20)
  (/ 25)
  -
  (+ 40))

(+ (- (/ (+ 5 20) 25)) 40) と同じことだと書かれています。
最初の 5(+ 20) の第1引数に入力されます。第1引数は省略された形として評価されるので 20 は第1引数ではなく第2引数です。つまり春日のここは (+ 春日のここ 20) です。

(thread-first
  (foo)
  (bar a b)
  (baz c d e)
  (qux f)))

を図解してみます。

[description]

これがこの非同期のためにぴったりなんです!

[description]

まず (consult--async-sink) で非同期用のジェネレータ、いわゆる非同期 sink 関数を作って返します。

consult--async-sink のドキュメント文字列に書かれているように、これが返す sink 関数は、次のように引数 action を受け取って動くようになっています。

  • 'setup が引数の場合、セットアップして nil を返す。
  • 'destroy が引数の場合、状態を壊して(やり直す感じ)、nil を返す。
  • 'flush が引数の場合は、ためていた候補をまっさらにして (flush) nil を返す。
  • 'refresh が引数場合、(consultの)UIをリフレッシュして nil を返す。
  • nil が引数の場合、Return the list of candidates.
  • リストが引数に来たら、今ある候補のリストに追加してそのリストを返す。
  • 文字列が引数に来たら、現在のユーザが入力している文字列を更新して nil を返す。

この仕様に沿っている関数を、thread-first でどんどん次の関数に渡しながら、「ご所望」の関数になるようにちょっとずついじっていき ます。面白いです。

例えば consult--async-refresh-immediate は、候補が追加されたらすぐにUIをリフレッシュするように、いじります。
consult--async-throttle は、スロットルします。web APIを使うときなんかは特にそうですが、同じ入力文字列(プロンプトで入力中の文字列です)が入っているときに、何度も同じ検索を流したくないです。そういうときに使えます。
consult--async-split は後述しますが、‘#’ 記号を挟んで検索絞り込みを外とローカルで分けてくれる超便利関数変更関数です。

このように consult.el では、自分のちょっとの仕事だけをうまくやる小さい関数を組み合わせて全体の機能を作り上げていく書き方がされていることがわかりました。UNIX哲学〜ですね。

今回は、 consult-hatena-bookmark--search-generator という関数を作ってみました。 https://github.com/Nyoho/consult-hatena-bookmark/blob/b85484b11705ebd896878d3ac7fdb12bc8c9637a/consult-hatena-bookmark.el#L205-L211

コードがかなり consult--async-command と似ていますが、外部コマンドを呼ぶ処理ではなく (consult-hatena-bookmark---async-search) が真ん中あたりに挟まっています。

ここで、必要な引数が来たときだけ、特に、文字列が来たときには、実際のはてなブックマーク検索をする consult-hatena-bookmark--search-all 関数が走るようにしました。

さらに工夫したところ、工夫できなかったところ

さらに今回はその中で async/await, promise が使える async-await を使っています。web API の1回分の問い合わせの結果を await して受け取ることに使いました。(追記: async-awaitパッケージという名前ですが、今回のconsult.el自体の非同期の仕組みのことではありません。)

さらに、念願のページネーション的な取得も実装しました。つまり最初は20件だけ取得しておいて、検索結果が20件より多い場合は、オフセットをずらしながら何度もAPIを発行して全件を取得するというものです。

このままでは、途中で検索ワードを変更した場合や、consult-hatena-bookmark コマンドを終了/キャンセルしたときに、全件取得のルーチンが動きっぱなしなってしまうので、 consult-hatena-bookmark--stopping という変数を作って、これが nil のときには検索を止めるようにしました。グローバル変数っぽくてかっこわるい実装なのかも知れませんが、どうしてもいい方法が思いつかなかったので、この変数を用いることにしました。いい方法がありましたらお教え下さい。または pull request をいただければ嬉しいです。

consult での絞り込みの好きなところ

ここで consult での絞り込みの好きなところをご紹介します。
consult--async-split による機能です。

それは ‘#’ 記号です。

M-x consult-hatena-bookmark してプロンプトが出てくると、キーワードを打ちます。emacs とか。ここでマイはてなブックマークの検索の外部通信が走ります。
[emacsと打ち込んだところ]

それに続けて ‘#’ 記号を1発入れて、さらに文字列を打ち込みます。29 とか。合わせて「emacs#29」が打ち込まれたところです。

[合わせて「emacs#29」が打ち込まれたところ]
そうすると、

  • ‘#’ の前は、web APIで取得する外部のデータへの問い合わせ
  • ‘#’ の後は、前者で得られたデータを絞り込むための文字列に!

これです! これがすごくいいです。

APIで検索する文字列(この段階で自分のブックマークから絞り込まれています)、さらにそれをローカルで絞り込むという、2段階の絞り込みが1行でできてしまいます!

ここ好き

コードリーディングの感想

Lisp万年初心者としてはかなり頑張ってコードリーディングし(て自分のコードを書き)ました。感想としましては、非同期処理のために、何か特別な別プロセスなどがあるわけではなくて、とにかく関数を関数に食わせてどんどん関数をいじって関数だけでなんとかしようとしているところが、とても関数型プログラミングっぽいなあと思ったりしてグッときました。以前の自分よりはちょっとだけLispが読めるようになった気もしました。この調子でもっとLispの面白さを学んでいきたいです。コナミ環。

Tags: Emacs lisp

2021 年 12 月 25 日 (土)

はてなブックマーク用のconsultコマンドを作っている

これはemacs Advent Calendar 2021の25日目の記事です。

minad氏による、Emacsの最近のパッケージの一つ、consultをすごく気に入ったので、自分のはてなブックマークを検索するパッケージを書いています。

https://github.com/Nyoho/consult-hatena-bookmark

です。

[description]

はてなブックマーク

はてなブックマークはソーシャルブックマーキングサービスです。

ソーシャルなので、ブックマークするときだけでも他の人のコメントを見て勉強になります。

そんな一期一会な使い方も面白いですが、ストックしていくものとしても便利です。そこで欲しくなるのが「自分のブックマークを全部検索する」機能です。実は、サイト上でもできます。これがEmacs上でもすばやくできたら楽だし楽しいなと思います。

counsel用のものは途中まで書いた

昨年 (consult ではなく) counsel 用のコマンド counsel-hatena-bookmark は書いていました。しかし、非同期的に読むところがまだうまく書けてなくてそのままになっていました。
そして放置しています。

それは置いといてconsult用で書いてみようと思って書き始めたところ、非同期的なところが割と簡単に書けました(気がします)。と言っても「結果が多いときに繰り返し読む」機能はまだ書けていません。

歴史と問題と全文検索API

実装に関係するので先行研究(事例)をご紹介します。

おそらく歴史的にはまず、anything用の anything-hatena-bookmark がありました。その後にhelm用の helm-hatena-bookmark がありました。わしもどちらも使っていました。

このどちらの実装も、はてなブックマークの自分のブックマークをダンプしたものを定期的に(または手動で) 全部 取得しておいて、それをローカルで串刺し検索するというものでした。

しばらくは楽しく、便利に使っていたのですが、

  • このダンプするURLがすごく重い
  • ブックマークが数万を超えてくると以前のものが取得されない

という問題がありました。

そんな中(わしが)見付けたのが、マイブックマーク全文検索APIです。

これはその都度クエリを投げて返答をもらうAPIで、定期的にローカルにダンプしておく必要がありません。そのため、今ブックマークしたばかりのブックマークもひっかかります。(anything/helm用の上の実装では、その前に重たい手動ダンプが必要です。)

また、このAPIは、そのページのタイトル、ブックマークコメントだけでなく、ページの本文にもヒットする仕様になっています。これが便利なときがあります。(便利ではないときもあります。)

そんなわけで、 dump v.s. API で、後者の全文検索APIを使う方法をとることにしました。(counsel用のものも同様の方針にしています。) これならブックマークが数万を超えていても安心ですし、いつでも最新のブックマークが検索できます。

実装

consultのいろいろなコマンドの実装のソースとにらめっこしながら少しずつ作っていきました。

基本的には consult--read 関数がメインです。これに絞り込みたい候補を突っ込みます。そうするとプロンプトの上で絞り込みが行えます。オプションが色々付いていて、ヒストリを作ったりできます。

ログインはw3mにまかせる

工夫したところの一つはw3mを使ったことです。

はてなブックマーク全文検索APIを使うのにログインが必要です。
ログインの認証コードやクッキー保持などを書くのは(わしには)大変そうなので、外部コマンドのCUIブラウザであるw3mにおまかせしました。

そうすると、consult--async-command で外部コマンドとして w3m でAPIにアクセスするものを呼び出して、結果をJSONテキストでゲットし、あとはEmacsで処理するだけにできます。

JSON解析は27.1の新機能を使ってみた

ゲットしたテキストのJSONデータを実際のJSONオブジェクトにするには、Emacs 27.1で導入された新関数 json-parse-string を使ってみました。ビルトインの関数なので高速に解析してくれると評判(?)です。

これでパースしてEmacsのリストにします。

リスト項目にpropertize

ブックマークは、タイトル、URL、ブックマークコメント、日付という様々な要素があります。これが結果のリストの項目です。

これをconsultでうまく受け取るために、文字列本体は
format した文字列にしました。これで割と整頓して表示できました。(これでいいのかな)

これだと絞り込んだ後のURLが表示用のこの文字列になってしまうので、 propertize'consult--candidate というキーに URLを値として付与しました。

こうしておいて、 consult--read:lookup:lookup #'consult--lookup-candidate としておくと、 このキーの値を返してくれるようになりました。表示用と実際の値をこのように分けることができたのでした。(これでいいのかな)

未来。今後の課題

以上で一旦公開までこぎ着けましたが、まだまだ課題があります。

MELPAかどこかに登録したい

せっかくなのですぐに使ってもらえるように、MELPAかどこかに登録したいです。

「結果が多いときに繰り返し読む」機能

APIでは、ディフォルトでヒットした最初の20件が返ってきます。本当はもっと多いときは、オフセットを指定して何度も問い合わせることで全件を取得できます。まだその機能は付けていません。どう書けばいいかまだわかっていないからです。わかる方は、どうかお教え下さい。🙏

Embarkへの受け渡し

今は絞り込み中に Embark を起動して、URLなので例えば eww に渡すとかしても、表示用の文字列が渡ってしまいます。ちゃんとURLはURLとしてEmbarkに渡したいです。こうするにはどうすればいいかまだわからないので、後回しにしています。
これもわかる方、是非ともお教え下さい。🙏

marginalia対応した方がいいのか

というかそもそもformatで自分で整形するより、そういうのはmarginalia対応してうまいこと日付とか表にしてもらった方がいいのではないだろうか、などと思うけど、maginaliaのことがよくわかっていないのでまだわからない。理解したい。

結論: 楽しい

ともかくこれで楽しく自分のブックマークを全文検索できるようになりました。Happy social bookmarking!

追記

はてなへのログインがJavaScript必須になってしまって w3m でアクセスする方法ではできなくなりました。

他の方法を模索中です。→WSSE認証にしました (後で書く)

Tags: emacs

2021 年 9 月 12 日 (日)

PyCharityでの広島コミュニティの発表をきっかけにして電子工作に入門できた #PyCharity

昨日 2021年9月11日(土) Python Charity Talks in Japan 2021.09 というイベントにすごい広島 with Pythonチームのメンバとして出ました。

出て得られたことのまとめ

  • 電子工作初心者だったわしが、電子工作に入門できた。
    • 広島のすごい広島 with Pythonコミュニティによって、電子工作・Pythonに精通した人たちから一歩一歩学ぶことができた。
    • 「ソフトウェアは趣味でずっとやってきたので少しは書けるが、ハードウェアは全くできない」という複素数、あ違った、コンプレックスが解消できた。
  • 「0が1に」なった実感。急に自分が手を下せる世界が広がった。
    • 普段生活しているときに、「あれ、これってこうやったら作れそうじゃないか」という視点で生活できるようになったと感じる。
    • 0の状態をレベル1にすることは本当に革命的だ。

当日の録画と提示資料

当日のYouTubeの録画はこちらです。

(広島チームの出演部分から再生が始まるようにしているつもり(30分))

わしの電子工作入門の発表部分 (およそ5分) へのジャンプもどうぞ。

スライドはこちらです。途中本番では動画が流れています。

今回の Python Charity Talks の構造

Python Charity Talks 自体は、日本のPythonコミュニティが PSF (Python Software Foundation) に寄付をするために開催されているイベントです。(わしも Python は、主に PythonJulia を使っているときに使っているので、日頃の感謝を込めて喜んで参加費を支払いました。) これまで何度も開催されています。

今回は日本のPythonコミュニティから4地域が発表するという構造でした。飛騨高山、駿河・静岡、山梨、広島です。コミュニティ活動技術という2面から話が聞けるというものになっていました。

その地域のコミュニティの一つとして、広島からはすごい広島 with Pythonが出演しました。すごい広島 with Python チーム全体で「これから始める電子工作とMicroPython」というテーマにしました。

すごい広島 with Pythonチームでは4人が出演、わしはそのうちの一人として出ました。

すごい広島チームでのわしの立ち位置とわしの出演経緯

すごい広島 with Pythonのわし以外の3人は、電子工作が中級・上級者です。まとめ役のにしもつ(@24motz)さんなんかは子供の頃から電子工作をされていたそうで、コンピュータ・電子工作の歴史も40年見てこられていて、技術的にもベテランです。

初めににしもつさんがこのPython Charity Talksの話を受けられていたときに、コミュニティ内 (PyCon広島のSlack) で「誰か一緒にしゃべりませんかー」と呼びかけられました。

わしは、電子工作は、いつかやりたいことの一つでしたので、「よしよし電子工作初心者としての視点を持って、聞き手として参加し、あわよくばこの機会に入門してみよう」という魂胆を抱きました。魂胆です。

早速にしもつさんに、初心者のマインドを持った聞き手として参加したいと名乗り出ました。その後むじん(@mu2in)さんとさんのみや(@sn3y2)さんが、実践者として名乗りを上げました。

電子工作の聞き手として

電子工作の「初心者視点での」聞き手として、本当に何もわからない状態から、初心者としてやってみた状態になることを目指しました。そうすることで本当に初心者が何がわからないかや、何に困っているのかがわかると思ったからです。

そのために「電子工作何もわからん」状態から一歩踏み出そうとしました。「電子工作何もわからん」の内訳はこちらです。

  1. 何を、どのパーツを買ったらいいのかわからない
  2. 買ったとしてもどう繋げばいいのかわからない
  3. プログラムをどう書けばいいのか

(↓当該スライドをページ指定して表示)

幸いわしは日曜プログラマなのでソフトウェア部分はある程度ならわかります。そこで、最初の二つについて、にしもつさんに課題を出してもらうことにしました。

  • わし「僕が素人の視点で感想を言うので、そろそろ初心者入門向けとしてこの辺を買ってやっといてくれという課題をぶっ込んでください。」
  • にしもつさん「じゃあ Raspberry Pi Pico で Lチカ を最初の目標にしましょうか。安いし流行ってるし技適の心配がないし」

なるほど!

ということで Raspberry Pi Pico と、LEDチカチカするための他のパーツを何を買えばいいのか、引き続きPyCon広島のSlackで聞きながら調べました。

このスライドではコピペしにくかったりしますので買ったもののリストを紹介しましょう。

買ったものとリンク

秋月電子通商で次を購入しました。

作例サイトを教えてもらう

作例サイトをいろいろ教えてもらいました。「単一のパーツを付けた動かすだけ」のようなものを教えてもらったところがポイントです。これで一歩一歩試すことができました。

これだけでも十分入門できました。

初めてのはんだ付け

はんだ付けも初めてです。Raspberry Pi Pico やセンサにピンヘッダという部品をつなげるために、はんだ付けをしました。これでブレッドボードというボードに「線を好きに刺して実験」することができます。そうでないと、直接パーツを線でつないだりしないといけないんだと思います。それは大変です。ブレッドボードがこういう実験には必須だと思います。

はんだ付けをミスったりやり直したいときには、はんだ吸い取り器を使います。動画ハンダ吸取器の使い方LED工作 (YouTube) が参考になりました。

プログラムをどう入れるか

Raspberry Pi Pico にまず MicroPython を入れます。

(失敗した場合は Raspberry Pi Pico の BOOTSEL ボタンを押しながらUSBに差し込むとまたマスストレージモードでマウントされます。)

MacにはThonnyという開発環境を入れました。

  • Homebrew なら brew install thonny でOK。
  • Thonny.app で右下メニューから "MicroPython (Raspberry Pi Pico)" を選択する

ちなみに、完全におかしくなったら flash_nuke.uf2 をダウンロードしてきて書き込む。そうするとまっさらなRaspberry Pi Pico になります。初めて次の中国語のブログが役に立ちました! 分享科技與遊戲 by HKGoldenMr.A: 解除死鎖狀態的 Raspberry Pi Pico (Google翻訳で読んだ)

自分でいじってみる

作例をいじったり、自分で組み合わせたりしてみます。

サーボモータで楽器

安いサーボモータである SG90 (400円) 側の

  • 黄を1(GP0)へ
  • 赤を40(VBUS)へ
  • 茶を38(GND)へ

接続して次のプログラム

from machine import PWM, Pin
import utime
import random

servo = PWM(Pin(0))
servo.freq(50)

max_duty = 65025
deg_m90 = 0.025  # -90 deg
deg_0   = 0.0725 #   0 deg
deg_p90 = 0.12   # +90 deg

def rot(deg):
    servo.duty_u16(int(max_duty*((deg/90.0)*(deg_p90-deg_0)+deg_0)))

basetime = 0.2 # [sec]

def p0():
    utime.sleep(basetime*4)

def p1():
    utime.sleep(basetime*2)

def p2():
    utime.sleep(basetime)

while True:
    rot(0.0)
    p1()
    rot(-45.0)
    p2()
    rot(-90.0)
    p2()
    rot(-45.0)
    p1()
    rot(0.0)
    p0()
    rot(45.0)
    p1()
    rot(90.0)
    p0()

を動かすと、楽器ができました!

さらにマラカスを付けてみました。

面白い!

今まで何十年も趣味でソフトウェアは書けましたが、を思いのままに動かせたのはこれが初めてです!!!!! 感動!!!!! この動き自分で作ったんよと言える!!!!!

マラカスはこのようにプログラムを書いてみました。

from machine import PWM, Pin
import utime
import random
import math

led = machine.Pin(15, machine.Pin.OUT)

servo = PWM(Pin(0))
servo.freq(50)

max_duty = 65025
deg_m90 = 0.025  # -90 deg
deg_0   = 0.0725 #   0 deg
deg_p90 = 0.12   # +90 deg

def rot(deg):
    servo.duty_u16(int(max_duty*((deg/90.0)*(deg_p90-deg_0)+deg_0)))

# hit
preparation_duration = 0.17

def h(duration):
    led.value(0)
    for i in range(10):
        rot(90 - i/10*45)
        utime.sleep(preparation_duration/10)
    rot(90)
    led.value(1)
    utime.sleep(duration - preparation_duration)

b = 60/144
led.value(0)
while True:
    h(2*b)
    h(2*b)
    h(b)
    h(b)
    h(2*b)
3軸加速度センサとOLEDディスプレイ

OLED (有機発光ダイオード) ディスプレイも、モノクロとカラーの2種類買うてみました。加速度センサが使えるとこのように、手を回してディスプレイに立方体を回転させることができます。3次元の数学を使えばどのように線分を描けばいいか計算できます。この辺はiPhoneで加速度センサを使ってプログラミングしているのと同じことですね。

しかし、今は、ディスプレイも、加速度センサも自分で買ってきたパーツを取り付けて配線しているのです! これが大きな違いです。

3軸加速度センサとサーボモータで機械学習の強化学習のQ学習

発表で紹介したのは、3軸加速度センサとサーボモータを組み合わせて、機械学習の強化学習のQ学習をしてブランコの揺れを強化学習してみようというものです。

今まで機械学習はソフトウェアの上でしかやったことがありませんでした。単なる思いつきですが、「何らかのセンサ」と「動かすもの」があれば、機械学習を実物でできると思いつきました。やってみた様子は当日の録画をご覧ください。

ソフトウェア的にやっていることは大して違いがありませんが、機械学習に便利な numpy や PyTorch が使えないので、float の list だけで書いていくのがこれはこれで楽しかったです。

終わり

というわけで、ソフトウェアしか作れなかったのがちょっと広がりました。きっかけとなった Python Charity Talks と、入門として一歩一歩やらせてもらえた広島のコミュニティの皆さんに感謝です。


トップ
© 2025 Nyoho