Dans l'article précédent, j'ai pu créer une application qui enregistre automatiquement le fichier journal de Tenho (format comme indiqué ci-dessous), je souhaite donc obtenir les informations agrégées de ce __log __.
Les informations agrégées sont, par exemple, les points accumulés, les jetons accumulés et les changements de points de chaque joueur.
Il existe un [outil d'agrégation] officiel (https://tenhou.net/ranking_tool.html) dans Tenho, mais il est difficile de copier et coller le journal pour une agrégation fréquente, donc je vais le programmer. Je veux le faire et le totaliser automatiquement.
Vous n'avez qu'à exécuter le programme à chaque fois que vous le faites par vous-même, mais comme les amis du mahjong ne peuvent fondamentalement pas programmer, je veux l'exécuter avec une interface familière afin que tout le monde puisse voir les informations agrégées à tout moment __.
A partir des motifs ci-dessus, j'ai décidé de créer un outil d'agrégation avec python et de créer l'interface LINE.
# coding:utf-8
import numpy as np
#import pandas as pd
import re
import matplotlib.pyplot as plt
def graph_plot(tip):
f = open('log.txt')
lines = f.readlines() #Tout lire jusqu'à la fin du fichier ligne par ligne(Comprend des caractères de saut de ligne)
f.close()
pointsA = [0] #Monsieur A
pointsB = [0] #Monsieur B
pointsC = [0] #Monsieur C
pointsD = [0] #M. D
pointSumA = [0] #
pointSumB = [0] #
pointSumC = [0] #
pointSumD = [0] #
tipA = [0] #
tipB = [0] #
tipC = [0] #
tipD = [0] #
tipSumA = [0] #
tipSumB = [0] #
tipSumC = [0] #
tipSumD = [0] #
LIST = []
for line in lines[1:]:
if len(line) > 10: #Passer des lignes étranges
roomid = line.split("|")[0]
time = line.split("|")[1]
rools = line.split("|")[2]
players = line.split("|")[3]
#Sans félicitations
if tip == False:
l = re.split('[ ()]', players)
LIST.append([l[1],float(l[2].replace("+",""))])
LIST.append([l[4],float(l[5].replace("+",""))])
LIST.append([l[7],float(l[8].replace("+",""))])
#S'il y a une fête
if tip == True:
l = re.split('[ (,)]', players)
print(l)
LIST.append([l[1],float(l[2].replace("+","")),float(l[3].replace("+","").replace("Feuille",""))])
LIST.append([l[5],float(l[6].replace("+","")),float(l[7].replace("+","").replace("Feuille",""))])
LIST.append([l[9],float(l[10].replace("+","")),float(l[11].replace("+","").replace("Feuille",""))])
# print(LIST)
for i,data in enumerate(LIST):
player = data[0]
point = data[1]
if tip == True:
tips = data[2]
if player == "Monsieur A":
pointsA.append(point)
pointSumA.append(pointSumA[-1]+point)
if tip == True:
tipA.append(tips)
tipSumA.append(tipSumA[-1]+tips)
elif player == "Monsieur B":
pointsB.append(point)
pointSumB.append(pointSumB[-1]+point)
if tip == True:
tipB.append(tips)
tipSumB.append(tipSumB[-1]+tips)
elif player == "Monsieur C":
pointsC.append(point)
pointSumC.append(pointSumC[-1]+point)
if tip == True:
tipC.append(tips)
tipSumC.append(tipSumC[-1]+tips)
elif player == "M. D":
pointsD.append(point)
pointSumD.append(pointSumD[-1]+point)
if tip == True:
tipD.append(tips)
tipSumD.append(tipSumD[-1]+tips)
xA = [i for i in range(len(pointsA))]
xB = [i for i in range(len(pointsB))]
xC = [i for i in range(len(pointsC))]
xD = [i for i in range(len(pointsD))]
plt.clf()
plt.plot(xA,pointSumA,label="Monsieur A")
plt.plot(xB,pointSumB,label="Monsieur B")
plt.plot(xC,pointSumC,label="Monsieur C")
plt.plot(xD,pointSumD,label="M. D")
plt.legend()
plt.savefig("graph_1.png ")
plt.clf()
plt.plot(xA,tipSumA,label="Monsieur A")
plt.plot(xB,tipSumB,label="Monsieur B")
plt.plot(xC,tipSumC,label="Monsieur C")
plt.plot(xD,tipSumD,label="M. D")
plt.legend()
plt.savefig("graph_2.png ")
if __name__ == "__main__":
graph_plot(tip=True)
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
'''
## references
1. Line Bot API
* [officiel-python](https://github.com/line/line-bot-sdk-python/blob/master/README.rst_)
* https://keinumata.hatenablog.com/entry/2018/05/08/122348
* [bottun](https://qiita.com/shimayu22/items/c599a94dfa39c6466dfa)
* [](https://dev.classmethod.jp/etc/line-messaging-api-action-object/)
* [Site d'évacuation LINE bot](https://qiita.com/lovemysoul/items/5ad818220d65b74351a5)
Ce site est vraiment facile à comprendre. Dieu.
2. DB,SQL
* https://baku1101.hatenablog.com/entry/2019/04/15/185003
* https://qiita.com/jacob_327/items/ec7d2223010ad4a0dd38
3. Python x S3(AWS)
* https://www.casleyconsulting.co.jp/blog/engineer/2861/
4. Heroku
* [Définition des variables d'environnement](https://qiita.com/colorrabbit/items/18db3c97734f32ebdfde)
* [Heroku x Linebot API](https://miyabi-lab.space/blog/21)
'''
# system
import os
import sys
import datetime
from argparse import ArgumentParser
# Web FlameWork
from flask import Flask, request, abort
# Line API
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent,
PostbackEvent,
TextMessage,
TextSendMessage,
ButtonsTemplate,
URIAction,
PostbackAction,
MessageAction,
ImageSendMessage,
ConfirmTemplate,
TemplateSendMessage,
QuickReply,
QuickReplyButton
)
# DF,Graph,etc
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import re #Expressions régulières
import pprint
#Je n'ai pas besoin de Google Drive car je ne l'utilise pas
# Google Drive API
# import os
# import pprint
# AWS
import boto3
LINE_CHANNEL_SECRET et `` `LINE_CHANNEL_ACCESS_TOKEN
sont lus par
ʻos.getenv```. Je me suis également référé au site ci-dessus pour la création de canal du bot LINE. Si vous faites cela, vous n'avez pas à écrire des informations telles que des secrets directement dans le code, cela semble donc bon pour la sécurité.
# Flask Web App Instance
app = Flask(__name__)
# get channel_secret and channel_access_token from your environment variable
channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
if channel_secret is None:
print('Specify LINE_CHANNEL_SECRET as environment variable.')
sys.exit(1)
if channel_access_token is None:
print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
sys.exit(1)
# PREPARE LINE messaging API Instance
line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(channel_secret)
# AWS Instance
aws_s3_bucket = os.environ['AWS_BUCKET']
s3 = boto3.resource("s3")
bucket = s3.Bucket(aws_s3_bucket)
s3_client = boto3.client('s3')
'''
Traitement des réponses lors des actions suivantes
'''
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
#
@ handler.add (MessageEvent, message = TextMessage) '' comme suit. Je vais.if
.`data =" request_point "`
etc.) que vous avez défini que l'un ou l'autre sera sélectionné.@handler.add(MessageEvent, message=TextMessage)
def message_text(event):
'''
Traitement lors de l'envoi d'un SMS
'''
try:
message = event.message.text
if message.count("Aragaki Yui") != 0:
text = "plotting...\n"
line_bot_api.reply_message(
event.reply_token,
ImageSendMessage(
original_content_url = "https://orionfdn.org/wp-content/uploads/2018/12/WS000011-69.jpg ",
preview_image_url = "https://orionfdn.org/wp-content/uploads/2018/12/WS000011-69.jpg "
)
)
# Graph Plot
elif message.count("Graphique") != 0:
# import download4
# import graph
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(
text="Lequel aimes-tu?",
quick_reply=QuickReply(
items=[
QuickReplyButton(
action=PostbackAction(
label="point", #Caractères à afficher sur le bouton
text="Afficher la transition de partition", #Caractères à envoyer sous forme de texte
data="request_point" # Postback
)
),
QuickReplyButton(
action=PostbackAction(
label="Puce",
text="Afficher la transition de puce",
data="request_tip"
)
)
]
)
)
)
# Summary
elif message.count("Shukei") != 0:
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(
text="Lequel aimes-tu?",
quick_reply=QuickReply(
items=[
QuickReplyButton(
action=PostbackAction(
label="Recettes et dépenses", #Caractères à afficher sur le bouton
text="Montrez l'équilibre", #Caractères à envoyer sous forme de texte
data="request_sum" # Postback
)
),
QuickReplyButton(
action=PostbackAction(
label="Ordre d'arrivée",
text="Afficher l'ordre d'arrivée",
data="request_rank"
)
),
QuickReplyButton(
action=PostbackAction(
label="équipe",
text="Montrez les résultats de votre équipe",
data="request_team"
)
),
QuickReplyButton(
action=PostbackAction(
label="Today",
text="Afficher les résultats du jour",
data="request_today"
)
)
]
)
)
)
#prime
elif message.count("Moge") != 0:
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = "Jonga")
)
elif message.count("Daa") != 0:
line_bot_api.reply_message(
event.reply_token,
ImageSendMessage(
original_content_url = "http://attrip.jp/wp-content/uploads/2013/07/20130716-130424.jpg ",
preview_image_url = "http://attrip.jp/wp-content/uploads/2013/07/20130716-130424.jpg "
)
)
elif message.count("Bretagne") != 0:
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = "Est-ce l'Angleterre?")
)
except:
import traceback
print("errrrrrrrrrror")
traceback.print_exc()
`download4``` (article précédent),`
summary, `` `` graph
des modules auto-créés sont import
.
Graph``` est un module pour créer un graphique de la transition de partition et de la transition de puce que j'ai écrit plus tôt.
summary``` n'est pas écrit car il sera long, mais fondamentalement il a la même structure que
graph ''`, et c'est un module pour calculer la distribution des commandes et le score total.
request_point '' `` `est expliqué.`download4.download (" /logvol2.txt "," log.txt ")`
.
graph.graph_plot (tip = True) `` `.
bucket.upload_file ("test.png ", "test.png ") `` `.
s3_image_url ... (Omis ci-dessous) Récupère l'URL du fichier téléchargé avec `` `.
@handler.add(PostbackEvent)
def handle_postback(event):
'''
Que se passe-t-il quand il y a une action PostBack
'''
import download4
import summary
import graph
postbackdata = event.postback.data
if postbackdata == "request_point":
download4.download("/logvol2.txt","log.txt")
graph.graph_plot(tip=True)
bucket.upload_file("test.png ", "test.png ")
s3_image_url = s3_client.generate_presigned_url(
ClientMethod = 'get_object',
Params = {'Bucket': aws_s3_bucket, 'Key': "test.png "},
ExpiresIn = 600,
HttpMethod = 'GET'
)
line_bot_api.reply_message(
event.reply_token,
ImageSendMessage(
original_content_url = s3_image_url,
preview_image_url = s3_image_url,
)
)
download4.upload("test.png ","/graph.png ")
if postbackdata == "request_tip":
download4.download("/logvol2.txt","log.txt")
graph.graph_plot(tip=True)
bucket.upload_file("test2.png ", "test2.png ")
s3_image_url = s3_client.generate_presigned_url(
ClientMethod = 'get_object',
Params = {'Bucket': aws_s3_bucket, 'Key': "test2.png "},
ExpiresIn = 600,
HttpMethod = 'GET'
)
line_bot_api.reply_message(
event.reply_token,
ImageSendMessage(
original_content_url = s3_image_url,
preview_image_url = s3_image_url,
)
)
download4.upload("test2.png ","/graph2.png ")
elif postbackdata == "request_sum":
import download4
import summary
download4.download("/logvol2.txt","log.txt")
summary.sumup(tip=True)
with open('summary.txt') as f:
lines = f.readlines()
text = ""
for line in lines:
text += "{}\n".format(line)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = text)
)
download4.upload("summary.txt","/summary.txt")
elif postbackdata == "request_today":
import download4
import summary
download4.download("/todays_score.txt","todays_log.txt")
summary.today(tip=True)
with open('todays_summary.txt') as f:
lines = f.readlines()
text = ""
for line in lines:
text += "{}\n".format(line)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = text)
)
download4.upload("todays_summary.txt","/todays_summary.txt")
elif postbackdata == "request_rank":
import download4
import summary
download4.download("/logvol2.txt","log.txt")
summary.sumup(tip=True)
with open('rank.txt') as f:
lines = f.readlines()
text = ""
for line in lines:
text += "{}\n".format(line)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = text)
)
download4.upload("rank.txt","/rank.txt")
elif postbackdata == "request_team":
import download4
import summary
download4.download("/logvol2.txt","log.txt")
summary.sumup(tip=True)
with open('team.txt') as f:
lines = f.readlines()
text = ""
for line in lines:
text += "{}\n".format(line)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text = text)
)
download4.upload("team.txt","/team.txt")
if __name__ == "__main__":
print("hello")
port = int(os.getenv("PORT", 5000))
app.run(host="0.0.0.0", port=port)
graph.py pour la création de graphique (le premier de l'article), `` `` summary.py
pour le calcul d'agrégation (je n'ai pas écrit sur le contenu cette fois), la réponse du bot LINE Tout ce que vous avez à faire est de déployer la partie `` tenhoulinebot.py '' (disons) sur Heroku.p.s.
Recommended Posts