KGNINJA commited on
Commit
9fbf9e2
·
verified ·
1 Parent(s): aabcb4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -103
app.py CHANGED
@@ -1,105 +1,81 @@
1
  import json
2
- import math
3
- from fastapi import FastAPI
4
- from fastapi.middleware.cors import CORSMiddleware
5
- from pydantic import BaseModel
6
  from shapely.geometry import shape, Point
7
- from pyproj import Transformer
8
- import requests
9
- import os
10
- from openai import OpenAI
11
-
12
-
13
- # ================
14
- # CONFIG
15
- # ================
16
- MLIT_TILE_API = "https://www.mlit-data.jp/api/v1/catalog/search"
17
- OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
18
-
19
- client = OpenAI(api_key=OPENAI_API_KEY)
20
-
21
- app = FastAPI()
22
-
23
- # CORS for GitHub Pages
24
- app.add_middleware(
25
- CORSMiddleware,
26
- allow_origins=["*"],
27
- allow_methods=["*"],
28
- allow_headers=["*"]
29
- )
30
-
31
- # Load HABS (明治村界)
32
- with open("habs_data/meiji_village.geojson", encoding="utf-8") as f:
33
- HABS = json.load(f)
34
-
35
- transformer = Transformer.from_crs("EPSG:4301", "EPSG:4612", always_xy=True)
36
-
37
-
38
- # ================
39
- # Request Model
40
- # ================
41
- class GeoQuery(BaseModel):
42
- old_name: str
43
- lat: float
44
- lng: float
45
- radius: int = 500
46
-
47
-
48
- # ================
49
- # Utility: Distance
50
- # ================
51
- def haversine(lat1, lon1, lat2, lon2):
52
- R = 6371000
53
- phi1, phi2 = math.radians(lat1), math.radians(lat2)
54
- dphi = math.radians(lat2 - lat1)
55
- dlambda = math.radians(lon2 - lon1)
56
-
57
- a = (
58
- math.sin(dphi / 2) ** 2 +
59
- math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2
60
- )
61
- return 2 * R * math.atan2(a ** 0.5, (1 - a) ** 0.5)
62
-
63
-
64
- # ================
65
- # Main API
66
- # ================
67
- @app.post("/match")
68
- def match_geo(q: GeoQuery):
69
-
70
- # 座標変換(古地図 → 現代)
71
- new_lon, new_lat = transformer.transform(q.lng, q.lat)
72
-
73
- # experimental_pni の現代地名取得(keyword は空で良い)
74
- resp = requests.get(
75
- MLIT_TILE_API,
76
- params={"keyword": "", "limit": 100},
77
- )
78
- modern = resp.json().get("data", [])
79
-
80
- # GPT に照合させる
81
- prompt = f"""
82
- 旧地名:{q.old_name}
83
- 座標:{new_lat}, {new_lon}
84
-
85
- 以下は周囲の現代地名候補です:
86
- {modern}
87
-
88
- 旧地名に最も対応する現在の地名を1つ選び、理由を説明し、
89
- JSON形式で name, score を出力してください。
90
- """
91
-
92
- gpt = client.chat.completions.create(
93
- model="gpt-4o",
94
- messages=[{"role": "user", "content": prompt}]
95
- )
96
-
97
- answer = gpt.choices[0].message["content"]
98
-
99
- return {
100
- "old_name": q.old_name,
101
- "lat": new_lat,
102
- "lng": new_lon,
103
- "gpt_match": answer,
104
- "modern_candidates": modern,
105
- }
 
1
  import json
2
+ import gradio as gr
 
 
 
3
  from shapely.geometry import shape, Point
4
+
5
+ # ===========================
6
+ # データロード
7
+ # ===========================
8
+ with open("data/meiji_village.geojson", "r", encoding="utf-8") as f:
9
+ geo = json.load(f)["features"]
10
+
11
+ # index 作成(高速検索)
12
+ village_index = []
13
+ for feat in geo:
14
+ props = feat["properties"]
15
+ geom = shape(feat["geometry"])
16
+ village_index.append({
17
+ "pref": props.get("pref"),
18
+ "gun": props.get("gun"),
19
+ "mura": props.get("mura"),
20
+ "id": props.get("id"),
21
+ "geometry": geom
22
+ })
23
+
24
+
25
+ # ===========================
26
+ # 古地名検索 API
27
+ # ===========================
28
+ def search_place(name, lat=None, lon=None):
29
+ results = []
30
+
31
+ # ① 地名(村名・郡名)から検索
32
+ if name:
33
+ key = name.strip()
34
+ for v in village_index:
35
+ if key in v["mura"] or key in v["gun"]:
36
+ results.append({
37
+ "都道府県": v["pref"],
38
+ "郡": v["gun"],
39
+ "村": v["mura"],
40
+ "ID": v["id"]
41
+ })
42
+
43
+ # ② 座標を与えられた場合 → 村界にポイントが含まれるか判定
44
+ if lat and lon:
45
+ pt = Point(float(lon), float(lat))
46
+ for v in village_index:
47
+ if v["geometry"].contains(pt):
48
+ results.append({
49
+ "都道府県": v["pref"],
50
+ "郡": v["gun"],
51
+ "村": v["mura"],
52
+ "ID": v["id"]
53
+ })
54
+
55
+ if len(results) == 0:
56
+ return "該当なし"
57
+
58
+ return results
59
+
60
+
61
+ # ===========================
62
+ # Gradio UI
63
+ # ===========================
64
+ def run_search(name, latitude, longitude):
65
+ return search_place(name, latitude, longitude)
66
+
67
+
68
+ with gr.Blocks() as app:
69
+ gr.Markdown("# 古地名 → 明治22年村界検索(京都+大阪)")
70
+
71
+ with gr.Row():
72
+ name = gr.Textbox(label="地名(村名・郡名)")
73
+ lat = gr.Textbox(label="緯度 lat(任意)")
74
+ lon = gr.Textbox(label="経度 lon(任意)")
75
+
76
+ btn = gr.Button("検索")
77
+ output = gr.JSON(label="結果")
78
+
79
+ btn.click(run_search, inputs=[name, lat, lon], outputs=output)
80
+
81
+ app.launch()