text: #!/usr/bin/env python3
  
  import argparse
  import numpy
  import importlib
  import os
  import yaml
  
  from utils.utils import ALGOS, create_test_env, get_saved_hyperparams
  from stable_baselines3.common.env_util import make_vec_env
  from stable_baselines3.common.utils import set_random_seed
  
  # Parse arguments
  
  parser = argparse.ArgumentParser()
  parser.add_argument("--env", required=True,
                      help="name of the environment to be run (REQUIRED)")
  parser.add_argument("--exp-id",
                      help="Experiment ID (default: 0: latest, -1: no exp folder)",
                      default=0, type=int)
  parser.add_argument("--algo", help="RL Algorithm", default="ppo", type=str,
                      required=False, choices=list(ALGOS.keys()))
  parser.add_argument("--seed", type=int, default=0,
                      help="random seed (default: 0)")
  parser.add_argument("-n_ep", "--n-episodes", help="number of episodes",
                      default=1, type=int)
  parser.add_argument("-n", "--n-timesteps", help="number of timesteps",
                      default=300, type=int)
  parser.add_argument("--pause", type=float, default=0.1,
                      help="pause duration between two consequent actions of the agent (default: 0.1)")
  parser.add_argument("--n-envs", help="number of environments",
                      default=1, type=int)
  parser.add_argument(
          "--gym-packages",
          type=str,
          nargs="+",
          default=[],
          help="Additional external Gym environment package modules to import (e.g. gym_minigrid)",
      )
  parser.add_argument(
          "--load-best", action="store_true", default=False, help="Load best model instead of last model if available"
      )
  parser.add_argument(
          "--load-checkpoint",
          type=int,
          help="Load checkpoint instead of last model if available, "
          "you must pass the number of timesteps corresponding to it",
      )
  parser.add_argument(
          "--load-last-checkpoint",
          action="store_true",
          default=False,
          help="Load last checkpoint instead of last model if available",
      )
  args = parser.parse_args()
  
  # Load environment
  for env_module in args.gym_packages:
      importlib.import_module(env_module)
  
  folder = 'logs'
  env_id = args.env
  log_path = os.path.join(folder, args.algo, f"{args.env}_{args.exp_id}")
  
  for ext in ["zip"]:
      model_path = os.path.join(log_path, f"{env_id}.{ext}")
  
  if args.load_best:
      model_path = os.path.join(log_path, "best_model.zip")
  
  if args.load_checkpoint is not None:
      model_path = os.path.join(log_path, f"rl_model_{args.load_checkpoint}_steps.zip")
  
  if args.load_last_checkpoint:
      checkpoints = glob.glob(os.path.join(log_path, "rl_model_*_steps.zip"))
      if len(checkpoints) == 0:
          raise ValueError(f"No checkpoint found for {algo} on {env_id}, path: {log_path}")
  
      def step_count(checkpoint_path: str) -> int:
          # path follow the pattern "rl_model_*_steps.zip", we count from the back to ignore any other _ in the path
          return int(checkpoint_path.split("_")[-2])
  
      checkpoints = sorted(checkpoints, key=step_count)
      model_path = checkpoints[-1]
  
  stats_path = os.path.join(log_path, env_id)
  hyperparams, stats_path = get_saved_hyperparams(stats_path, norm_reward=False, test_mode=True)
  env_kwargs = {}
  
  args_path = os.path.join(log_path, env_id, "args.yml")
  if os.path.isfile(args_path):
      with open(args_path, "r") as f:
          loaded_args = yaml.load(f, Loader=yaml.UnsafeLoader)  # pytype: disable=module-attr
          if loaded_args["env_kwargs"] is not None:
              env_kwargs = loaded_args["env_kwargs"]
  
  set_random_seed(args.seed)
  
  env = create_test_env(
          env_id,
          n_envs=args.n_envs,
          stats_path=stats_path,
          seed=args.seed,
          log_dir=None,
          should_render=False,
          hyperparams=hyperparams,
          env_kwargs=env_kwargs,
      )
  
  kwargs = dict(seed=args.seed)
  kwargs.update(dict(buffer_size=1))
  
  print("Environment loaded\n")
  
  # Load agent
  custom_objects = {}
  model = ALGOS[args.algo].load(model_path, env=env,
                                custom_objects=custom_objects, **kwargs)
  # model.policy.eval()
  print("Model loaded\n")
  
  obs = env.reset()
  
  # Run the agent
  
  from array2gif import write_gif
  frames = []
  
  # Create a window to view the environment
  env.render('human')
  
  state = None
  for episode in range(args.n_episodes):
      obs = env.reset()
  
      for episode in range(args.n_timesteps):
          env.render('human')
          frames.append(numpy.moveaxis(env.render("rgb_array"), 2, 0))
  
          action, state = model.predict(obs, state=state, deterministic=True)
          obs, reward, done, _ = env.step(action)
  
          if done:
              break
  
      if env.get_attr("window")[0].close:
          break
  
  print("Saving gif... ", end="")
  write_gif(numpy.array(frames), "gif_{}_{}_{}.gif".format(args.env, args.exp_id, args.seed), fps=1/args.pause)
  print("Done.")
  