|
|
|
|
|
|
|
|
|
|
|
import time |
|
|
|
from flask import Flask, request, jsonify |
|
from flask_restx import Api, Resource, fields |
|
|
|
app = Flask(__name__) |
|
api = Api( |
|
app=app, |
|
version="0.0.1", |
|
title="gomoku_server_ui App", |
|
description="Play Gomoku with LightZero Agent, Powered by OpenDILab" |
|
) |
|
|
|
|
|
@app.after_request |
|
def after_request(response): |
|
|
|
response.headers.add('Access-Control-Allow-Origin', '*') |
|
|
|
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') |
|
|
|
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') |
|
return response |
|
|
|
|
|
|
|
name_space = api.namespace('gomoku_server_ui', description='gomoku_server_ui APIs') |
|
|
|
model = api.model( |
|
'gomoku_server_ui params', { |
|
'command': fields.String(required=False, description="Command Field", help="可选参数为:reset, step"), |
|
'argument': fields.Integer(required=False, description="Argument Field", help="如果输入 cmd 是 reset,则 argument 表示 agent type, 如果输入 cmd 是 step,则 argument 表示 [action_x, action_y, agent_type]"), |
|
} |
|
) |
|
|
|
MAX_ENV_NUM = 50 |
|
ENV_TIMEOUT_SECOND = 6000 |
|
|
|
import sys |
|
|
|
from easydict import EasyDict |
|
from zoo.board_games.gomoku.envs.gomoku_env import GomokuEnv |
|
from agent import Agent |
|
|
|
|
|
cfg = EasyDict( |
|
prob_random_agent=0, |
|
board_size=15, |
|
battle_mode='self_play_mode', |
|
channel_last=False, |
|
scale=False, |
|
agent_vs_human=False, |
|
bot_action_type='v1', |
|
prob_random_action_in_bot=0., |
|
check_action_to_connect4_in_agent_v0=False, |
|
render_mode='state_realtime_mode', |
|
replay_path=None, |
|
screen_scaling=9, |
|
alphazero_mcts_ctree=False, |
|
) |
|
env = GomokuEnv(cfg) |
|
obs = env.reset() |
|
agent = Agent() |
|
|
|
envs = {} |
|
envs['127.0.0.1:1'] = {'env': env, 'update_time': time.time()} |
|
|
|
|
|
|
|
from threading import Thread, Lock |
|
|
|
envs_lock = Lock() |
|
|
|
|
|
|
|
def env_monitor(): |
|
while True: |
|
with envs_lock: |
|
cur_time = time.time() |
|
pop_keys = [] |
|
for k, v in envs.items(): |
|
if cur_time - v['update_time'] >= ENV_TIMEOUT_SECOND: |
|
pop_keys.append(k) |
|
for k in pop_keys: |
|
envs.pop(k) |
|
time.sleep(1) |
|
|
|
|
|
|
|
api.env_thread = Thread(target=env_monitor, daemon=True) |
|
api.env_thread.start() |
|
|
|
|
|
|
|
@name_space.route("/", methods=['POST']) |
|
class MainClass(Resource): |
|
|
|
@api.expect(model) |
|
def post(self): |
|
try: |
|
t_start = time.time() |
|
data = request.json |
|
cmd, arg, uid = data['command'], data['argument'], data['uid'] |
|
print("请求来源的IP地址:", request.remote_addr) |
|
ip = request.remote_addr + uid |
|
print("命令、参数、用户ID: ", cmd, arg, uid) |
|
print('envs:', envs) |
|
|
|
|
|
if ip not in envs: |
|
print('ip not in envs') |
|
if cmd == 'reset': |
|
if len(envs) >= MAX_ENV_NUM: |
|
|
|
response = jsonify( |
|
{ |
|
"statusCode": 501, |
|
"status": "No enough env resource, please wait a moment", |
|
} |
|
) |
|
return response |
|
else: |
|
|
|
env = GomokuEnv(cfg) |
|
envs[ip] = {'env': env, 'update_time': time.time()} |
|
else: |
|
|
|
response = jsonify( |
|
{ |
|
"statusCode": 501, |
|
"status": "No response for too long time, please reset the game", |
|
} |
|
) |
|
return response |
|
else: |
|
|
|
env = envs[ip]['env'] |
|
envs[ip]['update_time'] = time.time() |
|
|
|
|
|
if cmd == 'reset': |
|
|
|
observation = env.reset() |
|
agent_type = arg |
|
print('agent type: {}'.format(agent_type)) |
|
if agent_type == -2: |
|
agent_action = env.random_action() |
|
elif agent_type == -1: |
|
agent_action = env.bot_action() |
|
elif agent_type == 0: |
|
agent_action = agent.compute_action(observation) |
|
|
|
observation, reward, done, info = env.step(agent_action) |
|
|
|
agent_action = {'i': int(agent_action // 15), 'j': int(agent_action % 15)} |
|
print('agent action: {}'.format(agent_action)) |
|
|
|
response = jsonify( |
|
{ |
|
"statusCode": 200, |
|
"status": "Execution action", |
|
"result": { |
|
'board': env.board.tolist(), |
|
'action': agent_action, |
|
'done': done, |
|
'info': info, |
|
} |
|
} |
|
) |
|
|
|
elif cmd == 'step': |
|
|
|
data = request.json |
|
action = data.get('argument')[:-1] |
|
print(f'前端发送过来的动作: {action}') |
|
agent_type = data.get('argument')[-1] |
|
print('agent type: {}'.format(agent_type)) |
|
action = action[0] * 15 + action[1] |
|
|
|
observation, reward, done, info = env.step(action) |
|
env.render() |
|
|
|
if not done: |
|
if agent_type == -2: |
|
agent_action = env.random_action() |
|
elif agent_type == -1: |
|
agent_action = env.bot_action() |
|
elif agent_type == 0: |
|
agent_action = agent.compute_action(observation) |
|
|
|
_, _, done, _ = env.step(agent_action) |
|
|
|
print('original agent action: {}'.format(agent_action)) |
|
agent_action = {'i': int(agent_action // 15), 'j': int(agent_action % 15)} |
|
print('agent action: {}'.format(agent_action)) |
|
else: |
|
|
|
agent_action = {'i': -1, 'j': -1} |
|
observation = env.reset() |
|
|
|
|
|
response = { |
|
"statusCode": 200, |
|
"status": "Execution action", |
|
"result": { |
|
'board': None, |
|
'action': agent_action, |
|
'done': done, |
|
} |
|
} |
|
else: |
|
response = jsonify({ |
|
"statusCode": 500, |
|
"status": "Invalid command: {}".format(cmd), |
|
}) |
|
return response |
|
print('backend process time: {}'.format(time.time() - t_start)) |
|
print('current env number: {}'.format(len(envs))) |
|
return response |
|
except Exception as e: |
|
import traceback |
|
print(repr(e)) |
|
print(traceback.format_exc()) |
|
response = jsonify({ |
|
"statusCode": 500, |
|
"status": "Could not execute action", |
|
}) |
|
return response |
|
|