🕷️
🕷️

Auto Collection

  • Puppeteerで主要テックサイトからイベントを自動巡回。

  • 「調べる苦労」をAIエージェントが肩代わり。

Slide 1 of 3Remaining 2

はじめに

「あれ、新しいPixelの発売日っていつだっけ?」 「このテックカンファレンス、申し込み忘れてた……」

ガジェット好きなら一度はあるこの悩み。情報はTwitter(X)、PR Times、ニュースサイトとあちこちに散らばっていて、追うだけで一苦労です。

筆者
筆者

自分で全部チェックするのは無理。なら、AIにやらせればいいじゃない。

というわけで、 Web上のイベント情報を勝手に集めてきて、綺麗に分類して、ついでに自分のブログ記事も合わせて表示してくれる「最強のガジェットカレンダー」 を作りました。

今回はその技術的な裏側を、コードを交えてガッツリ解説します。

成果物:これが「AIガジェットカレンダー」だ

まずは完成品をご覧ください。サイト内の /calendar ページに実装されています。

今回のこだわりポイントはここ。

主な機能
  • 完全自動収集 : コマンド一発で主要サイトを巡回。 * AIカテゴリ分類 : 「新製品発売」「カンファレンス」「セール」などをAIが自動判別。 * ブログ統合 : 自分の書いたレビュー記事も同じタイムラインに並ぶ。 * Premium UI : グラスモーフィズムを採用した、所有欲を満たすデザイン。

技術スタック:AI時代のWeb開発

このカレンダーを実現するために選んだスタックがこちら。

  1. Astro DB : データの母艦。SQL(LibSQL)ベースで、ローカルでも本番(Studio)でも爆速。
  2. Puppeteer : Webスクレイピング担当。動的なサイトもレンダリングして情報を引っこ抜きます。
  3. Vercel AI SDK : 頭脳担当。取得したグチャグチャなHTMLから、必要な情報だけをGPT-4oに抽出させます。
  4. React + Framer Motion : UI担当。Astroの中にReactコンポーネントをマウントして、リッチなインタラクションを実現。

実装の裏側

1. AIエージェントによる情報収集

一番の肝は、「どうやってWebの無秩序なテキストから、正確にイベント情報を抜くか」です。 ここで Vercel AI SDK が火を噴きます。

以下は、実際に使っているスクリプト(scripts/collect-events.ts)の一部です。

// スクレイピングした生のテキストをAIに投げ、構造化データとして返してもらう
const { text } = await generateText({
 model: "openai('gpt-4o')",
 prompt: "`Extract upcoming tech/gadget events from the following text.
 For each event", provide: "title", date (YYYY-MM-DD), category (e.g., "Release", "Conference", "Sale"), description, and sourceUrl.
 Return as a JSON array of objects.
 Text: "${rawContent"}`,
});
Assistant
Assistant

従来の正規表現やCSSセレクタだと、サイトの構造が変わるたびにコード修正が必要でした。しかしLLMなら、「テキストの意味」を理解して日付やタイトルを抽出してくれるので、保守コストが劇的に下がります。

2. Astro DBへの保存

抽出したデータは Astro DB に保存します。スキーマ定義(db/config.ts)は非常に直感的です。

export const Events = defineTable({
  columns: {
    id: column.text({ primaryKey: true }),
    title: column.text(),
    date: column.date(),
    category: column.text(),
    sourceUrl: column.text({ optional: true }),
    // ...
  },
});

これを await db.insert(Events).values(...) で放り込むだけ。ORMの設定もマイグレーションファイルの管理も不要。Astro最高です。

3. ブログ記事との統合

このカレンダーの真骨頂は 「外部のイベント情報」と「自分のブログ記事」が混ざり合っていること です。

src/pages/calendar/index.astro で、この2つのデータをマージしています。

// 1. スクレイピングしたイベントを取得
const scrapedEvents = await db.select().from(Events);

// 2. ブログ記事を取得
const blogPosts = await getCollection("blog");

// 3. 両者を「Event」型として正規化して結合
const allEvents = [
  ...scrapedEvents.map((e) => ({ ...e, type: "scraped" })),
  ...blogPosts.map((p) => ({
    title: "p.data.title",
    date: "p.data.date",
    type: "blog",
  })),
];

これをReactコンポーネントの <CalendarContainer /> に渡すことで、シームレスなタイムラインを実現しています。

Deep Dive: 外部 iCal データのパーシング

AI エージェントだけでなく、既存の iCal カレンダー(Google Calendar 等)との統合も行っています。

// iCalパースの簡易実装例
import ical from 'node-ical';

async function fetchExternalEvents(url: string) {
  const events = await ical.async.fromURL(url);
  
  return Object.values(events)
    .filter(e => e.type === 'VEVENT')
    .map(e => ({
      title: e.summary,
      start: e.start,
      description: e.description
    }));
}

「AI による自動抽出」と「既存プロトコル(iCal)による確実な取得」を組み合わせるのが、最強のカレンダーを作るコツです。

まとめ:Webサイトは「メディア」から「ツール」へ

ただ情報を発信するだけの静的なブログは、もう古いのかもしれません。

バックグラウンドでエージェントが動き回り、ユーザーのために情報を集め、整理して提示する。 Astro DBAI SDK を組み合わせることで、そんな「生きたWebサイト」が個人でも簡単に作れるようになりました。

📝 Next Roadmap

次は、気になるイベントを登録しておくと、前日にDiscordに通知してくれる機能を実装予定です。お楽しみに!

このカレンダー機能は、右上のメニュー(または /calendar)からいつでもアクセスできます。ぜひ、あなたのガジェットライフのリズム作りに役立ててください。