Skip to content

Commit

Permalink
[add] DBの連携、デプロイ
Browse files Browse the repository at this point in the history
  • Loading branch information
Simo-C3 committed Mar 15, 2022
1 parent a663460 commit c63147c
Show file tree
Hide file tree
Showing 7 changed files with 478 additions and 22 deletions.
4 changes: 3 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ sqlalchemy-utils = "*"
python-dotenv = "*"
pyjwt = "*"
cerberus = "*"
line-bot-sdk = "*"
flask = "*"
pyzbar = "*"
pillow = "*"
python-dateutil = "*"
fastapi-pagination = "*"
aiofiles = "*"
line-bot-sdk = "*"
opencensus-ext-azure = "*"

[dev-packages]

Expand Down
266 changes: 266 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

51 changes: 40 additions & 11 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
from dotenv import load_dotenv
from pathlib import Path
import os
from cruds.bot import save_img, get_isbn_by_bar_code, get_book_info_by_isbn
from db.main import get_db
from sqlalchemy.orm import Session
from schemas.bot import User
from cruds.bot import save_img, book_register, create_user
from exception import GetIsbnException, GetBookInfoException, RegisterBookException, SaveImageException

from linebot import (
LineBotApi, WebhookHandler
Expand All @@ -11,13 +15,15 @@
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, ImageMessage
MessageEvent, TextSendMessage, ImageMessage
)

load_dotenv()
YOUR_CHANNEL_ACCESS_TOKEN=os.environ.get('YOUR_CHANNEL_ACCESS_TOKEN')
YOUR_CHANNEL_SECRET=os.environ.get('YOUR_CHANNEL_SECRET')

db: Session = next(get_db())

SAVE_DIR=os.environ.get('SAVE_DIR')
SRC_IMG_PATH = SAVE_DIR + "/{}.jpg"

Expand Down Expand Up @@ -47,24 +53,47 @@ def callback():

return 'OK'

# @handler.add(MessageEvent, message=TextMessage)
# def handle_message(event):
# line_bot_api.reply_message(
# event.reply_token,
# TextSendMessage(text=event.message.text)) #ここでオウム返しのメッセージを返します。

# 画像を受け取った際の処理
@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
profile = line_bot_api.get_profile(event.source.user_id)
user = create_user(db, profile.user_id, profile.display_name)
message_id = event.message.id
src_img_path = SRC_IMG_PATH.format(message_id) # 保存する画像のパス

save_img(message_id, src_img_path) # 画像を一時保存する
isbn = get_isbn_by_bar_code(src_img_path) # ISBNの取得
book_info = get_book_info_by_isbn(isbn)
print(book_info)

try:
save_img(message_id, src_img_path) # 画像を一時保存する
book_info = book_register(db, src_img_path, user)
print(book_info)
except GetIsbnException as e:
resText = "バーコードの読み込みに失敗しました。もう一度、全体がきれいに写るように写真を撮影してください。"
print(e)
except GetBookInfoException as e:
resText = "書籍情報の取得が取得できませんでした。"
print(e)
except RegisterBookException as e:
resText = "書籍の登録に失敗しました。"
print(e)
except SaveImageException as e:
resText = "エラーが発生しました"
print(e)
else:
resText = f"タイトル:{book_info.title}\n著者:{book_info.author}サムネ:{book_info.thumbnail_url}"
finally:
# 一時保存していた画像を削除
Path(SRC_IMG_PATH.format(message_id)).absolute().unlink()

# 書籍情報を返す
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=f"タイトル:{book_info['items'][0]['volumeInfo']['title']}\n著者:{book_info['items'][0]['volumeInfo']['authors'][0]}")
TextSendMessage(text=resText)
)
# 一時保存していた画像を削除
Path(SRC_IMG_PATH.format(message_id)).absolute().unlink()

if __name__ == "__main__":
app.run()
app.run(debug=True)
96 changes: 86 additions & 10 deletions cruds/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,36 @@
from pyzbar.pyzbar import decode
from PIL import Image
import requests
from db import models
from sqlalchemy.orm.session import Session
from schemas.api import Book
from schemas.bot import User
from exception import GetIsbnException, GetBookInfoException, SaveImageException, RegisterBookException, LeadAlreadyExistsException

from linebot import (
LineBotApi
)

load_dotenv()
load_dotenv("localhost.env")
YOUR_CHANNEL_ACCESS_TOKEN=os.environ.get('YOUR_CHANNEL_ACCESS_TOKEN')

GOOGLE_API=os.environ.get('GOOGLE_API')

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)

# 写真の保存
def save_img(message_id, src_img_path):
def save_img(message_id: str, src_img_path: str):
# message_idから画像のバイナリデータを取得
message_content = line_bot_api.get_message_content(message_id)
with open(src_img_path, "wb") as f:
# バイナリを1024バイトずつ書き込む
for chunk in message_content.iter_content():
f.write(chunk)

try:
with open(src_img_path, "wb") as f:
# バイナリを1024バイトずつ書き込む
for chunk in message_content.iter_content():
f.write(chunk)
except Exception as e:
raise SaveImageException("画像の保存に失敗しました", e)
# 画像内のバーコードからISBNの抽出
def get_isbn_by_bar_code(src_img_path):
def get_isbn_by_bar_code(db: Session, src_img_path: str) -> str:
# 画像ファイルの指定
img_path = Path(rf"{src_img_path}")
# バーコードの読取
Expand All @@ -35,9 +42,78 @@ def get_isbn_by_bar_code(src_img_path):
return data[1][0].decode('utf-8', 'ignore')

# ISBNから書籍情報を検索・取得
def get_book_info_by_isbn(isbn):
def get_book_info_by_isbn(db: Session, isbn: str) -> object:
# 検索リクエストURL
req_url = GOOGLE_API + isbn
# リクエスト
response = requests.get(req_url)
return response.json()
return response.json()

def create_user(db: Session, user_id: str, user_name: str) -> User:
user_orm = db.query(models.User).filter(models.User.user_id == user_id).first()
if user_orm is None:
user_orm = models.User(
user_id = user_id,
name = user_name
)

db.add(user_orm)
db.commit()
db.refresh(user_orm)
user = User.from_orm(user_orm)

else:
user = User.from_orm(user_orm)

return user

def book_register(db: Session, src_img_path: str, user: User) -> object:
isbn = get_isbn_by_bar_code(db, src_img_path) # ISBNの取得
if isbn is None:
raise GetIsbnException('ISBNの取得に失敗しました', 404)

book_orm = db.query(models.Book).filter(models.Book.isbn == isbn).first()

if book_orm is None:
book_info = get_book_info_by_isbn(db, isbn)
print(book_info)
if book_info is None:
raise GetBookInfoException('書籍の情報取得に失敗しました', 404)

book_orm = models.Book(
isbn = isbn,
title = book_info['items'][0]['volumeInfo']['title'],
author = book_info['items'][0]['volumeInfo']['authors'][0],
thumbnail_url = book_info['items'][0]['volumeInfo']['imageLinks']['smallThumbnail'],
published_date = book_info['items'][0]['volumeInfo']['publishedDate']
)

db.add(book_orm)
db.commit()
db.refresh(book_orm)
book = Book.from_orm(book_orm)


try:
book_user_intermediate_table_register(db, user.user_id, isbn)
except LeadAlreadyExistsException as e:
db.delete(book_orm)
db.commit()
raise RegisterBookException('書籍の登録に失敗しました', e)
else:
return book

def book_user_intermediate_table_register(db: Session, user_id: str, isbn: str):
read_orm = db.query(models.Read).filter(models.Read.user_id == user_id, models.Read.isbn == isbn).first()

if read_orm is not None:
raise LeadAlreadyExistsException('Readにデータがすでに存在しています', 400)
else:
read_orm = models.Read(
user_id = user_id,
isbn = isbn
)

db.add(read_orm)
db.commit()
db.refresh(read_orm)
19 changes: 19 additions & 0 deletions exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class GetIsbnException(Exception):
"""ISBNの取得中にエラーが発生したことを知らせる例外クラス"""
pass

class GetBookInfoException(Exception):
"""書籍の情報取得中にエラーが発生したことを知らせる例外クラス"""
pass

class LeadAlreadyExistsException(Exception):
"""Readにすでにデータが存在していることを知らせる例外クラス"""
pass

class RegisterBookException(Exception):
"""書籍の登録中にエラーが発生したことを知らせる例外クラス"""
pass

class SaveImageException(Exception):
"""画像の保存中にエラーが発生したことを知らせる例外クラス"""
pass
54 changes: 54 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,49 @@ pydantic[email]==1.9.0
pyflakes==2.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pyjwt==2.3.0
pyparsing==3.0.7; python_version >= '3.6'
aiofiles==0.8.0
aiohttp==3.8.1
aiosignal==1.2.0
anyio==3.5.0
asgiref==3.5.0
async-timeout==4.0.2
atomicwrites==1.4.0
attrs==21.4.0
bcrypt==3.2.0
Cerberus==1.3.4
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.12
click==8.0.4
colorama==0.4.4
dnspython==2.2.1
email-validator==1.1.3
fastapi==0.75.0
flake8==4.0.1
Flask==2.0.3
frozenlist==1.3.0
future==0.18.2
greenlet==1.1.2
h11==0.13.0
idna==3.3
iniconfig==1.1.1
itsdangerous==2.1.1
Jinja2==3.0.3
line-bot-sdk==2.1.0
MarkupSafe==2.1.0
mccabe==0.6.1
multidict==6.0.2
packaging==21.3
Pillow==9.0.1
pluggy==1.0.0
psycopg2==2.9.3
py==1.11.0
pycodestyle==2.8.0
pycparser==2.21
pydantic==1.9.0
pyflakes==2.4.0
PyJWT==2.3.0
pyparsing==3.0.7
pytest==7.1.0
python-dotenv==0.19.2
python-multipart==0.0.5
Expand All @@ -65,3 +108,14 @@ urllib3==1.26.8; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.
uvicorn==0.17.6
werkzeug==2.0.3; python_version >= '3.6'
yarl==1.7.2; python_version >= '3.6'
six==1.16.0
sniffio==1.2.0
SQLAlchemy==1.4.32
SQLAlchemy-Utils==0.38.2
starlette==0.17.1
tomli==2.0.1
typing_extensions==4.1.1
urllib3==1.26.8
uvicorn==0.17.6
Werkzeug==2.0.3
yarl==1.7.2
10 changes: 10 additions & 0 deletions schemas/bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import BaseModel

from db import models

class User(BaseModel):
user_id: str
name: str

class Config:
orm_mode = True

0 comments on commit c63147c

Please sign in to comment.