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
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: 返還後
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: 取得文字列
213 def get_conversations(self, m: "MessageParserProtocol") -> dict: 214 """abstractmethod dummy""" 215 216 _ = m 217 return {}
abstractmethod dummy