初めに
だいぶ説明を端折ります。ごめんなさい。
多分、コードも汚いと思います。ごめんなさい。--
日本ではほぼすべての人が使っている(?)であろうLINEBotをビジネス用途で利用すると有人機能が必要になりますよね?(多分)
そのため、なるべく簡単に有人対応ができるような予約システムを構築します!
やるぞ!!!
ゴール
結論:制作物はこれです。
実際にどんなものを作ったコードが、実物を見たほうがわかりやすいかと!
オペレーターは僕につながっています(笑)
データベースとPUSHMessageを連携することによって有人対応機能は可能です!!
無料版だと一か月1000件までしかできないので、実際に業務で使う場合は有料のライトプランとかで利用されるといいと思います。
必要なインストール等
代表的なもの
pip install Flask
pip install line-bot-sdk
pip install flask_sqlalchemy
pip install Pillow
・
・
その他もろもろ
ディレクトリ構成
こんな感じです。少し端折った部分もあるかもですが、アクションに関して最低限分割してわかりやすく管理しようという魂胆です。
├── projects
├── static
└── contents
├── FollowAction.py
├── ImageAction.py
├── PostBackAction.py
└── TextAction.py
└── server.py
└── Settings.py
└── config.ini
『server.py』
ここでは、サーバーを立てる役割をしているのですが、データベースの設計もここでやってます。本当は分けたほうがいいですが、
今回は、まあいいでしょう。
# coding:utf-8
from flask import Flask, request, abort
from flask_sqlalchemy import SQLAlchemy
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, PostbackEvent, ButtonsTemplate, PostbackTemplateAction, TemplateSendMessage, FollowEvent
, LocationSendMessage, LocationMessage, ImagemapSendMessage, MessageTemplateAction, ConfirmTemplate, DatetimePickerAction, DatetimePickerTemplateAction
, ImageMessage, ImageSendMessage, FlexSendMessage, BoxComponent, TextComponent, BubbleContainer, ButtonComponent,MessageAction
, CarouselContainer, URIAction, ImageComponent, PostbackAction, CameraAction, CameraRollAction, QuickReplyButton, QuickReply
)
import re
from PIL import Image
from io import BytesIO
import configparser
# 各アクションモジュール
from contents import FollowAction, ImageAction, TextAction, PostBackAction
app = Flask(__name__)
""" ------------------------ 設定ファイルの読み込み ---------------------------"""
# 設定ファイルの読み込み
cfg = configparser.ConfigParser()
cfg.read('config.ini')
# SQLALCHEMY
url = cfg["SQL"]["URL"]
app.config['SQLALCHEMY_DATABASE_URI'] = url
db = SQLAlchemy(app)
# LINEの設定
chansec = cfg["LINE"]["SECRET"]
acctoken = cfg["LINE"]["TOKEN"]
line_bot_api = LineBotApi(acctoken)
handler = WebhookHandler(chansec)
superuser_securekey = cfg["SUPERUSER"]["SECUREKEY"]
superuser_securepwd = cfg["SUPERUSER"]["SECUREPASS"]
# オウム返しを有効にするかどうか1が有効
Parrot_return = False
# ドメインとなるサーバーURL
base_url = cfg["SERVER"]["URL"]
"""--------------------------------------------------------------------------------------------"""
"""-------------------------------- データベースの定義 ----------------------------"""
class lineuser(db.Model):#一般ユーザー用データベース
__tablename__ = "lineuser"
__table_args__ = {'mysql_collate': 'utf8_general_ci'}
user_id = db.Column(db.String(80), primary_key=True)
username = db.Column(db.String(255))
tel = db.Column(db.String(255))
plan = db.Column(db.String(255))
usermessage = db.Column(db.String(255))
step = db.Column(db.Integer)
status = db.Column(db.String(255))
retention = db.Column(db.String(255))
requested_at = db.Column(db.String(255))
def __init__(self, user_id, username, tel, plan, usermessage, step, status, retention, requested_at):
self.user_id = user_id
self.username = username
self.tel = tel
self.plan = plan
self.usermessage = usermessage
self.step = step
self.retention = retention
self.status = status
self.requested_at = requested_at
def __repr__(self):
return '<lineuser %r>' % self.user_id
class administrator(db.Model):#管理者用データベース
__tablename__ = "administrator"
__table_args__ = {'mysql_collate': 'utf8_general_ci'}
admin_id = db.Column(db.String(80), primary_key=True)
admin_name = db.Column(db.String(255))
password = db.Column(db.String(255))
adminstatus = db.Column(db.String(255))
to_user = db.Column(db.String(255))
page_options = db.Column(db.Integer)
def __init__(self, admin_id, admin_name, password, adminstatus, to_user, page_options):
self.admin_id = admin_id
self.admin_name = admin_name
self.password = password
self.adminstatus = adminstatus
self.to_user = to_user
self.page_options = page_options
def __repr__(self):
return '<administrator %r>' % self.admin_id
"""---------------------------------------------------------------------------------------------------"""
"""-------------------------------- MessagingAPIの処理 ----------------------------"""
# LINEからのリクエストを受け取る箇所
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
# もし、フォローされたら
@handler.add(FollowEvent)
def on_follow(event):
FollowAction.Start(line_bot_api, event, db, lineuser, administrator)
# もしメッセージが来たら
@handler.add(MessageEvent, message=TextMessage)
def on_message(event):
TextAction.Start(line_bot_api, event, db, lineuser, administrator, Parrot_return)
# ボタンとかおされたら
@handler.add(PostbackEvent)
def on_postback(event):
PostBackAction.Start(line_bot_api, event, db, lineuser, administrator)
# 画像が送られてきたら
@handler.add(MessageEvent, message=ImageMessage)
def Image_message(event):
ImageAction.Start(line_bot_api, event, db, lineuser, administrator)
"""----------------------------------------------------------------------------------------------------"""
if __name__ == "__main__":
app.run(port=????)#好きなポート番号を指定
設定ファイル『Settings.py』とconfig.ini
import configparser
cfg = configparser.ConfigParser()
cfg['DEFAULT'] = {
'debug': True
}
cfg['LINE'] = {
'SECRET': "ここにLINEのシークレットキー"
, 'TOKEN': "ここにアクセストークン"
}
cfg["SQL"] = {
"URL": "ここにSQLALCHEMYで利用するDBのURIを記述"
}
cfg["SUPERUSER"] = {
"SECUREKEY": "管理者利用するためのKEY"
, "SECUREPASS": "管理者利用するためのPASS"
}
cfg["SERVER"] = {
"URL": "サーバーのURL"
}
with open('config.ini', 'w') as config_file:
cfg.write(config_file)
DBのテーブル作ります
作ります
>>python Settings.py
>>python
from server import db
db.create_all()
exit()
『TextAction.py』
次のコード、LINEからTEXT入力を受け取ったときの処理です。
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, PostbackEvent, ButtonsTemplate, PostbackTemplateAction, TemplateSendMessage, FollowEvent
, LocationSendMessage, LocationMessage, ImagemapSendMessage, MessageTemplateAction, ConfirmTemplate, DatetimePickerAction, DatetimePickerTemplateAction
, ImageMessage, ImageSendMessage, FlexSendMessage, BoxComponent, TextComponent, BubbleContainer, ButtonComponent,MessageAction
, CarouselContainer, URIAction, ImageComponent, PostbackAction, CameraAction, CameraRollAction, QuickReplyButton, QuickReply
)
import re
import configparser
""" ------------------------ 設定ファイルの読み込み ---------------------------"""
# 設定ファイルの読み込み
cfg = configparser.ConfigParser()
cfg.read('config.ini')
superuser_securekey = cfg["SUPERUSER"]["SECUREKEY"]
superuser_securepwd = cfg["SUPERUSER"]["SECUREPASS"]
"""-----------------------------------------------------------------------------------------"""
def Start(line_bot_api, event, db, lineuser, administrator, Parrot_return):
txt = event.message.text
user_id = event.source.user_id
reply_token = event.reply_token
if Parrot_return == 1:
line_bot_api.reply_message(reply_token, TextSendMessage(text=txt))
else:
if db.session.query(administrator).filter(administrator.admin_id == user_id).count() == True and txt == "管理者利用":
user = db.session.query(lineuser).filter_by(user_id=user_id).first()
if user.status == "end":
line_bot_api.push_message(to=user_id, messages=TextSendMessage(text="管理者として利用を開始します。"))
user.status = "admin"
db.session.add(user)
db.session.commit()
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="通常利用を完了してからお願いします!"))
if not db.session.query(lineuser).filter(lineuser.user_id == user_id).count():
reg = lineuser(user_id, None, None, None, None, 0, None, None, None)
db.session.add(reg)
db.session.commit()
user = db.session.query(lineuser).filter_by(user_id=user_id).first()
if txt == superuser_securekey and user.status == "end":
if not db.session.query(administrator).filter(administrator.admin_id == user_id).count():
user.status = "preadmin"
db.session.add(user)
db.session.commit()
line_bot_api.push_message(to=user_id,
messages=TextSendMessage(text="あともう一歩!パスワードを教えて下さい。")) # 管理者登録一歩前
else:
line_bot_api.push_message(to=user_id,
messages=TextSendMessage(text="すでに管理者権限があります。")) # すでに管理者登録されてるよ
############# ステータスチェックと修正確認 ##########
status = user.status
if status == None:
user.status = "name"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="あなたのお名前を教えてください!"))
elif status == "name":
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal', margin="xs",
contents=[
TextComponent("『%s』様 でよろしいですか?" % txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal", spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="name@@@0@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@0",
display_text=notxt))], flex=0))
image_confirm_to_message = FlexSendMessage(alt_text="メッセージの確認", contents=bubble)
line_bot_api.reply_message(reply_token, image_confirm_to_message)
elif status == "tel":
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal', margin="xs",
contents=[
TextComponent("お電話番号は、『%s』でよろしいですか?" % txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal", spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="tel@@@1@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@1",
display_text=notxt))], flex=0))
image_confirm_to_message = FlexSendMessage(alt_text="メッセージの確認", contents=bubble)
line_bot_api.reply_message(reply_token, image_confirm_to_message)
elif status == "plan":
plan_ls = ["Aプラン", "Bプラン", "Cプラン", "GOLDプラン"]
if txt in plan_ls:
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal', margin="xs",
contents=[
TextComponent("ご希望のプランは、『%s』でよろしいですか?" % txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal", spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="plan@@@2@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@2",
display_text=notxt))], flex=0))
image_confirm_to_message = FlexSendMessage(alt_text="メッセージの確認", contents=bubble)
line_bot_api.reply_message(reply_token, image_confirm_to_message)
elif status == "message":
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal', margin="xs",
contents=[
TextComponent("最後のメッセージは、『%s』でよろしいですか?" % txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal", spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="message@@@3@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@3",
display_text=notxt))], flex=0))
image_confirm_to_message = FlexSendMessage(alt_text="メッセージの確認", contents=bubble)
line_bot_api.reply_message(reply_token, image_confirm_to_message)
elif status == "end":
if txt == "接続":
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal', margin="xs",
contents=[
TextComponent("オペレーターに接続申請をしますか?", size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal", spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="end@@@4@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@1",
display_text=notxt))], flex=0))
image_confirm_to_message = FlexSendMessage(alt_text="確認", contents=bubble)
line_bot_api.reply_message(reply_token, image_confirm_to_message)
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="オペレーターへの接続申請をする場合は、『接続』とご入力ください。"))
elif status == "preadmin" and txt != superuser_securekey:
if txt == cfg["SUPERUSER"]["SECUREPASS"]:
add_admin = administrator(user_id, None, 0, None, None, None)
db.session.add(add_admin)
db.session.commit()
user.status = "end"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="あなたを管理者として付与しました。『管理者利用』とご入力ください。"))
else:
user.status = "end"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="もう一度最初からご入力ください。"))
elif status == "response":
text = txt + " --from %s"%user.username
line_bot_api.push_message(to=user.retention, messages=TextSendMessage(text=text))
elif status == "admin":
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
# 管理者名の入力
if admin.admin_name == None and admin.adminstatus != "admin_name":
admin.adminstatus = "admin_name"
db.session.add(user)
db.session.commit()
line_bot_api.push_message(to=user_id, messages=TextSendMessage(text="管理者様のお名前をご入力ください。"))
# 管理者名の入力確認
elif admin.adminstatus == "admin_name":
qtxt = "管理者:『%s』様でよろしいですか?" % txt
yestxt = "はい"
notxt = "いいえ"
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal',
margin="xs",
contents=[TextComponent(text=qtxt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal",
spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackAction(label=yestxt,
data="admin_name@@@1@@@" + txt,
display_text=yestxt)),
ButtonComponent(style="link", height="sm",
action=PostbackAction(label=notxt, data="no@@@1@@@no",
display_text=notxt))], flex=0))
message = FlexSendMessage(alt_text="管理者名を入力してください。", contents=bubble)
line_bot_api.push_message(to=user_id, messages=message)
elif txt == "切断":
if admin.to_user != None:
line_bot_api.push_message(to=admin.to_user, messages=TextSendMessage(text="オペレーターとの接続が終了しました。"))
line_bot_api.reply_message(reply_token, TextSendMessage(text="有人接続を切断しました。"))
to_user = db.session.query(lineuser).filter_by(user_id=admin.to_user).first()
to_user.retention = None
to_user.status = "end"
db.session.add(to_user)
db.session.commit()
admin.to_user = None
db.session.add(user)
db.session.commit()
# 「通常利用」の入力受け取り
elif txt == "通常利用":
if admin.to_user != None:
line_bot_api.reply_message(reply_token,
TextSendMessage(text="有人対応中です。『通常利用』の切り替えは必ず、『切断』で有人対応を切ってからご使用ください。"))
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="通常利用に切り替えました。有人対応する際は、『管理者利用』とご入力ください。"))
user.status = "end"
db.session.add(user)
db.session.commit()
to_user = db.session.query(lineuser).filter_by(user_id=user_id).first()
to_user.retention = None
to_user.status = "end"
db.session.add(to_user)
db.session.commit()
admin.to_user = None
db.session.add(user)
db.session.commit()
else:
if admin.to_user != None:
line_bot_api.push_message(to=admin.to_user, messages=TextSendMessage(text=txt))
line_bot_api.reply_message(reply_token, TextSendMessage(text="%s とメッセージを送信しました。"%txt))
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="誰にも接続されていません。"))
めっちゃ雑な記事ですみません。
どんどんいきます。
『PostBackAction.py』
ボタン入力とかそういう特殊な入力を受け取った際に
処理する機構です。
Learn more or give us feedback
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, PostbackEvent, ButtonsTemplate, PostbackTemplateAction, TemplateSendMessage, FollowEvent
, LocationSendMessage, LocationMessage, ImagemapSendMessage, MessageTemplateAction, ConfirmTemplate, DatetimePickerAction, DatetimePickerTemplateAction
, ImageMessage, ImageSendMessage, FlexSendMessage, BoxComponent, TextComponent, BubbleContainer, ButtonComponent,MessageAction
, CarouselContainer, URIAction, ImageComponent, PostbackAction, CameraAction, CameraRollAction, QuickReplyButton, QuickReply, FillerComponent,IconComponent
)
# from .ExtraCreateMessage import admin_sight_client_list
import configparser
""" ------------------------ 設定ファイルの読み込み ---------------------------"""
# 設定ファイルの読み込み
cfg = configparser.ConfigParser()
cfg.read('config.ini')
base_url = cfg["SERVER"]["URL"]
def create_image_container(title_name, url):
container = BubbleContainer(
body=BoxComponent(layout="vertical", spacing="sm", margin="sm", contents=[
BoxComponent(layout="vertical", contents=[
ImageComponent(url=url, size="full", aspect_mode="cover", aspect_ratio="1:1", gravity="top"),
BoxComponent(layout="vertical", contents=[
BoxComponent(layout="vertical", contents=[
TextComponent(text=title_name, size="xl", color="#ffffff", weight="bold")
]),
BoxComponent(layout="vertical", contents=[
FillerComponent(),
BoxComponent(layout="baseline", spacing="sm",contents=[
FillerComponent(),
TextComponent(text="このプランにする", offset_top="-2px", color="#ffffff",flex=0, action=MessageAction(text=title_name)),
FillerComponent(),
]),
FillerComponent(),
], border_width="1px", border_color="#ffffff", corner_radius="4px",
height="40px", spacing="sm", margin="xxl"),
], position="absolute", offset_bottom="0px", offset_start="0px", offset_end="0px",
background_color="#03303Acc", padding_all="20px", padding_top="18px"),
], padding_all="0px"),
],padding_all="0px")
)
return container
def Start(line_bot_api, event, db, lineuser, administrator):
user_id = event.source.user_id
reply_token = event.reply_token
postback_msg = event.postback.data
msg = postback_msg.split("@@@") # @@@に変更する
user = db.session.query(lineuser).filter_by(user_id=user_id).first()
step = user.step
if len(msg) == 2:
post_msg = msg[0] # YESかNO
post_num = int(msg[1]) # 質問ナンバー
elif len(msg) == 3:
post_msg = msg[0]
post_num = int(msg[1])
data = msg[2]
if post_msg == "admin_name":
if post_num == 1:
ad_name = data
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
admin.admin_name = data
admin.adminstatus = None
db.session.add(admin)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="%s さん、管理者登録ありがとうございます!"%ad_name))
elif step == post_num:
if post_msg == "name":
user.username = data
user.status = "tel"
user.step = step + 1
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="%sさん、ありがとうございます。"
"次にお電話番号をご入力ください!"
"※デモ用なので、本当の電話番号を入れないでください!!" % data))
elif post_msg == "tel":
user.tel = data
user.step = step + 1
user.status = "plan"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。次にご利用になるプランをご選択ください。" % user.username))
plan_ls = ["Aプラン", "Bプラン", "Cプラン", "GOLDプラン"]
url_ls = ["A.png", "B.png", "C.png", "GOLD.png"]
bubble_container = []
for (p, url) in zip(plan_ls, url_ls):
url_ = base_url + "static/" + url
container = create_image_container(p, url_)
bubble_container.append(container)
bubble2 = CarouselContainer(contents=bubble_container)
select_messa = FlexSendMessage(alt_text="プランを選択してください。", contents=bubble2)
line_bot_api.push_message(to=user_id, messages=select_messa)
elif post_msg == "plan":
user.plan = data
user.step = step + 1
user.status = "message"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。最後に何かメッセージがあればご入力ください!なしの場合、『なし』とご入力ください。" % user.username))
elif post_msg == "message":
user.usermessage = data
user.step = step + 1
user.status = "end"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。これで申請が完了です!※そのまま、オペレーターに接続したい場合は、『接続』とご入力ください。" % user.username))
### -------- 有人対応処理 ---------- ####
elif post_msg == "end":
line_bot_api.reply_message(reply_token, TextSendMessage(
text="オペレーター(製作者)に接続申請しています。そのまましばらくお待ちください。"))
yestxt = "接続"
id_ls = db.session.query(administrator.admin_id).all()
for id_ in id_ls:
try:
txt = "%s 様よりオペレーター接続申請が来ております。『接続』ボタンを押して対応をお願いします。" %user.username
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal',
margin="xs",
contents=[TextComponent(txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal",
spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackTemplateAction(label=yestxt,
data="demand@@@4@@@" + user_id,
display_text=yestxt))], flex=0))
admin_access_message = FlexSendMessage(alt_text="対応申請が来ております。", contents=bubble)
line_bot_api.push_message(to=id_[0], messages=admin_access_message)
except:
pass
elif post_msg == "demand":
to_user_id = data
to_user = db.session.query(lineuser).filter_by(user_id=to_user_id).first()
to_user.retention = user_id
to_user.status = "response"
db.session.add(to_user)
db.session.commit()
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
admin.to_user = to_user_id
db.session.add(admin)
db.session.commit()
adminuser = db.session.query(lineuser).filter_by(user_id=user_id).first()
adminuser.status = "admin"
db.session.add(adminuser)
db.session.commit()
adminname = admin.admin_name
line_bot_api.push_message(to=to_user_id, messages=TextSendMessage(text="オペレーターの%s と接続されました"%adminname))
line_bot_api.reply_message(reply_token, TextSendMessage(text="%s 様と接続されました。"%to_user.username))
###----------------------------------------------------------####
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="もう一度お願いします。"))
else:
if user.status == "end":
line_bot_api.reply_message(reply_token, TextSendMessage(text="キャンセルしました。"))
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="それは最新ではありません!"))
『ImageAction.py』
画像が送られてきたときに反応するコードです。
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, PostbackEvent, ButtonsTemplate, PostbackTemplateAction, TemplateSendMessage, FollowEvent
, LocationSendMessage, LocationMessage, ImagemapSendMessage, MessageTemplateAction, ConfirmTemplate, DatetimePickerAction, DatetimePickerTemplateAction
, ImageMessage, ImageSendMessage, FlexSendMessage, BoxComponent, TextComponent, BubbleContainer, ButtonComponent,MessageAction
, CarouselContainer, URIAction, ImageComponent, PostbackAction, CameraAction, CameraRollAction, QuickReplyButton, QuickReply, FillerComponent,IconComponent
)
# from .ExtraCreateMessage import admin_sight_client_list
import configparser
""" ------------------------ 設定ファイルの読み込み ---------------------------"""
# 設定ファイルの読み込み
cfg = configparser.ConfigParser()
cfg.read('config.ini')
base_url = cfg["SERVER"]["URL"]
def create_image_container(title_name, url):
container = BubbleContainer(
body=BoxComponent(layout="vertical", spacing="sm", margin="sm", contents=[
BoxComponent(layout="vertical", contents=[
ImageComponent(url=url, size="full", aspect_mode="cover", aspect_ratio="1:1", gravity="top"),
BoxComponent(layout="vertical", contents=[
BoxComponent(layout="vertical", contents=[
TextComponent(text=title_name, size="xl", color="#ffffff", weight="bold")
]),
BoxComponent(layout="vertical", contents=[
FillerComponent(),
BoxComponent(layout="baseline", spacing="sm",contents=[
FillerComponent(),
TextComponent(text="このプランにする", offset_top="-2px", color="#ffffff",flex=0, action=MessageAction(text=title_name)),
FillerComponent(),
]),
FillerComponent(),
], border_width="1px", border_color="#ffffff", corner_radius="4px",
height="40px", spacing="sm", margin="xxl"),
], position="absolute", offset_bottom="0px", offset_start="0px", offset_end="0px",
background_color="#03303Acc", padding_all="20px", padding_top="18px"),
], padding_all="0px"),
],padding_all="0px")
)
return container
def Start(line_bot_api, event, db, lineuser, administrator):
user_id = event.source.user_id
reply_token = event.reply_token
postback_msg = event.postback.data
msg = postback_msg.split("@@@") # @@@に変更する
user = db.session.query(lineuser).filter_by(user_id=user_id).first()
step = user.step
if len(msg) == 2:
post_msg = msg[0] # YESかNO
post_num = int(msg[1]) # 質問ナンバー
elif len(msg) == 3:
post_msg = msg[0]
post_num = int(msg[1])
data = msg[2]
if post_msg == "admin_client_list_next":
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
page_options = admin.page_options
admin.page_options = page_options + 1
db.session.add(admin)
db.session.commit()
#admin_sight_client_list(user_id)
elif post_msg == "admin_client_list_prev":
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
page_options = admin.page_options
if page_options > 0:
admin.page_options = page_options - 1
db.session.add(admin)
db.session.commit()
#admin_sight_client_list(user_id)
else:
pass
#admin_sight_client_list(user_id)
elif post_msg == "admin_name":
if post_num == 1:
ad_name = data
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
admin.admin_name = data
admin.adminstatus = None
db.session.add(admin)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="%s さん、管理者登録ありがとうございます!"%ad_name))
elif step == post_num:
if post_msg == "name":
user.username = data
user.status = "tel"
user.step = step + 1
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(text="%sさん、ありがとうございます。"
"次にお電話番号をご入力ください!"
"※デモ用なので、本当の電話番号を入れないでください!!" % data))
elif post_msg == "tel":
user.tel = data
user.step = step + 1
user.status = "plan"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。次にご利用になるプランをご選択ください。" % user.username))
plan_ls = ["Aプラン", "Bプラン", "Cプラン", "GOLDプラン"]
url_ls = ["A.png", "B.png", "C.png", "GOLD.png"]
bubble_container = []
for (p, url) in zip(plan_ls, url_ls):
url_ = base_url + "static/" + url
container = create_image_container(p, url_)
bubble_container.append(container)
bubble2 = CarouselContainer(contents=bubble_container)
select_messa = FlexSendMessage(alt_text="プランを選択してください。", contents=bubble2)
line_bot_api.push_message(to=user_id, messages=select_messa)
elif post_msg == "plan":
user.plan = data
user.step = step + 1
user.status = "message"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。最後に何かメッセージがあればご入力ください!なしの場合、『なし』とご入力ください。" % user.username))
elif post_msg == "message":
user.usermessage = data
user.step = step + 1
user.status = "end"
db.session.add(user)
db.session.commit()
line_bot_api.reply_message(reply_token, TextSendMessage(
text="%sさん、ありがとうございました。これで申請が完了です!※そのまま、オペレーターに接続したい場合は、『接続』とご入力ください。" % user.username))
### -------- 有人対応処理 ---------- ####
elif post_msg == "end":
line_bot_api.reply_message(reply_token, TextSendMessage(
text="オペレーター(製作者)に接続申請しています。そのまましばらくお待ちください。"))
yestxt = "接続"
id_ls = db.session.query(administrator.admin_id).all()
for id_ in id_ls:
try:
txt = "%s 様よりオペレーター接続申請が来ております。『接続』ボタンを押して対応をお願いします。" %user.username
bubble = BubbleContainer(
body=BoxComponent(
layout='horizontal',
margin="xs",
contents=[TextComponent(txt, size='md', wrap=True, type="text", margin="xs", )]),
footer=BoxComponent(
layout="horizontal",
spacing="sm",
contents=[ButtonComponent(style="link", height="sm",
action=PostbackTemplateAction(label=yestxt,
data="demand@@@4@@@" + user_id,
display_text=yestxt))], flex=0))
admin_access_message = FlexSendMessage(alt_text="対応申請が来ております。", contents=bubble)
line_bot_api.push_message(to=id_[0], messages=admin_access_message)
except:
pass
elif post_msg == "demand":
to_user_id = data
to_user = db.session.query(lineuser).filter_by(user_id=to_user_id).first()
to_user.retention = user_id
to_user.status = "response"
db.session.add(to_user)
db.session.commit()
admin = db.session.query(administrator).filter_by(admin_id=user_id).first()
admin.to_user = to_user_id
db.session.add(admin)
db.session.commit()
adminuser = db.session.query(lineuser).filter_by(user_id=user_id).first()
adminuser.status = "admin"
db.session.add(adminuser)
db.session.commit()
adminname = admin.admin_name
line_bot_api.push_message(to=to_user_id, messages=TextSendMessage(text="オペレーターの%s と接続されました"%adminname))
line_bot_api.reply_message(reply_token, TextSendMessage(text="%s 様と接続されました。"%to_user.username))
###----------------------------------------------------------####
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="もう一度お願いします。"))
else:
if user.status == "end":
line_bot_api.reply_message(reply_token, TextSendMessage(text="キャンセルしました。"))
else:
line_bot_api.reply_message(reply_token, TextSendMessage(text="それは最新ではありません!"))
長い!!!でも次で最後!
『FollowAction.py』
なぜ最初にフォローアクションを描かなかったのか・・
まぁ最初しか実行されないコードだし、あってもなくてもいいかな、なんて
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, PostbackEvent, ButtonsTemplate, PostbackTemplateAction, TemplateSendMessage, FollowEvent
, LocationSendMessage, LocationMessage, ImagemapSendMessage, MessageTemplateAction, ConfirmTemplate, DatetimePickerAction, DatetimePickerTemplateAction
, ImageMessage, ImageSendMessage, FlexSendMessage, BoxComponent, TextComponent, BubbleContainer, ButtonComponent,MessageAction
, CarouselContainer, URIAction, ImageComponent, PostbackAction, CameraAction, CameraRollAction, QuickReplyButton, QuickReply
)
def Start(line_bot_api, event, db, lineuser, adminstrator):
reply_token = event.reply_token
line_bot_api.reply_message(reply_token, TextSendMessage(text="フォローありがとうございます!有人対応機能付きの予約システムです!"))
user_id = event.source.user_id
# ユーザー情報を登録する。
if not db.session.query(lineuser).filter(lineuser.user_id == user_id).count():
reg = lineuser(user_id, None, None, None, None, 0, None, None, None)
db.session.add(reg)
db.session.commit()
お疲れ様でした
お疲れ様でした。
自分のメモ書きみたいなところも強いので、だれかの参考になればと思いました。
結構非効率な処理があると思いますが、まぁテストなんで問題ない!
と思って、爆速で作りました。
Python最高!!!