From 1ec248b6c1183a02ae668030042f5b800fad67ca Mon Sep 17 00:00:00 2001 From: shinkuan Date: Fri, 15 Mar 2024 17:06:18 +0800 Subject: [PATCH 1/4] online mode --- mjai/bot/bot.py | 23 +++++++++++++++++- mjai/bot/model.py | 55 ++++++++++++++++++++++++++++++++++++++++++-- mjai/bot/online.json | 5 ++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 mjai/bot/online.json diff --git a/mjai/bot/bot.py b/mjai/bot/bot.py index fac8953..92f1d1a 100644 --- a/mjai/bot/bot.py +++ b/mjai/bot/bot.py @@ -2,8 +2,9 @@ import sys import hashlib import pathlib +import requests -from loguru import logger +from my_logger import logger from . import model @@ -15,6 +16,24 @@ def __init__(self, player_id: int): self.model = model.load_model(player_id) with open(model_path, "rb") as f: self.model_hash = hashlib.sha256(f.read()).hexdigest() + try: + with open(pathlib.Path(__file__).parent / "online.json", "r") as f: + online_json = json.load(f) + self.online = online_json["online"] + if not self.online: + return + api_key = online_json["api_key"] + server = online_json["server"] + headers = { + 'Authorization': api_key, + } + r = requests.post(f"{server}/check", headers=headers) + r_json = r.json() + if r_json["result"] == "success": + self.model_hash = "online" + except Exception as e: + logger.error(e) + self.online = False def react(self, events: str) -> str: events = json.loads(events) @@ -27,6 +46,8 @@ def react(self, events: str) -> str: return json.dumps({"type":"none"}, separators=(",", ":")) else: raw_data = json.loads(return_action) + if self.online: + raw_data["online"] = model.online_valid return json.dumps(raw_data, separators=(",", ":")) def state(self): diff --git a/mjai/bot/model.py b/mjai/bot/model.py index 1d65f24..bc9964d 100644 --- a/mjai/bot/model.py +++ b/mjai/bot/model.py @@ -1,3 +1,4 @@ +import json import numpy as np import torch import pathlib @@ -9,6 +10,8 @@ from functools import partial from itertools import permutations import riichi +import gzip +import requests class ChannelAttention(nn.Module): def __init__(self, channels, ratio=16, actv_builder=nn.ReLU, bias=True): @@ -233,6 +236,7 @@ def forward(self, phi, mask): q = (v + a - a_mean).masked_fill(~mask, -torch.inf) return q +online_valid = False class MortalEngine: def __init__( @@ -250,6 +254,9 @@ def __init__( boltzmann_epsilon = 0, boltzmann_temp = 1, top_p = 1, + online = False, + api_key = None, + server = None, ): self.engine_type = 'mortal' self.device = device or torch.device('cpu') @@ -269,7 +276,38 @@ def __init__( self.boltzmann_temp = boltzmann_temp self.top_p = top_p + self.online = online + self.api_key = api_key + self.server = server + def react_batch(self, obs, masks, invisible_obs): + if self.online: + global online_valid + try: + list_obs = [o.tolist() for o in obs] + list_masks = [m.tolist() for m in masks] + post_data = { + 'obs': list_obs, + 'masks': list_masks, + } + data = json.dumps(post_data, separators=(',', ':')) + compressed_data = gzip.compress(data.encode('utf-8')) + headers = { + 'Authorization': self.api_key, + 'Content-Encoding': 'gzip', + } + r = requests.post(f'{self.server}/react_batch', + headers=headers, + data=compressed_data, + timeout=2) + assert r.status_code == 200 + online_valid = True + r_json = r.json() + return r_json['actions'], r_json['q_out'], r_json['masks'], r_json['is_greedy'] + except: + online_valid = False + pass + with ( torch.autocast(self.device.type, enabled=self.enable_amp), torch.no_grad(), @@ -320,6 +358,11 @@ def sample_top_p(logits, p): return sampled def load_model(seat: int) -> riichi.mjai.Bot: + engine = get_engine() + bot = riichi.mjai.Bot(engine, seat) + return bot + +def get_engine() -> MortalEngine: # check if GPU is available if torch.cuda.is_available(): @@ -341,6 +384,12 @@ def load_model(seat: int) -> riichi.mjai.Bot: mortal.load_state_dict(state['mortal']) dqn.load_state_dict(state['current_dqn']) + with open(pathlib.Path(__file__).parent / 'online.json', 'r') as f: + json_load = json.load(f) + server = json_load['server'] + online = json_load['online'] + api_key = json_load['api_key'] + engine = MortalEngine( mortal, dqn, @@ -351,7 +400,9 @@ def load_model(seat: int) -> riichi.mjai.Bot: enable_rule_based_agari_guard = False, name = 'mortal', version = state['config']['control']['version'], + online = online, + api_key = api_key, + server = server, ) - bot = riichi.mjai.Bot(engine, seat) - return bot \ No newline at end of file + return engine \ No newline at end of file diff --git a/mjai/bot/online.json b/mjai/bot/online.json new file mode 100644 index 0000000..f8e35dd --- /dev/null +++ b/mjai/bot/online.json @@ -0,0 +1,5 @@ +{ + "server": "http://34.71.176.237:5000", + "online": false, + "api_key": "your_api_key_here" +} \ No newline at end of file From b0355ffb7a048943f3c6b4a7e59adcb506fa3492 Mon Sep 17 00:00:00 2001 From: shinkuan Date: Fri, 15 Mar 2024 17:38:16 +0800 Subject: [PATCH 2/4] online use v4 --- mjai/bot/model.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mjai/bot/model.py b/mjai/bot/model.py index bc9964d..aa6cfc4 100644 --- a/mjai/bot/model.py +++ b/mjai/bot/model.py @@ -279,6 +279,8 @@ def __init__( self.online = online self.api_key = api_key self.server = server + if self.online: + self.version = 4 def react_batch(self, obs, masks, invisible_obs): if self.online: From be21d6b0f448aa72de5c364426b558d18d9c2f4c Mon Sep 17 00:00:00 2001 From: shinkuan Date: Sat, 16 Mar 2024 15:19:36 +0800 Subject: [PATCH 3/4] assert v4 for online mode --- mjai/bot/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mjai/bot/model.py b/mjai/bot/model.py index aa6cfc4..80a51b2 100644 --- a/mjai/bot/model.py +++ b/mjai/bot/model.py @@ -280,7 +280,7 @@ def __init__( self.api_key = api_key self.server = server if self.online: - self.version = 4 + assert self.version == 4, 'To use online, local model version must be 4' def react_batch(self, obs, masks, invisible_obs): if self.online: From aafb3a08b7abb424d743cd7de9df8dc5c9cde068 Mon Sep 17 00:00:00 2001 From: shinkuan Date: Sat, 16 Mar 2024 15:51:38 +0800 Subject: [PATCH 4/4] Add random time setting, remove v10 setting. --- action.py | 16 +++++------ client.py | 79 +++++++++++++++++++++++++++++++++++---------------- client.tcss | 27 ++++++++++++++++++ settings.json | 69 ++++++-------------------------------------- 4 files changed, 98 insertions(+), 93 deletions(-) diff --git a/action.py b/action.py index 80b725b..60733ef 100644 --- a/action.py +++ b/action.py @@ -94,17 +94,18 @@ #^^^^^^^^^^^^^^^^Self Discard^^^^^^^^^^^^^^^^ } -with open("settings.json", "r") as f: - settings = json.load(f) - PLAYWRIGHT_RESOLUTION = (settings['Playwright']['width'], settings['Playwright']['height']) - SCALE = PLAYWRIGHT_RESOLUTION[0]/16 - class Action: def __init__(self, rpc_server: ServerProxy): self.isNewRound = True self.reached = False self.latest_operation_list = [] self.rpc_server = rpc_server + with open("settings.json", "r") as f: + settings = json.load(f) + self.new_min = settings['RandomTime']['new_min'] + self.new_max = settings['RandomTime']['new_max'] + self.min = settings['RandomTime']['min'] + self.max = settings['RandomTime']['max'] pass def page_clicker(self, coord: tuple[float, float]): @@ -115,9 +116,8 @@ def do_autohu(self): def decide_random_time(self): if self.isNewRound: - return random.uniform(3.5, 4.5) - return random.uniform(1.0, 3.2) - + return random.uniform(self.new_min, self.new_max) + return random.uniform(self.min, self.max) def click_chiponkan(self, mjai_msg: dict | None, tehai: list[str], tsumohai: str | None): latest_operation_list_temp = self.latest_operation_list.copy() diff --git a/client.py b/client.py index 2e37328..89365a4 100644 --- a/client.py +++ b/client.py @@ -283,11 +283,12 @@ def __init__(self, *args, **kwargs) -> None: self.value_port_setting_mitm_input = settings["Port"]["MITM"] self.value_port_setting_xmlrpc_input = settings["Port"]["XMLRPC"] self.value_unlocker_setting_enable_checkbox = settings["Unlocker"] - self.value_unlocker_setting_v10_checkbox = settings["v10"] self.value_helper_setting_checkbox = settings["Helper"] self.value_autoplay_setting_enable_checkbox = settings["Autoplay"] - # self.value_autoplay_setting_random_time_min_input = settings["Autoplay"]["Random Time"]["Min"] - # self.value_autoplay_setting_random_time_max_input = settings["Autoplay"]["Random Time"]["Max"] + self.value_autoplay_setting_random_time_new_min_input = settings["RandomTime"]["new_min"] + self.value_autoplay_setting_random_time_new_max_input = settings["RandomTime"]["new_max"] + self.value_autoplay_setting_random_time_min_input = settings["RandomTime"]["min"] + self.value_autoplay_setting_random_time_max_input = settings["RandomTime"]["max"] self.value_playwright_setting_enable_checkbox = settings["Playwright"]["enable"] self.value_playwright_setting_width_input = settings["Playwright"]["width"] self.value_playwright_setting_height_input = settings["Playwright"]["height"] @@ -304,8 +305,7 @@ def compose(self) -> ComposeResult: self.unlocker_setting_label = Label("Unlocker", id="unlocker_setting_label") self.unlocker_setting_enable_checkbox = Checkbox("Enable", id="unlocker_setting_enable_checkbox", classes="short", value=self.value_unlocker_setting_enable_checkbox) - self.unlocker_setting_v10_checkbox = Checkbox("v10", id="unlocker_setting_v10_checkbox", classes="short", value=self.value_unlocker_setting_v10_checkbox) - self.unlocker_setting_container = Horizontal(self.unlocker_setting_label, self.unlocker_setting_enable_checkbox, self.unlocker_setting_v10_checkbox, id="unlocker_setting_container") + self.unlocker_setting_container = Horizontal(self.unlocker_setting_label, self.unlocker_setting_enable_checkbox, id="unlocker_setting_container") self.unlocker_setting_container.border_title = "Unlocker" self.helper_setting_label = Label("Helper", id="helper_setting_label") @@ -316,11 +316,15 @@ def compose(self) -> ComposeResult: self.autoplay_setting_enable_label = Label("Enable", id="autoplay_setting_enable_label") self.autoplay_setting_enable_checkbox = Checkbox("Enable", id="autoplay_setting_enable_checkbox", classes="short", value=self.value_autoplay_setting_enable_checkbox) self.autoplay_setting_enable_container = Horizontal(self.autoplay_setting_enable_label, self.autoplay_setting_enable_checkbox, id="autoplay_setting_enable_container") - self.autoplay_setting_random_time_label = Label("Random Time", id="autoplay_setting_random_time_label") - self.autoplay_setting_random_time_min_input = Input(placeholder="Min", type="number", id="autoplay_setting_random_time_min_input") - self.autoplay_setting_random_time_max_input = Input(placeholder="Max", type="number", id="autoplay_setting_random_time_max_input") + self.autoplay_setting_random_time_new_label = Label("Random New", id="autoplay_setting_random_time_new_label") + self.autoplay_setting_random_time_new_min_input = Input(placeholder="Min", type="number", id="autoplay_setting_random_time_new_min_input", value=str(self.value_autoplay_setting_random_time_new_min_input)) + self.autoplay_setting_random_time_new_max_input = Input(placeholder="Max", type="number", id="autoplay_setting_random_time_new_max_input", value=str(self.value_autoplay_setting_random_time_new_max_input)) + self.autoplay_setting_random_time_new_container = Horizontal(self.autoplay_setting_random_time_new_label, self.autoplay_setting_random_time_new_min_input, self.autoplay_setting_random_time_new_max_input, id="autoplay_setting_random_time_new_container") + self.autoplay_setting_random_time_label = Label("Random", id="autoplay_setting_random_time_label") + self.autoplay_setting_random_time_min_input = Input(placeholder="Min", type="number", id="autoplay_setting_random_time_min_input", value=str(self.value_autoplay_setting_random_time_min_input)) + self.autoplay_setting_random_time_max_input = Input(placeholder="Max", type="number", id="autoplay_setting_random_time_max_input", value=str(self.value_autoplay_setting_random_time_max_input)) self.autoplay_setting_random_time_container = Horizontal(self.autoplay_setting_random_time_label, self.autoplay_setting_random_time_min_input, self.autoplay_setting_random_time_max_input, id="autoplay_setting_random_time_container") - self.autoplay_setting_container = Vertical(self.autoplay_setting_enable_container, self.autoplay_setting_random_time_container, id="autoplay_setting_container") + self.autoplay_setting_container = Vertical(self.autoplay_setting_enable_container, self.autoplay_setting_random_time_new_container, self.autoplay_setting_random_time_container, id="autoplay_setting_container") self.autoplay_setting_container.border_title = "Autoplay" self.playwright_setting_enable_label = Label("Enable", id="playwright_setting_enable_label") @@ -352,11 +356,17 @@ def compose(self) -> ComposeResult: @on(Input.Changed, "#port_setting_mitm_input") def port_setting_mitm_input_changed(self, event: Input.Changed) -> None: - self.value_port_setting_mitm_input = int(event.value) + try: + self.value_port_setting_mitm_input = int(event.value) + except: + pass @on(Input.Changed, "#port_setting_xmlrpc_input") def port_setting_xmlrpc_input_changed(self, event: Input.Changed) -> None: - self.value_port_setting_xmlrpc_input = int(event.value) + try: + self.value_port_setting_xmlrpc_input = int(event.value) + except: + pass @on(Checkbox.Changed, "#unlocker_setting_enable_checkbox") def unlocker_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> None: @@ -366,25 +376,39 @@ def unlocker_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> N def helper_setting_checkbox_changed(self, event: Checkbox.Changed) -> None: self.value_helper_setting_checkbox = event.value - @on(Checkbox.Changed, "#unlocker_setting_v10_checkbox") - def unlocker_setting_v10_checkbox_changed(self, event: Checkbox.Changed) -> None: - self.value_unlocker_setting_v10_checkbox = event.value - @on(Checkbox.Changed, "#autoplay_setting_enable_checkbox") def autoplay_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> None: global AUTOPLAY AUTOPLAY = event.value self.value_autoplay_setting_enable_checkbox = event.value + @on(Input.Changed, "#autoplay_setting_random_time_new_min_input") + def autoplay_setting_random_time_new_min_input_changed(self, event: Input.Changed) -> None: + try: + self.value_autoplay_setting_random_time_new_min_input = float(event.value) + except: + pass + + @on(Input.Changed, "#autoplay_setting_random_time_new_max_input") + def autoplay_setting_random_time_new_max_input_changed(self, event: Input.Changed) -> None: + try: + self.value_autoplay_setting_random_time_new_max_input = float(event.value) + except: + pass + @on(Input.Changed, "#autoplay_setting_random_time_min_input") def autoplay_setting_random_time_min_input_changed(self, event: Input.Changed) -> None: - # self.value_autoplay_setting_random_time_min_input = event.value - pass + try: + self.value_autoplay_setting_random_time_min_input = float(event.value) + except: + pass @on(Input.Changed, "#autoplay_setting_random_time_max_input") def autoplay_setting_random_time_max_input_changed(self, event: Input.Changed) -> None: - # self.value_autoplay_setting_random_time_max_input = event.value - pass + try: + self.value_autoplay_setting_random_time_max_input = float(event.value) + except: + pass @on(Checkbox.Changed, "#playwright_setting_enable_checkbox") def playwright_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> None: @@ -392,11 +416,17 @@ def playwright_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> @on(Input.Changed, "#playwright_setting_width_input") def playwright_setting_width_input_changed(self, event: Input.Changed) -> None: - self.value_playwright_setting_width_input = int(event.value) + try: + self.value_playwright_setting_width_input = int(event.value) + except: + pass @on(Input.Changed, "#playwright_setting_height_input") def playwright_setting_height_input_changed(self, event: Input.Changed) -> None: - self.value_playwright_setting_height_input = int(event.value) + try: + self.value_playwright_setting_height_input = int(event.value) + except: + pass @on(Button.Pressed, "#setting_save_button") def setting_save_button_pressed(self) -> None: @@ -405,11 +435,12 @@ def setting_save_button_pressed(self) -> None: settings["Port"]["MITM"] = self.value_port_setting_mitm_input settings["Port"]["XMLRPC"] = self.value_port_setting_xmlrpc_input settings["Unlocker"] = self.value_unlocker_setting_enable_checkbox - settings["v10"] = self.value_unlocker_setting_v10_checkbox settings["Helper"] = self.value_helper_setting_checkbox settings["Autoplay"] = self.value_autoplay_setting_enable_checkbox - # settings["Autoplay"]["Random Time"]["Min"] = self.value_autoplay_setting_random_time_min_input - # settings["Autoplay"]["Random Time"]["Max"] = self.value_autoplay_setting_random_time_max_input + settings["RandomTime"]["new_min"] = self.value_autoplay_setting_random_time_new_min_input + settings["RandomTime"]["new_max"] = self.value_autoplay_setting_random_time_new_max_input + settings["RandomTime"]["min"] = self.value_autoplay_setting_random_time_min_input + settings["RandomTime"]["max"] = self.value_autoplay_setting_random_time_max_input settings["Playwright"]["enable"] = self.value_playwright_setting_enable_checkbox settings["Playwright"]["width"] = self.value_playwright_setting_width_input settings["Playwright"]["height"] = self.value_playwright_setting_height_input diff --git a/client.tcss b/client.tcss index abb8469..96c2b24 100644 --- a/client.tcss +++ b/client.tcss @@ -349,6 +349,33 @@ Button.action_nukidora.-active { margin: 0; } +#autoplay_setting_random_time_new_label { + padding: 1 0; + width: 11; + height: 3; + align: center middle; + margin: 0 1; +} + +#autoplay_setting_random_time_new_min_input { + width: 1fr; + align: center top; + margin: 0 1; +} + +#autoplay_setting_random_time_new_max_input { + width: 1fr; + align: center top; + margin: 0 1; +} + +#autoplay_setting_random_time_new_container { + width: 1fr; + height: auto; + align: center top; + margin: 0; +} + #autoplay_setting_random_time_label { padding: 1 0; width: 11; diff --git a/settings.json b/settings.json index ea0e9ff..075f3c8 100644 --- a/settings.json +++ b/settings.json @@ -1,9 +1,14 @@ { "Unlocker": false, - "v10": false, "Autoplay": false, + "RandomTime": { + "new_min": 3.5, + "new_max": 4.5, + "min": 1.0, + "max": 3.2 + }, "Helper": false, - "Autohu": true, + "Autohu": false, "Port": { "MITM": 7878, "XMLRPC": 7879, @@ -13,63 +18,5 @@ "enable": true, "width": 1280, "height": 720 - }, - "views": [ - { - "itemId": 308008, - "slot": 0, - "type": 0, - "itemIdList": [] - }, - { - "slot": 1, - "itemId": 305215, - "type": 0, - "itemIdList": [] - }, - { - "slot": 2, - "itemId": 305315, - "type": 0, - "itemIdList": [] - }, - { - "slot": 4, - "itemId": 306201, - "type": 0, - "itemIdList": [] - }, - { - "slot": 5, - "itemId": 305529, - "type": 0, - "itemIdList": [] - }, - { - "slot": 6, - "itemId": 305816, - "type": 0, - "itemIdList": [] - }, - { - "slot": 7, - "itemId": 308015, - "type": 0, - "itemIdList": [] - }, - { - "slot": 8, - "itemId": 307010, - "type": 0, - "itemIdList": [] - }, - { - "slot": 10, - "itemId": 305901, - "type": 0, - "itemIdList": [] - } - ], - "main_character": 200052, - "title": 600037 + } } \ No newline at end of file