メインコンテンツへスキップ
見出し画像

「今日いつ空いてる?」をSlackで一発!予定ではなく“すき間”を返すcalendar機能

    こんにちは!Accel-Hack (アクセルハック)開発チームです。

    社内AIアシスタント「Airi」の開発プロセスをお届けする開発記ブログ。
    第20回目の今回は、前回整えた Google 連携の土台の上に建てる、最初の実用機能――カレンダー機能(calendar機能)をお届けします。

    前回の Vol.19 では、サービスアカウントで Google API を叩く通行証(アクセストークン)を手に入れました。

    いよいよこれを活かすときです。

    今回作るのは /airi calendar open というコマンド。
    「今日いつ空いてる?」という日常の問いに、Slack から一発で答えます。

    ポイントは、予定の一覧ではなく“空き時間”を返すという発想の転換です。



    1. 欲しいのは「予定一覧」ではなく「空き時間」

    打ち合わせを入れたいとき、本当に知りたいのは「どんな予定が入っているか」ではなく、「いつなら空いているか」です。

    予定一覧を眺めて、頭の中で“すき間”を逆算する――あの地味な手間を、Airi に肩代わりさせたい。

    そこで作ったのが /airi calendar open です。

    叩けば、その人の今日の空き時間だけがパッと返ってくる。
    カレンダーアプリを開く必要すらありません。

    小さな機能ですが、「探す」を「尋ねる」に変える、気持ちのいい一歩です。


    2. 実行者が誰かは、Slackが知っている

    まず必要なのは「誰のカレンダーを見るか」です。

    これは Slack が教えてくれます。
    コマンドを叩いた人のプロフィールから、メールアドレスを取得します。

    const userInfo = await context.client.users.info({ user: payload.user_id });
    const email = userInfo.user?.profile?.email;
    if (!email) {
      await context.respond({
        text: "Slackプロフィールにメールアドレスが設定されていません。",
        response_type: "ephemeral",
      });
      return;
    }

    Slack のメールアドレスと Google カレンダーのアカウントが揃っていれば、これだけで「あなたの」カレンダーを対象にできます。

    メールが未設定なら、無理に進めず丁寧に案内して終了。

    入り口でのこうした気配りが、地味に効きます。


    3. 「今日の枠」を決める

    次に、空きを探す範囲を決めます。

    Airi では業務時間を 10:00〜19:00 JST とし、その枠の中だけを見ます。

    const businessEnd = new Date(now);
    businessEnd.setUTCHours(19 - 9, 0, 0, 0); // 19:00 JST
    
    if (now >= businessEnd) {
      await context.respond({
        text: "本日の業務時間は終了しています。ゆっくり休んでくださいね!",
        response_type: "ephemeral",
      });
      return;
    }

    すでに業務時間を過ぎていたら、空きを計算せず「ゆっくり休んでくださいね」と返します。
    また、検索の起点は「業務開始前なら 10:00 から、途中ならいまから」。

    過ぎた時間の空きを出しても仕方ないので、常に“これから”だけを見るようにしています。


    4. FreeBusy で予定を取り、busy を反転して open を出す

    ここが機能の心臓部です。

    Google には FreeBusy API という、「指定した期間に予定が入っている時間帯(busy)」だけを返してくれる便利なAPIがあります。

    予定の件名や参加者といった中身は返さず、「埋まっている/空いている」だけを教えてくれるのです。

    これを Vol.19 のサービスアカウントで認証して呼び出します。
    得られるのは「埋まっている時間(busy)」の一覧。


    でも私たちが欲しいのはその逆、「空いている時間(open)」です。

    そこで、busy を反転させる小さなアルゴリズムを書きました。

    let currentStart = businessStart;
    for (const busy of sortedBusy) {
      if (busy.start > currentStart) {
        openSlots.push({ start: currentStart, end: busy.start }); // すき間 = 空き
      }
      if (busy.end > currentStart) currentStart = busy.end;
    }
    if (currentStart < businessEnd) {
      openSlots.push({ start: currentStart, end: businessEnd });
    }

    busy を時系列に並べ、先頭から「予定と予定のすき間」を順に拾っていくだけ。
    やっていることは単純ですが、これで「予定表」が「空き時間表」に早変わりします。

    この反転のイメージを図にすると、次のとおりです。

    画像

    そして嬉しいのは、この方式がプライバシーに優しいことです。


    Airi は予定の中身を一切見ません。
    「埋まっているか・空いているか」だけを扱うので、他人の予定の詳細が漏れる心配がないのです。


    5. 本人にだけ、そっと返す

    最後に、計算した空き時間を Slack に返します。

    このとき使うのが ephemeral メッセージ――実行した本人にだけ見える投稿です。

    自分の空き時間が、チャンネル全員に流れてしまっては気まずいですよね。

    ephemeral なら、コマンドを叩いた人だけに、Block Kit で整形された空き時間リストがそっと表示されます。

    チャンネルを汚さず、必要な人に必要な情報だけを届ける。
    Slack ならではの気の利いた返し方です。


    6. おわりに

    今回は、/airi calendar open を題材に、「予定ではなく“すき間”を返す」カレンダー機能をお届けしました。

    FreeBusy API で埋まっている時間を取り、それを反転して空きを出し、本人にだけそっと返す。

    小さな機能ですが、「カレンダーを開いて逆算する」というありふれた手間を、見事に一発で消してくれます。

    次回は、同じ Google 連携でも、今度は向こうから飛んでくる情報を扱います。
    「Vol.21: 大事なメールだけ、Slackに届く。Gmail Push × ルール振り分けの作り方」 として、Gmail の Push 通知(Webhook)を受け取り、特定のメールを Slack へ自動で振り分ける仕組みをお届けします。
    お楽しみに!



    この記事は以下の体制で作成されました。

    • ドラフト作成・執筆: Airi (社内AIアシスタント)

    • アイデア出し・レビュー: CTO

    • デザイン: 事務スタッフ

    Accel-Hackでは、テクノロジーを駆使して世の中の課題を解決していく仲間を募集しています。
    私たちの取り組みに少しでも興味を持っていただけたら、ぜひ採用ページや会社サイトも覗いてみてくださいね。


    あなたへのおすすめ