import os import time import random import googlemaps import pandas as pd import plotly.express as px import gradio as gr # ===================================================== # 1. Google Maps API # ===================================================== API_KEY = os.getenv("GOOGLE_MAPS_API_KEY") if API_KEY is None: raise RuntimeError("GOOGLE_MAPS_API_KEY not set") gmaps = googlemaps.Client(key=API_KEY) # ===================================================== # 2. Data Fetch # ===================================================== def fetch_places(): query = "Hawaiian pizza in Seoul" rows = [] res = gmaps.places(query=query, language="ko") while True: for r in res["results"]: rows.append({ "name": r["name"], "address": r.get("formatted_address", ""), "rating": r.get("rating", 0), "lat": r["geometry"]["location"]["lat"], "lon": r["geometry"]["location"]["lng"], }) if "next_page_token" not in res: break time.sleep(2) res = gmaps.places( page_token=res["next_page_token"], language="ko", ) return pd.DataFrame(rows) DATA = fetch_places() # ===================================================== # 3. Entertainment # ===================================================== QUOTES = [ "🍍 νŒŒμΈμ• ν”Œμ€ λ…ΌμŸμ μ΄μ§€λ§Œ λ§›μžˆμŠ΅λ‹ˆλ‹€", "πŸ• μ΄νƒˆλ¦¬μ•„μΈμ—κ²ŒλŠ” λΉ„λ°€λ‘œβ€¦", "πŸ”₯ ν•˜μ™€μ΄μ•ˆ ν”Όμž μ°¬μ„± 1ν‘œ", "🀝 λ‹¨μ§ μ˜ ν‰ν™”ν˜‘μ •", "🧠 미각은 μžμœ μž…λ‹ˆλ‹€", ] # ===================================================== # 4. Plotly Map Builder # ===================================================== def build_map(df, zoom=11): if df.empty: center = dict(lat=37.5665, lon=126.9780) else: center = dict(lat=df.lat.mean(), lon=df.lon.mean()) fig = px.scatter_mapbox( df, lat="lat", lon="lon", hover_name="name", hover_data={ "rating": True, "address": True, "lat": False, "lon": False, }, color="rating", size="rating", size_max=18, zoom=zoom, center=center, height=650, ) # OpenStreetMap β†’ Mapbox 토큰 ν•„μš” μ—†μŒ fig.update_layout( mapbox_style="open-street-map", margin={"r": 0, "t": 0, "l": 0, "b": 0}, ) return fig # ===================================================== # 5. UI Logic # ===================================================== def update(min_rating): df = DATA[DATA["rating"] >= min_rating] pct = int(100 * len(df) / len(DATA)) if len(DATA) else 0 return ( build_map(df), f"**{len(df)}개 λ§€μž₯ ν‘œμ‹œ 쀑**", f"🍍 Pineapple Power: {pct}%", random.choice(QUOTES), ) def random_pick(): row = DATA.sample(1) r = row.iloc[0] return ( build_map(row, zoom=15), f""" ### 🎲 였늘의 ν•˜μ™€μ΄μ•ˆ 🍍 **{r.name}** ⭐ {r.rating} πŸ“ {r.address} """, ) # ===================================================== # 6. Gradio UI # ===================================================== with gr.Blocks() as demo: gr.Markdown( """ ## 🍍 μ„œμšΈ ν•˜μ™€μ΄μ•ˆ ν”Όμž 지도 **Plotly 기반 Β· Gradio/HF Spaces μ•ˆμ • 버전** """ ) with gr.Row(): with gr.Column(scale=1): rating = gr.Slider(0, 5, 3.5, 0.1, label="μ΅œμ†Œ 평점") count = gr.Markdown() power = gr.Markdown() quote = gr.Markdown() btn = gr.Button("🍍 였늘의 ν•˜μ™€μ΄μ•ˆ") rec = gr.Markdown() with gr.Column(scale=3): plot = gr.Plot() rating.change( fn=update, inputs=rating, outputs=[plot, count, power, quote], ) btn.click( fn=random_pick, inputs=None, outputs=[plot, rec], ) demo.load( fn=update, inputs=rating, outputs=[plot, count, power, quote], ) demo.launch( ssr_mode=False # 지도 μ•ˆμ •μ„± ↑ )