diff --git a/README.md b/README.md index c155884..ad1c8b9 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# Keys \ No newline at end of file +#AIDungeon Code \ No newline at end of file diff --git a/__pycache__/generator.cpython-36.pyc b/__pycache__/generator.cpython-36.pyc new file mode 100644 index 0000000..a0f7f3b Binary files /dev/null and b/__pycache__/generator.cpython-36.pyc differ diff --git a/__pycache__/utils.cpython-36.pyc b/__pycache__/utils.cpython-36.pyc index a29c2e3..a0806d4 100644 Binary files a/__pycache__/utils.cpython-36.pyc and b/__pycache__/utils.cpython-36.pyc differ diff --git a/cortex.sh b/cortex/cortex.sh similarity index 100% rename from cortex.sh rename to cortex/cortex.sh diff --git a/cortex.yaml b/cortex/cortex.yaml similarity index 100% rename from cortex.yaml rename to cortex/cortex.yaml diff --git a/cortex/encoder.py b/cortex/encoder.py new file mode 100644 index 0000000..ce76006 --- /dev/null +++ b/cortex/encoder.py @@ -0,0 +1,129 @@ +# This file includes code which was modified from https://github.com/openai/gpt-2 + +import tensorflow as tf +import os +import json +import regex as re +from functools import lru_cache +import requests +import boto3 + + +@lru_cache() +def bytes_to_unicode(): + bs = ( + list(range(ord("!"), ord("~") + 1)) + + list(range(ord("¡"), ord("¬") + 1)) + + list(range(ord("®"), ord("ÿ") + 1)) + ) + cs = bs[:] + n = 0 + for b in range(2 ** 8): + if b not in bs: + bs.append(b) + cs.append(2 ** 8 + n) + n += 1 + cs = [chr(n) for n in cs] + return dict(zip(bs, cs)) + + +def get_pairs(word): + pairs = set() + prev_char = word[0] + for char in word[1:]: + pairs.add((prev_char, char)) + prev_char = char + return pairs + + +class Encoder: + def __init__(self, encoder, bpe_merges, errors="replace"): + self.encoder = encoder + self.decoder = {v: k for k, v in self.encoder.items()} + self.errors = errors + self.byte_encoder = bytes_to_unicode() + self.byte_decoder = {v: k for k, v in self.byte_encoder.items()} + self.bpe_ranks = dict(zip(bpe_merges, range(len(bpe_merges)))) + self.cache = {} + self.pat = re.compile( + r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""" + ) + + def bpe(self, token): + if token in self.cache: + return self.cache[token] + word = tuple(token) + pairs = get_pairs(word) + + if not pairs: + return token + + while True: + bigram = min(pairs, key=lambda pair: self.bpe_ranks.get(pair, float("inf"))) + if bigram not in self.bpe_ranks: + break + first, second = bigram + new_word = [] + i = 0 + while i < len(word): + try: + j = word.index(first, i) + new_word.extend(word[i:j]) + i = j + except: + new_word.extend(word[i:]) + break + + if word[i] == first and i < len(word) - 1 and word[i + 1] == second: + new_word.append(first + second) + i += 2 + else: + new_word.append(word[i]) + i += 1 + new_word = tuple(new_word) + word = new_word + if len(word) == 1: + break + else: + pairs = get_pairs(word) + word = " ".join(word) + self.cache[token] = word + return word + + def encode(self, text): + bpe_tokens = [] + for token in re.findall(self.pat, text): + token = "".join(self.byte_encoder[b] for b in token.encode("utf-8")) + bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(" ")) + return bpe_tokens + + def decode(self, tokens): + text = "".join([self.decoder[token] for token in tokens]) + text = bytearray([self.byte_decoder[c] for c in text]).decode("utf-8", errors=self.errors) + return text + + +def get_encoder(): + s3 = boto3.client("s3") + encoder = json.load( + s3.get_object(Bucket="cortex-examples", Key="gpt-2/774M/encoder.json")["Body"] + ) + bpe_data = ( + s3.get_object(Bucket="cortex-examples", Key="gpt-2/774M/vocab.bpe")["Body"] + .read() + .decode("utf-8") + ) + bpe_merges = [tuple(merge_str.split()) for merge_str in bpe_data.split("\n")[1:-1]] + return Encoder(encoder=encoder, bpe_merges=bpe_merges) + + +encoder = get_encoder() + + +def pre_inference(sample, metadata): + context = encoder.encode(sample["text"]) + return {"context": [context]} + + +def post_inference(prediction, metadata): + return {encoder.decode(prediction["response"]["sample"])} diff --git a/generator.py b/generator.py index ac1e8b0..4e2576a 100644 --- a/generator.py +++ b/generator.py @@ -8,6 +8,7 @@ from tensorflow.contrib import predictor import gpt2.src.sample as sample import gpt2.src.encoder as encoder from utils import * +import pdb pos_action_starts = ["You attack", "You tell", "You use", "You go"] @@ -24,7 +25,9 @@ class StoryGenerator(): self.enc = encoder.get_encoder(model_path) hparams = model.default_hparams() with open(os.path.join(model_path, 'hparams.json')) as f: - hparams.override_from_dict(json.load(f)) + hparams.override_from_dict(json.load(f)) + + pdb.set_trace() self.context = tf.placeholder(tf.int32, [batch_size, None]) np.random.seed(seed) @@ -38,8 +41,7 @@ class StoryGenerator(): saver = tf.train.Saver() ckpt = tf.train.latest_checkpoint(model_path) saver.restore(self.sess, ckpt) - - + def generate(self, prompt): context_tokens = self.enc.encode(prompt) out = self.sess.run(self.output, feed_dict={ @@ -72,7 +74,6 @@ class StoryGenerator(): action_result = story_replace(action_result) action = first_sentence(action) - return action, action_result @@ -107,31 +108,12 @@ def save_model(): tf.saved_model.simple_save(sess, "./saved2", inputs={"context": context}, outputs={"output": output}) - -def generate_gpu_config(memory_fraction): - config = tf.ConfigProto() - config.gpu_options.allow_growth = True - config.gpu_options.per_process_gpu_memory_fraction = memory_fraction - return config - -def run_interactive(): - pass - - def load_model(): # Set your memory fraction equal to a value less than 1, 0.6 is a good starting point. # If no fraction is defined, the tensorflow algorithm may run into gpu out of memory problems. fraction = 0.6 - config = config=generate_gpu_config(fraction) path_to_graph = "./saved" - #tf.saved_model.loader.load( - # session, - # [tf.saved_model.tag_constants.SERVING], - # path_to_graph) - - #output = session.graph.get_tensor_by_name('output:0') - #context = session.graph.get_tensor_by_name('context:0') model_path = 'gpt2/models/117M' enc = encoder.get_encoder(model_path) diff --git a/gpt2/__pycache__/__init__.cpython-36.pyc b/gpt2/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..4421449 Binary files /dev/null and b/gpt2/__pycache__/__init__.cpython-36.pyc differ diff --git a/pytorch_version.py b/gpt2/pytorch_generator.py similarity index 100% rename from pytorch_version.py rename to gpt2/pytorch_generator.py diff --git a/gpt2/src/__pycache__/encoder.cpython-36.pyc b/gpt2/src/__pycache__/encoder.cpython-36.pyc index 87795a6..cf5999a 100644 Binary files a/gpt2/src/__pycache__/encoder.cpython-36.pyc and b/gpt2/src/__pycache__/encoder.cpython-36.pyc differ diff --git a/gpt2/src/__pycache__/model.cpython-36.pyc b/gpt2/src/__pycache__/model.cpython-36.pyc new file mode 100644 index 0000000..8ef3bed Binary files /dev/null and b/gpt2/src/__pycache__/model.cpython-36.pyc differ diff --git a/gpt2/src/__pycache__/sample.cpython-36.pyc b/gpt2/src/__pycache__/sample.cpython-36.pyc new file mode 100644 index 0000000..7c9ca06 Binary files /dev/null and b/gpt2/src/__pycache__/sample.cpython-36.pyc differ diff --git a/main.py b/main.py index 8f327bc..f1dd7a5 100644 --- a/main.py +++ b/main.py @@ -1,20 +1,6 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# [START gae_python37_render_template] import datetime from flask import g +from flask import session import os import googleapiclient.discovery from utils import * @@ -35,6 +21,7 @@ phrases = [" You attack", " You use", " You tell", " You go"] prompts = ["You enter a dungeon with your trusty sword and shield. You are searching for the evil necromancer who killed your family. You've heard that he resides at the bottom of the dungeon, guarded by legions of the undead. You enter the first door and see"] continuing_prompts = ["You are in a dungeon with your sword and shield. You are on a quest to defeat the necromancer. This dungeon is full of zombie and skeletons."] app = Flask(__name__) +app.secret_key = '#d\xe0\xd1\xfb\xee\xa4\xbb\xd0\xf0/e)\xb5g\xdd<`\xc7\xa5\xb0-\xb8d0S' # Encoder Info encoder_path='gpt2/models/117M' @@ -49,8 +36,7 @@ storage_client = storage.Client() bucket = storage_client.get_bucket("dungeon-cache") # Local generator functionality -RUN_LOCAL = True -session = None +RUN_LOCAL = False local_generator = None def get_local_generator(): if "gen" not in g: @@ -134,7 +120,6 @@ def root(): data = {'seed': seed} return render_template('index.html', data=data) - @app.route('/') def rootseed(seed): if seed == "": @@ -142,6 +127,7 @@ def rootseed(seed): else: seed = int(seed) data = {'seed': seed} + session["seed"] = seed return render_template('index.html', data=data) @app.route('/index.html') @@ -192,15 +178,17 @@ def story_request(): prompt_num = int(request.form["prompt_num"]) gen_actions = request.form["actions"] + print("Session Seed is ", session["seed"]) + if int(seed) < 0 or int(seed) > 100: - print("Invalid seed: " + seed) + #print("Invalid seed: " + seed) abort(404) if gen_actions == "true": #prompt = request.form["prompt"] choices = json.loads(request.form["choices"]) - print("Getting response for seed ", seed, " prompt_num ", prompt_num, " and choices ", choices) + #print("Getting response for seed ", seed, " prompt_num ", prompt_num, " and choices ", choices) action_results = retrieve_from_cache(seed, prompt_num, choices, "choices") @@ -209,13 +197,13 @@ def story_request(): else: last_action_result = request.form["last_action_result"] prompt = continuing_prompts[prompt_num] + last_action_result - print("\n\nAction prompt is \n ", prompt) + #print("\n\nAction prompt is \n ", prompt) action_results = [generate_action_result(prompt, phrase, local=RUN_LOCAL) for phrase in phrases] response = json.dumps(action_results) cache_file(seed, prompt_num, choices, response, "choices") else: - print("Getting response for seed ", seed, " prompt_num ", prompt_num) + #print("Getting response for seed ", seed, " prompt_num ", prompt_num) result = retrieve_from_cache(seed, prompt_num, [], "story") if result is not None: @@ -225,68 +213,10 @@ def story_request(): response = generate_story_block(prompt, local=RUN_LOCAL) cache_file(seed, prompt_num, [], response, "story") - print("\nGenerated response is: \n", response) - print("") + #print("\nGenerated response is: \n", response) + #print("") return response - - -def generate_cache(): - - start_seed = int(sys.argv[1]) - end_seed = int(sys.argv[2]) - - # Generate story sections - prompt_num = 0 - action_queue = [] - prompt = prompts[prompt_num] - for seed in range(start_seed,end_seed): - result = retrieve_from_cache(seed, prompt_num, [], "story") - if result is not None: - response = result - else: - prompt = prompts[prompt_num] - #print("\n Story prompt is ", prompt) - response = generate_story_block(prompt) - #print("\n Story response is ", response) - cache_file(seed, prompt_num, [], response, "story") - - action_queue.append([seed,0,[],response]) - - while(True): - - next_gen = action_queue.pop(0) - seed = next_gen[0] - prompt_num = next_gen[1] - choices = next_gen[2] - last_action_result = next_gen[3] - - action_results = retrieve_from_cache(seed, prompt_num, choices, "choices") - - if action_results is not None: - response = action_results - - else: - if len(choices) is 0: - prompt = prompts[prompt_num] + last_action_result - else: - prompt = continuing_prompts[prompt_num] + last_action_result - #print("\n\n Action prompt is \n ", prompt) - action_results = [generate_action_result(prompt, phrase) for phrase in phrases] - response = json.dumps(action_results) - - #print("\n\n Action - cache_file(seed, prompt_num, choices, response, "choices") - - un_jsoned = json.loads(response) - for j in range(4): - new_choices = choices[:] - new_choices.append(j) - action_queue.append([seed, 0, new_choices, un_jsoned[j][1]]) if __name__ == '__main__': - app.run(host='0.0.0.0', port=8080) - - - -# [START gae_python37_render_template] + app.run(host='0.0.0.0', port=8080) \ No newline at end of file diff --git a/generate.sh b/other/generate.sh similarity index 100% rename from generate.sh rename to other/generate.sh diff --git a/other/generate_cache.py b/other/generate_cache.py new file mode 100644 index 0000000..f4a057a --- /dev/null +++ b/other/generate_cache.py @@ -0,0 +1,51 @@ +def generate_cache(): + start_seed = int(sys.argv[1]) + end_seed = int(sys.argv[2]) + + # Generate story sections + prompt_num = 0 + action_queue = [] + prompt = prompts[prompt_num] + for seed in range(start_seed, end_seed): + result = retrieve_from_cache(seed, prompt_num, [], "story") + if result is not None: + response = result + else: + prompt = prompts[prompt_num] + # print("\n Story prompt is ", prompt) + response = generate_story_block(prompt) + # print("\n Story response is ", response) + cache_file(seed, prompt_num, [], response, "story") + + action_queue.append([seed, 0, [], response]) + + while (True): + + next_gen = action_queue.pop(0) + seed = next_gen[0] + prompt_num = next_gen[1] + choices = next_gen[2] + last_action_result = next_gen[3] + + action_results = retrieve_from_cache(seed, prompt_num, choices, "choices") + + if action_results is not None: + response = action_results + + else: + if len(choices) is 0: + prompt = prompts[prompt_num] + last_action_result + else: + prompt = continuing_prompts[prompt_num] + last_action_result + # print("\n\n Action prompt is \n ", prompt) + action_results = [generate_action_result(prompt, phrase) for phrase in phrases] + response = json.dumps(action_results) + + # print("\n\n Action + cache_file(seed, prompt_num, choices, response, "choices") + + un_jsoned = json.loads(response) + for j in range(4): + new_choices = choices[:] + new_choices.append(j) + action_queue.append([seed, 0, new_choices, un_jsoned[j][1]]) \ No newline at end of file diff --git a/story_prompts.yaml b/other/story_prompts.yaml similarity index 100% rename from story_prompts.yaml rename to other/story_prompts.yaml diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..b58323e Binary files /dev/null and b/static/favicon.ico differ diff --git a/templates/index.html b/templates/index.html index 8800ab6..426ca77 100644 --- a/templates/index.html +++ b/templates/index.html @@ -13,7 +13,8 @@ ga('send', 'pageview'); - Dungeon + + AI Dungeon