[Python] Erstellen Sie einen Linebot, um den Namen und das Alter auf das Bild zu schreiben

Was ich gemacht habe

Der zuvor erstellte Linienbot, der ein beliebiges Datum auf ein Foto zeichnet wurde verbessert, speichert den Namen und das Geburtsdatum in der Datenbank und wie alt es vom Aufnahmedatum ist Ich habe einen Linienbot erstellt, der berechnet, ob es sich um ein Foto handelt oder ob es in ein Bild geschrieben wird. Klicken Sie hier für Github

・ Assistent für Wachstumsaufzeichnungen (ID: @ 033cynwe) スクリーンショット 2020-05-05 17.14.38.png IMG_20200513_101654.png IMG_20200513_101617.png

Umgebung

Was nicht in diesem Artikel zu schreiben

--LineBot-Kanalerstellung

Voller Text

main.py

main.py


from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (FollowEvent, PostbackEvent, TemplateSendMessage, MessageAction,\
                                            ButtonsTemplate, DatetimePickerTemplateAction, ImageMessage, \
                                            ImageSendMessage, MessageEvent, TextMessage, TextSendMessage)
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import datetime
import os

import database

app = Flask(__name__)
app.debug = False

#Umgebungsvariablen abrufen
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

#Bildverweispfad
SRC_IMAGE_PATH = "static/images/{}.jpg "
MAIN_IMAGE_PATH = "static/images/{}_main.jpg "
PREVIEW_IMAGE_PATH = "static/images/{}_preview.jpg "

@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'

#Ereignis verfolgen
@handler.add(FollowEvent)
def handle_follow(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=
        "Vielen Dank, dass Sie sich als Freund registriert haben. Ich werde auf dem Bild schreiben, wie alt die Person auf dem Bild ist. Bitte senden Sie mir ein Bild."))

#Bilder empfangen
@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
    global message_id, user_id, name_list, user_dict, num, src_image_path
    
    #Liste zum Speichern von Benutzerinformationen
    name_list = []
    day_list = []
    user_dict = {}
    #message_ID abrufen
    message_id = event.message.id
    #user_ID abrufen
    user_id = event.source.user_id
    
    #Dateiname Nachricht_Pfad in ID konvertiert
    src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()

    #Speichern Sie Bilder vorübergehend in Heroku
    save_image(message_id, src_image_path)
    
    #Überprüfen Sie die Benutzerinformationen und bestehen Sie sie, wenn Sie nicht registriert sind
    try:
        name_list, day_list = database.serch_data(user_id)
    except TypeError:
        pass
        
    #Registrationsnummer
    num = len(name_list)
    
    #Wenn nicht registriert, überprüfen Sie Ihren Namen
    if num == 0:
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="Wie heißt die Person auf dem Foto?"))
        #user_ID hinzufügen
        database.add_data(user_id)
    #Wenn Sie eine Registrierung haben, überprüfen Sie, wer auf dem Bild ist
    elif num != 0:
        #Erstellen Sie ein Wörterbuch mit Name und Tag
        user_dict = dict(zip(name_list, day_list))
        
        #Bei der Registrierung einer Person
        if num == 1:
            name_1 = name_list[0]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        #Bei Anmeldung von 2 Personen
        elif num == 2:
            name_1 = name_list[0]
            name_2 = name_list[1]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label=name_2, text=name_2),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        #Bei 3 Personen Registrierung
        elif num == 3:
            name_1 = name_list[0]
            name_2 = name_list[1]
            name_3 = name_list[2]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label=name_2, text=name_2),
                        MessageAction(label=name_3, text=name_3),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        line_bot_api.reply_message(event.reply_token, buttons_template)

#Text empfangen
@handler.add(MessageEvent, message=TextMessage)
def handle_text(event):
    global text_name, birthday
    
    #Bestätigung des Geburtsdatums, falls nicht registriert
    if num == 0:
        text_name = event.message.text
        select_day(event)
    #Wenn andere ausgewählt ist, überprüfen Sie den Namen
    elif event.message.text == "Andere":
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="Wie heißt die Person auf dem Foto?"))
    else:
        text_name = event.message.text
            
        #Wenn der Name bereits registriert ist, erhalten Sie das Geburtsdatum
        if text_name in name_list:
            birthday = user_dict[text_name]
        
        #Wenn ja, wählen Sie das Aufnahmedatum, andernfalls das Geburtsdatum
        select_day(event)
    
#Bilder verarbeiten und senden
@handler.add(PostbackEvent)
def handle_postback(event):
    global birthday
    
    #Dateiname Nachricht_Pfad in ID konvertiert
    main_image_path = MAIN_IMAGE_PATH.format(message_id)
    preview_image_path = PREVIEW_IMAGE_PATH.format(message_id)
    
    #Wenn der Geburtstag nicht definiert ist
    if not "birthday" in globals():
        #Ersetzen Sie das Ergebnis der Datumsauswahlaktion durch den Geburtstag
        birthday = event.postback.params["date"]
        #Name und Tag aktualisieren
        database.update_data(user_id, num, text_name, birthday)
        
        #Auswahl des Aufnahmedatums
        select_day(event)
    #Wenn Geburtstag definiert ist
    elif "birthday" in globals():
        #Bildverarbeitung
        date_the_image(src_image_path, Path(main_image_path).absolute(), event)
        date_the_image(src_image_path, Path(preview_image_path).absolute(), event)

        #Bild angeben
        image_message = ImageSendMessage(
                original_content_url=f"https://<Heroku App Name>.herokuapp.com/{main_image_path}",
                preview_image_url=f"https://<Heroku App Name>.herokuapp.com/{preview_image_path}"
        )
    
        #Protokoll abrufen
        app.logger.info(f"https://<Heroku App Name>.herokuapp.com/{main_image_path}")
        
        #Bild senden
        line_bot_api.reply_message(event.reply_token, image_message)
        
        #Entfernen Sie die Variable Geburtstag
        del birthday
        
        #Speichern Sie Datenbankänderungen und trennen Sie die Verbindung
        database.close_db()

#Bildspeicherfunktion
def save_image(message_id: str, save_path: str) -> None:
    # message_Holen Sie sich Binärdaten des Bildes von ID
    message_content = line_bot_api.get_message_content(message_id)
    with open(save_path, "wb") as f:
        #Schreiben Sie die erfassten Binärdaten
        for chunk in message_content.iter_content():
            f.write(chunk)

#Datumsauswahlfunktion
def select_day(event):
    #Wenn Geburtstag definiert ist
    if "birthday" in globals():
        message = "Bitte wählen Sie das Aufnahmedatum"
    #Wenn der Geburtstag nicht definiert ist
    elif not "birthday" in globals():
        message = "Bitte wählen Sie Ihr Geburtsdatum"
    
    #Datumsauswahlaktion
    date_picker = TemplateSendMessage(
        alt_text=message,
        template=ButtonsTemplate(
            text=message,
            actions=[
                DatetimePickerTemplateAction(
                    label="Wahl",
                    data="action=buy&itemid=1",
                    mode="date",
                    initial=str(datetime.date.today()),
                    max=str(datetime.date.today())
                )
            ]
        )
    )
    
    line_bot_api.reply_message(event.reply_token, date_picker)

#Bildverarbeitungsfunktion
def date_the_image(src: str, desc: str, event) -> None:
    im = Image.open(src)
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype("./fonts/AquaKana.ttc", 50)
    
    #Holen Sie sich das Aufnahmedatum
    date = event.postback.params["date"]
    #Berechnen Sie die Anzahl der Tage nach der Geburt, indem Sie das Geburtsdatum vom Aufnahmedatum abziehen
    how_old = datetime.datetime.strptime(date, "%Y-%m-%d") - datetime.datetime.strptime(str(birthday), "%Y-%m-%d")
    #Geburtstage und 365(Tag)Quotient und Rest mit berechnen
    years, days = divmod(how_old.days, 365)
    #Rest 30(Tag)Quotient berechnen mit
    month = days // 30
    text = text_name + f"({years}Talent{month}Monate)"
    
    #Textgröße
    text_width = draw.textsize(text, font=font)[0]
    text_height = draw.textsize(text, font=font)[1]
    margin = 10
    x = im.width - text_width
    y = im.height - text_height
    #Die Größe des zu zeichnenden Rechtecks
    rect_size = ((text_width + margin * 6), (text_height + margin * 2))
    #Zeichne ein Rechteck
    rect = Image.new("RGB", rect_size, (0, 0, 0))
    #Maske, um das Rechteck transparent zu machen
    mask = Image.new("L", rect_size, 128)
    
    #Fügen Sie ein Rechteck und eine Maske in das Bild ein
    im.paste(rect, (x - margin * 6, y - margin * 3), mask)
    #Text schreiben
    draw.text((x - margin * 3, y - margin * 2), text, fill=(255, 255, 255), font=font)
    im.save(desc)

if __name__ == "__main__":
    #app.run()
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)
database.py

database.py


from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine, Column, String, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import NoResultFound
import datetime
import os

#Datenbank-URL von Umgebungsvariable abrufen
DATABASE_URL = os.environ["DATABASE_URL"]

engine = create_engine(DATABASE_URL)
Base = declarative_base()

#Tabellendefinition
class User(Base):
	__tablename__ = "user_list"
	user_id = Column("user_id", String(50), primary_key=True)
	name1 = Column("name1", String(10))
	day1 = Column("day1", Date)
	name2 = Column("name2", String(10))
	day2 = Column("day2", Date)
	name3 = Column("name3", String(10))
	day3 = Column("day3", Date)

Base.metadata.create_all(engine)
session = Session(bind=engine)

#user_ID-Suche
def serch_data(user_id):
	try:
		#user_Suche nach ID
		res = session.query(User.name1, User.day1, User.name2, User.day2, User.name3, User.day3).filter(User.user_id==f"{user_id}").one()
		
		#Geben Sie den Namen und den Tag in die Liste ein
		name_list = [n for n in res if type(n) is str]
		day_list = [str(d) for d in res if type(d) is datetime.date]
		return name_list, day_list
	#user_Bestehen, wenn die ID nicht registriert ist
	except NoResultFound:
		pass

#user_ID-Registrierung
def add_data(user_id):
	session.add(User(user_id=f"{user_id}"))

#Benutzerinformationen aktualisieren
def update_data(user_id, num, text_name, birthday):
	user_data = session.query(User).filter(User.user_id==f"{user_id}").one()
	
	#Speichern Sie Name und Tag entsprechend der Anzahl der Registrierungen
	if num == 0:
		user_data.name1 = text_name
		user_data.day1 = birthday
	elif num == 1:
		user_data.name2 = text_name
		user_data.day2 = birthday
	elif num == 2:
		user_data.name3 = text_name
		user_data.day3 = birthday
    
#Speichern Sie Datenbankänderungen und trennen Sie die Verbindung
def close_db():
	session.commit()
	session.close()

Kommentar

main.py

Vorbereitung

main.py


from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (FollowEvent, PostbackEvent, TemplateSendMessage, MessageAction,\
                                            ButtonsTemplate, DatetimePickerTemplateAction, ImageMessage, \
                                            ImageSendMessage, MessageEvent, TextMessage, TextSendMessage)
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import datetime
import os

import database

app = Flask(__name__)
app.debug = False

#Umgebungsvariablen abrufen
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

#Bildverweispfad
SRC_IMAGE_PATH = "static/images/{}.jpg "
MAIN_IMAGE_PATH = "static/images/{}_main.jpg "
PREVIEW_IMAGE_PATH = "static/images/{}_preview.jpg "

@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'

Importieren Sie das Modul und stellen Sie die Umgebungsvariablen im Voraus ein. Überprüfen Sie jedoch die entsprechende Rolle. Stellen Sie den Pfad der später beschriebenen Bildreferenzquelle ein und ersetzen Sie den Teil "{}" durch die "message_id", wenn das Bild empfangen wurde.

Senden Sie Text, wenn Sie folgen

main.py


#Ereignis verfolgen
@handler.add(FollowEvent)
def handle_follow(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=
        "Vielen Dank, dass Sie sich als Freund registriert haben. Ich werde auf dem Bild schreiben, wie alt die Person auf dem Bild ist. Bitte senden Sie mir ein Bild."))

Eine Nachricht wird gesendet, wenn ein Benutzer einen Freund hinzufügt.

Bilder empfangen

main.py


#Bilder empfangen
@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
    global message_id, user_id, name_list, user_dict, num, src_image_path
    
    #Liste zum Speichern von Benutzerinformationen
    name_list = []
    day_list = []
    user_dict = {}
    #message_ID abrufen
    message_id = event.message.id
    #user_
    user_id = event.source.user_id
    
    #_
    src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()

    #
    save_image(message_id, src_image_path)
    
    #
    try:
        name_list, day_list = database.serch_data(user_id)
    except TypeError:
        pass
        
    #
    num = len(name_list)
    
    #Pfad, in dem der Dateiname in messageid konvertiert wird Speichern Sie das Bild vorübergehend in Heroku. Überprüfen Sie die Benutzerinformationen und übergeben Sie, wenn keine Registrierung vorhanden ist. Anzahl der Registrierungen Wenn keine Registrierung vorliegt, überprüfen Sie den Namen
    if num == 0:
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="Wie heißt die Person auf dem Foto?"))
        #user_ID hinzufügen
        database.add_data(user_id)
    #Wenn Sie eine Registrierung haben, überprüfen Sie, wer auf dem Bild ist
    elif num != 0:
        #Erstellen Sie ein Wörterbuch mit Name und Tag
        user_dict = dict(zip(name_list, day_list))
        
        #Bei der Registrierung einer Person
        if num == 1:
            name_1 = name_list[0]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        #Bei Anmeldung von 2 Personen
        elif num == 2:
            name_1 = name_list[0]
            name_2 = name_list[1]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label=name_2, text=name_2),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        #Bei 3 Personen Registrierung
        elif num == 3:
            name_1 = name_list[0]
            name_2 = name_list[1]
            name_3 = name_list[2]
            buttons_template = TemplateSendMessage(
                alt_text="Wer ist auf dem Bild?",
                template=ButtonsTemplate(
                    text="Wer ist auf dem Bild?", actions=[
                        MessageAction(label=name_1, text=name_1),
                        MessageAction(label=name_2, text=name_2),
                        MessageAction(label=name_3, text=name_3),
                        MessageAction(label="Andere", text="Andere")
                    ]
                )
            )
        
        line_bot_api.reply_message(event.reply_token, buttons_template)

Geben Sie die Variable, die Sie außer MessageEvent verwenden möchten, in "global" an, damit Sie darauf verweisen können.

In der try-Anweisung "name_list, day_list = database.serch_data (user_id)" werden die "name_list", in der der Name gespeichert ist, und die "day_list", in der das Geburtsdatum gespeichert ist, von der Funktion "serch_data" der Datei "database" abgerufen. Aktualisieren zu. Wenn zu diesem Zeitpunkt user_id nicht registriert ist, wird kein Wert zurückgegeben und kann nicht aktualisiert werden. Geben Sie daher in Ausnahme "TypeError" an.

Aufgrund der Bezugnahme auf die Daten wird die Verarbeitung in Fälle ohne Registrierung und Fälle ohne Registrierung unterteilt. Wenn nicht, überprüfen Sie den Namen und fügen Sie user_id hinzu. Wenn dies der Fall ist, verwenden Sie "user_dict = dict (zip (name_list, day_list))", um ein Wörterbuch zu erstellen, das sich auf das Geburtsdatum bezieht und den Namen als Schlüssel verwendet. Danach wird der Prozess weiter durch 1 bis 3 registrierte Personen aufgeteilt und die Person auf dem Bild wird durch "TemplateSendMessage" bestätigt.

Text empfangen

main.py


#Text empfangen
@handler.add(MessageEvent, message=TextMessage)
def handle_text(event):
    global text_name, birthday
    
    #Bestätigung des Geburtsdatums, falls nicht registriert
    if num == 0:
        text_name = event.message.text
        select_day(event)
    #Wenn andere ausgewählt ist, überprüfen Sie den Namen
    elif event.message.text == "Andere":
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="Wie heißt die Person auf dem Foto?"))
    else:
        text_name = event.message.text
            
        #Wenn der Name bereits registriert ist, erhalten Sie das Geburtsdatum
        if text_name in name_list:
            birthday = user_dict[text_name]
        
        #Wenn ja, wählen Sie das Aufnahmedatum, andernfalls das Geburtsdatum
        select_day(event)

if num == 0: wird ausgeführt, wenn Sie eine Antwort erhalten, die den Namen bestätigt, wenn keine Registrierung vorliegt, und das Geburtsdatum nach Erhalt des Namens bestätigt.

elif event.message.text ==" Other ": wird ausgeführt, wenn Other bei TemplateSendMessage ausgewählt ist, wenn eine Registrierung vorliegt, und bestätigt den Namen.

else: wird ausgeführt, wenn ein anderer registrierter Name in TemplateSendMessage als dem oben genannten ausgewählt ist und wenn nach Bestätigung des Namens eine Antwort eingeht. Wenn registriert, verwenden Sie geburtstag = user_dict [text_name], um das Geburtsdatum mit dem Namen als Schlüssel zu erhalten. Fahren Sie für andere Antworten mit der Datumsauswahl fort und bitten Sie sie, ihr Geburtsdatum auszuwählen.

Handhabung von Datumsauswahlaktionen

main.py


#Bilder verarbeiten und senden
@handler.add(PostbackEvent)
def handle_postback(event):
    global birthday
    
    #Dateiname Nachricht_Pfad in ID konvertiert
    main_image_path = MAIN_IMAGE_PATH.format(message_id)
    preview_image_path = PREVIEW_IMAGE_PATH.format(message_id)
    
    #Wenn der Geburtstag nicht definiert ist
    if not "birthday" in globals():
        #Ersetzen Sie das Ergebnis der Datumsauswahlaktion durch den Geburtstag
        birthday = event.postback.params["date"]
        #Name und Tag aktualisieren
        database.update_data(user_id, num, text_name, birthday)
        
        #Auswahl des Aufnahmedatums
        select_day(event)
    #Wenn Geburtstag definiert ist
    elif "birthday" in globals():
        #Bildverarbeitung
        date_the_image(src_image_path, Path(main_image_path).absolute(), event)
        date_the_image(src_image_path, Path(preview_image_path).absolute(), event)

        #Bild angeben
        image_message = ImageSendMessage(
                original_content_url=f"https://<Heroku App Name>.herokuapp.com/{main_image_path}",
                preview_image_url=f"https://<Heroku App Name>.herokuapp.com/{preview_image_path}"
        )
    
        #Protokoll abrufen
        app.logger.info(f"https://<Heroku App Name>.herokuapp.com/{main_image_path}")
        
        #Bild senden
        line_bot_api.reply_message(event.reply_token, image_message)
        
        #Entfernen Sie die Variable Geburtstag
        del birthday
        
        #Speichern Sie Datenbankänderungen und trennen Sie die Verbindung
        database.close_db()

Führt die Verarbeitung durch, wenn der Geburtstag in "wenn nicht" Geburtstag "in globals () undefiniert ist:" (das Geburtsdatum wurde durch die Datumsauswahlaktion ausgewählt). Holen Sie sich das von geburtstag = event.postback.params [" Datum "] ausgewählte Datum und aktualisieren Sie den Datenbanknamen und das Geburtsdatum mit database.update_data (Benutzer_ID, Nummer, Textname, Geburtstag) Bitten Sie sie, das Aufnahmedatum auszuwählen.

Führt die Verarbeitung durch, wenn der Geburtstag in "elif" Geburtstag "in globals () definiert ist:" (das Aufnahmedatum wurde durch die Datumsauswahlaktion ausgewählt). image_message = ImageSendMessage( original_content_url = f "https: // <Name der Heroku-App> .herokuapp.com / {main_image_path}", Vorschau_image_url = f "https: // <Name der Heroku-App> .herokuapp.com / {Vorschau_Bildpfad}" ) Geben Sie das verarbeitete Bild an und senden Sie es.

Löschen Sie den variablen Geburtstag mit "Geburtstag löschen", damit er auch dann normal verarbeitet werden kann, wenn Bilder kontinuierlich gesendet werden. Speichern Sie abschließend die Datenbankänderungen mit "close_db ()" in der Datenbankdatei, trennen Sie die Verbindung und beenden Sie sie.

Bildspeicherfunktion

main.py


#Bildspeicherfunktion
def save_image(message_id: str, save_path: str) -> None:
    # message_Holen Sie sich Binärdaten des Bildes von ID
    message_content = line_bot_api.get_message_content(message_id)
    with open(save_path, "wb") as f:
        #Schreiben Sie die erfassten Binärdaten
        for chunk in message_content.iter_content():
            f.write(chunk)

Eigentlich wollte ich die Exif-Informationen des Bildes abrufen und das Aufnahmedatum automatisch eingeben, aber ich konnte es mit dieser Methode nicht abrufen, daher nahm ich die Form der obigen Datumsauswahlaktion als sorgfältige Maßnahme. Wenn jemand weiß, wie es geht, lass es mich wissen.

Datumsauswahlfunktion

main.py


#Datumsauswahlfunktion
def select_day(event):
    #Wenn Geburtstag definiert ist
    if "birthday" in globals():
        message = "Bitte wählen Sie das Aufnahmedatum"
    #Wenn der Geburtstag nicht definiert ist
    elif not "birthday" in globals():
        message = "Bitte wählen Sie Ihr Geburtsdatum"
    
    #Datumsauswahlaktion
    date_picker = TemplateSendMessage(
        alt_text=message,
        template=ButtonsTemplate(
            text=message,
            actions=[
                DatetimePickerTemplateAction(
                    label="Wahl",
                    data="action=buy&itemid=1",
                    mode="date",
                    initial=str(datetime.date.today()),
                    max=str(datetime.date.today())
                )
            ]
        )
    )
    
    line_bot_api.reply_message(event.reply_token, date_picker)

Diese Funktion wird einmal ausgeführt, wenn das Geburtsdatum registriert ist, und insgesamt zweimal, wenn es nicht registriert ist. Wenn also Geburtstag definiert ist, wird die Nachricht auf das Aufnahmedatum geändert, und wenn es nicht definiert ist, wird die Nachricht auf das Geburtsdatum geändert.

Bildverarbeitungsfunktion

main.py


#Bildverarbeitungsfunktion
def date_the_image(src: str, desc: str, event) -> None:
    im = Image.open(src)
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype("./fonts/AquaKana.ttc", 50)
    
    #Holen Sie sich das Aufnahmedatum
    date = event.postback.params["date"]
    #Berechnen Sie die Anzahl der Tage nach der Geburt, indem Sie das Geburtsdatum vom Aufnahmedatum abziehen
    how_old = datetime.datetime.strptime(date, "%Y-%m-%d") - datetime.datetime.strptime(str(birthday), "%Y-%m-%d")
    #Geburtstage und 365(Tag)Quotient und Rest mit berechnen
    years, days = divmod(how_old.days, 365)
    #Rest 30(Tag)Quotient berechnen mit
    month = days // 30
    text = text_name + f"({years}Talent{month}Monate)"
    
    #Textgröße
    text_width = draw.textsize(text, font=font)[0]
    text_height = draw.textsize(text, font=font)[1]
    margin = 10
    x = im.width - text_width
    y = im.height - text_height
    #Die Größe des zu zeichnenden Rechtecks
    rect_size = ((text_width + margin * 6), (text_height + margin * 2))
    #Zeichne ein Rechteck
    rect = Image.new("RGB", rect_size, (0, 0, 0))
    #Maske, um das Rechteck transparent zu machen
    mask = Image.new("L", rect_size, 128)
    
    #Fügen Sie ein Rechteck und eine Maske in das Bild ein
    im.paste(rect, (x - margin * 6, y - margin * 3), mask)
    #Text schreiben
    draw.text((x - margin * 3, y - margin * 2), text, fill=(255, 255, 255), font=font)
    im.save(desc)

Geben Sie die zu zeichnende Schriftart und Größe mit font = ImageFont.truetype (" ./fonts/AquaKana.ttc ", 50) an. Beim Zeichnen von Japanisch werden einige Schriftarten nicht unterstützt. Wählen Sie daher eine aus, die Japanisch in der Vorschau enthält.

Holen Sie sich das Aufnahmedatum mit date = event.postback.params [" date "] und how_old = datetime.datetime.strptime (Datum,"% Y-% m-% d ") --datetime.datetime.strptime ( Verwenden Sie str (Geburtstag), "% Y-% m-% d") , um die Anzahl der Tage zu erhalten, die durch Subtrahieren des Geburtsdatums vom Aufnahmedatum erhalten wurden. Berechnen Sie den Quotienten und den Rest, indem Sie die Anzahl der Tage durch 365 (Tage) durch "Jahre, Tage = divmod (how_old.days, 365)" teilen und das Alter für Jahre und die Anzahl der Tage für den Rest durch Tage ersetzen. month = days // 12 konvertiert die verbleibenden Tage in Monate und text = text_name + f" ({Jahre} Jahre {Monat} Monate) " definiert, was geschrieben werden soll.

Verwenden Sie rect_size = ((text_width + margin * 6), (text_height + margin * 2)), um die Größe des Rechtecks und der Maske festzulegen, und lassen Sie links und rechts einen Rand von 30px und oben und unten einen Rand von 10px. Geben Sie abschließend die Position des Rechtecks und der Maske mit "im.paste (rect, (x - Rand * 6, y - Rand * 3), Maske)" an und fügen Sie sie ein und "draw.text" ( Schreiben Sie den Text mit (x - Rand * 3, y - Rand * 2), Text, Füllung = (255, 255, 255), Schriftart = Schriftart) und fertig.

Lauf

main.py


if __name__ == "__main__":
    #app.run()
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

database.py

Vorbereitung

database.py


from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine, Column, String, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import NoResultFound
import datetime
import os

#Datenbank-URL von Umgebungsvariable abrufen
DATABASE_URL = os.environ["DATABASE_URL"]

engine = create_engine(DATABASE_URL)
Base = declarative_base()

Importieren Sie zunächst die erforderlichen Module in die Datenbankdatei. DATABASE_URL gibt die URL der in "heroku config" festgelegten Datenbank an. engine = create_engine (DATABASE_URL) undBase = declative_base ()werden für die nächste Tabellenerstellung verwendet.

Tabelle erstellen

database.py


#Tabellendefinition
class User(Base):
	__tablename__ = "user_list"
	user_id = Column("user_id", String(50), primary_key=True)
	name1 = Column("name1", String(10))
	day1 = Column("day1", Date)
	name2 = Column("name2", String(10))
	day2 = Column("day2", Date)
	name3 = Column("name3", String(10))
	day3 = Column("day3", Date)

Base.metadata.create_all(engine)
session = Session(bind=engine)

Geben Sie in class User (Base): den Tabellennamen und den Spalteninhalt nur zum Zeitpunkt der Erstellung an. Zu diesem Zeitpunkt ist es erforderlich, in einer Spalte den Primärschlüssel anzugeben. Geben Sie ihn daher in einer Spalte an, die keine Duplizierung verursacht. Bereiten Sie die Verbindung zur Datenbank mit "Base.metadata.create_all (engine)", "session = Session (bind = engine)" vor.

Suchen Sie nach user_id

database.py


#user_ID-Suche
def serch_data(user_id):
	try:
		#user_Suche nach ID
		res = session.query(User.name1, User.day1, User.name2, User.day2, User.name3, User.day3).filter(User.user_id==f"{user_id}").one()
		
		#Geben Sie den Namen und den Tag in die Liste ein
		name_list = [n for n in res if type(n) is str]
		day_list = [str(d) for d in res if type(d) is datetime.date]
		return name_list, day_list
	#user_Bestehen, wenn die ID nicht registriert ist
	except NoResultFound:
		pass

res = session.query (User.name1, User.day1, User.name2, User.day2, User.name3, User.day3) .filter (User.user_id == f" {user_id} "). one () Rufen Sie andere Informationen als user_id in der Zeile ab, in der user_id mit übereinstimmt. Da user_id nicht dupliziert werden kann, geben Sie nur eins mit one () an.

name_list = [n für n in res, wenn Typ (n) str ist] um den str-Typ (name) in name_list zu ändern, day_list = [str (d) für d in res, wenn Typ (d) datetime.date ist] Fügen Sie den Typ datetime.date (Geburtsdatum) als Zeichenfolge mit in day_list ein. Wenn Sie die Informationen mit "res" erhalten, wird in der leeren Spalte "Keine" angezeigt, dies gilt jedoch nicht für einen der oben genannten Typen. Sie benötigen also "Wenn ~ nicht" Keine "ist. Gibt zwei Listen mit return name_list, day_list zurück und aktualisiert die Liste in main.py.

Wenn user_id nicht in res registriert ist, ist es NoResultFound. Geben Sie es daher mit Ausnahme an, um dies zu vermeiden.

Benutzerinformationen ändern

database.py


#user_ID-Registrierung
def add_data(user_id):
	session.add(User(user_id=f"{user_id}"))

#Benutzerinformationen aktualisieren
def update_data(user_id, num, text_name, birthday):
	user_data = session.query(User).filter(User.user_id==f"{user_id}").one()
	
	#Speichern Sie Name und Tag entsprechend der Anzahl der Registrierungen
	if num == 0:
		user_data.name1 = text_name
		user_data.day1 = birthday
	elif num == 1:
		user_data.name2 = text_name
		user_data.day2 = birthday
	elif num == 2:
		user_data.name3 = text_name
		user_data.day3 = birthday

Wenn user_id nicht in session.add (User (user_id = f" {user_id} ")) registriert ist, wird es hinzugefügt.

Erhalten Sie Benutzerinformationen mit user_data = session.query (User) .filter (User.user_id == f" {user_id} "). One (), verzweigen Sie mit if und aktualisieren Sie die entsprechende Spalte. Zu diesem Zeitpunkt habe ich versucht, nur die erforderlichen Spalten abzurufen und zu aktualisieren. Es ist jedoch ein Fehler aufgetreten, sodass es sicherer erscheint, alle Informationen abzurufen.

Trennen Sie die Datenbank

database.py


#Speichern Sie Datenbankänderungen und trennen Sie die Verbindung
def close_db():
	session.commit()
	session.close()

Speichern Sie die Datenbankänderungen mit "session.commit ()" und trennen Sie die Verbindung mit "session.close ()", um den Vorgang abzuschließen.

Dateiorganisation

Zusammenfassung

Ungefähr zwei Monate nach letzter Fertigstellung gelang es mir, die Datenbank, mit der ich mich zum ersten Mal befasste, bis zu dem Punkt einzubinden, den ich anstrebte. Unterwegs habe ich neue Dinge ausprobiert, wie den Wechsel von MySQL zu PostgreSQL und die Verwendung von SQLalchemy, die ich zu Beginn nicht verwenden wollte, aber ich konnte sie im Vergleich zum vorherigen Mal relativ reibungslos implementieren, und ich konnte ein leichtes Wachstum spüren. ..

Für diesen Bot möchte ich ihn einmal ausfüllen und eine Anwendung erstellen, die die Unannehmlichkeiten verbessert, wenn ich Zeit habe.

Referenz

Recommended Posts

[Python] Erstellen Sie einen Linebot, um den Namen und das Alter auf das Bild zu schreiben
[Python] Kombinieren von Listen mit Zahlen zu Zeichenfolgen und Schreiben in eine Ausgabedatei
So erstellen Sie einen Bild-Uploader mit Bottle (Python)
Erstellen Sie unter Windows eine anständige Shell- und Python-Umgebung
Erstellt eine Python-Bibliothek, um komplexe Einschlüsse zu schreiben und auf einfach zu lesende Weise zu reduzieren
So stellen Sie pyenv unter Amazon Linux und Ubuntu ein, um eine Python 3.6.0-Umgebung zu erstellen
Versuchen Sie, Schedule auszuführen, um Instanzen in AWS Lambda (Python) zu starten und zu stoppen.
[Python] Ändern Sie den Namen der Bilddatei in eine Seriennummer
[Python] Erstellen Sie einen Linebot, der ein beliebiges Datum auf ein Foto zeichnet
So schreiben Sie eine Meta-Klasse, die sowohl Python2 als auch Python3 unterstützt
So erstellen Sie eine ISO-Datei (CD-Image) unter Linux
Erstellen Sie eine Python-Umgebung in Centos
Konvertieren Sie eine Zeichenfolge in ein Bild
5 Möglichkeiten zum Erstellen eines Python-Chatbots
[MariaDB] Installieren Sie MariaDB unter Linux und erstellen Sie eine Datenbank und einen Benutzer.
Versuchen Sie, mit Python3 eine Zeichenfolge aus einem Bild zu extrahieren
Erstellen Sie einen einfachen geplanten Stapel mit Dockers Python Image und parse-crontab
Python vba zum Erstellen einer Datumszeichenfolge zum Erstellen eines Dateinamens
Der Weg zur Installation von Python und Flask auf einem Offline-PC
Ich habe versucht, einen Linebot zu erstellen (Implementierung)
Qiita (1) Wie schreibe ich einen Codenamen?
Ich habe versucht, einen Linebot zu erstellen (Vorbereitung)
Erstellen Sie mit Python + PIL ein Dummy-Image.
Erstellen Sie eine Python-Umgebung auf Ihrem Mac
Ein Memo mit Python2.7 und Python3 in CentOS
Erstellen Sie eine OpenCV3 + python3-Umgebung unter OSX
[Python] Erstellen Sie einen LineBot, der regelmäßig ausgeführt wird
Komprimieren Sie Python-Daten und schreiben Sie in SQLite
Erstellen Sie Verknüpfungen, um Python-Dateien auf dem Terminal mit VScode auszuführen
Vorgehensweise zum Erstellen einer virtuellen Python-Umgebung mit VS-Code unter Windows
Ein Python-Programm, das die Größe eines Videos ändert und es in ein Bild verwandelt
Versuchen Sie, Python-Code zu schreiben, um Go-Code zu generieren. - Versuchen Sie, JSON-to-Go usw. zu portieren
Erstellen Sie eine Python3-Umgebung mit pyenv auf einem Mac und zeigen Sie NetworkX-Diagramme an
Ich habe ein Beispiel für den Zugriff auf Salesforce mit Python und Bottle erstellt
Ich habe ein POST-Skript erstellt, um ein Problem in Github zu erstellen und es im Projekt zu registrieren
Die Geschichte, ein Tool zum Laden von Bildern mit Python zu erstellen ⇒ Speichern unter
Testen Sie das Hochladen von Bildern, indem Sie in Python erstellen, ohne Dummy-Bilddateien in Django zu platzieren
[Python] Listenverständnis Verschiedene Möglichkeiten zum Erstellen einer Liste
Bearbeiten Sie Excel in Python, um eine Pivot-Tabelle zu erstellen
Eine Geschichte über einen Versuch, uwsgi auf einer fehlgeschlagenen EC2-Instanz zu installieren
Ich möchte mit Python ein Fenster erstellen
So erstellen Sie eine JSON-Datei in Python
Ich möchte ein Element mit numpy in eine Datei schreiben und es überprüfen.
Ich habe ein privates Python-Paket, möchte aber pipenv auf GitHub Actions installieren und ein Docker-Image erstellen
Erstellen Sie eine Webmap mit Python und GDAL
Warum muss Python einen Doppelpunkt schreiben?
Erstellen Sie ein Bild mit Zeichen mit Python (Japanisch)
Ich habe ein Bildklassifizierungsmodell erstellt und versucht, es auf dem Handy zu verschieben
Schritte zum Erstellen eines Twitter-Bots mit Python
[Venv] Erstellen Sie eine virtuelle Python-Umgebung unter Ubuntu
Versuchen Sie, einen neuen Befehl unter Linux zu erstellen
Schreiben wir ein Python-Programm und führen es aus
Auf der Suche nach einer effizienten Möglichkeit, eine Docker-Datei mit Python mit Gedichten zu schreiben
So schreiben Sie in Error Repoting in Python auf GAE
[Python] Ich habe ein Skript erstellt, das Dateien auf dem lokalen PC automatisch ausschneidet und auf eine externe SSD einfügt.
Ich möchte mit Python in eine Datei schreiben