kyle9574 commited on
Commit
dc9267e
·
verified ·
1 Parent(s): 39355c7

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -0
app.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, abort
2
+ from linebot.v3.webhook import WebhookParser, WebhookHandler
3
+ from linebot.v3.webhooks import MessageEvent, TextMessageContent
4
+ from linebot.v3.messaging import MessagingApi, Configuration, ApiClient
5
+ from linebot.v3.messaging.models import (
6
+ TextMessage, ReplyMessageRequest,
7
+ FlexMessage, FlexBubble, FlexBox, FlexText, FlexButton, URIAction,
8
+ QuickReply, QuickReplyItem, LocationAction
9
+ )
10
+ from linebot.v3.exceptions import InvalidSignatureError
11
+
12
+ import sqlite3
13
+ import requests
14
+ import os
15
+ from dotenv import load_dotenv
16
+
17
+ load_dotenv()
18
+
19
+ app = Flask(__name__)
20
+
21
+ CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
22
+ CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
23
+ GOOGLE_MAP_API_KEY = os.getenv("GOOGLE_MAP_API_KEY")
24
+
25
+ configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
26
+ parser = WebhookParser(CHANNEL_SECRET)
27
+ handler = WebhookHandler(CHANNEL_SECRET)
28
+
29
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
30
+ DB_PATH = os.path.join(BASE_DIR, "medicine.db")
31
+
32
+ @app.route("/callback", methods=["POST"])
33
+ def callback():
34
+ signature = request.headers.get("X-Line-Signature", "")
35
+ body = request.get_data(as_text=True)
36
+
37
+ try:
38
+ events = parser.parse(body, signature)
39
+ except InvalidSignatureError:
40
+ abort(400)
41
+ except Exception as e:
42
+ print("Webhook parse error:", e)
43
+ abort(400)
44
+
45
+ with ApiClient(configuration) as api_client:
46
+ messaging_api = MessagingApi(api_client)
47
+
48
+ for event in events:
49
+ if event.type == "message":
50
+ if event.message.type == "text":
51
+ user_input = event.message.text.strip()
52
+ print("📨 收到訊息:", user_input)
53
+
54
+ if user_input == "查詢藥品":
55
+ reply_text = "請輸入藥品名稱,例如:口服感冒藥"
56
+ reply_request = ReplyMessageRequest(
57
+ reply_token=event.reply_token,
58
+ messages=[TextMessage(text=reply_text)]
59
+ )
60
+ messaging_api.reply_message(reply_message_request=reply_request)
61
+
62
+ elif "查詢藥局" in user_input:
63
+ quick_reply = QuickReply(
64
+ items=[QuickReplyItem(action=LocationAction(label="傳送我的位置"))]
65
+ )
66
+ reply_request = ReplyMessageRequest(
67
+ reply_token=event.reply_token,
68
+ messages=[TextMessage(text="請點選下方按鈕傳送你的位置,我才能幫你找附近藥局喔~", quick_reply=quick_reply)]
69
+ )
70
+ messaging_api.reply_message(reply_message_request=reply_request)
71
+
72
+ else:
73
+ # 直接當作藥品名稱查詢
74
+ medicine_name = user_input
75
+ try:
76
+ conn = sqlite3.connect(DB_PATH)
77
+ cursor = conn.cursor()
78
+ query = """
79
+ SELECT DISTINCT 中文品名, 英文品名, 適應症
80
+ FROM drugs
81
+ WHERE 中文品名 LIKE ?
82
+ LIMIT 3
83
+ """
84
+ cursor.execute(query, ('%' + medicine_name + '%',))
85
+ rows = cursor.fetchall()
86
+ conn.close()
87
+
88
+ if not rows:
89
+ reply_text = f"找不到與「{medicine_name}」相關的藥品。"
90
+ else:
91
+ reply_text = ""
92
+ for row in rows:
93
+ reply_text += (
94
+ f"🔹 中文品名:{row[0]}\n"
95
+ f"📌 英文品名:{row[1]}\n"
96
+ f"📄 適應症:{row[2]}\n\n"
97
+ )
98
+ except Exception as e:
99
+ reply_text = f"⚠️ 查詢資料時發生錯誤:{str(e)}"
100
+
101
+ reply_request = ReplyMessageRequest(
102
+ reply_token=event.reply_token,
103
+ messages=[TextMessage(text=reply_text.strip())]
104
+ )
105
+ messaging_api.reply_message(reply_message_request=reply_request)
106
+
107
+ elif event.message.type == "location":
108
+ user_lat = event.message.latitude
109
+ user_lng = event.message.longitude
110
+
111
+ nearby_url = (
112
+ f"https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
113
+ f"location={user_lat},{user_lng}&radius=1000&type=pharmacy&key={GOOGLE_MAP_API_KEY}"
114
+ )
115
+ nearby_res = requests.get(nearby_url).json()
116
+
117
+ if not nearby_res.get('results'):
118
+ reply_request = ReplyMessageRequest(
119
+ reply_token=event.reply_token,
120
+ messages=[TextMessage(text="附近找不到藥局")]
121
+ )
122
+ messaging_api.reply_message(reply_message_request=reply_request)
123
+ continue
124
+
125
+ place = nearby_res['results'][0]
126
+ place_id = place['place_id']
127
+ name = place.get('name', '藥局名稱未知')
128
+ location = place['geometry']['location']
129
+ dest_lat, dest_lng = location['lat'], location['lng']
130
+
131
+ details_url = (
132
+ f"https://maps.googleapis.com/maps/api/place/details/json?"
133
+ f"place_id={place_id}&fields=name,formatted_phone_number&key={GOOGLE_MAP_API_KEY}"
134
+ )
135
+ details_res = requests.get(details_url).json()
136
+ phone = details_res.get('result', {}).get('formatted_phone_number', '電話不詳')
137
+
138
+ dist_url = (
139
+ f"https://maps.googleapis.com/maps/api/distancematrix/json?"
140
+ f"origins={user_lat},{user_lng}&destinations={dest_lat},{dest_lng}&key={GOOGLE_MAP_API_KEY}"
141
+ )
142
+ dist_res = requests.get(dist_url).json()
143
+ distance = dist_res['rows'][0]['elements'][0]['distance']['text']
144
+
145
+ map_url = f"https://www.google.com/maps/search/?api=1&query={dest_lat},{dest_lng}"
146
+
147
+ bubble = FlexBubble(
148
+ body=FlexBox(
149
+ layout="vertical",
150
+ contents=[
151
+ FlexText(text=name, weight="bold", size="lg"),
152
+ FlexText(text=f"電話:{phone}", size="sm", color="#555555"),
153
+ FlexText(text=f"距離:{distance}", size="sm", color="#777777"),
154
+ ],
155
+ ),
156
+ footer=FlexBox(
157
+ layout="vertical",
158
+ contents=[
159
+ FlexButton(
160
+ style="link",
161
+ height="sm",
162
+ action=URIAction(label="地圖導航", uri=map_url),
163
+ )
164
+ ],
165
+ ),
166
+ )
167
+
168
+ flex_message = FlexMessage(
169
+ alt_text="附近藥局推薦",
170
+ contents=bubble
171
+ )
172
+
173
+ reply_request = ReplyMessageRequest(
174
+ reply_token=event.reply_token,
175
+ messages=[flex_message]
176
+ )
177
+ messaging_api.reply_message(reply_message_request=reply_request)
178
+
179
+ return "OK"
180
+
181
+
182
+ if __name__ == "__main__":
183
+ app.run(debug=True, port=8000)