integrations.web.functions

integrations/web/functions.py

  1"""
  2integrations/web/functions.py
  3"""
  4
  5import re
  6from typing import TYPE_CHECKING
  7
  8import pandas as pd
  9from flask import make_response, render_template
 10
 11from integrations.base.interface import FunctionsInterface
 12
 13if TYPE_CHECKING:
 14    from flask import Request, Response
 15
 16    from integrations.base.interface import MessageParserProtocol
 17
 18
 19class SvcFunctions(FunctionsInterface):
 20    """WebUI専用関数"""
 21
 22    def to_styled_html(self, df: pd.DataFrame, padding: str, index: bool = False) -> str:
 23        """データフレームをHTML表に変換
 24
 25        Args:
 26            df (pd.DataFrame): 変換元データ
 27            padding (str): パディング
 28            index (bool): インデックスの表示
 29
 30        Returns:
 31            str: HTML表
 32        """
 33
 34        styled = (
 35            df.style
 36            .format(
 37                {
 38                    "通算": "{:+.1f} pt",
 39                    "ポイント": "{:+.1f} pt",
 40                    ("東家", "ポイント"): "{:+.1f} pt",
 41                    ("南家", "ポイント"): "{:+.1f} pt",
 42                    ("西家", "ポイント"): "{:+.1f} pt",
 43                    ("北家", "ポイント"): "{:+.1f} pt",
 44                    "平均": "{:+.1f} pt",
 45                    "順位差": "{:.1f} pt",
 46                    "トップ差": "{:.1f} pt",
 47                    "ポイント合計": "{:.1f} pt",
 48                    "ゲーム参加率": "{:.2%}",
 49                    "通算ポイント": "{:+.1f} pt",
 50                    "平均ポイント": "{:+.1f} pt",
 51                    "最大獲得ポイント": "{:.1f} pt",
 52                    "平均収支": "{:+.1f}",
 53                    "平均素点": "{:.1f}",
 54                    "平均順位": "{:.2f}",
 55                    "1位率": "{:.2%}",
 56                    "連対率": "{:.2%}",
 57                    "ラス回避率": "{:.2%}",
 58                    "トビ率": "{:.2%}",
 59                    "役満和了率": "{:.2%}",
 60                    "レート": "{:.1f}",
 61                    "順位偏差": "{:.0f}",
 62                    "得点偏差": "{:.0f}",
 63                    "経過日数": "{:.0f} 日",
 64                    "プレイ回数": "{:.0f} ゲーム",
 65                    # レポート
 66                    ("ポイント", "通算"): "{:+.1f} pt",
 67                    ("ポイント", "平均"): "{:+.1f} pt",
 68                    ("1位", "獲得率"): "{:.2%}",
 69                    ("2位", "獲得率"): "{:.2%}",
 70                    ("3位", "獲得率"): "{:.2%}",
 71                    ("4位", "獲得率"): "{:.2%}",
 72                    ("トビ", "率"): "{:.2%}",
 73                    ("役満", "和了率"): "{:.2%}",
 74                    ("1位", "獲得ポイント"): "{:+.1f} pt",
 75                    ("2位", "獲得ポイント"): "{:+.1f} pt",
 76                    ("3位", "獲得ポイント"): "{:+.1f} pt",
 77                    ("4位", "獲得ポイント"): "{:+.1f} pt",
 78                    ("5位", "獲得ポイント"): "{:+.1f} pt",
 79                    # 成績統計
 80                    "ゲーム数": "{:.0f}",
 81                    ("", "ゲーム数"): "{:.0f}",
 82                    ("1位", "獲得数"): "{:.0f}",
 83                    ("2位", "獲得数"): "{:.0f}",
 84                    ("3位", "獲得数"): "{:.0f}",
 85                    ("4位", "獲得数"): "{:.0f}",
 86                    ("", "平均順位"): "{:.2f}",
 87                    ("区間成績", "区間ポイント"): "{:+.1f} pt",
 88                    ("区間成績", "区間平均"): "{:+.1f} pt",
 89                    ("", "通算ポイント"): "{:+.1f} pt",
 90                },
 91                na_rep="-----",
 92            )
 93            .set_table_attributes('class="data_table"')
 94            .set_table_styles([
 95                {"selector": "th", "props": [("color", "#ffffff"), ("background-color", "#000000"), ("text-align", "center"), ("padding", padding)]},
 96                {"selector": "td", "props": [("text-align", "center"), ("padding", padding)]},
 97                {"selector": "tr:nth-child(odd)", "props": [("background-color", "#f0f0f0f0")]},
 98                {"selector": "tr:nth-child(even)", "props": [("background-color", "#dfdfdfdf")]},
 99            ])
100        )
101        if not index:
102            styled = styled.hide(axis="index")
103
104        ret = styled.to_html()
105        ret = re.sub(r" >-(\d+)</td>", r" >▲\1</td>", ret)  # 素点
106        ret = re.sub(r" >-(\d+\.\d)</td>", r" >▲\1</td>", ret)  # 素点(小数点付き)
107        ret = re.sub(r" >-(\d+\.\d) pt</td>", r" >▲\1 pt</td>", ret)  # ポイント
108
109        return ret
110
111    def to_text_html(self, text: str) -> str:
112        """テキストをHTMLに変換
113
114        Args:
115            text (str): 変換元
116
117        Returns:
118            str: 返還後
119        """
120
121        ret: str = "<p>\n"
122        for line in text.splitlines():
123            ret += f"{line.strip()}<br>\n"
124        ret += "</p>\n"
125
126        return ret
127
128    def header_message(self, m: "MessageParserProtocol") -> str:
129        """ヘッダ情報取得
130
131        Args:
132            m (MessageParserProtocol): メッセージデータ
133
134        Returns:
135            str: 取得文字列
136        """
137
138        message = ""
139        if m.post.headline:
140            title, headline = next(iter(m.post.headline.items()))
141            if not title.isnumeric() and title:
142                message = f"<h1>{title}</h1>\n"
143            message += f"<p>\n{headline.replace("\n", "<br>\n")}</p>\n"
144
145        return message
146
147    def set_cookie(self, html: str, req: "Request", data: dict) -> "Response":
148        """cookie保存
149
150        Args:
151            html (str): テンプレートHTML
152            req (Request): Request
153            data (dict): データ
154
155        Returns:
156            Response: Response
157        """
158
159        page = make_response(render_template(html, **data))
160        if req.method == "POST":
161            if req.form.get("action") == "reset":  # cookie削除
162                for k in req.cookies.keys():
163                    page.delete_cookie(k, path=req.path)
164            else:
165                for k, v in req.form.to_dict().items():
166                    if k == "action":
167                        continue
168                    page.set_cookie(k, v, path=req.path)
169
170        return page
171
172    def get_cookie(self, req: "Request") -> dict:
173        """cookie取得
174
175        Args:
176            req (Request): Request
177
178        Returns:
179            dict: cookieデータ
180        """
181
182        initial_value: dict = {
183            "range": "",
184            "guest": "ゲストなし",
185            "display": "",
186            "result": "",
187            "collect": "",
188        }
189
190        target_keys: list = [
191            "collect",
192            "display",
193            "guest",
194            "player",
195            "range",
196            "result",
197            "text",
198        ]
199
200        if req.method == "POST":
201            cookie_data = req.form.to_dict()
202            if req.form.get("action") == "reset":
203                cookie_data = initial_value
204            else:
205                cookie_data.pop("action")
206        else:
207            cookie_data = initial_value
208            cookie_data.update(req.cookies)
209
210        return {k: v for k, v in cookie_data.items() if k in target_keys}
211
212    def get_conversations(self, m: "MessageParserProtocol") -> dict:
213        """abstractmethod dummy"""
214
215        _ = m
216        return {}
217
218    def post_processing(self, m: "MessageParserProtocol"):
219        """abstractmethod dummy"""
220
221        _ = m
class SvcFunctions(integrations.base.interface.FunctionsInterface):
 20class SvcFunctions(FunctionsInterface):
 21    """WebUI専用関数"""
 22
 23    def to_styled_html(self, df: pd.DataFrame, padding: str, index: bool = False) -> str:
 24        """データフレームをHTML表に変換
 25
 26        Args:
 27            df (pd.DataFrame): 変換元データ
 28            padding (str): パディング
 29            index (bool): インデックスの表示
 30
 31        Returns:
 32            str: HTML表
 33        """
 34
 35        styled = (
 36            df.style
 37            .format(
 38                {
 39                    "通算": "{:+.1f} pt",
 40                    "ポイント": "{:+.1f} pt",
 41                    ("東家", "ポイント"): "{:+.1f} pt",
 42                    ("南家", "ポイント"): "{:+.1f} pt",
 43                    ("西家", "ポイント"): "{:+.1f} pt",
 44                    ("北家", "ポイント"): "{:+.1f} pt",
 45                    "平均": "{:+.1f} pt",
 46                    "順位差": "{:.1f} pt",
 47                    "トップ差": "{:.1f} pt",
 48                    "ポイント合計": "{:.1f} pt",
 49                    "ゲーム参加率": "{:.2%}",
 50                    "通算ポイント": "{:+.1f} pt",
 51                    "平均ポイント": "{:+.1f} pt",
 52                    "最大獲得ポイント": "{:.1f} pt",
 53                    "平均収支": "{:+.1f}",
 54                    "平均素点": "{:.1f}",
 55                    "平均順位": "{:.2f}",
 56                    "1位率": "{:.2%}",
 57                    "連対率": "{:.2%}",
 58                    "ラス回避率": "{:.2%}",
 59                    "トビ率": "{:.2%}",
 60                    "役満和了率": "{:.2%}",
 61                    "レート": "{:.1f}",
 62                    "順位偏差": "{:.0f}",
 63                    "得点偏差": "{:.0f}",
 64                    "経過日数": "{:.0f} 日",
 65                    "プレイ回数": "{:.0f} ゲーム",
 66                    # レポート
 67                    ("ポイント", "通算"): "{:+.1f} pt",
 68                    ("ポイント", "平均"): "{:+.1f} pt",
 69                    ("1位", "獲得率"): "{:.2%}",
 70                    ("2位", "獲得率"): "{:.2%}",
 71                    ("3位", "獲得率"): "{:.2%}",
 72                    ("4位", "獲得率"): "{:.2%}",
 73                    ("トビ", "率"): "{:.2%}",
 74                    ("役満", "和了率"): "{:.2%}",
 75                    ("1位", "獲得ポイント"): "{:+.1f} pt",
 76                    ("2位", "獲得ポイント"): "{:+.1f} pt",
 77                    ("3位", "獲得ポイント"): "{:+.1f} pt",
 78                    ("4位", "獲得ポイント"): "{:+.1f} pt",
 79                    ("5位", "獲得ポイント"): "{:+.1f} pt",
 80                    # 成績統計
 81                    "ゲーム数": "{:.0f}",
 82                    ("", "ゲーム数"): "{:.0f}",
 83                    ("1位", "獲得数"): "{:.0f}",
 84                    ("2位", "獲得数"): "{:.0f}",
 85                    ("3位", "獲得数"): "{:.0f}",
 86                    ("4位", "獲得数"): "{:.0f}",
 87                    ("", "平均順位"): "{:.2f}",
 88                    ("区間成績", "区間ポイント"): "{:+.1f} pt",
 89                    ("区間成績", "区間平均"): "{:+.1f} pt",
 90                    ("", "通算ポイント"): "{:+.1f} pt",
 91                },
 92                na_rep="-----",
 93            )
 94            .set_table_attributes('class="data_table"')
 95            .set_table_styles([
 96                {"selector": "th", "props": [("color", "#ffffff"), ("background-color", "#000000"), ("text-align", "center"), ("padding", padding)]},
 97                {"selector": "td", "props": [("text-align", "center"), ("padding", padding)]},
 98                {"selector": "tr:nth-child(odd)", "props": [("background-color", "#f0f0f0f0")]},
 99                {"selector": "tr:nth-child(even)", "props": [("background-color", "#dfdfdfdf")]},
100            ])
101        )
102        if not index:
103            styled = styled.hide(axis="index")
104
105        ret = styled.to_html()
106        ret = re.sub(r" >-(\d+)</td>", r" >▲\1</td>", ret)  # 素点
107        ret = re.sub(r" >-(\d+\.\d)</td>", r" >▲\1</td>", ret)  # 素点(小数点付き)
108        ret = re.sub(r" >-(\d+\.\d) pt</td>", r" >▲\1 pt</td>", ret)  # ポイント
109
110        return ret
111
112    def to_text_html(self, text: str) -> str:
113        """テキストをHTMLに変換
114
115        Args:
116            text (str): 変換元
117
118        Returns:
119            str: 返還後
120        """
121
122        ret: str = "<p>\n"
123        for line in text.splitlines():
124            ret += f"{line.strip()}<br>\n"
125        ret += "</p>\n"
126
127        return ret
128
129    def header_message(self, m: "MessageParserProtocol") -> str:
130        """ヘッダ情報取得
131
132        Args:
133            m (MessageParserProtocol): メッセージデータ
134
135        Returns:
136            str: 取得文字列
137        """
138
139        message = ""
140        if m.post.headline:
141            title, headline = next(iter(m.post.headline.items()))
142            if not title.isnumeric() and title:
143                message = f"<h1>{title}</h1>\n"
144            message += f"<p>\n{headline.replace("\n", "<br>\n")}</p>\n"
145
146        return message
147
148    def set_cookie(self, html: str, req: "Request", data: dict) -> "Response":
149        """cookie保存
150
151        Args:
152            html (str): テンプレートHTML
153            req (Request): Request
154            data (dict): データ
155
156        Returns:
157            Response: Response
158        """
159
160        page = make_response(render_template(html, **data))
161        if req.method == "POST":
162            if req.form.get("action") == "reset":  # cookie削除
163                for k in req.cookies.keys():
164                    page.delete_cookie(k, path=req.path)
165            else:
166                for k, v in req.form.to_dict().items():
167                    if k == "action":
168                        continue
169                    page.set_cookie(k, v, path=req.path)
170
171        return page
172
173    def get_cookie(self, req: "Request") -> dict:
174        """cookie取得
175
176        Args:
177            req (Request): Request
178
179        Returns:
180            dict: cookieデータ
181        """
182
183        initial_value: dict = {
184            "range": "",
185            "guest": "ゲストなし",
186            "display": "",
187            "result": "",
188            "collect": "",
189        }
190
191        target_keys: list = [
192            "collect",
193            "display",
194            "guest",
195            "player",
196            "range",
197            "result",
198            "text",
199        ]
200
201        if req.method == "POST":
202            cookie_data = req.form.to_dict()
203            if req.form.get("action") == "reset":
204                cookie_data = initial_value
205            else:
206                cookie_data.pop("action")
207        else:
208            cookie_data = initial_value
209            cookie_data.update(req.cookies)
210
211        return {k: v for k, v in cookie_data.items() if k in target_keys}
212
213    def get_conversations(self, m: "MessageParserProtocol") -> dict:
214        """abstractmethod dummy"""
215
216        _ = m
217        return {}
218
219    def post_processing(self, m: "MessageParserProtocol"):
220        """abstractmethod dummy"""
221
222        _ = m

WebUI専用関数

def to_styled_html( self, df: pandas.core.frame.DataFrame, padding: str, index: bool = False) -> str:
 23    def to_styled_html(self, df: pd.DataFrame, padding: str, index: bool = False) -> str:
 24        """データフレームをHTML表に変換
 25
 26        Args:
 27            df (pd.DataFrame): 変換元データ
 28            padding (str): パディング
 29            index (bool): インデックスの表示
 30
 31        Returns:
 32            str: HTML表
 33        """
 34
 35        styled = (
 36            df.style
 37            .format(
 38                {
 39                    "通算": "{:+.1f} pt",
 40                    "ポイント": "{:+.1f} pt",
 41                    ("東家", "ポイント"): "{:+.1f} pt",
 42                    ("南家", "ポイント"): "{:+.1f} pt",
 43                    ("西家", "ポイント"): "{:+.1f} pt",
 44                    ("北家", "ポイント"): "{:+.1f} pt",
 45                    "平均": "{:+.1f} pt",
 46                    "順位差": "{:.1f} pt",
 47                    "トップ差": "{:.1f} pt",
 48                    "ポイント合計": "{:.1f} pt",
 49                    "ゲーム参加率": "{:.2%}",
 50                    "通算ポイント": "{:+.1f} pt",
 51                    "平均ポイント": "{:+.1f} pt",
 52                    "最大獲得ポイント": "{:.1f} pt",
 53                    "平均収支": "{:+.1f}",
 54                    "平均素点": "{:.1f}",
 55                    "平均順位": "{:.2f}",
 56                    "1位率": "{:.2%}",
 57                    "連対率": "{:.2%}",
 58                    "ラス回避率": "{:.2%}",
 59                    "トビ率": "{:.2%}",
 60                    "役満和了率": "{:.2%}",
 61                    "レート": "{:.1f}",
 62                    "順位偏差": "{:.0f}",
 63                    "得点偏差": "{:.0f}",
 64                    "経過日数": "{:.0f} 日",
 65                    "プレイ回数": "{:.0f} ゲーム",
 66                    # レポート
 67                    ("ポイント", "通算"): "{:+.1f} pt",
 68                    ("ポイント", "平均"): "{:+.1f} pt",
 69                    ("1位", "獲得率"): "{:.2%}",
 70                    ("2位", "獲得率"): "{:.2%}",
 71                    ("3位", "獲得率"): "{:.2%}",
 72                    ("4位", "獲得率"): "{:.2%}",
 73                    ("トビ", "率"): "{:.2%}",
 74                    ("役満", "和了率"): "{:.2%}",
 75                    ("1位", "獲得ポイント"): "{:+.1f} pt",
 76                    ("2位", "獲得ポイント"): "{:+.1f} pt",
 77                    ("3位", "獲得ポイント"): "{:+.1f} pt",
 78                    ("4位", "獲得ポイント"): "{:+.1f} pt",
 79                    ("5位", "獲得ポイント"): "{:+.1f} pt",
 80                    # 成績統計
 81                    "ゲーム数": "{:.0f}",
 82                    ("", "ゲーム数"): "{:.0f}",
 83                    ("1位", "獲得数"): "{:.0f}",
 84                    ("2位", "獲得数"): "{:.0f}",
 85                    ("3位", "獲得数"): "{:.0f}",
 86                    ("4位", "獲得数"): "{:.0f}",
 87                    ("", "平均順位"): "{:.2f}",
 88                    ("区間成績", "区間ポイント"): "{:+.1f} pt",
 89                    ("区間成績", "区間平均"): "{:+.1f} pt",
 90                    ("", "通算ポイント"): "{:+.1f} pt",
 91                },
 92                na_rep="-----",
 93            )
 94            .set_table_attributes('class="data_table"')
 95            .set_table_styles([
 96                {"selector": "th", "props": [("color", "#ffffff"), ("background-color", "#000000"), ("text-align", "center"), ("padding", padding)]},
 97                {"selector": "td", "props": [("text-align", "center"), ("padding", padding)]},
 98                {"selector": "tr:nth-child(odd)", "props": [("background-color", "#f0f0f0f0")]},
 99                {"selector": "tr:nth-child(even)", "props": [("background-color", "#dfdfdfdf")]},
100            ])
101        )
102        if not index:
103            styled = styled.hide(axis="index")
104
105        ret = styled.to_html()
106        ret = re.sub(r" >-(\d+)</td>", r" >▲\1</td>", ret)  # 素点
107        ret = re.sub(r" >-(\d+\.\d)</td>", r" >▲\1</td>", ret)  # 素点(小数点付き)
108        ret = re.sub(r" >-(\d+\.\d) pt</td>", r" >▲\1 pt</td>", ret)  # ポイント
109
110        return ret

データフレームをHTML表に変換

Arguments:
  • df (pd.DataFrame): 変換元データ
  • padding (str): パディング
  • index (bool): インデックスの表示
Returns:

str: HTML表

def to_text_html(self, text: str) -> str:
112    def to_text_html(self, text: str) -> str:
113        """テキストをHTMLに変換
114
115        Args:
116            text (str): 変換元
117
118        Returns:
119            str: 返還後
120        """
121
122        ret: str = "<p>\n"
123        for line in text.splitlines():
124            ret += f"{line.strip()}<br>\n"
125        ret += "</p>\n"
126
127        return ret

テキストをHTMLに変換

Arguments:
  • text (str): 変換元
Returns:

str: 返還後

def header_message(self, m: integrations.protocols.MessageParserProtocol) -> str:
129    def header_message(self, m: "MessageParserProtocol") -> str:
130        """ヘッダ情報取得
131
132        Args:
133            m (MessageParserProtocol): メッセージデータ
134
135        Returns:
136            str: 取得文字列
137        """
138
139        message = ""
140        if m.post.headline:
141            title, headline = next(iter(m.post.headline.items()))
142            if not title.isnumeric() and title:
143                message = f"<h1>{title}</h1>\n"
144            message += f"<p>\n{headline.replace("\n", "<br>\n")}</p>\n"
145
146        return message

ヘッダ情報取得

Arguments:
  • m (MessageParserProtocol): メッセージデータ
Returns:

str: 取得文字列

def get_conversations(self, m: integrations.protocols.MessageParserProtocol) -> dict:
213    def get_conversations(self, m: "MessageParserProtocol") -> dict:
214        """abstractmethod dummy"""
215
216        _ = m
217        return {}

abstractmethod dummy

def post_processing(self, m: integrations.protocols.MessageParserProtocol):
219    def post_processing(self, m: "MessageParserProtocol"):
220        """abstractmethod dummy"""
221
222        _ = m

abstractmethod dummy