tbdavid2019 commited on
Commit
56e1415
·
1 Parent(s): 3f0bb34

穩定版本

Browse files
Files changed (2) hide show
  1. .gitignore +2 -1
  2. app.py +178 -225
.gitignore CHANGED
@@ -1 +1,2 @@
1
- /myenv
 
 
1
+ /myenv
2
+ /docs/assets
app.py CHANGED
@@ -1,268 +1,226 @@
1
  import gradio as gr
2
  import requests
3
- import re
4
  import json
5
  import os
6
  import pandas as pd
7
- from xml.etree import ElementTree
8
  from geopy.distance import geodesic
9
 
10
- # =============== 檔案路徑設定 (你可依需要修改) ===============
11
- DATA_DIR = "docs/assets" # "./data"
12
- os.makedirs(DATA_DIR, exist_ok=True)
 
 
13
 
14
- SEVEN_ELEVEN_PRODUCTS_FILE = os.path.join(DATA_DIR, "seven_eleven_products.json")
15
- FAMILY_MART_STORES_FILE = os.path.join(DATA_DIR, "family_mart_stores.json")
16
- FAMILY_MART_PRODUCTS_FILE = os.path.join(DATA_DIR, "family_mart_products.json")
17
 
18
  # 3 公里範圍
19
  MAX_DISTANCE = 3000
20
 
21
  # -----------------------------------------------------------
22
- # 1. 下載或更新 7-11 商品資料 (目前只示範商品,若要店家需另尋API)
23
  # -----------------------------------------------------------
24
- def fetch_seven_eleven_products(force_update=False):
25
  """
26
- https://www.7-11.com.tw/freshfoods/Read_Food_xml_hot.aspx
27
- 以各種 category 抓取商品資料(XML),轉成 JSON 存檔。
28
- force_update=True 時,強制重新抓取。
29
  """
30
- if os.path.exists(SEVEN_ELEVEN_PRODUCTS_FILE) and not force_update:
31
- print("7-11 商品 JSON 已存在,跳過下載 (如要強制更新請設 force_update=True)")
32
- return
33
-
34
- base_url = "https://www.7-11.com.tw/freshfoods/Read_Food_xml_hot.aspx"
35
  headers = {
36
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
37
  }
38
-
39
- categories = [
40
- "19_star", "1_Ricerolls", "16_sandwich", "2_Light", "3_Cuisine",
41
- "4_Snacks", "5_ForeignDishes", "6_Noodles", "7_Oden", "8_Bigbite",
42
- "9_Icecream", "10_Slurpee", "11_bread", "hot", "12_steam",
43
- "13_luwei", "15_health", "17_ohlala", "18_veg", "20_panini", "21_ice", "22_ice"
44
- ]
45
-
46
- data_list = []
47
-
48
- # 按照分類依序爬取
49
- for index, cat in enumerate(categories):
50
- # 注意:實際參數可能需要你自行測試
51
- params = {"": index}
52
- try:
53
- resp = requests.get(base_url, headers=headers, params=params, timeout=10)
54
- if resp.status_code == 200:
55
- try:
56
- root = ElementTree.fromstring(resp.content)
57
- # 解析 XML
58
- for item in root.findall(".//Item"):
59
- data_list.append({
60
- "category": cat,
61
- "name": item.findtext("name", ""),
62
- "kcal": item.findtext("kcal", ""),
63
- "price": item.findtext("price", ""),
64
- "image": f'https://www.7-11.com.tw/freshfoods/{cat}/' + item.findtext("image", ""),
65
- "special_sale": item.findtext("special_sale", ""),
66
- "new": item.findtext("new", ""),
67
- "content": item.findtext("content", ""),
68
- # 如果你另外有店家經緯度資訊,請自行加上:
69
- # "latitude": ...,
70
- # "longitude": ...
71
- })
72
- except ElementTree.ParseError:
73
- print(f"分類 {cat} 返回非 XML 格式資料,略過。")
74
- else:
75
- print(f"分類 {cat} 請求失敗,HTTP 狀態碼: {resp.status_code}")
76
- except Exception as e:
77
- print(f"分類 {cat} 請求錯誤: {e}")
78
-
79
- # 儲存到 JSON
80
- with open(SEVEN_ELEVEN_PRODUCTS_FILE, "w", encoding="utf-8") as jf:
81
- json.dump(data_list, jf, ensure_ascii=False, indent=4)
82
-
83
- print(f"✅ 7-11 商品資料抓取完成,共 {len(data_list)} 筆,已存為 {SEVEN_ELEVEN_PRODUCTS_FILE}")
84
 
85
  # -----------------------------------------------------------
86
- # 2. 下載或更新 全家門市資料 (內含經緯度 py_wgs84, px_wgs84)
87
  # -----------------------------------------------------------
88
- def fetch_family_stores(force_update=False):
89
  """
90
- https://family.map.com.tw/famiport/api/dropdownlist/Select_StoreName
91
- 下載所有全家門市資料(含經緯度 py_wgs84, px_wgs84)並存檔。
92
- force_update=True 時,強制重新抓取。
93
  """
94
- if os.path.exists(FAMILY_MART_STORES_FILE) and not force_update:
95
- print("全家門市 JSON 已存在,跳過下載 (如要強制更新請設 force_update=True)")
96
- return
97
-
98
- url = "https://family.map.com.tw/famiport/api/dropdownlist/Select_StoreName"
99
- post_data = {"store": ""}
100
- try:
101
- resp = requests.post(url, json=post_data, timeout=10)
102
- if resp.status_code == 200:
103
- data = resp.json()
104
- with open(FAMILY_MART_STORES_FILE, "w", encoding="utf-8") as f:
105
- json.dump(data, f, ensure_ascii=False, indent=4)
106
- print(f" 全家門市資料抓取完成,共 {len(data)} 筆,已存為 {FAMILY_MART_STORES_FILE}")
107
- else:
108
- print(f"❌ 全家門市 API 請求失敗,HTTP 狀態碼: {resp.status_code}")
109
- except Exception as e:
110
- print(f"❌ 全家門市 API 請求錯誤: {e}")
 
 
 
 
111
 
112
  # -----------------------------------------------------------
113
- # 3. 下載或更新 全家商品資料
114
  # -----------------------------------------------------------
115
- def fetch_family_products(force_update=False):
116
  """
117
- https://famihealth.family.com.tw/Calculator 解析網頁 JS 中的
118
- var categories = [...] 取得商品清單。
119
- force_update=True 時,強制重新抓取。
120
  """
121
- if os.path.exists(FAMILY_MART_PRODUCTS_FILE) and not force_update:
122
- print("全家商品 JSON 已存在,跳過下載 (如要強制更新請設 force_update=True)")
123
- return
124
-
125
- url = "https://famihealth.family.com.tw/Calculator"
126
- headers = {"User-Agent": "Mozilla/5.0"}
127
- try:
128
- resp = requests.get(url, headers=headers, timeout=10)
129
- if resp.status_code == 200:
130
- match = re.search(r'var categories = (\[.*?\]);', resp.text, re.S)
131
- if match:
132
- categories_data = json.loads(match.group(1))
133
- results = []
134
- for cat in categories_data:
135
- cat_name = cat.get("name", "")
136
- for product in cat.get("products", []):
137
- results.append({
138
- "category": cat_name,
139
- "title": product.get("name"),
140
- "picture_url": product.get("imgurl"),
141
- "protein": product.get("protein", 0),
142
- "carb": product.get("carb", 0),
143
- "calories": product.get("calo", 0),
144
- "fat": product.get("fat", 0),
145
- "description": product.get("description", ""),
146
- })
147
- with open(FAMILY_MART_PRODUCTS_FILE, "w", encoding="utf-8") as jf:
148
- json.dump(results, jf, ensure_ascii=False, indent=4)
149
- print(f"✅ 全家商品資料抓取完成,共 {len(results)} 筆,已存為 {FAMILY_MART_PRODUCTS_FILE}")
150
- else:
151
- print("❌ 找不到 var categories = ... 之內容,無法解析全家商品。")
152
- else:
153
- print(f"❌ 全家商品頁面請求失敗,HTTP 狀態碼: {resp.status_code}")
154
- except Exception as e:
155
- print(f"❌ 全家商品頁面請求錯誤: {e}")
156
 
157
  # -----------------------------------------------------------
158
- # 工具:讀取 JSON
159
  # -----------------------------------------------------------
160
- def load_json(path):
161
- if os.path.exists(path):
162
- with open(path, "r", encoding="utf-8") as f:
163
- return json.load(f)
164
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  # -----------------------------------------------------------
167
- # 4. 主邏輯:依使用者座標,篩選店家並顯示(3 公里內所有店家)
168
  # -----------------------------------------------------------
169
  def find_nearest_store(address, lat, lon):
 
 
 
 
 
170
  print(f"🔍 收到查詢請求: address={address}, lat={lat}, lon={lon}")
171
-
172
  if lat == 0 or lon == 0:
173
  return [["❌ 請輸入地址或提供 GPS 座標", "", "", "", ""]]
174
 
175
- user_coords = (lat, lon)
176
-
177
- # ========== 讀取 7-11 JSON 並印出前 10 筆 (檢查欄位用) ==========
178
- seven_data = load_json(SEVEN_ELEVEN_PRODUCTS_FILE)
179
- print(f"7-11 JSON 總筆數: {len(seven_data)}")
180
- print("===== 7-11 JSON 前 10 筆 =====")
181
- print(seven_data[:10])
182
-
183
- # 將 7-11 資料轉成 DataFrame (假設內含 latitude, longitude)
184
- seven_df = pd.DataFrame(seven_data)
185
- if {"latitude", "longitude"}.issubset(seven_df.columns):
186
- seven_df["latitude"] = seven_df["latitude"].astype(float)
187
- seven_df["longitude"] = seven_df["longitude"].astype(float)
188
- # 計算距離
189
- seven_df["distance_m"] = seven_df.apply(
190
- lambda row: geodesic(user_coords, (row["latitude"], row["longitude"])).meters,
191
- axis=1
192
- )
193
- else:
194
- print("⚠️ 7-11 JSON 裡沒有 'latitude' 或 'longitude' 欄位,無法計算距離。")
195
- seven_df = pd.DataFrame() # 清空,代表無法顯示 7-11 門市
196
-
197
- # ========== 讀取 全家門市 JSON 並印出前 10 筆 (檢查欄位用) ==========
198
- family_stores = load_json(FAMILY_MART_STORES_FILE)
199
- print(f"全家 JSON 總筆數: {len(family_stores)}")
200
- print("===== 全家 JSON 前 10 筆 =====")
201
- print(family_stores[:10])
202
 
203
- # 轉成 DataFrame (內含 py_wgs84, px_wgs84)
204
- family_df = pd.DataFrame(family_stores)
205
- if {"py_wgs84", "px_wgs84"}.issubset(family_df.columns):
206
- family_df["latitude"] = family_df["py_wgs84"].astype(float)
207
- family_df["longitude"] = family_df["px_wgs84"].astype(float)
208
- family_df["distance_m"] = family_df.apply(
209
- lambda row: geodesic(user_coords, (row["latitude"], row["longitude"])).meters,
210
- axis=1
211
- )
212
- else:
213
- print("⚠️ 全家 JSON 裡沒有 'py_wgs84' 或 'px_wgs84' 欄位,無法計算距離。")
214
- family_df = pd.DataFrame()
215
-
216
- # ========== 篩選 3 公里內的店家 (不只前 5 筆,全部顯示) ==========
217
- nearby_seven = pd.DataFrame()
218
- if not seven_df.empty and "distance_m" in seven_df.columns:
219
- nearby_seven = seven_df[seven_df["distance_m"] <= MAX_DISTANCE].sort_values("distance_m")
220
-
221
- nearby_family = pd.DataFrame()
222
- if not family_df.empty and "distance_m" in family_df.columns:
223
- nearby_family = family_df[family_df["distance_m"] <= MAX_DISTANCE].sort_values("distance_m")
224
-
225
- # 若都沒資料
226
- if nearby_seven.empty and nearby_family.empty:
227
- return [["❌ 附近 3 公里內沒有便利商店", "", "", "", ""]]
228
-
229
- # ========== 合併輸出 ==========
230
- output = []
 
 
 
 
 
 
231
 
232
- # 7-11 門市
233
- if not nearby_seven.empty:
234
- for _, row in nearby_seven.iterrows():
235
- store_name = row.get("StoreName", "7-11 未提供店名")
236
- dist_str = f"{row['distance_m']:.1f} m"
237
- # 假設要顯示「即期食品」,可自行加判斷或先示範顯示固定字串
238
- output.append([
239
- f"7-11 {store_name}",
240
- dist_str,
241
- "7-11即期食品(示意)",
242
- "1"
243
- ])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
- # 全家 門市
246
- if not nearby_family.empty:
247
- for _, row in nearby_family.iterrows():
248
- store_name = row.get("Name", "全家 未提供店名")
249
- dist_str = f"{row['distance_m']:.1f} m"
250
- output.append([
251
- f"全家 {store_name}",
252
- dist_str,
253
- "全家即期食品(示意)",
254
- "1"
255
- ])
256
 
257
- return output
258
 
259
  # -----------------------------------------------------------
260
- # 5. 建立 Gradio 介面
261
  # -----------------------------------------------------------
262
  with gr.Blocks() as demo:
263
- gr.Markdown("## 便利商店門市與商品搜尋 (示範)")
264
- gr.Markdown("1. 按下「使用目前位置」或自行輸入緯度/經度\n2. 點選「搜尋」查詢 3 公里內的所有店家\n3. 請於 Logs 查看 7-11 和全家 JSON 的前 10 筆結構")
265
-
 
 
 
 
266
  address = gr.Textbox(label="輸入地址(可留空)")
267
  lat = gr.Number(label="GPS 緯度", value=0, elem_id="lat")
268
  lon = gr.Number(label="GPS 經度", value=0, elem_id="lon")
@@ -306,14 +264,9 @@ with gr.Blocks() as demo:
306
 
307
  def main():
308
  """
309
- 主程式入口,可在本地端執行 python 檔案時呼叫此函式,
310
- 先下載/更新資料,再啟動 Gradio。
311
  """
312
- # 下載 / 更新 所有資料
313
- fetch_seven_eleven_products(force_update=False)
314
- fetch_family_stores(force_update=False)
315
- fetch_family_products(force_update=False)
316
-
317
  demo.launch(server_name="0.0.0.0", server_port=7860, debug=True)
318
 
319
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  import requests
 
3
  import json
4
  import os
5
  import pandas as pd
 
6
  from geopy.distance import geodesic
7
 
8
+ # =============== 7-11 所需常數 ===============
9
+ # 請確認此處的 MID_V 是否有效,若過期請更新
10
+ MID_V = "W0_DiF4DlgU5OeQoRswrRcaaNHMWOL7K3ra3385ocZcv-bBOWySZvoUtH6j-7pjiccl0C5h30uRUNbJXsABCKMqiekSb7tdiBNdVq8Ro5jgk6sgvhZla5iV0H3-8dZfASc7AhEm85679LIK3hxN7Sam6D0LAnYK9Lb0DZhn7xeTeksB4IsBx4Msr_VI" # 請填入有效的 mid_v
11
+ USER_AGENT_7_11 = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
12
+ API_7_11_BASE = "https://lovefood.openpoint.com.tw/LoveFood/api"
13
 
14
+ # =============== FamilyMart 所需常數 ===============
15
+ FAMILY_PROJECT_CODE = "202106302" # 若有需要請自行調整
16
+ API_FAMILY = "https://stamp.family.com.tw/api/maps/MapProductInfo"
17
 
18
  # 3 公里範圍
19
  MAX_DISTANCE = 3000
20
 
21
  # -----------------------------------------------------------
22
+ # 7-11: 取得 AccessToken
23
  # -----------------------------------------------------------
24
+ def get_7_11_token():
25
  """
26
+ POST /Auth/FrontendAuth/AccessToken?mid_v=$mid_v
27
+ 回傳 JWT token
 
28
  """
29
+ url = f"{API_7_11_BASE}/Auth/FrontendAuth/AccessToken?mid_v={MID_V}"
 
 
 
 
30
  headers = {
31
+ "user-agent": USER_AGENT_7_11
32
  }
33
+ resp = requests.post(url, headers=headers, data="")
34
+ resp.raise_for_status()
35
+ js = resp.json()
36
+ if not js.get("isSuccess"):
37
+ raise RuntimeError(f"取得 7-11 token 失敗: {js}")
38
+ token = js["element"]
39
+ return token
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  # -----------------------------------------------------------
42
+ # 7-11: 取得附近門市清單 (含剩餘即期品總數量)
43
  # -----------------------------------------------------------
44
+ def get_7_11_nearby_stores(token, lat, lon):
45
  """
46
+ POST /Search/FrontendStoreItemStock/GetNearbyStoreList?token=$token
47
+ 取得附近門市的「即期品」總數量
 
48
  """
49
+ url = f"{API_7_11_BASE}/Search/FrontendStoreItemStock/GetNearbyStoreList?token={token}"
50
+ headers = {
51
+ "user-agent": USER_AGENT_7_11,
52
+ "content-type": "application/json",
53
+ }
54
+ body = {
55
+ "CurrentLocation": {
56
+ "Latitude": lat,
57
+ "Longitude": lon
58
+ },
59
+ "SearchLocation": {
60
+ "Latitude": lat,
61
+ "Longitude": lon
62
+ }
63
+ }
64
+ resp = requests.post(url, headers=headers, json=body)
65
+ resp.raise_for_status()
66
+ js = resp.json()
67
+ if not js.get("isSuccess"):
68
+ raise RuntimeError(f"取得 7-11 附近門市失敗: {js}")
69
+ return js["element"].get("StoreStockItemList", [])
70
 
71
  # -----------------------------------------------------------
72
+ # 7-11: 取得單一門市的即期品清單
73
  # -----------------------------------------------------------
74
+ def get_7_11_store_detail(token, lat, lon, store_no):
75
  """
76
+ POST /Search/FrontendStoreItemStock/GetStoreDetail?token=$token
77
+ 回傳該門市的即期品細項 (商品名稱 / 剩餘數量 等)
 
78
  """
79
+ url = f"{API_7_11_BASE}/Search/FrontendStoreItemStock/GetStoreDetail?token={token}"
80
+ headers = {
81
+ "user-agent": USER_AGENT_7_11,
82
+ "content-type": "application/json",
83
+ }
84
+ body = {
85
+ "CurrentLocation": {
86
+ "Latitude": lat,
87
+ "Longitude": lon
88
+ },
89
+ "StoreNo": store_no
90
+ }
91
+ resp = requests.post(url, headers=headers, json=body)
92
+ resp.raise_for_status()
93
+ js = resp.json()
94
+ if not js.get("isSuccess"):
95
+ raise RuntimeError(f"取得 7-11 門市({store_no})資料失敗: {js}")
96
+ return js["element"].get("StoreStockItem", {})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  # -----------------------------------------------------------
99
+ # FamilyMart: 取得附近門市即期品清單 (單次呼叫可拿到所有商品細項)
100
  # -----------------------------------------------------------
101
+ def get_family_nearby_stores(lat, lon):
102
+ """
103
+ POST https://stamp.family.com.tw/api/maps/MapProductInfo
104
+ 查詢附近門市及即期品庫存,回傳資料中 code 應為 1 代表成功
105
+ """
106
+ headers = {
107
+ "Content-Type": "application/json;charset=utf-8",
108
+ }
109
+ body = {
110
+ "ProjectCode": FAMILY_PROJECT_CODE,
111
+ "latitude": lat,
112
+ "longitude": lon
113
+ }
114
+ resp = requests.post(API_FAMILY, headers=headers, json=body)
115
+ resp.raise_for_status()
116
+ js = resp.json()
117
+ # 修改判斷:根據回傳範例,成功時 code 為 1
118
+ if js.get("code") != 1:
119
+ raise RuntimeError(f"取得全家門市資料失敗: {js}")
120
+ return js["data"]
121
 
122
  # -----------------------------------------------------------
123
+ # Gradio 查詢邏輯
124
  # -----------------------------------------------------------
125
  def find_nearest_store(address, lat, lon):
126
+ """
127
+ 1. 使用者輸入經緯度
128
+ 2. 查詢 7-11 與 FamilyMart 的即期品清單
129
+ 3. 合併結果後顯示
130
+ """
131
  print(f"🔍 收到查詢請求: address={address}, lat={lat}, lon={lon}")
 
132
  if lat == 0 or lon == 0:
133
  return [["❌ 請輸入地址或提供 GPS 座標", "", "", "", ""]]
134
 
135
+ result_rows = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
+ # ------------------ 7-11 ------------------
138
+ try:
139
+ token_711 = get_7_11_token()
140
+ nearby_stores_711 = get_7_11_nearby_stores(token_711, lat, lon)
141
+ for store in nearby_stores_711:
142
+ dist_m = store.get("Distance", 999999)
143
+ if dist_m <= MAX_DISTANCE:
144
+ store_no = store.get("StoreNo")
145
+ store_name = store.get("StoreName", "7-11 未提供店名")
146
+ remaining_qty = store.get("RemainingQty", 0)
147
+ if remaining_qty > 0:
148
+ detail = get_7_11_store_detail(token_711, lat, lon, store_no)
149
+ for cat in detail.get("CategoryStockItems", []):
150
+ cat_name = cat.get("Name", "")
151
+ for item in cat.get("ItemList", []):
152
+ item_name = item.get("ItemName", "")
153
+ item_qty = item.get("RemainingQty", 0)
154
+ row = [
155
+ f"7-11 {store_name}",
156
+ f"{dist_m:.1f} m",
157
+ f"{cat_name} - {item_name}",
158
+ str(item_qty)
159
+ ]
160
+ result_rows.append(row)
161
+ else:
162
+ row = [
163
+ f"7-11 {store_name}",
164
+ f"{dist_m:.1f} m",
165
+ "即期品 0 項",
166
+ "0"
167
+ ]
168
+ result_rows.append(row)
169
+ except Exception as e:
170
+ print(f"❌ 取得 7-11 即期品時發生錯誤: {e}")
171
 
172
+ # ------------------ FamilyMart ------------------
173
+ try:
174
+ nearby_stores_family = get_family_nearby_stores(lat, lon)
175
+ for store in nearby_stores_family:
176
+ dist_m = store.get("distance", 999999)
177
+ if dist_m <= MAX_DISTANCE:
178
+ store_name = store.get("name", "全家 未提供店名")
179
+ info_list = store.get("info", [])
180
+ has_item = False
181
+ for big_cat in info_list:
182
+ big_cat_name = big_cat.get("name", "")
183
+ for subcat in big_cat.get("categories", []):
184
+ subcat_name = subcat.get("name", "")
185
+ for product in subcat.get("products", []):
186
+ product_name = product.get("name", "")
187
+ qty = product.get("qty", 0)
188
+ if qty > 0:
189
+ has_item = True
190
+ row = [
191
+ f"全家 {store_name}",
192
+ f"{dist_m:.1f} m",
193
+ f"{big_cat_name} - {subcat_name} - {product_name}",
194
+ str(qty)
195
+ ]
196
+ result_rows.append(row)
197
+ if not has_item:
198
+ row = [
199
+ f"全家 {store_name}",
200
+ f"{dist_m:.1f} m",
201
+ "即期品 0 項",
202
+ "0"
203
+ ]
204
+ result_rows.append(row)
205
+ except Exception as e:
206
+ print(f"❌ 取得全家 即期品時發生錯誤: {e}")
207
 
208
+ if not result_rows:
209
+ return [["❌ 附近 3 公里內沒有即期食品", "", "", "", ""]]
 
 
 
 
 
 
 
 
 
210
 
211
+ return result_rows
212
 
213
  # -----------------------------------------------------------
214
+ # Gradio 介面
215
  # -----------------------------------------------------------
216
  with gr.Blocks() as demo:
217
+ gr.Markdown("## 便利商店「即期食品」搜尋示範")
218
+ gr.Markdown("""
219
+ 1. 按下「使用目前位置」或自行輸入緯度/經度
220
+ 2. 點選「搜尋」查詢 3 公里內 7-11 / 全家的即期品
221
+ 3. 若要執行,需要有效的 mid_v (7-11 愛食記憶官網)
222
+ 4. 在 Logs 查看詳細錯誤或除錯資訊
223
+ """)
224
  address = gr.Textbox(label="輸入地址(可留空)")
225
  lat = gr.Number(label="GPS 緯度", value=0, elem_id="lat")
226
  lon = gr.Number(label="GPS 經度", value=0, elem_id="lon")
 
264
 
265
  def main():
266
  """
267
+ 主程式入口,在本地端執行:
268
+ python your_script.py
269
  """
 
 
 
 
 
270
  demo.launch(server_name="0.0.0.0", server_port=7860, debug=True)
271
 
272
  if __name__ == "__main__":