solnone commited on
Commit
6d166b5
·
1 Parent(s): 1885646
Files changed (1) hide show
  1. main.py +883 -19
main.py CHANGED
@@ -1,37 +1,132 @@
1
- from flask import Flask, request, abort
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import os
 
 
 
 
 
 
3
  import google.generativeai as genai
4
 
5
  from linebot.v3 import (
6
  WebhookHandler
7
  )
8
-
 
 
9
  from linebot.v3.exceptions import (
10
  InvalidSignatureError
11
  )
12
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  from linebot.v3.messaging import (
14
  Configuration,
15
  ApiClient,
16
  MessagingApi,
 
17
  ReplyMessageRequest,
18
- TextMessage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  )
20
 
21
- from linebot.v3.webhooks import (
22
- MessageEvent,
23
- TextMessageContent
24
  )
25
 
26
  app = Flask(__name__)
 
 
 
 
 
 
27
 
28
- configuration = Configuration(access_token=os.environ.get("ACCESS_TOKEN"))
29
- handler = WebhookHandler(os.environ.get("CHANNEL_SECRET"))
 
 
 
 
 
 
 
 
 
30
 
31
- genai.configure(api_key=os.environ.get("GOOGLE_API_KEY"))
32
  model = genai.GenerativeModel('gemini-pro')
33
  chats: dict[str, genai.ChatSession] = {}
34
 
 
35
  def get_chat(user_id: str) -> genai.ChatSession:
36
  if user_id in chats:
37
  return chats.get(user_id)
@@ -40,11 +135,23 @@ def get_chat(user_id: str) -> genai.ChatSession:
40
  chats[user_id] = chat
41
  return chat
42
 
 
43
  @app.route("/")
44
  def home():
45
  return {"message": "Line Webhook Server"}
46
 
47
 
 
 
 
 
 
 
 
 
 
 
 
48
  @app.route("/callback", methods=['POST'])
49
  def callback():
50
  # get X-Line-Signature header value
@@ -57,25 +164,782 @@ def callback():
57
  # handle webhook body
58
  try:
59
  handler.handle(body, signature)
 
 
60
  except InvalidSignatureError:
61
- app.logger.info("Invalid signature. Please check your channel access token/channel secret.")
62
  abort(400)
63
 
64
  return 'OK'
65
 
66
 
67
  @handler.add(MessageEvent, message=TextMessageContent)
68
- def handle_message(event):
69
- app.logger.info(f"UserID: {event.source.user_id}")
70
- app.logger.info(f"Q: {event.message.text}")
71
- chat = get_chat(event.source.user_id)
72
- response = chat.send_message(event.message.text)
73
- app.logger.info(f"A: {response.text}")
74
  with ApiClient(configuration) as api_client:
75
  line_bot_api = MessagingApi(api_client)
76
- line_bot_api.reply_message_with_http_info(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  ReplyMessageRequest(
78
  reply_token=event.reply_token,
79
- messages=[TextMessage(text=response.text)]
 
 
 
80
  )
81
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+
16
+ import datetime
17
+ import errno
18
  import os
19
+ import sys
20
+ import logging
21
+ import tempfile
22
+ from argparse import ArgumentParser
23
+
24
+ from flask import Flask, request, abort, send_from_directory
25
  import google.generativeai as genai
26
 
27
  from linebot.v3 import (
28
  WebhookHandler
29
  )
30
+ from linebot.v3.models import (
31
+ UnknownEvent
32
+ )
33
  from linebot.v3.exceptions import (
34
  InvalidSignatureError
35
  )
36
+ from linebot.v3.webhooks import (
37
+ MessageEvent,
38
+ TextMessageContent,
39
+ LocationMessageContent,
40
+ StickerMessageContent,
41
+ ImageMessageContent,
42
+ VideoMessageContent,
43
+ AudioMessageContent,
44
+ FileMessageContent,
45
+ UserSource,
46
+ RoomSource,
47
+ GroupSource,
48
+ FollowEvent,
49
+ UnfollowEvent,
50
+ JoinEvent,
51
+ LeaveEvent,
52
+ PostbackEvent,
53
+ BeaconEvent,
54
+ MemberJoinedEvent,
55
+ MemberLeftEvent,
56
+ )
57
  from linebot.v3.messaging import (
58
  Configuration,
59
  ApiClient,
60
  MessagingApi,
61
+ MessagingApiBlob,
62
  ReplyMessageRequest,
63
+ PushMessageRequest,
64
+ MulticastRequest,
65
+ BroadcastRequest,
66
+ TextMessage,
67
+ ApiException,
68
+ LocationMessage,
69
+ StickerMessage,
70
+ ImageMessage,
71
+ TemplateMessage,
72
+ FlexMessage,
73
+ Emoji,
74
+ QuickReply,
75
+ QuickReplyItem,
76
+ ConfirmTemplate,
77
+ ButtonsTemplate,
78
+ CarouselTemplate,
79
+ CarouselColumn,
80
+ ImageCarouselTemplate,
81
+ ImageCarouselColumn,
82
+ FlexBubble,
83
+ FlexImage,
84
+ FlexBox,
85
+ FlexText,
86
+ FlexIcon,
87
+ FlexButton,
88
+ FlexSeparator,
89
+ FlexContainer,
90
+ MessageAction,
91
+ URIAction,
92
+ PostbackAction,
93
+ DatetimePickerAction,
94
+ CameraAction,
95
+ CameraRollAction,
96
+ LocationAction,
97
+ ErrorResponse
98
  )
99
 
100
+ from linebot.v3.insight import (
101
+ ApiClient as InsightClient,
102
+ Insight
103
  )
104
 
105
  app = Flask(__name__)
106
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
107
+ app.logger.setLevel(logging.INFO)
108
+
109
+ # get channel_secret and channel_access_token from your environment variable
110
+ channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
111
+ channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
112
 
113
+ if channel_secret is None or channel_access_token is None:
114
+ print('Specify LINE_CHANNEL_SECRET and LINE_CHANNEL_ACCESS_TOKEN as environment variables.')
115
+ sys.exit(1)
116
+
117
+ handler = WebhookHandler(channel_secret)
118
+
119
+ static_tmp_path = os.path.join(os.path.dirname(__file__), 'static', 'tmp')
120
+
121
+ configuration = Configuration(
122
+ access_token=channel_access_token
123
+ )
124
 
125
+ genai.configure(api_key=os.getenv('GOOGLE_API_KEY', None))
126
  model = genai.GenerativeModel('gemini-pro')
127
  chats: dict[str, genai.ChatSession] = {}
128
 
129
+
130
  def get_chat(user_id: str) -> genai.ChatSession:
131
  if user_id in chats:
132
  return chats.get(user_id)
 
135
  chats[user_id] = chat
136
  return chat
137
 
138
+
139
  @app.route("/")
140
  def home():
141
  return {"message": "Line Webhook Server"}
142
 
143
 
144
+ # function for create tmp dir for download content
145
+ def make_static_tmp_dir():
146
+ try:
147
+ os.makedirs(static_tmp_path)
148
+ except OSError as exc:
149
+ if exc.errno == errno.EEXIST and os.path.isdir(static_tmp_path):
150
+ pass
151
+ else:
152
+ raise
153
+
154
+
155
  @app.route("/callback", methods=['POST'])
156
  def callback():
157
  # get X-Line-Signature header value
 
164
  # handle webhook body
165
  try:
166
  handler.handle(body, signature)
167
+ except ApiException as e:
168
+ app.logger.warn("Got exception from LINE Messaging API: %s\n" % e.body)
169
  except InvalidSignatureError:
 
170
  abort(400)
171
 
172
  return 'OK'
173
 
174
 
175
  @handler.add(MessageEvent, message=TextMessageContent)
176
+ def handle_text_message(event):
177
+ text = event.message.text
 
 
 
 
178
  with ApiClient(configuration) as api_client:
179
  line_bot_api = MessagingApi(api_client)
180
+ if text == 'profile':
181
+ if isinstance(event.source, UserSource):
182
+ profile = line_bot_api.get_profile(user_id=event.source.user_id)
183
+ line_bot_api.reply_message(
184
+ ReplyMessageRequest(
185
+ reply_token=event.reply_token,
186
+ messages=[
187
+ TextMessage(text='Display name: ' + profile.display_name),
188
+ TextMessage(text='Status message: ' + str(profile.status_message))
189
+ ]
190
+ )
191
+ )
192
+ else:
193
+ line_bot_api.reply_message(
194
+ ReplyMessageRequest(
195
+ reply_token=event.reply_token,
196
+ messages=[TextMessage(text="Bot can't use profile API without user ID")]
197
+ )
198
+ )
199
+ elif text == 'emojis':
200
+ emojis = [Emoji(index=0, product_id="5ac1bfd5040ab15980c9b435", emoji_id="001"),
201
+ Emoji(index=13, product_id="5ac1bfd5040ab15980c9b435", emoji_id="002")]
202
+ line_bot_api.reply_message(
203
+ ReplyMessageRequest(
204
+ reply_token=event.reply_token,
205
+ messages=[TextMessage(text='$ LINE emoji $', emojis=emojis)]
206
+ )
207
+ )
208
+ elif text == 'quota':
209
+ quota = line_bot_api.get_message_quota()
210
+ line_bot_api.reply_message(
211
+ ReplyMessageRequest(
212
+ reply_token=event.reply_token,
213
+ messages=[
214
+ TextMessage(text='type: ' + quota.type),
215
+ TextMessage(text='value: ' + str(quota.value))
216
+ ]
217
+ )
218
+ )
219
+ elif text == 'quota_consumption':
220
+ quota_consumption = line_bot_api.get_message_quota_consumption()
221
+ line_bot_api.reply_message(
222
+ ReplyMessageRequest(
223
+ reply_token=event.reply_token,
224
+ messages=[
225
+ TextMessage(text='total usage: ' + str(quota_consumption.total_usage))
226
+ ]
227
+ )
228
+ )
229
+ elif text == 'push':
230
+ line_bot_api.push_message(
231
+ PushMessageRequest(
232
+ to=event.source.user_id,
233
+ messages=[TextMessage(text='PUSH!')]
234
+ )
235
+ )
236
+ elif text == 'multicast':
237
+ line_bot_api.multicast(
238
+ MulticastRequest(
239
+ to=[event.source.user_id],
240
+ messages=[TextMessage(text="THIS IS A MULTICAST MESSAGE, but it's slower than PUSH.")]
241
+ )
242
+ )
243
+ elif text == 'broadcast':
244
+ line_bot_api.broadcast(
245
+ BroadcastRequest(
246
+ messages=[TextMessage(text='THIS IS A BROADCAST MESSAGE')]
247
+ )
248
+ )
249
+ elif text.startswith('broadcast '): # broadcast 20190505
250
+ date = text.split(' ')[1]
251
+ app.logger.info("Getting broadcast result: " + date)
252
+ result = line_bot_api.get_number_of_sent_broadcast_messages(var_date=date)
253
+ line_bot_api.reply_message(
254
+ ReplyMessageRequest(
255
+ reply_token=event.reply_token,
256
+ messages=[
257
+ TextMessage(text='Number of sent broadcast messages: ' + date),
258
+ TextMessage(text='status: ' + str(result.status)),
259
+ TextMessage(text='success: ' + str(result.success)),
260
+ ]
261
+ )
262
+ )
263
+ elif text == 'bye':
264
+ if isinstance(event.source, GroupSource):
265
+ line_bot_api.reply_message(
266
+ ReplyMessageRequest(
267
+ reply_token=event.reply_token,
268
+ messages=[TextMessage(text="Leaving group")]
269
+ )
270
+ )
271
+ line_bot_api.leave_group(event.source.group_id)
272
+ elif isinstance(event.source, RoomSource):
273
+ line_bot_api.reply_message(
274
+ ReplyMessageRequest(
275
+ reply_token=event.reply_token,
276
+ messages=[TextMessage(text="Leaving room")]
277
+ )
278
+ )
279
+ line_bot_api.leave_room(room_id=event.source.room_id)
280
+ else:
281
+ line_bot_api.reply_message(
282
+ ReplyMessageRequest(
283
+ reply_token=event.reply_token,
284
+ messages=[
285
+ TextMessage(text="Bot can't leave from 1:1 chat")
286
+ ]
287
+ )
288
+ )
289
+ elif text == 'image':
290
+ url = 'https://placehold.co/400'
291
+ app.logger.info("url=" + url)
292
+ line_bot_api.reply_message(
293
+ ReplyMessageRequest(
294
+ reply_token=event.reply_token,
295
+ messages=[
296
+ ImageMessage(original_content_url=url, preview_image_url=url)
297
+ ]
298
+ )
299
+ )
300
+ elif text == 'confirm':
301
+ confirm_template = ConfirmTemplate(
302
+ text='Do it?',
303
+ actions=[
304
+ MessageAction(label='Yes', text='Yes!'),
305
+ MessageAction(label='No', text='No!')
306
+ ]
307
+ )
308
+ template_message = TemplateMessage(
309
+ alt_text='Confirm alt text',
310
+ template=confirm_template
311
+ )
312
+ line_bot_api.reply_message(
313
+ ReplyMessageRequest(
314
+ reply_token=event.reply_token,
315
+ messages=[template_message]
316
+ )
317
+ )
318
+ elif text == 'buttons':
319
+ buttons_template = ButtonsTemplate(
320
+ title='My buttons sample',
321
+ text='Hello, my buttons',
322
+ actions=[
323
+ URIAction(label='Go to line.me', uri='https://line.me'),
324
+ PostbackAction(label='ping', data='ping'),
325
+ PostbackAction(label='ping with text', data='ping', text='ping'),
326
+ MessageAction(label='Translate Rice', text='米')
327
+ ])
328
+ template_message = TemplateMessage(
329
+ alt_text='Buttons alt text',
330
+ template=buttons_template
331
+ )
332
+ line_bot_api.reply_message(
333
+ ReplyMessageRequest(
334
+ reply_token=event.reply_token,
335
+ messages=[template_message]
336
+ )
337
+ )
338
+ elif text == 'carousel':
339
+ carousel_template = CarouselTemplate(
340
+ columns=[
341
+ CarouselColumn(
342
+ text='hoge1',
343
+ title='fuga1',
344
+ actions=[
345
+ URIAction(label='Go to line.me', uri='https://line.me'),
346
+ PostbackAction(label='ping', data='ping')
347
+ ]
348
+ ),
349
+ CarouselColumn(
350
+ text='hoge2',
351
+ title='fuga2',
352
+ actions=[
353
+ PostbackAction(label='ping with text', data='ping', text='ping'),
354
+ MessageAction(label='Translate Rice', text='米')
355
+ ]
356
+ )
357
+ ]
358
+ )
359
+ template_message = TemplateMessage(
360
+ alt_text='Carousel alt text', template=carousel_template)
361
+ line_bot_api.reply_message(
362
+ ReplyMessageRequest(
363
+ reply_token=event.reply_token,
364
+ messages=[template_message]
365
+ )
366
+ )
367
+ elif text == 'image_carousel':
368
+ image_carousel_template = ImageCarouselTemplate(columns=[
369
+ ImageCarouselColumn(image_url='https://via.placeholder.com/1024x1024',
370
+ action=DatetimePickerAction(label='datetime',
371
+ data='datetime_postback',
372
+ mode='datetime')),
373
+ ImageCarouselColumn(image_url='https://via.placeholder.com/1024x1024',
374
+ action=DatetimePickerAction(label='date',
375
+ data='date_postback',
376
+ mode='date'))
377
+ ])
378
+ template_message = TemplateMessage(
379
+ alt_text='ImageCarousel alt text', template=image_carousel_template)
380
+ line_bot_api.reply_message(
381
+ ReplyMessageRequest(
382
+ reply_token=event.reply_token,
383
+ messages=[template_message]
384
+ )
385
+ )
386
+ elif text == 'imagemap':
387
+ pass
388
+ elif text == 'flex':
389
+ bubble = FlexBubble(
390
+ direction='ltr',
391
+ hero=FlexImage(
392
+ url='https://example.com/cafe.jpg',
393
+ size='full',
394
+ aspect_ratio='20:13',
395
+ aspect_mode='cover',
396
+ action=URIAction(uri='http://example.com', label='label')
397
+ ),
398
+ body=FlexBox(
399
+ layout='vertical',
400
+ contents=[
401
+ # title
402
+ FlexText(text='Brown Cafe', weight='bold', size='xl'),
403
+ # review
404
+ FlexBox(
405
+ layout='baseline',
406
+ margin='md',
407
+ contents=[
408
+ FlexIcon(size='sm', url='https://example.com/gold_star.png'),
409
+ FlexIcon(size='sm', url='https://example.com/grey_star.png'),
410
+ FlexIcon(size='sm', url='https://example.com/gold_star.png'),
411
+ FlexIcon(size='sm', url='https://example.com/gold_star.png'),
412
+ FlexIcon(size='sm', url='https://example.com/grey_star.png'),
413
+ FlexText(text='4.0', size='sm', color='#999999', margin='md', flex=0)
414
+ ]
415
+ ),
416
+ # info
417
+ FlexBox(
418
+ layout='vertical',
419
+ margin='lg',
420
+ spacing='sm',
421
+ contents=[
422
+ FlexBox(
423
+ layout='baseline',
424
+ spacing='sm',
425
+ contents=[
426
+ FlexText(
427
+ text='Place',
428
+ color='#aaaaaa',
429
+ size='sm',
430
+ flex=1
431
+ ),
432
+ FlexText(
433
+ text='Shinjuku, Tokyo',
434
+ wrap=True,
435
+ color='#666666',
436
+ size='sm',
437
+ flex=5
438
+ )
439
+ ],
440
+ ),
441
+ FlexBox(
442
+ layout='baseline',
443
+ spacing='sm',
444
+ contents=[
445
+ FlexText(
446
+ text='Time',
447
+ color='#aaaaaa',
448
+ size='sm',
449
+ flex=1
450
+ ),
451
+ FlexText(
452
+ text="10:00 - 23:00",
453
+ wrap=True,
454
+ color='#666666',
455
+ size='sm',
456
+ flex=5,
457
+ ),
458
+ ],
459
+ ),
460
+ ],
461
+ )
462
+ ],
463
+ ),
464
+ footer=FlexBox(
465
+ layout='vertical',
466
+ spacing='sm',
467
+ contents=[
468
+ # callAction
469
+ FlexButton(
470
+ style='link',
471
+ height='sm',
472
+ action=URIAction(label='CALL', uri='tel:000000'),
473
+ ),
474
+ # separator
475
+ FlexSeparator(),
476
+ # websiteAction
477
+ FlexButton(
478
+ style='link',
479
+ height='sm',
480
+ action=URIAction(label='WEBSITE', uri="https://example.com")
481
+ )
482
+ ]
483
+ ),
484
+ )
485
+ line_bot_api.reply_message(
486
+ ReplyMessageRequest(
487
+ reply_token=event.reply_token,
488
+ messages=[FlexMessage(alt_text="hello", contents=bubble)]
489
+ )
490
+ )
491
+ elif text == 'flex_update_1':
492
+ bubble_string = """
493
+ {
494
+ "type": "bubble",
495
+ "body": {
496
+ "type": "box",
497
+ "layout": "vertical",
498
+ "contents": [
499
+ {
500
+ "type": "image",
501
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip3.jpg",
502
+ "position": "relative",
503
+ "size": "full",
504
+ "aspectMode": "cover",
505
+ "aspectRatio": "1:1",
506
+ "gravity": "center"
507
+ },
508
+ {
509
+ "type": "box",
510
+ "layout": "horizontal",
511
+ "contents": [
512
+ {
513
+ "type": "box",
514
+ "layout": "vertical",
515
+ "contents": [
516
+ {
517
+ "type": "text",
518
+ "text": "Brown Hotel",
519
+ "weight": "bold",
520
+ "size": "xl",
521
+ "color": "#ffffff"
522
+ },
523
+ {
524
+ "type": "box",
525
+ "layout": "baseline",
526
+ "margin": "md",
527
+ "contents": [
528
+ {
529
+ "type": "icon",
530
+ "size": "sm",
531
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
532
+ },
533
+ {
534
+ "type": "icon",
535
+ "size": "sm",
536
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
537
+ },
538
+ {
539
+ "type": "icon",
540
+ "size": "sm",
541
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
542
+ },
543
+ {
544
+ "type": "icon",
545
+ "size": "sm",
546
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
547
+ },
548
+ {
549
+ "type": "icon",
550
+ "size": "sm",
551
+ "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gray_star_28.png"
552
+ },
553
+ {
554
+ "type": "text",
555
+ "text": "4.0",
556
+ "size": "sm",
557
+ "color": "#d6d6d6",
558
+ "margin": "md",
559
+ "flex": 0
560
+ }
561
+ ]
562
+ }
563
+ ]
564
+ },
565
+ {
566
+ "type": "box",
567
+ "layout": "vertical",
568
+ "contents": [
569
+ {
570
+ "type": "text",
571
+ "text": "¥62,000",
572
+ "color": "#a9a9a9",
573
+ "decoration": "line-through",
574
+ "align": "end"
575
+ },
576
+ {
577
+ "type": "text",
578
+ "text": "¥42,000",
579
+ "color": "#ebebeb",
580
+ "size": "xl",
581
+ "align": "end"
582
+ }
583
+ ]
584
+ }
585
+ ],
586
+ "position": "absolute",
587
+ "offsetBottom": "0px",
588
+ "offsetStart": "0px",
589
+ "offsetEnd": "0px",
590
+ "backgroundColor": "#00000099",
591
+ "paddingAll": "20px"
592
+ },
593
+ {
594
+ "type": "box",
595
+ "layout": "vertical",
596
+ "contents": [
597
+ {
598
+ "type": "text",
599
+ "text": "SALE",
600
+ "color": "#ffffff"
601
+ }
602
+ ],
603
+ "position": "absolute",
604
+ "backgroundColor": "#ff2600",
605
+ "cornerRadius": "20px",
606
+ "paddingAll": "5px",
607
+ "offsetTop": "10px",
608
+ "offsetEnd": "10px",
609
+ "paddingStart": "10px",
610
+ "paddingEnd": "10px"
611
+ }
612
+ ],
613
+ "paddingAll": "0px"
614
+ }
615
+ }
616
+ """
617
+ message = FlexMessage(alt_text="hello", contents=FlexContainer.from_json(bubble_string))
618
+ line_bot_api.reply_message(
619
+ ReplyMessageRequest(
620
+ reply_token=event.reply_token,
621
+ messages=[message]
622
+ )
623
+ )
624
+ elif text == 'quick_reply':
625
+ line_bot_api.reply_message(
626
+ ReplyMessageRequest(
627
+ reply_token=event.reply_token,
628
+ messages=[TextMessage(
629
+ text='Quick reply',
630
+ quick_reply=QuickReply(
631
+ items=[
632
+ QuickReplyItem(
633
+ action=PostbackAction(label="label1", data="data1")
634
+ ),
635
+ QuickReplyItem(
636
+ action=MessageAction(label="label2", text="text2")
637
+ ),
638
+ QuickReplyItem(
639
+ action=DatetimePickerAction(label="label3",
640
+ data="data3",
641
+ mode="date")
642
+ ),
643
+ QuickReplyItem(
644
+ action=CameraAction(label="label4")
645
+ ),
646
+ QuickReplyItem(
647
+ action=CameraRollAction(label="label5")
648
+ ),
649
+ QuickReplyItem(
650
+ action=LocationAction(label="label6")
651
+ ),
652
+ ]
653
+ )
654
+ )]
655
+ )
656
+ )
657
+ elif text == 'link_token' and isinstance(event.source, UserSource):
658
+ link_token_response = line_bot_api.issue_link_token(user_id=event.source.user_id)
659
+ line_bot_api.reply_message(
660
+ ReplyMessageRequest(
661
+ reply_token=event.reply_token,
662
+ messages=[TextMessage(text='link_token: ' + link_token_response.link_token)]
663
+ )
664
+ )
665
+ elif text == 'insight_message_delivery':
666
+ with InsightClient(configuration) as api_client:
667
+ line_bot_insight_api = Insight(api_client)
668
+ today = datetime.date.today().strftime("%Y%m%d")
669
+ response = line_bot_insight_api.get_number_of_message_deliveries(var_date=today)
670
+ if response.status == 'ready':
671
+ messages = [
672
+ TextMessage(text='broadcast: ' + str(response.broadcast)),
673
+ TextMessage(text='targeting: ' + str(response.targeting)),
674
+ ]
675
+ else:
676
+ messages = [TextMessage(text='status: ' + response.status)]
677
+ line_bot_api.reply_message(
678
+ ReplyMessageRequest(
679
+ reply_token=event.reply_token,
680
+ messages=messages
681
+ )
682
+ )
683
+ elif text == 'insight_followers':
684
+ with InsightClient(configuration) as api_client:
685
+ line_bot_insight_api = Insight(api_client)
686
+ today = datetime.date.today().strftime("%Y%m%d")
687
+ response = line_bot_insight_api.get_number_of_followers(var_date=today)
688
+ if response.status == 'ready':
689
+ messages = [
690
+ TextMessage(text='followers: ' + str(response.followers)),
691
+ TextMessage(text='targetedReaches: ' + str(response.targeted_reaches)),
692
+ TextMessage(text='blocks: ' + str(response.blocks)),
693
+ ]
694
+ else:
695
+ messages = [TextMessage(text='status: ' + response.status)]
696
+ line_bot_api.reply_message(
697
+ ReplyMessageRequest(
698
+ reply_token=event.reply_token,
699
+ messages=messages
700
+ )
701
+ )
702
+ elif text == 'insight_demographic':
703
+ with InsightClient(configuration) as api_client:
704
+ line_bot_insight_api = Insight(api_client)
705
+ response = line_bot_insight_api.get_friends_demographics()
706
+ if response.available:
707
+ messages = ["{gender}: {percentage}".format(gender=it.gender, percentage=it.percentage)
708
+ for it in response.genders]
709
+ else:
710
+ messages = [TextMessage(text='available: false')]
711
+ line_bot_api.reply_message(
712
+ ReplyMessageRequest(
713
+ reply_token=event.reply_token,
714
+ messages=messages
715
+ )
716
+ )
717
+ elif text == 'with http info':
718
+ response = line_bot_api.reply_message_with_http_info(
719
+ ReplyMessageRequest(
720
+ reply_token=event.reply_token,
721
+ messages=[TextMessage(text='see application log')]
722
+ )
723
+ )
724
+ app.logger.info("Got response with http status code: " + str(response.status_code))
725
+ app.logger.info("Got x-line-request-id: " + response.headers['x-line-request-id'])
726
+ app.logger.info("Got response with http body: " + str(response.data))
727
+ elif text == 'with http info error':
728
+ try:
729
+ line_bot_api.reply_message_with_http_info(
730
+ ReplyMessageRequest(
731
+ reply_token='invalid-reply-token',
732
+ messages=[TextMessage(text='see application log')]
733
+ )
734
+ )
735
+ except ApiException as e:
736
+ app.logger.info("Got response with http status code: " + str(e.status))
737
+ app.logger.info("Got x-line-request-id: " + e.headers['x-line-request-id'])
738
+ app.logger.info("Got response with http body: " + str(ErrorResponse.from_json(e.body)))
739
+ else:
740
+ chat = get_chat(event.source.user_id)
741
+ response = chat.send_message(text)
742
+ line_bot_api.reply_message(
743
+ ReplyMessageRequest(
744
+ reply_token=event.reply_token,
745
+ messages=[TextMessage(text=response.text)]
746
+ )
747
+ )
748
+
749
+
750
+ @handler.add(MessageEvent, message=LocationMessageContent)
751
+ def handle_location_message(event):
752
+ with ApiClient(configuration) as api_client:
753
+ line_bot_api = MessagingApi(api_client)
754
+ line_bot_api.reply_message(
755
+ ReplyMessageRequest(
756
+ reply_token=event.reply_token,
757
+ messages=[LocationMessage(
758
+ title='Location',
759
+ address=event.message.address,
760
+ latitude=event.message.latitude,
761
+ longitude=event.message.longitude
762
+ )]
763
+ )
764
+ )
765
+
766
+
767
+ @handler.add(MessageEvent, message=StickerMessageContent)
768
+ def handle_sticker_message(event):
769
+ with ApiClient(configuration) as api_client:
770
+ line_bot_api = MessagingApi(api_client)
771
+ line_bot_api.reply_message(
772
  ReplyMessageRequest(
773
  reply_token=event.reply_token,
774
+ messages=[StickerMessage(
775
+ package_id=event.message.package_id,
776
+ sticker_id=event.message.sticker_id)
777
+ ]
778
  )
779
  )
780
+
781
+
782
+ # Other Message Type
783
+ @handler.add(MessageEvent, message=(ImageMessageContent,
784
+ VideoMessageContent,
785
+ AudioMessageContent))
786
+ def handle_content_message(event):
787
+ if isinstance(event.message, ImageMessageContent):
788
+ ext = 'jpg'
789
+ elif isinstance(event.message, VideoMessageContent):
790
+ ext = 'mp4'
791
+ elif isinstance(event.message, AudioMessageContent):
792
+ ext = 'm4a'
793
+ else:
794
+ return
795
+
796
+ with ApiClient(configuration) as api_client:
797
+ line_bot_blob_api = MessagingApiBlob(api_client)
798
+ message_content = line_bot_blob_api.get_message_content(message_id=event.message.id)
799
+ with tempfile.NamedTemporaryFile(dir=static_tmp_path, prefix=ext + '-', delete=False) as tf:
800
+ tf.write(message_content)
801
+ tempfile_path = tf.name
802
+
803
+ dist_path = tempfile_path + '.' + ext
804
+ dist_name = os.path.basename(dist_path)
805
+ os.rename(tempfile_path, dist_path)
806
+
807
+ with ApiClient(configuration) as api_client:
808
+ line_bot_api = MessagingApi(api_client)
809
+ line_bot_api.reply_message(
810
+ ReplyMessageRequest(
811
+ reply_token=event.reply_token,
812
+ messages=[
813
+ TextMessage(text='Save content.'),
814
+ TextMessage(text=request.host_url + os.path.join('static', 'tmp', dist_name))
815
+ ]
816
+ )
817
+ )
818
+
819
+
820
+ @handler.add(MessageEvent, message=FileMessageContent)
821
+ def handle_file_message(event):
822
+ with ApiClient(configuration) as api_client:
823
+ line_bot_blob_api = MessagingApiBlob(api_client)
824
+ message_content = line_bot_blob_api.get_message_content(message_id=event.message.id)
825
+ with tempfile.NamedTemporaryFile(dir=static_tmp_path, prefix='file-', delete=False) as tf:
826
+ tf.write(message_content)
827
+ tempfile_path = tf.name
828
+
829
+ dist_path = tempfile_path + '-' + event.message.file_name
830
+ dist_name = os.path.basename(dist_path)
831
+ os.rename(tempfile_path, dist_path)
832
+
833
+ with ApiClient(configuration) as api_client:
834
+ line_bot_api = MessagingApi(api_client)
835
+ line_bot_api.reply_message(
836
+ ReplyMessageRequest(
837
+ reply_token=event.reply_token,
838
+ messages=[
839
+ TextMessage(text='Save file.'),
840
+ TextMessage(text=request.host_url + os.path.join('static', 'tmp', dist_name))
841
+ ]
842
+ )
843
+ )
844
+
845
+
846
+ @handler.add(FollowEvent)
847
+ def handle_follow(event):
848
+ app.logger.info("Got Follow event:" + event.source.user_id)
849
+ with ApiClient(configuration) as api_client:
850
+ line_bot_api = MessagingApi(api_client)
851
+ line_bot_api.reply_message(
852
+ ReplyMessageRequest(
853
+ reply_token=event.reply_token,
854
+ messages=[TextMessage(text='Got follow event')]
855
+ )
856
+ )
857
+
858
+
859
+ @handler.add(UnfollowEvent)
860
+ def handle_unfollow(event):
861
+ app.logger.info("Got Unfollow event:" + event.source.user_id)
862
+
863
+
864
+ @handler.add(JoinEvent)
865
+ def handle_join(event):
866
+ with ApiClient(configuration) as api_client:
867
+ line_bot_api = MessagingApi(api_client)
868
+ line_bot_api.reply_message(
869
+ ReplyMessageRequest(
870
+ reply_token=event.reply_token,
871
+ messages=[TextMessage(text='Joined this ' + event.source.type)]
872
+ )
873
+ )
874
+
875
+
876
+ @handler.add(LeaveEvent)
877
+ def handle_leave():
878
+ app.logger.info("Got leave event")
879
+
880
+
881
+ @handler.add(PostbackEvent)
882
+ def handle_postback(event: PostbackEvent):
883
+ with ApiClient(configuration) as api_client:
884
+ line_bot_api = MessagingApi(api_client)
885
+ if event.postback.data == 'ping':
886
+ line_bot_api.reply_message(
887
+ ReplyMessageRequest(
888
+ reply_token=event.reply_token,
889
+ messages=[TextMessage(text='pong')]
890
+ )
891
+ )
892
+ elif event.postback.data == 'datetime_postback':
893
+ line_bot_api.reply_message(
894
+ ReplyMessageRequest(
895
+ reply_token=event.reply_token,
896
+ messages=[TextMessage(text=event.postback.params['datetime'])]
897
+ )
898
+ )
899
+ elif event.postback.data == 'date_postback':
900
+ line_bot_api.reply_message(
901
+ ReplyMessageRequest(
902
+ reply_token=event.reply_token,
903
+ messages=[TextMessage(text=event.postback.params['date'])]
904
+ )
905
+ )
906
+
907
+
908
+ @handler.add(BeaconEvent)
909
+ def handle_beacon(event: BeaconEvent):
910
+ with ApiClient(configuration) as api_client:
911
+ line_bot_api = MessagingApi(api_client)
912
+ line_bot_api.reply_message(
913
+ ReplyMessageRequest(
914
+ reply_token=event.reply_token,
915
+ messages=[TextMessage(text='Got beacon event. hwid={}, device_message(hex string)={}'.format(
916
+ event.beacon.hwid, event.beacon.dm))]
917
+ )
918
+ )
919
+
920
+
921
+ @handler.add(MemberJoinedEvent)
922
+ def handle_member_joined(event):
923
+ with ApiClient(configuration) as api_client:
924
+ line_bot_api = MessagingApi(api_client)
925
+ line_bot_api.reply_message(
926
+ ReplyMessageRequest(
927
+ reply_token=event.reply_token,
928
+ messages=[TextMessage(text='Got memberJoined event. event={}'.format(event))]
929
+ )
930
+ )
931
+
932
+
933
+ @handler.add(MemberLeftEvent)
934
+ def handle_member_left(event):
935
+ app.logger.info("Got memberLeft event")
936
+
937
+
938
+ @handler.add(UnknownEvent)
939
+ def handle_unknown_left(event):
940
+ app.logger.info(f"unknown event {event}")
941
+
942
+
943
+ @app.route('/static/<path:path>')
944
+ def send_static_content(path):
945
+ return send_from_directory('static', path)