3v324v23 commited on
Commit
ec794b6
·
1 Parent(s): 9d45670

使用新版google genai

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