working on api + frontend; todo: switch corpus

This commit is contained in:
voje 2019-03-24 02:08:22 +01:00
parent 8c6d6ab8ab
commit bc4e8e2cf1
12 changed files with 149 additions and 55 deletions

View File

@ -12,7 +12,7 @@ $ git submodule update
### Database (2 containers) ### Database (2 containers)
Set db admin, user, pass, etc in Makefile. Set db admin, user, pass, etc in 'Makefile'.
Spin up the database service and create users: Spin up the database service and create users:
```bash ```bash
# $ make database-clean # opt # $ make database-clean # opt
@ -38,11 +38,15 @@ $ make python-env-install
$ make fill-database $ make fill-database
``` ```
If all goes well, we should be able to inspect the database on `0.0.0.0:8087`. If all goes well, we should be able to inspect the database, filled with corpora, on `0.0.0.0:8087`.
### Flask backend (1 container) ### Flask backend (1 container)
Input: see Database Relies heavily on the database. Set that up first.
```bash
# $ make backend=dev # development
$ make backend-prod
```
API endpoints: API endpoints:
@ -53,17 +57,13 @@ API endpoints:
### Vue frontend (1 container) ### Vue frontend (1 container)
Relies on Flask backend.
Before running `make`, you might need to set the correct api address.
Check `./src/frontend_vue/config/config_prod.json`.
bash
```
# $ make frontend-dev # development
$ make frontend-prod
```
* ngnix server App available on: `http://0.0.0.0:8080`.
## Deployment
Preflight:
* get up DB
* prepare DB
Flight:
* start backend
* start frontend

View File

@ -26,9 +26,13 @@ from pathlib import Path
from pymongo import MongoClient from pymongo import MongoClient
import argparse import argparse
CORPORA = ["ssj", "kres"]
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
app = Flask(__name__) app = Flask(__name__)
app_index = {c: {} for c in CORPORA}
# when running vuejs via webpack # when running vuejs via webpack
# CORS(app) # CORS(app)
CORS(app, resources={r"/api/*": { CORS(app, resources={r"/api/*": {
@ -54,20 +58,18 @@ def home(pathname):
return redirect(url_for("index"), code=302) return redirect(url_for("index"), code=302)
# @app.route("/api/words/<corpus>")
# def api_words(corpus):
@app.route("/api/words") @app.route("/api/words")
def api_words(): def api_words():
return json.dumps({ return json.dumps({
"sorted_words": vallex.sorted_words, "sorted_words": app_index["ssj"]["words"], # todo - make corpus as arg
"has_se": vallex.has_se
}) })
@app.route("/api/functors") @app.route("/api/functors")
def api_functors(): def api_functors():
res = [] # return array ([functor, len])
for key in sorted(vallex.functors_index.keys()): return json.dumps(app_index["ssj"]["functors"])
res.append((key, len(vallex.functors_index[key])))
return json.dumps(res)
@app.route("/api/register", methods=["POST"]) @app.route("/api/register", methods=["POST"])
@ -376,6 +378,60 @@ def api_senses_update():
vallex.db["v2_sense_map"].insert(data) vallex.db["v2_sense_map"].insert(data)
return "OK" return "OK"
def prepare_db():
def helper_tid_to_token(tid, tokens):
for t in tokens:
if t["tid"] == tid:
return t
return None
# update entries (add headwords and fuctors for indexing)
for corpus in ["ssj", "kres"]:
for e in valdb[corpus].find({}):
#! hw_tids are not array ids
hw_tids = list(set([x["from"] for x in e["srl_links"]]))
hw_tokens = [helper_tid_to_token(tid, e["tokens"]) for tid in hw_tids]
headwords = [(t["lemma"] if t["msd"][0] == "G" else t["lemma"] + "_") for t in hw_tokens]
e["headwords"] = headwords
functors = list(set([x["afun"] for x in e["srl_links"]]))
e["headwords"] = headwords
e["functors"] = functors
valdb[corpus].save(e)
# create app_index (used in frontend, left side word index)
for corpus in CORPORA:
res_hws = {}
res_fns = {}
for e in valdb[corpus].find({}):
for hw in e["headwords"]:
if hw in res_hws:
res_hws[hw] += 1
else:
res_hws[hw] = 1
for fn in e["functors"]:
if fn in res_fns:
res_fns[fn] += 1
else:
res_fns[fn] = 1
alphabetical = {}
for k, e in res_hws.items():
fst = k[0].lower()
if fst in alphabetical:
alphabetical[fst].append((k, e))
else:
alphabetical[fst] = [(k, e)]
for k, e in alphabetical.items():
alphabetical[k] = sorted(e, key=lambda x: x[0])
app_index[corpus]["words"] = alphabetical
functors = [(k, e) for (k, e) in res_fns.items()]
functors = sorted(functors, key=lambda x: x[0])
app_index[corpus]["functors"] = functors
if __name__ == "__main__": if __name__ == "__main__":
print("Starting app.py main()") print("Starting app.py main()")
@ -407,8 +463,10 @@ if __name__ == "__main__":
) )
valdb = client.valdb valdb = client.valdb
if config["prepare_db"]:
prepare_db()
# log.info("[*] Starting app.py with config:\n%s".format(config)) # log.info("[*] Starting app.py with config:\n%s".format(config))
log.info("[*] Starting app.py with config:\n{}".format(config)) log.info("[*] Starting app.py with config:\n{}".format(config))
sys.exit()
app.run(host=str(config["host"]), port=int(config["port"])) app.run(host=str(config["host"]), port=int(config["port"]))

View File

@ -3,4 +3,5 @@ debug: True
port: 5004 port: 5004
host: localhost host: localhost
logfile: "/var/log/valency_backend.log" logfile: "/var/log/valency_backend.log"
prepare_db: True
--- ---

View File

@ -1,3 +1,3 @@
{ {
"api_addr": "http://193.2.76.103:5004" "api_addr": "http://0.0.0.0:5004"
} }

View File

@ -1,3 +1,3 @@
{ {
"api_addr": "http://localhost:5004" "api_addr": "http://0.0.0.0:5004"
} }

View File

@ -1,3 +1,3 @@
{ {
"api_addr": "http://193.2.76.103:5004" "api_addr": "0.0.0.0:5004"
} }

View File

@ -116,7 +116,7 @@
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true, "dev": true,
"requires": { "requires": {
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
@ -2979,9 +2979,9 @@
} }
}, },
"esprima": { "esprima": {
"version": "2.7.3", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true "dev": true
}, },
"esrecurse": { "esrecurse": {
@ -5128,13 +5128,13 @@
"dev": true "dev": true
}, },
"js-yaml": { "js-yaml": {
"version": "3.7.0", "version": "3.13.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz",
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"argparse": "^1.0.7", "argparse": "^1.0.7",
"esprima": "^2.6.0" "esprima": "^4.0.0"
} }
}, },
"jsesc": { "jsesc": {
@ -5255,9 +5255,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.10", "version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
}, },
"lodash.camelcase": { "lodash.camelcase": {
"version": "4.3.0", "version": "4.3.0",
@ -9679,6 +9679,24 @@
"mkdirp": "~0.5.1", "mkdirp": "~0.5.1",
"sax": "~1.2.1", "sax": "~1.2.1",
"whet.extend": "~0.9.9" "whet.extend": "~0.9.9"
},
"dependencies": {
"esprima": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
"integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
"dev": true
},
"js-yaml": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^2.6.0"
}
}
} }
}, },
"tapable": { "tapable": {

View File

@ -10,7 +10,7 @@
<div class="my-home container-fluid"> <div class="my-home container-fluid">
<div class="row"> <div class="row">
<div id="serach" class="col-sm-2 border-right fill"> <div id="serach" class="col-sm-2 border-right fill">
<LWords v-if="navSS()"></LWords> <LWords v-if="this.$root.store.selIndex === 'words'"></LWords>
<LFunctors v-else></LFunctors> <LFunctors v-else></LFunctors>
</div> </div>
<div class="col-sm-10"> <div class="col-sm-10">
@ -35,11 +35,6 @@ export default {
LFunctors: LFunctors, LFunctors: LFunctors,
MainDispl: MainDispl, MainDispl: MainDispl,
}, },
methods: {
navSS: function () {
return this.$root.storeGet("navSS") === "words"
}
}
} }
</script> </script>

View File

@ -30,7 +30,7 @@ export default {
this.$http.get(this.$root.storeGet("api_addr") + "/api/words") this.$http.get(this.$root.storeGet("api_addr") + "/api/words")
.then(function(response) { .then(function(response) {
component.$root.store.api_error = null component.$root.store.api_error = null
component.$root.store.has_se = response.data["has_se"] // component.$root.store.has_se = response.data["has_se"]
component.letters = response.data["sorted_words"] component.letters = response.data["sorted_words"]
}) })
.catch(function(error) { .catch(function(error) {

View File

@ -32,7 +32,7 @@
<tr> <tr>
<label class="radio-inline"><input value="one" v-model="$root.store.radio" v-on:change="reload()" checked="" type="radio" name="optradio">posamezne povedi</label>&nbsp;&nbsp; <label class="radio-inline"><input value="one" v-model="$root.store.radio" v-on:change="reload()" checked="" type="radio" name="optradio">posamezne povedi</label>&nbsp;&nbsp;
<label class="radio-inline"><input value="two" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">skupne udeleženske vloge</label>&nbsp;&nbsp; <label class="radio-inline"><input value="two" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">skupne udeleženske vloge</label>&nbsp;&nbsp;
<label v-if="this.$root.store.navSS === 'words'" class="radio-inline"><input value="three" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">po meri</label> <label v-if="this.$root.store.selIndex === 'words'" class="radio-inline"><input value="three" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">po meri</label>
</tr> </tr>
</table> </table>
</div> </div>
@ -206,7 +206,7 @@ export default {
reload: function () { reload: function () {
this.state = "loading" this.state = "loading"
this.sentences = {} this.sentences = {}
if (this.$root.store.navSS === "functors") this.getFFrames(this.hw) if (this.$root.store.selIndex === "functors") this.getFFrames(this.hw)
else { else {
this.getFrames(this.hw) this.getFrames(this.hw)
if (this.$root.store.radio === "three") { if (this.$root.store.radio === "three") {

View File

@ -6,11 +6,24 @@
<b-collapse is-nav id="nav_collapse"> <b-collapse is-nav id="nav_collapse">
<b-navbar-nav> <b-navbar-nav>
<b-nav-item-dropdown text="Prikaz" right> <b-nav-item-dropdown text="korpus" right>
<b-dropdown-item v-for="option in search_options" <b-dropdown-item v-for="option in optCorpora"
:value="option"
:key="option"
v-on:click="updateCorpus(option)"
>
{{ option }}
</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
<b-navbar-nav>
<b-nav-item-dropdown text="prikaz" right>
<b-dropdown-item v-for="option in optIndexes"
:value="option.val" :value="option.val"
:key="option.val" :key="option.val"
v-on:click="setNavSS(option.val)"> v-on:click="updateIndex(option.val)"
>
{{ option.key }} {{ option.key }}
</b-dropdown-item> </b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
@ -46,19 +59,27 @@ export default {
name: "Nav", name: "Nav",
props: ["appState"], props: ["appState"],
data() {return { data() {return {
search_options: [ optIndexes: [
{key: "besede", val: "words"}, {key: "besede", val: "words"},
{key: "udeleženske vloge", val: "functors"}, {key: "udeleženske vloge", val: "functors"},
], ],
optCorpora: ["kres", "ssj"],
}}, }},
methods: { methods: {
setNavSS(val) { updateAll() {
this.$root.store.radio = "one" this.$root.store.radio = "one"
this.$root.store.navSS = val
this.$router.push({ this.$router.push({
name: "Home" name: "Home"
}) })
}, },
updateCorpus(val) {
this.$root.store.selCorpus = val
this.updateAll()
},
updateIndex(val) {
this.$root.store.selIndex = val
this.updateAll()
},
loggedIn() { loggedIn() {
return (this.$root.store.token !== null) return (this.$root.store.token !== null)
}, },

View File

@ -38,7 +38,8 @@ const store = {
// api_addr: "http://193.2.76.103:5004", // production // api_addr: "http://193.2.76.103:5004", // production
token: null, token: null,
username: null, username: null,
navSS: "words", selIndex: "words",
selCorpus: "kres",
radio: "one", radio: "one",
has_se: [], // used for appending (se) to certain verbs has_se: [], // used for appending (se) to certain verbs
} }