Clawdbot Skills

Local Places Skill - Google Places APIプロキシによる店舗検索をClawdbotで実現

Clawdbot向けLocal Places Skillを利用して、ローカルサーバー経由でGoogle Places API検索、位置情報解決、詳細取得を実行する方法を解説します。

投稿者: AI Tools Hub
Clawdbot Local Places Google Places API Python FastAPI 位置情報

概要

Local Places Skillは、Clawdbotフレームワーク内でGoogle Places APIのプロキシサーバーを起動し、ローカルHTTPエンドポイント経由で店舗検索を実行するためのスキルである。Python製のFastAPIアプリケーションとして実装されており、uvパッケージマネージャーとuvicornサーバーで動作する。

本スキルは、Google Places API(New)を利用し、位置情報解決(住所→座標変換)と店舗検索を2ステップのワークフローで提供する。ユーザーとの対話的な検索体験を想定した設計である。

公式リポジトリは https://github.com/Hyaxia/local_places で公開されている。

技術的背景

Google Places APIを直接利用する場合、認証情報管理、リクエストフォーマット、エラーハンドリングが煩雑である。Local Places Skillは、これらをローカルプロキシサーバーでラップし、シンプルなREST APIとして提供する。

提供される主要機能は以下の通り:

  • 位置情報解決(住所・地名→座標・Place ID)
  • 店舗検索(キーワード、営業中フィルタ、評価フィルタ、価格帯フィルタ)
  • 詳細情報取得(Place ID→営業時間、電話番号等)
  • ページネーション(大量結果の分割取得)

技術的仕様

システム要件

  • Python 3.10以上
  • uv パッケージマネージャー(Pythonパッケージ管理ツール)
  • Google Places API Key
  • 環境変数 GOOGLE_PLACES_API_KEY

インストール方法

1. uvのインストール:

curl -LsSf https://astral.sh/uv/install.sh | sh

2. プロジェクトのクローン:

cd {baseDir}  # Clawdbotスキルのベースディレクトリ

3. 環境変数設定:

echo "GOOGLE_PLACES_API_KEY=your-key" > .env

4. 依存関係のインストール:

uv venv
uv pip install -e ".[dev]"

5. サーバー起動:

uv run --env-file .env uvicorn local_places.main:app --host 127.0.0.1 --port 8000

サーバーは http://127.0.0.1:8000 で起動する。

主要機能

サーバー稼働確認

Pingエンドポイント:

curl http://127.0.0.1:8000/ping

正常時のレスポンス:

{"status": "ok"}

位置情報解決

リクエスト:

curl -X POST http://127.0.0.1:8000/locations/resolve \
  -H "Content-Type: application/json" \
  -d '{"location_text": "Soho, London", "limit": 5}'

レスポンス:

{
  "results": [
    {
      "place_id": "ChIJ...",
      "name": "Soho",
      "address": "Soho, London, UK",
      "location": {
        "lat": 51.5137,
        "lng": -0.1366
      }
    }
  ]
}

複数候補が返された場合、Clawdbotは番号付きリストで提示し、ユーザーに選択を促す。

店舗検索

リクエスト:

curl -X POST http://127.0.0.1:8000/places/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "coffee shop",
    "location_bias": {
      "lat": 51.5137,
      "lng": -0.1366,
      "radius_m": 1000
    },
    "filters": {
      "open_now": true,
      "min_rating": 4.0
    },
    "limit": 10
  }'

レスポンス:

{
  "results": [
    {
      "place_id": "ChIJ...",
      "name": "Coffee Shop",
      "address": "123 Main St, London",
      "location": {
        "lat": 51.5,
        "lng": -0.1
      },
      "rating": 4.6,
      "price_level": 2,
      "types": ["cafe", "food"],
      "open_now": true
    }
  ],
  "next_page_token": "..."
}

フィルタ仕様

types(店舗タイプ):

  • 値: 1つのみ指定可能(例: "restaurant", "cafe", "gym"
  • 複数タイプは未対応

price_levels(価格帯):

  • 値: 整数0〜4のリスト(例: [1, 2]
  • 意味: 0=無料、1=安価、2=中程度、3=高価、4=非常に高価

min_rating(最低評価):

  • 値: 0〜5の範囲(0.5刻み)
  • 例: 4.0, 4.5

open_now(営業中フィルタ):

  • 値: true / false

location_bias(位置バイアス):

  • lat: 緯度(必須)
  • lng: 経度(必須)
  • radius_m: 半径(メートル、必須、>0)

limit(結果数制限):

  • 検索: 1〜20
  • 位置情報解決: 1〜10

詳細情報取得

リクエスト:

curl http://127.0.0.1:8000/places/{place_id}

レスポンス: 詳細な営業時間、電話番号、ウェブサイト、レビュー等を含む。

ページネーション

検索結果にnext_page_tokenが含まれる場合、次ページを取得可能:

curl -X POST http://127.0.0.1:8000/places/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "coffee shop",
    "page_token": "NEXT_PAGE_TOKEN",
    "limit": 10
  }'

実装例

例1: Clawdbotとの対話的検索

# Clawdbot内部でのPython実装例
import requests

def search_nearby_cafes(user_location: str):
    # ステップ1: 位置情報解決
    resolve_resp = requests.post(
        "http://127.0.0.1:8000/locations/resolve",
        json={"location_text": user_location, "limit": 5}
    )
    locations = resolve_resp.json()["results"]
    
    if len(locations) > 1:
        # 複数候補がある場合、ユーザーに選択を促す
        print("Multiple locations found:")
        for i, loc in enumerate(locations):
            print(f"{i+1}. {loc['name']} ({loc['address']})")
        choice = int(input("Select location: ")) - 1
    else:
        choice = 0
    
    selected = locations[choice]
    
    # ステップ2: 店舗検索
    search_resp = requests.post(
        "http://127.0.0.1:8000/places/search",
        json={
            "query": "cafe",
            "location_bias": {
                "lat": selected["location"]["lat"],
                "lng": selected["location"]["lng"],
                "radius_m": 1000
            },
            "filters": {
                "open_now": True,
                "min_rating": 4.0
            },
            "limit": 10
        }
    )
    
    results = search_resp.json()["results"]
    for cafe in results:
        print(f"{cafe['name']} - {cafe['rating']}/5 - {cafe['address']}")

例2: Bash自動化スクリプト

#!/bin/bash
# 営業中のレストランを検索してSlack通知
LOCATION=$(curl -s -X POST http://127.0.0.1:8000/locations/resolve \
  -H "Content-Type: application/json" \
  -d '{"location_text": "Tokyo, Japan", "limit": 1}' | \
  jq -r '.results[0]')

LAT=$(echo "$LOCATION" | jq -r '.location.lat')
LNG=$(echo "$LOCATION" | jq -r '.location.lng')

RESTAURANTS=$(curl -s -X POST http://127.0.0.1:8000/places/search \
  -H "Content-Type: application/json" \
  -d "{
    \"query\": \"restaurant\",
    \"location_bias\": {
      \"lat\": $LAT,
      \"lng\": $LNG,
      \"radius_m\": 2000
    },
    \"filters\": {
      \"open_now\": true
    },
    \"limit\": 5
  }")

COUNT=$(echo "$RESTAURANTS" | jq '.results | length')
curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"Found $COUNT open restaurants in Tokyo\"}"

例3: 価格帯別検索

#!/bin/bash
# 安価なレストラン(価格レベル0-1)を検索
curl -X POST http://127.0.0.1:8000/places/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "restaurant",
    "location_bias": {
      "lat": 40.7128,
      "lng": -74.0060,
      "radius_m": 3000
    },
    "filters": {
      "price_levels": [0, 1]
    },
    "limit": 20
  }' | jq '.results[] | {name: .name, price_level: .price_level, rating: .rating}'

例4: 定期的な店舗データ更新

#!/bin/bash
# 1時間ごとに新規オープンした店舗を監視
while true; do
  NEW_PLACES=$(curl -s -X POST http://127.0.0.1:8000/places/search \
    -H "Content-Type: application/json" \
    -d '{
      "query": "new restaurant",
      "location_bias": {
        "lat": 51.5074,
        "lng": -0.1278,
        "radius_m": 5000
      },
      "limit": 10
    }' | jq '.results[].name')
  
  echo "$NEW_PLACES" >> new_places.log
  sleep 3600
done

例5: タイプ別店舗統計

#!/bin/bash
# カフェ、レストラン、バーの数を集計
for type in "cafe" "restaurant" "bar"; do
  COUNT=$(curl -s -X POST http://127.0.0.1:8000/places/search \
    -H "Content-Type: application/json" \
    -d "{
      \"query\": \"$type\",
      \"location_bias\": {
        \"lat\": 35.6812,
        \"lng\": 139.7671,
        \"radius_m\": 5000
      },
      \"filters\": {
        \"types\": [\"$type\"]
      },
      \"limit\": 20
    }" | jq '.results | length')
  echo "$type: $COUNT"
done

ユースケース

Clawdbotによる対話的店舗検索

ユーザーが「近くのカフェを探して」と依頼した場合、Clawdbotは以下のフローを実行:

  1. ユーザーの位置情報(「近く」「Soho, London」等)を解決
  2. 複数候補がある場合、選択を促す
  3. 営業中・評価・価格帯の希望を確認
  4. 検索結果を番号付きリストで提示
  5. 詳細情報取得または再検索

マーケティング分析

特定エリアの競合店舗数、平均評価、価格帯分布を分析。新規出店の候補地選定、競合分析に活用。

データ収集パイプライン

Google Places APIのデータを定期的に取得し、データベース(PostgreSQL、MongoDB等)に保存。時系列分析、トレンド検出に活用。

ロケーションベースの推薦システム

ユーザーの現在地と好みに基づき、最適な店舗を推薦。旅行アプリ、グルメアプリのバックエンドとして利用。

制限事項・セキュリティ考慮事項

APIキーの管理

.envファイルは、.gitignoreに必ず追加すること。公開リポジトリへのコミットは厳禁。

フィルタ制約

以下の制約に注意:

  • types: 1つのみ指定可能(複数タイプフィルタ未対応)
  • radius_m: 必ず正の整数(0や負の値は不可)
  • limit: 検索は1〜20、位置情報解決は1〜10

ページネーション遅延

Google Places APIのページネーションは、次ページトークン発行直後に無効な場合がある。推奨される遅延時間は2秒。

ローカルサーバーのセキュリティ

デフォルト設定(127.0.0.1:8000)では、ローカルホストからのみアクセス可能。外部公開する場合:

  • HTTPS化(Let’s Encryptで証明書取得)
  • 認証機能の追加(API Key、OAuth等)
  • レート制限の実装(DDoS対策)

Google Places API料金

Google Places API(New)は従量課金制。2026年2月時点の料金(米国):

  • Text Search: $0.032/リクエスト
  • Place Details: $0.017/リクエスト

無料枠(毎月$200クレジット)を超過するとコストが発生するため、リクエスト数の監視を推奨。

Python環境の依存関係

uvは高速なPythonパッケージマネージャーだが、従来のpippoetryと併用する場合、依存関係の競合に注意。

参考リンク


本記事の情報は2026年2月15日時点のものです。Local Places Skillの機能、API仕様、依存関係は変更される可能性があります。最新情報は公式リポジトリ(https://github.com/Hyaxia/local_places)をご確認ください。APIキーの管理には十分注意し、Google Places APIの利用規約を遵守してください。

この記事をシェア

人気記事

Comparison

ChatGPT(OpenAI)とClaude(Anthropic)の機能比較 2026年版。コーディング・長文解析・コスト・API料金の違いを検証

ChatGPT(GPT-4o/o3)とClaude(Sonnet 4.6/Opus 4.5)を2026年時点の最新情報で比較する。コーディング能力、長文処理、日本語品質、API料金、無料プランの違いをSWE-benchなどのベンチマーク結果とともに解説する。

続きを読む →
opinion

【2026年2月20日 所感】「AIがコードを書く」は仮説から現実になった——しかし私たちはその意味をまだ消化できていない

2026年2月20日に観測したコーディングエージェント関連ニュースの総括と所感。Anthropicの自律性研究、cmux、MJ Rathbunのエージェント事故、HN「外骨格 vs チーム」論争、Stripe Minions週1000件PR、Taalas 17k tokens/sec——朝から夜までの流れを通じて見えてきた「AIがコードを書く時代」の実相を考察する。

続きを読む →
tool

868のスキルをnpx 1コマンドで——「Antigravity Awesome Skills」が主要AIコーディングエージェントの共通スキル基盤になりつつある

Claude Code・Gemini CLI・Codex CLI・Cursor・GitHub Copilotなど主要AIコーディングアシスタントを横断する868以上のスキルライブラリ「Antigravity Awesome Skills」(v5.4.0)を詳細分析。Anthropic・Vercel・OpenAI・Supabase・Microsoftの公式スキルを統合した設計思想、ロール別バンドル・ワークフロー機能、SKILL.mdによる相互運用性のアーキテクチャを解説する。

続きを読む →

他のAIツールも探す

生産性、創造性、イノベーションのための60以上のAIツールの厳選ディレクトリをご覧ください。

0 tools selected