Lorsque j'envoie une image, il renvoie une action de sélection de date et crée un robot de ligne qui dessine la date sélectionnée sur l'image. En gros, je viens de permettre de sélectionner moi-même la partie date de cet article, mais comme il y avait différents points d'achoppement, je vais le résumer cette fois. Référence: [Python] J'ai créé un Bot LINE qui date les photos
--Création de canaux LineBot --Déployer sur heroku
main.py
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (PostbackEvent, TemplateSendMessage, ButtonsTemplate, DatetimePickerTemplateAction,
ImageMessage, ImageSendMessage, MessageEvent, TextMessage, TextSendMessage)
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import datetime
import os
import re
app = Flask(__name__)
app.debug = False
#Obtenir des variables d'environnement
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)
#Chemin de référence de l'image
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'
#Suivez l'événement
@handler.add(FollowEvent)
def handle_follow(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=
"Merci de vous être inscrit comme ami. Si vous envoyez une image et me dites la date de prise de vue, j'écrirai cette date sur l'image"))
#Retourner le perroquet de texte
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
#Recevoir des images
@handler.add(MessageEvent, message=ImageMessage)
def get_image(event):
global message_id
#message_Obtenir l'identifiant
message_id = event.message.id
#Message de nom de fichier_Chemin converti en identifiant
src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()
#Enregistrer temporairement les images sur heroku
save_image(message_id, src_image_path)
#Enregistrer en tant qu'image à afficher lors de la sélection de la date et de l'heure
im = Image.open(src_image_path)
im.save(src_image_path)
#Sélection de la date de prise de vue
date_picker = TemplateSendMessage(
alt_text='Veuillez sélectionner la date de prise de vue',
template=ButtonsTemplate(
text='Veuillez sélectionner la date de prise de vue',
thumbnail_image_url=f"https://<nom de l'application heroku>.herokuapp.com/{src_image_path}",
actions=[
DatetimePickerTemplateAction(
label='Choix',
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
)
#Traiter et envoyer des images
@handler.add(PostbackEvent)
def handle_postback(event):
#Message de nom de fichier_Chemin converti en identifiant
src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()
main_image_path = MAIN_IMAGE_PATH.format(message_id)
preview_image_path = PREVIEW_IMAGE_PATH.format(message_id)
#Traitement d'image
date_the_image(src_image_path, Path(main_image_path).absolute(), event)
date_the_image(src_image_path, Path(preview_image_path).absolute(), event)
#Envoyer l'image
image_message = ImageSendMessage(
original_content_url=f"https://<nom de l'application heroku>.herokuapp.com/{main_image_path}",
preview_image_url=f"https://<nom de l'application heroku>.herokuapp.com/{preview_image_path}"
)
#Obtenir le journal
app.logger.info(f"https://<nom de l'application heroku>.herokuapp.com/{main_image_path}")
line_bot_api.reply_message(event.reply_token, image_message)
#Fonction de stockage d'image
def save_image(message_id: str, save_path: str) -> None:
# message_Obtenir les données binaires de l'image à partir de l'identifiant
message_content = line_bot_api.get_message_content(message_id)
with open(save_path, "wb") as f:
#Ecrire les données binaires acquises
for chunk in message_content.iter_content():
f.write(chunk)
#Fonction de traitement d'image
def date_the_image(src: str, desc: str, event) -> None:
im = Image.open(src)
draw = ImageDraw.Draw(im)
font = ImageFont.truetype("./fonts/Helvetica.ttc", 50)
#Obtenir la date de l'action de sélection de la date et de l'heure
text = event.postback.params['date']
#Remplacement de chaîne par une expression régulière
text_mod = re.sub("-", "/", text)
#Taille du texte
text_width = draw.textsize(text_mod, font=font)[0]
text_height = draw.textsize(text_mod, font=font)[1]
margin = 10
x = im.width - text_width
y = im.height - text_height
#La taille du rectangle à dessiner
rect_size = ((text_width + margin * 6), (text_height + margin * 2))
#Dessinez un rectangle
rect = Image.new("RGB", rect_size, (0, 0, 0))
#Masque pour rendre le rectangle transparent
mask = Image.new("L", rect_size, 128)
#Coller un rectangle et un masque sur l'image
im.paste(rect, (x - margin * 6, y - margin * 3), mask)
#Rédaction de texte
draw.text((x - margin * 3, y - margin * 2), text_mod, 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)
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (PostbackEvent, TemplateSendMessage, ButtonsTemplate, DatetimePickerTemplateAction,
ImageMessage, ImageSendMessage, MessageEvent, TextMessage, TextSendMessage)
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import datetime
import os
import re
app = Flask(__name__)
app.debug = False
#Obtenir des variables d'environnement
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)
#Chemin de référence de l'image
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'
Importez le module et obtenez les variables d'environnement définies à l'avance, mais veuillez vérifier le rôle détaillé le cas échéant.
Définissez le chemin de la source de référence d'image décrite plus loin et créez une liste vide pour stocker ~~ message_id
. ~~
Remplacez la partie {}
par message_id
lorsque l'image a été reçue.
#Suivez l'événement
@handler.add(FollowEvent)
def handle_follow(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=
"Merci de vous être inscrit comme ami. Si vous envoyez une image et me dites la date de prise de vue, j'écrirai cette date sur l'image"))
Un message est envoyé lorsqu'un utilisateur ajoute un ami.
#Retourner le perroquet de texte
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
Je vais retourner le texte perroquet, mais ce n'est pas nécessaire.
#Recevoir des images
@handler.add(MessageEvent, message=ImageMessage)
def get_image(event):
global message_id
#message_Obtenir l'identifiant
message_id = event.message.id
#Message de nom de fichier_Chemin converti en identifiant
src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()
#Enregistrer temporairement les images sur heroku
save_image(message_id, src_image_path)
#Enregistrer en tant qu'image à afficher lors de la sélection de la date et de l'heure
im = Image.open(src_image_path)
im.save(src_image_path)
#Sélection de la date de prise de vue
date_picker = TemplateSendMessage(
alt_text='Veuillez sélectionner la date de prise de vue',
template=ButtonsTemplate(
text='Veuillez sélectionner la date de prise de vue',
thumbnail_image_url=f"https://<nom de l'application heroku>.herokuapp.com/{src_image_path}",
actions=[
DatetimePickerTemplateAction(
label='Choix',
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
)
ʻEvent.message_idobtient l'identifiant attribué à chaque message et le définit globalement pour une utilisation dans d'autres événements. .. ~~ Cet identifiant ne peut pas être obtenu dans d'autres événements, alors stockez-le dans la
liste_messagesvide créée à l'avance. ~~ Après avoir temporairement enregistré les données dans heroku, ouvrez les données enregistrées pour les afficher pendant l'action de sélection de la date et enregistrez-les à nouveau en tant qu'image. Lors du retour de l'action de sélection de date avec
TemplateSendMessage et en demandant à l'utilisateur de sélectionner la date de prise de vue, elle sera affichée si l'URL de la destination d'enregistrement est spécifiée avec
thumbnail_image_url`.
#Traiter et envoyer des images
@handler.add(PostbackEvent)
def handle_postback(event):
#Message de nom de fichier_Chemin converti en identifiant
src_image_path = Path(SRC_IMAGE_PATH.format(message_id)).absolute()
main_image_path = MAIN_IMAGE_PATH.format(message_id)
preview_image_path = PREVIEW_IMAGE_PATH.format(message_id)
#Traitement d'image
date_the_image(src_image_path, Path(main_image_path).absolute(), event)
date_the_image(src_image_path, Path(preview_image_path).absolute(), event)
#Envoyer l'image
image_message = ImageSendMessage(
original_content_url=f"https://<nom de l'application heroku>.herokuapp.com/{main_image_path}",
preview_image_url=f"https://<nom de l'application heroku>.herokuapp.com/{preview_image_path}"
)
#Obtenir le journal
app.logger.info(f"https://<nom de l'application heroku>.herokuapp.com/{main_image_path}")
line_bot_api.reply_message(event.reply_token, image_message)
Obtient l'image reçue dans MessageEvent (ImageMessage) mentionné ci-dessus. ~~ Obtenez l'id qui sera le nom de l'image à partir de message_list
pour le déterminer.
Si les images sont envoyées en continu, le nouvel identifiant sera stocké avant que les données ne soient initialisées, alors spécifiez le dernier (le plus récent) avec message_list [-1]
.
Récupérez la date sélectionnée par l'utilisateur avec handl_postback (event)
et assignez-la à text
de la fonction data_the_image
pour écrire du texte, etc.
Lorsque le processus est terminé, enregistrez l'image et renvoyez-la à l'utilisateur pour terminer.
#Fonction de stockage d'image
def save_image(message_id: str, save_path: str) -> None:
# message_Obtenir les données binaires de l'image à partir de l'identifiant
message_content = line_bot_api.get_message_content(message_id)
with open(save_path, "wb") as f:
#Ecrire les données binaires acquises
for chunk in message_content.iter_content():
f.write(chunk)
En fait, je voulais obtenir les informations Exif de l'image et entrer automatiquement la date de prise de vue, mais je ne pouvais pas l'obtenir avec cette méthode, j'ai donc pris la forme de l'action de sélection de la date ci-dessus comme une mesure minutieuse. Si quelqu'un sait comment le faire, faites-le moi savoir.
#Fonction de traitement d'image
def date_the_image(src: str, desc: str, event) -> None:
im = Image.open(src)
draw = ImageDraw.Draw(im)
font = ImageFont.truetype("./fonts/Helvetica.ttc", 50)
#Obtenir la date de l'action de sélection de la date et de l'heure
text = event.postback.params['date']
#Remplacement de chaîne par une expression régulière
text_mod = re.sub("-", "/", text)
#Taille du texte
text_width = draw.textsize(text_mod, font=font)[0]
text_height = draw.textsize(text_mod, font=font)[1]
margin = 10
x = im.width - text_width
y = im.height - text_height
#La taille du rectangle à dessiner
rect_size = ((text_width + margin * 6), (text_height + margin * 2))
#Dessinez un rectangle
rect = Image.new("RGB", rect_size, (0, 0, 0))
#Masque pour rendre le rectangle transparent
mask = Image.new("L", rect_size, 128)
#Coller un rectangle et un masque sur l'image
im.paste(rect, (x - margin * 6, y - margin * 3), mask)
#Rédaction de texte
draw.text((x - margin * 3, y - margin * 2), text_mod, fill=(255, 255, 255), font=font)
im.save(desc)
Je voulais le rendre beau dans une certaine mesure, alors j'ai ajouté un peu de traitement.
ʻEvent.postback.params ['date'] pour obtenir la date sélectionnée par l'utilisateur, et
re.sub ("-", "/", text) pour changer" YYYY-MM-DD "en" YYYY / Convertissez au format "MM / JJ". Utilisez
((text_width + margin * 6), (text_height + margin * 2)) pour définir la taille du rectangle et du masque, et laissez une marge de 30px à gauche et à droite et 10px en haut et en bas du texte. Enfin, spécifiez la position du rectangle et du masque avec ʻim.paste (rect, (x --margin * 6, y --margin * 3), mask) ʻet collez-le, et
draw.text ( Écrivez le texte avec (x --margin * 3, y --margin * 2), text_mod, fill = (255, 255, 255), font = font) `et vous avez terminé.
if __name__ == "__main__":
#app.run()
port = int(os.getenv("PORT", 5000))
app.run(host="0.0.0.0", port=port)
Ce bot de ligne a été la première application que j'ai créée après avoir étudié par moi-même, mais il a fallu environ six mois (environ 1 à 2 heures par jour en moyenne) pour y parvenir. Environ 80% du temps de production a été consacré à enquêter sur ce que je ne comprenais pas, et il y avait des moments où c'était assez difficile. En fait, il y a eu des moments où je n'ai pas ouvert mon ordinateur pendant environ une semaine, mais je n'ai jamais pensé à abandonner la programmation, alors je pense que je m'amusais à le faire.
En fait, il y a eu des rebondissements depuis la première chose que je voulais faire, et je me suis installé sur cette forme, mais j'ai appris qu'il est très important de faire tout le flux à l'avance dans une certaine mesure. Cependant, il est difficile de comprendre quel genre de choses peut être fait avec combien d'efforts avec peu d'expérience, donc à la fin je pense qu'il n'y a pas d'autre choix que de procéder régulièrement par essais et erreurs.
Actuellement, j'étudie la base de données et j'essaie d'enregistrer le nom et la date de naissance de la personne sur la photo afin de pouvoir calculer à partir de la date de prise de vue et afficher l'âge de la photo, dès qu'elle est terminée Je vais le publier.
Recommended Posts