3v324v23 commited on
Commit
9d3e16e
·
1 Parent(s): 0911ff4

linting main.py

Browse files
Files changed (1) hide show
  1. main.py +91 -82
main.py CHANGED
@@ -1,32 +1,26 @@
1
- # ===東吳大學資料系 2025 年 LINEBOT ===
2
  import base64
3
-
4
  import os
5
  import tempfile
6
- import logging
7
- import markdown
8
 
9
- from flask import Flask, request, abort, send_from_directory
10
- from bs4 import BeautifulSoup
11
  import google.generativeai as genai
12
- from openai import OpenAI
13
-
 
14
  from linebot.v3 import WebhookHandler
15
  from linebot.v3.exceptions import InvalidSignatureError
16
  from linebot.v3.messaging import (
17
- Configuration,
18
  ApiClient,
 
 
19
  MessagingApi,
20
  MessagingApiBlob,
21
  ReplyMessageRequest,
22
  TextMessage,
23
- ImageMessage
24
- )
25
- from linebot.v3.webhooks import (
26
- MessageEvent,
27
- TextMessageContent,
28
- ImageMessageContent
29
  )
 
 
30
 
31
  # === 初始化 Google Gemini ===
32
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
@@ -34,19 +28,20 @@ genai.configure(api_key=GOOGLE_API_KEY)
34
  model = genai.GenerativeModel("gemini-2.0-flash")
35
 
36
  # === 初始化OpenAI模型 ===
37
- api_key = os.getenv("OPENAI_API_KEY")
38
- client = OpenAI(api_key=api_key)
39
 
40
 
41
  # === 初始設定 ===
42
- # static_tmp_path = "/tmp"
43
  static_tmp_path = tempfile.gettempdir()
44
  os.makedirs(static_tmp_path, exist_ok=True)
45
  base_url = os.getenv("SPACE_HOST") # e.g., "your-space-name.hf.space"
46
 
47
  # === Flask 應用初始化 ===
48
  app = Flask(__name__)
49
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
 
 
50
  app.logger.setLevel(logging.INFO)
51
 
52
  channel_secret = os.environ.get("YOUR_CHANNEL_SECRET")
@@ -55,21 +50,25 @@ channel_access_token = os.environ.get("YOUR_CHANNEL_ACCESS_TOKEN")
55
  configuration = Configuration(access_token=channel_access_token)
56
  handler = WebhookHandler(channel_secret)
57
 
 
58
  # === AI Query 包裝 ===
59
  def query(payload):
60
  response = model.generate_content(payload)
61
  return response.text
62
 
 
63
  # === 靜態圖檔路由 ===
64
  @app.route("/images/<filename>")
65
  def serve_image(filename):
66
  return send_from_directory(static_tmp_path, filename)
67
 
 
68
  # === LINE Webhook 接收端點 ===
69
  @app.route("/")
70
  def home():
71
  return {"message": "Line Webhook Server"}
72
 
 
73
  @app.route("/", methods=["POST"])
74
  def callback():
75
  signature = request.headers.get("X-Line-Signature")
@@ -84,65 +83,67 @@ def callback():
84
 
85
  return "OK"
86
 
 
87
  # === 處理文字訊息 ===
88
  @handler.add(MessageEvent, message=TextMessageContent)
89
  def handle_text_message(event):
90
- user_input = event.message.text.strip()
91
- if user_input.startswith("AI "):
92
- prompt = user_input[3:].strip()
93
- try:
94
- response = client.images.generate(
95
- model="dall-e-3",
96
- prompt=f"使用下面的文字來畫一幅畫:{prompt}",
97
- size="1024x1024",
98
- quality="standard",
99
- n=1,
100
- )
101
- image_url = response.data[0].url
102
- app.logger.info(image_url)
103
- with ApiClient(configuration) as api_client:
104
- line_bot_api = MessagingApi(api_client)
105
- line_bot_api.reply_message(
106
- ReplyMessageRequest(
107
- reply_token=event.reply_token,
108
- messages=[
109
- ImageMessage(
110
- original_content_url=image_url,
111
- preview_image_url=image_url
112
- )
113
- ]
114
- )
115
- )
116
- except Exception as e:
117
- app.logger.error(f"DALL·E 3 API error: {e}")
118
- with ApiClient(configuration) as api_client:
119
- line_bot_api = MessagingApi(api_client)
120
- line_bot_api.reply_message(
121
- ReplyMessageRequest(
122
- reply_token=event.reply_token,
123
- messages=[TextMessage(text="抱歉,生成圖像時發生錯誤。")]
124
- )
125
  )
126
- else:
 
 
127
  with ApiClient(configuration) as api_client:
128
  line_bot_api = MessagingApi(api_client)
129
- response = query(event.message.text)
130
- html_msg = markdown.markdown(response)
131
- soup = BeautifulSoup(html_msg, "html.parser")
132
-
133
- line_bot_api.reply_message_with_http_info(
134
  ReplyMessageRequest(
135
  reply_token=event.reply_token,
136
- messages=[TextMessage(text=soup.get_text())]
137
  )
138
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  # === 處理圖片訊息 ===
141
  @handler.add(MessageEvent, message=ImageMessageContent)
142
  def handle_image_message(event):
143
-
144
  # === 以下是處理圖片回傳部分 === #
145
-
146
  with ApiClient(configuration) as api_client:
147
  blob_api = MessagingApiBlob(api_client)
148
  content = blob_api.get_message_content(message_id=event.message.id)
@@ -150,36 +151,45 @@ def handle_image_message(event):
150
 
151
  # Step 2:轉成 base64 字串
152
  base64_string = base64.b64encode(image_bytes).decode("utf-8")
153
-
154
  # Step 3:組成 OpenAI 的 data URI 格式
155
  data_uri = f"data:image/png;base64,{base64_string}"
 
156
 
157
- with tempfile.NamedTemporaryFile(dir=static_tmp_path, suffix=".jpg", delete=False) as tf:
 
 
 
158
  tf.write(content)
159
  filename = os.path.basename(tf.name)
160
 
161
  image_url = f"https://{base_url}/images/{filename}"
162
-
163
  app.logger.info(f"Image URL: {image_url}")
164
 
165
  # === 以下是處理解釋圖片部分 === #
166
  response = client.responses.create(
167
  model="gpt-4.1-nano",
168
- input=[{
169
- "role": "user",
170
- "content": [
171
- {"type": "input_text", "text": "describe the image in traditional chinese"},
172
- {
173
- "type": "input_image",
174
- "image_url": data_uri,
175
- },
176
- ],
177
- }],
 
 
 
 
 
178
  )
179
  app.logger.info(response.output_text)
180
-
181
  # === 以下是回傳圖片部分 === #
182
-
183
  with ApiClient(configuration) as api_client:
184
  line_bot_api = MessagingApi(api_client)
185
  line_bot_api.reply_message(
@@ -187,10 +197,9 @@ def handle_image_message(event):
187
  reply_token=event.reply_token,
188
  messages=[
189
  ImageMessage(
190
- original_content_url=image_url,
191
- preview_image_url=image_url
192
  ),
193
  TextMessage(text=response.output_text),
194
- ]
195
  )
196
- )
 
1
+ # ===東吳大學資料系 2025 年 LINEBOT ===
2
  import base64
3
+ import logging
4
  import os
5
  import tempfile
 
 
6
 
 
 
7
  import google.generativeai as genai
8
+ import markdown
9
+ from bs4 import BeautifulSoup
10
+ from flask import Flask, abort, request, send_from_directory
11
  from linebot.v3 import WebhookHandler
12
  from linebot.v3.exceptions import InvalidSignatureError
13
  from linebot.v3.messaging import (
 
14
  ApiClient,
15
+ Configuration,
16
+ ImageMessage,
17
  MessagingApi,
18
  MessagingApiBlob,
19
  ReplyMessageRequest,
20
  TextMessage,
 
 
 
 
 
 
21
  )
22
+ from linebot.v3.webhooks import ImageMessageContent, MessageEvent, TextMessageContent
23
+ from openai import OpenAI
24
 
25
  # === 初始化 Google Gemini ===
26
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
 
28
  model = genai.GenerativeModel("gemini-2.0-flash")
29
 
30
  # === 初始化OpenAI模型 ===
31
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
32
+ client = OpenAI(api_key=OPENAI_API_KEY)
33
 
34
 
35
  # === 初始設定 ===
 
36
  static_tmp_path = tempfile.gettempdir()
37
  os.makedirs(static_tmp_path, exist_ok=True)
38
  base_url = os.getenv("SPACE_HOST") # e.g., "your-space-name.hf.space"
39
 
40
  # === Flask 應用初始化 ===
41
  app = Flask(__name__)
42
+ logging.basicConfig(
43
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
44
+ )
45
  app.logger.setLevel(logging.INFO)
46
 
47
  channel_secret = os.environ.get("YOUR_CHANNEL_SECRET")
 
50
  configuration = Configuration(access_token=channel_access_token)
51
  handler = WebhookHandler(channel_secret)
52
 
53
+
54
  # === AI Query 包裝 ===
55
  def query(payload):
56
  response = model.generate_content(payload)
57
  return response.text
58
 
59
+
60
  # === 靜態圖檔路由 ===
61
  @app.route("/images/<filename>")
62
  def serve_image(filename):
63
  return send_from_directory(static_tmp_path, filename)
64
 
65
+
66
  # === LINE Webhook 接收端點 ===
67
  @app.route("/")
68
  def home():
69
  return {"message": "Line Webhook Server"}
70
 
71
+
72
  @app.route("/", methods=["POST"])
73
  def callback():
74
  signature = request.headers.get("X-Line-Signature")
 
83
 
84
  return "OK"
85
 
86
+
87
  # === 處理文字訊息 ===
88
  @handler.add(MessageEvent, message=TextMessageContent)
89
  def handle_text_message(event):
90
+ user_input = event.message.text.strip()
91
+ if user_input.startswith("AI "):
92
+ prompt = user_input[3:].strip()
93
+ try:
94
+ response = client.images.generate(
95
+ model="dall-e-3",
96
+ prompt=f"使用下面的文字來畫一幅畫:{prompt}",
97
+ size="1024x1024",
98
+ quality="standard",
99
+ n=1,
100
+ )
101
+ image_url = response.data[0].url
102
+ app.logger.info(image_url)
103
+ with ApiClient(configuration) as api_client:
104
+ line_bot_api = MessagingApi(api_client)
105
+ line_bot_api.reply_message(
106
+ ReplyMessageRequest(
107
+ reply_token=event.reply_token,
108
+ messages=[
109
+ ImageMessage(
110
+ original_content_url=image_url,
111
+ preview_image_url=image_url,
112
+ )
113
+ ],
 
 
 
 
 
 
 
 
 
 
 
114
  )
115
+ )
116
+ except Exception as e:
117
+ app.logger.error(f"DALL·E 3 API error: {e}")
118
  with ApiClient(configuration) as api_client:
119
  line_bot_api = MessagingApi(api_client)
120
+ line_bot_api.reply_message(
 
 
 
 
121
  ReplyMessageRequest(
122
  reply_token=event.reply_token,
123
+ messages=[TextMessage(text="抱歉,生成圖像時發生錯誤。")],
124
  )
125
  )
126
+ else:
127
+ with ApiClient(configuration) as api_client:
128
+ line_bot_api = MessagingApi(api_client)
129
+ response = query(event.message.text)
130
+ html_msg = markdown.markdown(response)
131
+ soup = BeautifulSoup(html_msg, "html.parser")
132
+
133
+ line_bot_api.reply_message_with_http_info(
134
+ ReplyMessageRequest(
135
+ reply_token=event.reply_token,
136
+ messages=[TextMessage(text=soup.get_text())],
137
+ )
138
+ )
139
+
140
 
141
  # === 處理圖片訊息 ===
142
  @handler.add(MessageEvent, message=ImageMessageContent)
143
  def handle_image_message(event):
144
+
145
  # === 以下是處理圖片回傳部分 === #
146
+
147
  with ApiClient(configuration) as api_client:
148
  blob_api = MessagingApiBlob(api_client)
149
  content = blob_api.get_message_content(message_id=event.message.id)
 
151
 
152
  # Step 2:轉成 base64 字串
153
  base64_string = base64.b64encode(image_bytes).decode("utf-8")
154
+
155
  # Step 3:組成 OpenAI 的 data URI 格式
156
  data_uri = f"data:image/png;base64,{base64_string}"
157
+ app.logger.info(f"Data URI: {data_uri}")
158
 
159
+ # Step 4:將圖片存到本地端
160
+ with tempfile.NamedTemporaryFile(
161
+ dir=static_tmp_path, suffix=".jpg", delete=False
162
+ ) as tf:
163
  tf.write(content)
164
  filename = os.path.basename(tf.name)
165
 
166
  image_url = f"https://{base_url}/images/{filename}"
167
+
168
  app.logger.info(f"Image URL: {image_url}")
169
 
170
  # === 以下是處理解釋圖片部分 === #
171
  response = client.responses.create(
172
  model="gpt-4.1-nano",
173
+ input=[
174
+ {
175
+ "role": "user",
176
+ "content": [
177
+ {
178
+ "type": "input_text",
179
+ "text": "describe the image in traditional chinese",
180
+ },
181
+ {
182
+ "type": "input_image",
183
+ "image_url": data_uri,
184
+ },
185
+ ],
186
+ }
187
+ ],
188
  )
189
  app.logger.info(response.output_text)
190
+
191
  # === 以下是回傳圖片部分 === #
192
+
193
  with ApiClient(configuration) as api_client:
194
  line_bot_api = MessagingApi(api_client)
195
  line_bot_api.reply_message(
 
197
  reply_token=event.reply_token,
198
  messages=[
199
  ImageMessage(
200
+ original_content_url=image_url, preview_image_url=image_url
 
201
  ),
202
  TextMessage(text=response.output_text),
203
+ ],
204
  )
205
+ )