神田カレースタンプラリー2025でスタンプがもらえる店(とスポット)を地図+一覧で見られるウェブアプリをつくった
google mapでもよかったのだが、一覧でみたい、近い(かつ食べたいジャンル)をサクサク見られるようにしたかったのでアプリケーションにした
データ
- カレー店位置情報取得
店やリンクはこちらから取得(AIにやらせた)
https://kanda-curry.com/stamprally2025/
- 住所などの情報追加
店の緯度経度、住所を情報がほしたかったので取得コードをつくった
google map apiで検索。こちらは毎月一定回数までは無料
https://developers.google.com/maps/documentation/javascript/get-api-key?hl=ja
import time
import pandas as pd
from geopy.geocoders import GoogleV3
def geocode_location(name, geolocator):
"""店名から住所、緯度、経度を取得する関数"""
try:
location = geolocator.geocode(name, timeout=10)
if location:
return location.address, location.latitude, location.longitude
else:
return "Not found", None, None
except Exception as e:
print(f"「{name}」のジオコーディング中にエラーが発生しました: {e}")
return "Error", None, None
geolocator = GoogleV3("GOOGLE_MAP_API_KEY")店名から緯度経度、住所を取得
results = []
from tqdm.notebook import tqdm
for name in tqdm(df['name'], desc="geocoding..."):
if not name: # 空の場合はスキップ
continue
address, lat, lon = geocode_location(name, geolocator)
if not lat or not lon or not address:
print(f'{name} not found geo')
print(f'address: {address}')
print(f'lat: {lat}')
print(f'lon: {lon}')
results.append({
'name': name,
'address': address,
'lat': lat,
'lon': lon
})
time.sleep(1)たまに店名についてグーグルが持ってるものと異なるものがあったので(英語表記とカタカナ表記の違いなど)適当に手動で調整も入れた
100件くらいなのでそこまで大変ではない作業だった
画面
ページはこちら
https://kanda-curry-stamprally2025.vercel.app/

機能
機能を列挙する気が起きなかったのだが、aiにURL渡して機能紹介してってお願いしたら、2割くらいつかえる記事を書いてくれたのでだいぶ敷居が下がった。多分名前のイメージだけでそれっぽい機能を書かれた
🍛神田カレーマップは、スタンプラリー参加者が効率的に店舗を巡り、楽しくイベントに参加するためのサポートを目的としています
- スタンプラリーを効率的に制覇したい方
- 近くの店をハシゴしたくなったとき、駅チカの店を探したいとき
- お知らせページへのリンクから、お店の営業時間や定休日を事前に確認可能
エレベータピッチみたい
機能面ではとりあえず、地図や距離の計算部分はリッチにしている。対象店舗が多いのでハシゴ前提で回る店を決めたり、混んでてあきらめたときなどに、次候補店の選定などに使いたかったため
地図をドラッグすると中心からの距離を計算し直したり、現在地からの距離を計算、をクリックすると距離が表に出てくる。後で思ったが、これは列を分けるべきだった気がする
ウェブアプリ側のnextjs+vercelのプロジェクトは初期構築から全てgemini cliに実装させたので、ほぼなにもしていない。結果として、パッと見8割くらいgeminiが作業した。
人間はvercelプロジェクトの設定とcssの細かい修正をおこなった。AIはレンダリングされたページを確認できないためそのあたりの精度は弱いみたい。
どんどん機能追加していくとコードが複雑になっていくのが体験できた。特に、表部分と地図部分のデータstateの連携、同期部分はもはやなぜ動いているのか、という感じ
あとはブラウザの位置情報取得apiやreact leafletを眺めるきっかけになってよかった