diff --git a/aiserver.py b/aiserver.py index 781c335a..36b11bdc 100644 --- a/aiserver.py +++ b/aiserver.py @@ -106,6 +106,7 @@ class vars: svowname = "" # Filename that was flagged for overwrite confirm saveow = False # Whether or not overwrite confirm has been displayed genseqs = [] # Temporary storage for generated sequences + recentback = False # Whether Back button was recently used without Submitting or Retrying after useprompt = True # Whether to send the full prompt with every submit action breakmodel = False # For GPU users, whether to use both system RAM and VRAM to conserve VRAM while offering speedup compared to CPU-only bmsupported = False # Whether the breakmodel option is supported (GPT-Neo/GPT-J only, currently) @@ -532,7 +533,7 @@ def do_connect(): #==================================================================# @socketio.on('message') def get_message(msg): - print("{0}Data recieved:{1}{2}".format(colors.GREEN, msg, colors.END)) + print("{0}Data received:{1}{2}".format(colors.GREEN, msg, colors.END)) # Submit action if(msg['cmd'] == 'submit'): if(vars.mode == "play"): @@ -668,6 +669,10 @@ def get_message(msg): vars.worldinfo[msg['data']]["selective"] = True elif(msg['cmd'] == 'wiseloff'): vars.worldinfo[msg['data']]["selective"] = False + elif(msg['cmd'] == 'wiconstanton'): + vars.worldinfo[msg['data']]["constant"] = True + elif(msg['cmd'] == 'wiconstantoff'): + vars.worldinfo[msg['data']]["constant"] = False elif(msg['cmd'] == 'sendwilist'): commitwi(msg['data']) elif(msg['cmd'] == 'aidgimport'): @@ -828,6 +833,7 @@ def actionsubmit(data, actionmode=0): return set_aibusy(1) + vars.recentback = False vars.actionmode = actionmode # "Action" mode @@ -881,13 +887,18 @@ def actionretry(data): return if(vars.aibusy): return - set_aibusy(1) # Remove last action if possible and resubmit - if(len(vars.actions) > 0): - last_key = vars.actions.get_last_key() - vars.actions.pop() - remove_story_chunk(last_key + 1) + if(vars.gamestarted if vars.useprompt else len(vars.actions) > 0): + set_aibusy(1) + if(not vars.recentback and len(vars.actions) != 0 and len(vars.genseqs) == 0): # Don't pop if we're in the "Select sequence to keep" menu or if there are no non-prompt actions + last_key = vars.actions.get_last_key() + vars.actions.pop() + remove_story_chunk(last_key + 1) + vars.genseqs = [] calcsubmit('') + vars.recentback = False + elif(not vars.useprompt): + emit('from_server', {'cmd': 'errmsg', 'data': "Please enable \"Always Add Prompt\" to retry with your prompt."}) #==================================================================# # @@ -896,10 +907,15 @@ def actionback(): if(vars.aibusy): return # Remove last index of actions and refresh game screen - if(len(vars.actions) > 0): + if(len(vars.genseqs) == 0 and len(vars.actions) > 0): last_key = vars.actions.get_last_key() vars.actions.pop() + vars.recentback = True remove_story_chunk(last_key + 1) + elif(len(vars.genseqs) == 0): + emit('from_server', {'cmd': 'errmsg', 'data': "Cannot delete the prompt."}) + else: + vars.genseqs = [] #==================================================================# # Take submitted text and build the text to be given to generator @@ -1515,7 +1531,7 @@ def togglewimode(): # #==================================================================# def addwiitem(): - ob = {"key": "", "keysecondary": "", "content": "", "num": len(vars.worldinfo), "init": False, "selective": False} + ob = {"key": "", "keysecondary": "", "content": "", "num": len(vars.worldinfo), "init": False, "selective": False, "constant": False} vars.worldinfo.append(ob); emit('from_server', {'cmd': 'addwiitem', 'data': ob}, broadcast=True) @@ -1570,6 +1586,7 @@ def commitwi(ar): vars.worldinfo[ob["num"]]["keysecondary"] = ob["keysecondary"] vars.worldinfo[ob["num"]]["content"] = ob["content"] vars.worldinfo[ob["num"]]["selective"] = ob["selective"] + vars.worldinfo[ob["num"]]["constant"] = ob.get("constant", False) # Was this a deletion request? If so, remove the requested index if(vars.deletewi >= 0): del vars.worldinfo[vars.deletewi] @@ -1628,6 +1645,10 @@ def checkworldinfo(txt): # Scan text for matches on WI keys wimem = "" for wi in vars.worldinfo: + if(wi.get("constant", False)): + wimem = wimem + wi["content"] + "\n" + continue + if(wi["key"] != ""): # Split comma-separated keys keys = wi["key"].split(",") @@ -1847,12 +1868,13 @@ def saveRequest(savpath): # Extract only the important bits of WI for wi in vars.worldinfo: - if(wi["key"] != ""): + if(wi["constant"] or wi["key"] != ""): js["worldinfo"].append({ "key": wi["key"], "keysecondary": wi["keysecondary"], "content": wi["content"], - "selective": wi["selective"] + "selective": wi["selective"], + "constant": wi["constant"] }) # Write it @@ -1917,7 +1939,8 @@ def loadRequest(loadpath): "content": wi["content"], "num": num, "init": True, - "selective": wi.get("selective", False) + "selective": wi.get("selective", False), + "constant": wi.get("constant", False) }) num += 1 @@ -2035,7 +2058,8 @@ def importgame(): "content": wi["entry"], "num": num, "init": True, - "selective": wi.get("selective", False) + "selective": wi.get("selective", False), + "constant": wi.get("constant", False) }) num += 1 @@ -2081,7 +2105,8 @@ def importAidgRequest(id): "content": wi["entry"], "num": num, "init": True, - "selective": wi.get("selective", False) + "selective": wi.get("selective", False), + "constant": wi.get("constant", False) }) num += 1 @@ -2114,7 +2139,8 @@ def wiimportrequest(): "content": wi["entry"], "num": num, "init": True, - "selective": wi.get("selective", False) + "selective": wi.get("selective", False), + "constant": wi.get("constant", False) }) num += 1 @@ -2163,13 +2189,17 @@ if __name__ == "__main__": loadsettings() # Start Flask/SocketIO (Blocking, so this must be last method!) - print("{0}Server started!\rYou may now connect with a browser at http://127.0.0.1:5000/{1}".format(colors.GREEN, colors.END)) + #socketio.run(app, host='0.0.0.0', port=5000) if(vars.remote): - from flask_cloudflared import start_cloudflared - start_cloudflared(5000) + from flask_cloudflared import _run_cloudflared + cloudflare = _run_cloudflared(5000) + with open('cloudflare.log', 'w') as cloudflarelog: + cloudflarelog.write("KoboldAI has finished loading and is available in the following link : " + cloudflare) + print(format(colors.GREEN) + "KoboldAI has finished loading and is available in the following link : " + cloudflare + format(colors.END)) socketio.run(app, host='0.0.0.0', port=5000) else: import webbrowser webbrowser.open_new('http://localhost:5000') + print("{0}Server started!\rYou may now connect with a browser at http://127.0.0.1:5000/{1}".format(colors.GREEN, colors.END)) socketio.run(app) diff --git a/fileops.py b/fileops.py index dc5cb66e..7ae96836 100644 --- a/fileops.py +++ b/fileops.py @@ -59,14 +59,23 @@ def getdirpath(dir, title): #==================================================================# def getstoryfiles(): list = [] - for file in listdir(getcwd()+"/stories"): + for file in listdir(path.dirname(path.realpath(__file__))+"/stories"): if file.endswith(".json"): ob = {} ob["name"] = file.replace(".json", "") - f = open(getcwd()+"/stories/"+file, "r") - js = json.load(f) + f = open(path.dirname(path.realpath(__file__))+"/stories/"+file, "r") + try: + js = json.load(f) + except: + print(f"Browser loading error: {file} is malformed or not a JSON file.") + f.close() + continue f.close() - ob["actions"] = len(js["actions"]) + try: + ob["actions"] = len(js["actions"]) + except TypeError: + print(f"Browser loading error: {file} has incorrect format.") + continue list.append(ob) return list @@ -74,4 +83,4 @@ def getstoryfiles(): # Returns True if json file exists with requested save name #==================================================================# def saveexists(name): - return path.exists(getcwd()+"/stories/"+name+".json") \ No newline at end of file + return path.exists(path.dirname(path.realpath(__file__))+"/stories/"+name+".json") diff --git a/requirements.txt b/requirements.txt index a17ea08f..40f66af4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -transformers == 4.5.1 +git+https://github.com/finetuneanon/transformers@gpt-neo-localattention3-rp-b tensorflow-gpu Flask == 1.1.2 Flask-SocketIO == 5.0.1 diff --git a/static/application.js b/static/application.js index 6de2a044..185c7448 100644 --- a/static/application.js +++ b/static/application.js @@ -189,13 +189,14 @@ function addWiLine(ob) { \ \ \ -
\ +
\ \ \ \ + \
\
\ - \ + \
\
\ \ @@ -209,10 +210,11 @@ function addWiLine(ob) { \ \
\ -
\ +
\ \ \ \ + \
\
\ \ @@ -239,13 +241,14 @@ function addWiLine(ob) { \ \
\ -
\ +
\ \ \ \ + \
\
\ - \ + \
\
\ \ @@ -258,6 +261,18 @@ function addWiLine(ob) { }); } // Assign actions to other elements + wientry_onfocus = function () { + $("#constant-key-"+ob.num).addClass("constant-key-icon-clickthrough"); + } + wientry_onfocusout = function () { + $("#constant-key-"+ob.num).removeClass("constant-key-icon-clickthrough"); + } + $("#wikey"+ob.num).on("focus", wientry_onfocus); + $("#wikeyprimary"+ob.num).on("focus", wientry_onfocus); + $("#wikeysecondary"+ob.num).on("focus", wientry_onfocus); + $("#wikey"+ob.num).on("focusout", wientry_onfocusout); + $("#wikeyprimary"+ob.num).on("focusout", wientry_onfocusout); + $("#wikeysecondary"+ob.num).on("focusout", wientry_onfocusout); $("#btn_wican"+ob.num).on("click", function () { hideWiDeleteConfirm(ob.num); }); @@ -270,10 +285,20 @@ function addWiLine(ob) { $("#btn_wiseloff"+ob.num).on("click", function () { disableWiSelective(ob.num); }); + $("#constant-key-"+ob.num).on("click", function () { + element = $("#constant-key-"+ob.num); + if(element.hasClass("constant-key-icon-enabled")) { + socket.send({'cmd': 'wiconstantoff', 'data': ob.num}); + element.removeClass("constant-key-icon-enabled") + } else { + socket.send({'cmd': 'wiconstanton', 'data': ob.num}); + element.addClass("constant-key-icon-enabled"); + } + }); } function expandWiLine(num) { - show([$("#wikey"+num), $("#wientry"+num), $("#btn_wiselon"+num)]); + show([$("#wikey"+num), $("#wientry"+num), $("#constant-key-"+num), $("#btn_wiselon"+num)]); $("#btn_wi"+num).html("X"); $("#btn_wi"+num).off(); // Tell server the WI entry was initialized @@ -297,6 +322,7 @@ function enableWiSelective(num) { hide([$("#btn_wiselon"+num), $("#wikey"+num)]); // Tell server the WI entry is now selective socket.send({'cmd': 'wiselon', 'data': num}); + $("#wikeyprimary"+num).val($("#wikey"+num).val()); show([$("#wikeyprimary"+num), $("#wikeysecondary"+num), $("#btn_wiseloff"+num)]); } @@ -304,6 +330,7 @@ function disableWiSelective(num) { hide([$("#btn_wiseloff"+num), $("#wikeyprimary"+num), $("#wikeysecondary"+num)]); // Tell server the WI entry is now non-selective socket.send({'cmd': 'wiseloff', 'data': num}); + $("#wikey"+num).val($("#wikeyprimary"+num).val()); show([$("#btn_wiselon"+num), $("#wikey"+num)]); } @@ -436,11 +463,12 @@ function returnWiList(ar) { var list = []; var i; for(i=0; i .constant-key-icon { + opacity: 40%; +} + +.constant-key-icon:hover { + opacity: 65%; + cursor: pointer; +} + +.constant-key-icon-enabled { + color: #3bf723; + opacity: 65% +} + +*:hover > .constant-key-icon-enabled { + opacity: 65%; +} + +.constant-key-icon-enabled:hover { + opacity: 100% +} + +.constant-key-icon-clickthrough { + opacity: 0% !important; + pointer-events: none; +} + +.constant-key-icon-clickthrough.constant-key-icon-enabled { + opacity: 35% !important; +} + .loadlistheader { padding-left: 10px; display: grid; diff --git a/static/open-iconic-bootstrap.min.css b/static/open-iconic-bootstrap.min.css new file mode 100644 index 00000000..a7012e57 --- /dev/null +++ b/static/open-iconic-bootstrap.min.css @@ -0,0 +1,24 @@ +/*! + * The MIT License (MIT) + * + * Copyright (c) 2014 Waybury + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +@font-face{font-family:Icons;src:url(open-iconic.eot);src:url(open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(open-iconic.woff) format('woff'),url(open-iconic.ttf) format('truetype'),url(open-iconic.otf) format('opentype'),url(open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'} \ No newline at end of file diff --git a/static/open-iconic.woff b/static/open-iconic.woff new file mode 100644 index 00000000..f9309988 Binary files /dev/null and b/static/open-iconic.woff differ diff --git a/templates/index.html b/templates/index.html index 196b6038..085d9245 100644 --- a/templates/index.html +++ b/templates/index.html @@ -13,6 +13,7 @@ +