🦇

【個人開発】🦇コウモリの番組お知らせBOT - スクレイピングなしでTV番組を自動通知!

に公開

こんにちは、未経験からエンジニアを目指して独学中です。

動物シリーズでLINE BOTを作成しており、今回は🦇コウモリの番組お知らせをリリースしました!

開発のきっかけ

普段テレビはあまり見ないけど、
「金曜ロードショーでジブリやるらしいけど、いつだっけ?」
「好きな映画がテレビでやるの、いつも見逃しちゃう…」
と思い、作ってみようと思いました。

番組表サイトを毎日チェックするのは面倒だし、有料の番組表APIは個人開発にはハードルが高い。スクレイピングは規約的にグレーだし、サイト構造が変わると動かなくなる…。

そこで思いついたのが、「Geminiの検索機能(Grounding)を使えば、番組表を自動で調べてくれるのでは?」 というアイデアでした。

夜行性でテレビっ子なキャラクターということで、「コウモリのチロちゃん」 が誕生しました🦇

🦇 作ったもの:「TV Bat」

キーワードを登録しておくと、放送予定が見つかったときだけLINEで通知してくれるボットです。

1. TV番組検索

「ジブリやる?」「来週の金曜ロードショーは?」と話しかけると、その場でGoogle検索して教えてくれます。

2. 見たい番組リスト管理

Firestoreを使って、監視したい番組を自由に登録できます。

  • 「追加: ポケモン」 → 監視リストに追加
  • 「削除: ポケモン」 → 監視リストから削除
  • 「リスト」 → 現在登録しているキーワードを確認

3. 自動通知

Cloud Schedulerで毎日チェックを実行し、直近1週間以内に放送予定が見つかった場合のみLINEで通知します。

📱 主な機能

Gemini Grounding(Google検索連携)

GeminiのGrounding機能を使って、リアルタイムでGoogle検索を実行します。番組表APIやスクレイピングなしで、最新の放送情報を取得できます。

Firestore(監視リスト管理)

ユーザーごとの監視キーワードをFirestoreに保存。追加・削除・一覧表示が簡単にできます。

Cloud Scheduler(定期実行)

毎日決まった時間に自動チェックを実行。放送予定が見つかったときだけ通知するので、うるさくありません。

🛠 使用技術

項目 技術
言語 Python 3.10+
フレームワーク FastAPI
AIモデル Gemini 2.5 Flash(Vertex AI)
検索機能 Grounding with Google Search
データベース Firestore
定期実行 Cloud Scheduler
インフラ Google Cloud Run
API LINE Messaging API

🏗 アーキテクチャ

💡 技術的なこだわりポイント

1. Grounding(Google検索連携)の活用

今回の肝は、GeminiのGrounding機能です。これを使うと、GeminiがリアルタイムでGoogle検索を実行して回答してくれます。

from google.genai import types

# Grounding設定
tools = [types.Tool(google_search=types.GoogleSearch())]

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=f"来週のテレビで「{keyword}」の放送予定はありますか?地上波優先で教えてください。",
    config=types.GenerateContentConfig(
        tools=tools,
        temperature=0.1  # 低めに設定して安定させる
    )
)

これにより、番組表APIの契約もスクレイピングも不要になりました。

2. ハルシネーション対策のプロンプト設計

LLMは「それっぽい嘘」をつくことがあります。存在しない放送予定を通知してしまうと大問題なので、プロンプトを工夫しました。

prompt = f"""
あなたはTV番組検索アシスタントです。

【質問】
来週のテレビで「{keyword}」の放送予定はありますか?

【回答ルール】
* 検索結果に明確な放送予定がある場合のみ、日時とチャンネルを回答してください
* 放送予定が見つからない場合は「見つかりませんでした」とだけ回答してください
* 推測や曖昧な情報は絶対に含めないでください
* 地上波(日テレ、テレ朝、TBS、テレ東、フジ、NHK)を優先してください
"""

「ある」と断定できた場合のみ回答させることで、誤通知を防いでいます。

3. Firestoreでユーザーごとのリスト管理

監視キーワードはFirestoreに保存しています。

from google.cloud import firestore

db = firestore.Client()

# キーワード追加
def add_keyword(user_id: str, keyword: str):
    doc_ref = db.collection("bat_watchlist").document(user_id)
    doc = doc_ref.get()
    
    if doc.exists:
        keywords = doc.to_dict().get("keywords", [])
        if keyword not in keywords:
            keywords.append(keyword)
            doc_ref.update({"keywords": keywords})
    else:
        doc_ref.set({"keywords": [keyword]})

# キーワード一覧取得
def get_keywords(user_id: str) -> list:
    doc = db.collection("bat_watchlist").document(user_id).get()
    if doc.exists:
        return doc.to_dict().get("keywords", [])
    return []

4. Cloud Schedulerで定期実行

毎日朝8時にチェックを実行する設定です。

# Cloud Scheduler設定
URL: https://YOUR-CLOUD-RUN-URL/cron/bat_check
Method: GET
Frequency: 0 8 * * *
Timezone: Asia/Tokyo

FastAPI側のエンドポイント:

@app.get("/cron/bat_check")
async def cron_check():
    # 全ユーザーの監視リストを取得
    users = db.collection("bat_watchlist").stream()
    
    for user in users:
        user_id = user.id
        keywords = user.to_dict().get("keywords", [])
        
        for keyword in keywords:
            # Geminiで検索
            result = search_tv_schedule(keyword)
            
            if result.found:
                # 放送予定が見つかったら通知
                send_line_message(user_id, result.message)
    
    return {"status": "ok"}

5. キャラクター設定

コウモリの「チロちゃん」というキャラクターで応答します。

system_prompt = """
あなたは「チロちゃん」というテレビコウモリです。

【性格】
* 夜行性でテレビっ子
* 少し毒舌だけど親切
* 語尾は「〜モリ」「〜キキ」

【例】
「その番組、来週やるモリ!見逃さないようにキキ!」
「残念だけど、見つからなかったモリ…」
"""

😿 ハマったポイント

Grounding の実装が大変だった

Vertex AIのGrounding機能は、ライブラリのバージョンによって書き方が全然違うので苦労しました。公式ドキュメントも頻繁に更新されるので、最新の書き方を追うのが大変でした。

検索結果の精度問題

「ジブリ」で検索すると、過去の放送情報や映画館の上映情報も混ざってきます。プロンプトで「地上波優先」「来週以内」と指定することで、ある程度絞り込めるようになりました。

通知のタイミング

最初は「見つかったら即通知」にしていましたが、同じ番組を何度も通知してしまう問題が発生。通知済みフラグを管理するか、通知頻度を1日1回に制限するかで悩みました。

🌟 このボットで学んだこと

LLMの検索機能の可能性

「APIがない」「スクレイピングできない」という状況でも、LLMの検索機能で代替できることがわかりました。精度は100%ではありませんが、個人開発には十分使えます。

ハルシネーション対策の重要性

通知系のボットでは、誤った情報を送らないことが最重要です。プロンプト設計で「確実な情報のみ回答させる」工夫が必要でした。

定期実行の仕組み

Cloud Schedulerを使った定期実行の仕組みを学べました。他のボットにも応用できそうです。

さいごに

https://github.com/miki-mini/my-line-bots

スクレイピングや有料APIなしで番組通知ができるのは、LLMならではの強みだと思います。
「好きな番組を見逃したくない」という方は、ぜひ試してみてください🦇

ここまで読んでいただきありがとうございました🦇❤️

Discussion