| @ブログ

OpenAI の API を利用してブログの本文の要約を自動生成する機能をつけてみた。ブログの編集画面に要約欄を追加し、チェックボックスにチェックが入っていれば OpenAI の API にリクエストを投げて記事本文の要約を生成して保存するようにした。

要約自動生成君

これも ChatGPT に設計を依頼してレビュー&手直ししながらやった。めっちゃ便利。要約生成君のコードはこんな感じ。

require 'openai'

class EntrySummarizer
  MODEL = 'gpt-4o-mini'

  def initialize(content)
    @content = content
    @client = OpenAI::Client.new(access_token: ENV['OPENAI_API_KEY'])
  end

  def summarize
    response = @client.chat(
      parameters: {
        model: MODEL,
        messages: [
          { role: "system", content: "以下のブログ記事を著者になりきって、日本語で簡潔に要約してください。文章の長さは200文字以内で、受動態表現と「ですます」調を避けて下さい。" },
          { role: "user", content: @content }
        ],
        temperature: 0.3,
        max_tokens: 150
      }
    )
    response.dig("choices", 0, "message", "content").strip
  rescue => e
    puts "要約生成エラー: #{e.message}"
    nil
  end
end

| @ブログ

OGP の og:image を動的に生成する機能をブログに実装していた( 1 年半も前)。

記事本文中に画像がある記事であれば og:image は本文中に含まれる最初の画像を og:image として設定するようにしている。画像がない文章だけの記事の場合はこれまでサイトのロゴを og:image として表示していた。それだと金太郎飴っぽくなってしまうので、はてなブログとか Qiita とかがやってるみたいに、タイトルとサイトロゴを使って動的に og:image を生成して表示することにした。

こだわりポイントとしては、日本語のタイトルの折り返し位置をいい感じにするために形態素解析して、ちょうどいい折り返し位置を決定するような処理を実装した。この辺のコードは結構頑張ってる。

def nm
  @nm ||= Natto::MeCab.new(
    userdic: File.expand_path('lib/tokenizer/userdic.dic'),
    node_format: "%M\t%H\n",
    unk_format: "%M\t%H\n"
  )
end

def prepare_text(text:)
  splitted_text = nm.enum_parse(text).map(&:feature)
  row_length = 0
  result = []
  do_loop = true
  while do_loop do
    splitted_text.each.with_index(1) do |item, i|
      result[row_length] ||= ''
      if (result[row_length].length + item.length) > INDENTION_COUNT
        row_length += 1
        result[row_length] = ''
      end
      result[row_length] += item
      do_loop = false if splitted_text.length == i
    end
    do_loop = false if ROW_LIMIT - 1 > row_length
  end
  result.each {|item| item.gsub!(/EOS\n\z/, '') }
  if result[-1].length == 1
    result[-2] += result[-1]
    result.pop
  end
  result.map(&:strip).join("\n").gsub(/"/, '\"').chomp
end

結果はこんな感じになる。

実際に動的に生成されたこの記事の og:image

| @ブログ

Photo Gallery

写真でふりかえるやつはフォトギャラリーとして実装した。

  1. PhotoSwipe を使えるように組み込む
  2. PhotoSwipe が期待するフォーマットで本文の HTML を書き出しつつ写真を S3 にアップロードする Rake タスクを作成
  3. PhotoSwipe の Dynamic Caption プラグインを組み込む
  4. ↑の Rake タスクから exiftool を呼び出し、 Exif データを HTML 内に Caption として埋め込む
  5. ↑の Rake タスクに緯度経度から住所を取得する機能を追加( Nominatim の API を利用)

ChatGPT に聞きながらやったらサクッとできてしまった。 AI 、ちょっとやる気がある人がその気になればサクッとプログラムを作れてすごい。 Rails で 10 分で Twitter もどきを作れる〜みたいなのがどんな種類のプログラムでもできる感じ。すごい世の中になった。


フォトギャラリーの機能が面白くて、むかし Flickr の存在を知ったときに猿のように画像をアップロードしてた頃を思い出した。あの頃はウェブ上に写真の Exif 情報が表示されるだけで面白かった。カメラの機種名とかレンズとか、焦点距離とか絞り値とか。自分のブログでそういうのをサクッと表示できてうれしい。 2025 年はもっと写真を撮ってブログにアップしていきたい。こういう発言、ウェブ縄文時代( 2000 年代)っぽい。

Flickr に関してはダメなサービスになってしまったし、悪口のような記事も過去に書いたけれど、 Flickr があるおかげで写真を撮ってアップロードするのが楽しかった側面はあったなぁと思う。 Flickr を使わなくなってから全く一眼カメラを使わなくなってしまった。

フォトギャラリーを作ったので、今後はまめにカメラを引っ張り出して写真を撮りたい。

| @ブログ

これから毎月写真でふりかえってみることにする。

SNS に写真を上げるだけではなく、自分で見え方まで考えて写真を整理してみたくなった。 Flickr に写真を上げてアルバムを作っていたようなことを自分のブログでやる感じ。

ギャラリーのライブラリは Medium Zoom だと足りなかったので PhotoSwipe に移行してみた。

| @ブログ

人気記事を確認できるようにしたという記事を以前書いている。もう 7 年も前のことのようだ。

調べればこういうログ集約・集計系のサービスはあるようだったが、個人ブログなのでなるべくお金はかけたくない。

しばらくの間は集計後のログを捨てていたが、 2 年半前からログローテートするタイミングで日付ごとのファイルを書き出し保存するようにしていた。日付ごとのログファイルは Amazon の S3 にアップロードしてさくらの VPS サーバーからは待避させている。現状、 2022 年の 6 月 13 日のログから S3 上にデータが残っているので、その日以後の日ごとの人気記事を確認できるようにした。こんな感じ。

日付の選択は最初 React のライブラリを使って作ろうかと思ったが、そういや最近のブラウザーは <input type="date" /> とすると結構ちゃんとしたカレンダー UI と日付選択の機能を提供してくれるので楽をすることにした。

max と min を指定すると選べない日付は非活性にされるし、無理に選択すると form を submit したときにバリデーションしてくれる。

選べない日付は非活性に
max と min を指定すると選べない日付は非活性にされる
バリデーション
選べない日付で無理に submit されたときにはバリデーションもしてくれる

ブログの閲覧者からしたらいつどの記事が読まれていたかなんて興味ないだろうけど、著者である自分には興味深い情報になる。セルフホストのブログだからできる機能だ。

| @ブログ

よく検索されているキーワード

検索フォームの下に「よく検索されているキーワード」を追加した。実はこれ完全に自己満足で Google Analytics のサイト内検索で調べる限りだと検索機能はほとんど使われていない。一方で自分はめちゃくちゃ使っている。なので自分自身の検索も含むすべての検索ログをアクセスログから抽出して集計し、検索回数が多い順に並べて表示した。

検索フォームにはインクリメンタルサーチ機能があって、検索ワード入力途中にも HTTP アクセスがあるので検索ログには不完全なキーワードも残る。それらが表示されないように 1 文字だけのキーワードや、実際に Tantiny に投げて返ってくる結果が少ないキーワードは除外している。

自己満足ではあるのだが、このサイトをもっとも閲覧していてもっとも検索している自分が便利になればそれで良い。

| @ブログ

嘉穂アルプス 屏山

最近結構走ってるから iOS のフィットネスアプリとか HealthFit でめっちゃログや統計を確認してる。

前月との比較 直近 12 ヶ月間の月ごとの走行距離 日毎の積み上げの前年比
前月との比較、直近 12 ヶ月間の月ごとの走行距離、日毎の積み上げの前年比

いま自分は月間 100km 以上走ることを目標にしている。月間 100km はガチラン勢からしたら大した距離ではないのだが、油断して 3, 4 日走るのをサボったり雨が降ったりすると達成が難しくなるので、前月の同日と比べて進捗はどうかを確認してる。

同じような感じで進捗や達成状況を確認できる機能がブログにも必要なのではないかと思って、自分のブログのアーカイブページで年を選ぶとその年の月ごとの投稿数をグラフで表示するようにした(これまでは年で絞っても年ごとのグラフしか表示されてなかった)。

これで去年の同月に比べてどうかとか、その時期にどんな内容(カテゴリー)の記事をよく書いていたのかがわかるようになった。ランニングと同じように自分の頑張り状況が可視化されるようになった。


そもそもブログを書くことの意義とは何だろうか。大まかに二つあって、以下のように整理されるのではないかと思う。

  1. バズる記事を書いてアクセスを集める
    • 集めたアクセスで自分の認知度を高める
    • 集めたアクセスをマネタイズする(広告)
    • 世の中を変える
  2. 自分の内省のために書く
    • 読書や学習で得た知識を貯めておく
    • 考えを整理する

1 の観点でいうとアクセス数が重要なのだが、いまどきブログで小銭を稼ごうとか世界を変えようとかしてる人はいないはずで、ほとんどのブログは著者自身のために書かれてる(↑の 2 の方)と思う。自分のために文章を書きたい人にとって、書いた内容と密度や頻度、また過去に書いた記事を簡単に振り返ることができることの方が重要なはずだ。

なのに、たいていのブログサービスはアクセス解析機能はあるが、過去の自分の執筆状況を統計的に確認できる機能はない(少なくとも ameblo とはてなブログと livedoor Blog にはなかった)。アクセス数は Twitter で影響力のある人にシェアされたとか外部要因で増えることもあるから、それだけで自分のブログアクティビティを正確に測るのは難しい。

同じような話を以前にもブログに書いている。

振り返りの観点でも既存のブログはあまり良くない。たいていのブログはそもそも自分で書いた過去記事を読むのも大変だったりする。時系列に全文表示されてページネーションして辿らないといけない。

検索機能もいまいちだ。自分の考えたことを貯めておく場としてはちょっと貧相すぎる。

世の中に一般的に出回ってるブログは著者自身のためというより、いかにアクセスを集めて広告でマネタイズするかに主眼が置かれているから、内省や情報の取り出しやすさはあまり考慮されていないのだろう。いかに PV を上げるか、いかに滞在時間を長くするか、いかに回遊させるかが大事になってくる。

しかし先ほども書いた通り、芸能人や著名人を除き、ブログは自分のために書いている人が多いはずで、アクセス数を集めることよりも書き手の体験にフォーカスしたブログがあってもよいのではないだろうか。

ランニングはアプリを使ってログを取ることでいろんなデータが可視化されめっちゃモチベーションが上がる。「今月 100km 走っちゃった〜」とか、「 1km のペースが 6 分切れるようになってきた〜」とか。前年同月との進捗比較も面白い。

ブログでも「今月は 10 記事書けた〜」とか「 1000 文字以上の記事を 5 記事書いた〜」みたいな達成感はあるんじゃないかと思う。つまり、 GitHub の Contribution グラフのブログ版みたいなやつが必要だと思うのだ。

GitHub Contributions Graph

ランニングだと時計だったり Strava などのサービスが走るモチベーションを喚起してくる。一方でブログは誰も書くのを促してくれない。

ブログを書く人が少なくなったのは SNS のせいという面は間違いなくあるけど、ブログ自体の進化が足りないのだと思う。もっと書き手の脳みそをハックして、著者に書きたいと思わせるような仕組みがないとブログは衰退していくばかりなんじゃないだろうか。

突き詰めると、ブログの主なマネタイズ手法が広告しかないのが根っこの問題な気がする。読み手に広告を見せることで収益化するのではなく、書き手の使い勝手や満足度を高めることで収益化できる可能性(書き手に対して機能課金する)はないのだろうか。ランニング系のサービスやアプリは実際そうやって収益化してる(うまく行っているかはわからない)。