diff --git a/main.py b/main.py index 61a0a9c..7c7ec58 100644 --- a/main.py +++ b/main.py @@ -22,7 +22,7 @@ os.environ['GOOGLE_APPLICATION_CREDENTIALS']="./AI-Adventure-2bb65e3a4e2f.json" from google.cloud import storage from google import cloud import json -from flask import Flask, render_template, request +from flask import Flask, render_template, request, abort storage_client = storage.Client() bucket = storage_client.get_bucket("dungeon-cache") from flask import Response @@ -84,61 +84,65 @@ def generate(prompt): @app.route('/') def root(): return render_template('index.html') - + @app.route('/index.html') def index(): return render_template('index.html') - + @app.route('/about.html') def about(): return render_template('about.html') - - + + def cache_file(seed, prompt_num, choices, response, tag): blob_file_name = "p" + str(prompt_num) + "/seed" + str(seed) + "/" + tag for action in choices: blob_file_name = blob_file_name + str(action) blob = bucket.blob(blob_file_name) - + blob.upload_from_string(response) - + print("File ", blob_file_name, " cached") def retrieve_from_cache(seed, prompt_num, choices, tag): blob_file_name = "p" + str(prompt_num) + "/seed" + str(seed) + "/" + tag - + for action in choices: blob_file_name = blob_file_name + str(action) - + blob = bucket.blob(blob_file_name) - + if blob.exists(storage_client): result = blob.download_as_string().decode("utf-8") print(blob_file_name, " found in cache") else: result = None print(blob_file_name, " not found in cache") - + return result - + @app.route('/generate', methods=['POST']) def story_request(): print("****Generating Story****") seed = request.form["seed"] prompt_num = int(request.form["prompt_num"]) - gen_actions = request.form["actions"] - + gen_actions = request.form["actions"] + + if int(seed) < 0 or int(seed) > 1000: + print("Invalid seed: " + seed) + abort(404) + if gen_actions == "true": - prompt = request.form["prompt"] + prompt = request.form["prompt"] choices = json.loads(request.form["choices"]) print("Getting response for seed ", seed, " prompt_num ", prompt_num, " and choices ", choices) - + action_results = retrieve_from_cache(seed, prompt_num, choices, "choices") - + if action_results is not None: response = action_results else: @@ -147,25 +151,25 @@ def story_request(): response = response.text cache_file(seed, prompt_num, choices, response, "choices") else: - + print("Getting response for seed ", seed, " prompt_num ", prompt_num) result = retrieve_from_cache(seed, prompt_num, [], "story") - + if result is not None: response = result else: response = requests.post(gen_ip + "/generate", data={"actions":"false","seed":seed, "prompt_num":prompt_num}) response=response.text cache_file(seed, prompt_num, [], response, "story") - + print("\nGenerated response is: \n", response) print("") - + return response - + if __name__ == '__main__': app.run(host='0.0.0.0', port=8080) - - - + + + # [START gae_python37_render_template] diff --git a/static/script.js b/static/script.js index 58f2eae..cc76314 100644 --- a/static/script.js +++ b/static/script.js @@ -13,7 +13,7 @@ var should_blink = false var blinkCounter = 0 var action_list = ["You attack", "You tell", "You use", "You go"] var prompt_num = 0 -var seed_max = 100 +var seed_max = 1000 var seed_min = 0 var seed = Math.floor(Math.random() * (+seed_max - +seed_min)) + +seed_min; //var seed = 108 @@ -33,6 +33,7 @@ function checkButtonDisplay() setTimeout(checkButtonDisplay, 1000); console.log("Not mobile device"); document.getElementById('buttons').style.visibility='hidden'; + } } @@ -65,11 +66,14 @@ var StoryTracker = { }, actionWait:function(){ - if(action_waiting == true || typing){ - setTimeout(StoryTracker.actionWait, 2000); - } - else{ - Typer.appendToText(" Generating...") + + if(action_waiting == true){ + if(typing == true || acceptInput == true){ + setTimeout(StoryTracker.actionWait, 5000); + } + else{ + Typer.appendToText(" Generating...") + } } }, @@ -98,8 +102,10 @@ var StoryTracker = { Typer.appendToText("\nWhich action do you choose? ") StoryTracker.action_int = 0 acceptInput = true + if(isMobileDevice(){ setTimeout(checkButtonDisplay, 1000); + } } } @@ -136,7 +142,7 @@ var StoryTracker = { StoryTracker.lastStory = StoryTracker.results[choice_int] StoryTracker.makeActionRequests(StoryTracker.firstStory + StoryTracker.lastStory) action_waiting = true - setTimeout(StoryTracker.actionWait, 2000); + setTimeout(StoryTracker.actionWait, 4000); Typer.appendToText("\n") Typer.appendToText(StoryTracker.lastStory) Typer.appendToText("\n\nOptions:") @@ -147,6 +153,11 @@ var StoryTracker = { Typer.appendToText("\nWhich action do you choose? ") acceptInput = true + + if(isMobileDevice()){ + setTimeout(buttonCheck, 500); + } + } @@ -191,7 +202,6 @@ var Typer={ var rtn= new RegExp("\n", "g") A solution would be to add position: relative for the button. This will move it above the label. $("#console").html(text.replace(rtn,"
")) - window.scrollBy(0,50) } else{ typing = false @@ -239,7 +249,7 @@ function typeWords() { document.onkeypress = function(evt) { - if(acceptInput){ + if(acceptInput && !isMobileDevice()){ evt = evt || window.event var charCode = evt.keyCode || evt.which @@ -260,6 +270,8 @@ document.onkeypress = function(evt) { function onButtonClick(num){ + document.getElementById('buttons').style.visibility='hidden'; + if (acceptInput == true){ acceptInput = false num = String(num) @@ -280,7 +292,7 @@ function start(){ startTyping() Typer.startBlinker() - + } diff --git a/static/style.css b/static/style.css index 33b212b..4009191 100644 --- a/static/style.css +++ b/static/style.css @@ -9,7 +9,7 @@ body { width:80%; margin-left:auto; margin-right:auto; - margin-top:100px; + margin-top:calc(30px + 4.0vh); font-size:14px; background-color: #000; } @@ -79,11 +79,13 @@ a { } button { - border-color: #000 + border-color: #fff; bottom: 40px; color: #fff; + margin-top: 40px; margin-left: 4%; margin-right: 4%; + margin-bottom: 20px; background-color: #111; width: 18%; height: 100px; @@ -93,10 +95,14 @@ button { } +button:focus{ + background-color: #0bc; +} + + /* Add a black background color to the top navigation */ .topnav { background-color: #000; - overflow: hidden; max-width: 800px; width:80%; margin-left:auto; @@ -106,13 +112,14 @@ button { /* Style the links inside the navigation bar */ .topnav a { - font-family: courier, monospace; + font-family: courier, monospace; display: inline-block; color: #0bc; text-align: center; padding: 10px 5px; text-decoration: none; - font-size: 16px; + font-size:calc(12px + 1.0vh ); + min-font-size: } /* Change the color of links on hover */ diff --git a/templates/about.html b/templates/about.html index 087853d..9ba5a66 100644 --- a/templates/about.html +++ b/templates/about.html @@ -10,7 +10,7 @@

About AI Dungeon

- AIDungeon is an AI generated text adventure that uses deep learning to create each adventure. It uses OpenAI's new GPT-2 model, which has 117 million parameters, to generate each story block and possible action. + AI Dungeon is an AI generated text adventure that uses deep learning to create each adventure. It uses OpenAI's new GPT-2 model, which has 117 million parameters, to generate each story block and possible action.

The first couple sentences of AIDungeon and the action verbs are handcrafted, but everything else is not. Each time an option is chosen, the initial prompt, the last story block, and the last action are fed into the neural network. The resulting story and action options are then output by the model.