alessandro trinca tornidor
commited on
Commit
·
e0b1feb
1
Parent(s):
5012c50
feat: add /words-frequency POST route to return a wordsapi compatible response from nltk wordnet corpus
Browse files- my_ghost_writer/app.py +39 -1
- my_ghost_writer/constants.py +1 -0
- my_ghost_writer/thesaurus.py +200 -0
- my_ghost_writer/type_hints.py +29 -1
- tests/events/expected_get_synsets_by_word_and_language_dog.json +1 -0
- tests/events/expected_get_synsets_by_word_and_language_look.json +1 -0
- tests/events/expected_get_synsets_by_word_and_language_power.json +1 -0
- tests/events/expected_get_synsets_by_word_and_language_term.json +1 -0
- tests/events/look_wordsapi_response.json +169 -0
- tests/events/thesaurus-wordnet.http +16 -0
- tests/events/thesaurus-wordsapi.http +16 -0
- tests/test_thesaurus_wordnet.py +49 -0
my_ghost_writer/app.py
CHANGED
@@ -21,6 +21,7 @@ from my_ghost_writer.constants import (app_logger, ALLOWED_ORIGIN_LIST, API_MODE
|
|
21 |
from my_ghost_writer.pymongo_utils import mongodb_health_check
|
22 |
from my_ghost_writer.text_parsers import text_stemming
|
23 |
from my_ghost_writer.type_hints import RequestTextFrequencyBody, RequestQueryThesaurusWordsapiBody
|
|
|
24 |
|
25 |
|
26 |
async def mongo_health_check_background_task():
|
@@ -28,7 +29,7 @@ async def mongo_health_check_background_task():
|
|
28 |
while ME_CONFIG_MONGODB_USE_OK:
|
29 |
try:
|
30 |
db_ok["mongo_ok"] = health_mongo() == "Mongodb: still alive..."
|
31 |
-
except PyMongoError:
|
32 |
db_ok["mongo_ok"] = False
|
33 |
await asyncio.sleep(ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP)
|
34 |
|
@@ -72,6 +73,17 @@ def health():
|
|
72 |
return "Still alive..."
|
73 |
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
@app.get("/health-mongo")
|
76 |
def health_mongo() -> str:
|
77 |
app_logger.info(f"pymongo driver version:{pymongo_version}!")
|
@@ -107,6 +119,32 @@ def get_words_frequency(body: RequestTextFrequencyBody | str) -> JSONResponse:
|
|
107 |
return JSONResponse(status_code=200, content=content_response)
|
108 |
|
109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
@app.post("/thesaurus-wordsapi")
|
111 |
def get_thesaurus_wordsapi(body: RequestQueryThesaurusWordsapiBody | str) -> JSONResponse:
|
112 |
t0 = datetime.now()
|
|
|
21 |
from my_ghost_writer.pymongo_utils import mongodb_health_check
|
22 |
from my_ghost_writer.text_parsers import text_stemming
|
23 |
from my_ghost_writer.type_hints import RequestTextFrequencyBody, RequestQueryThesaurusWordsapiBody
|
24 |
+
from my_ghost_writer.thesaurus import get_current_info_wordnet, get_synsets_by_word_and_language
|
25 |
|
26 |
|
27 |
async def mongo_health_check_background_task():
|
|
|
29 |
while ME_CONFIG_MONGODB_USE_OK:
|
30 |
try:
|
31 |
db_ok["mongo_ok"] = health_mongo() == "Mongodb: still alive..."
|
32 |
+
except (PyMongoError, HTTPException):
|
33 |
db_ok["mongo_ok"] = False
|
34 |
await asyncio.sleep(ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP)
|
35 |
|
|
|
73 |
return "Still alive..."
|
74 |
|
75 |
|
76 |
+
@app.get("/health-wordnet")
|
77 |
+
def get_wordnet_languages():
|
78 |
+
try:
|
79 |
+
info = get_current_info_wordnet()
|
80 |
+
return JSONResponse(status_code=200, content={"msg": info})
|
81 |
+
except Exception as e:
|
82 |
+
app_logger.error("exception:")
|
83 |
+
app_logger.error(e)
|
84 |
+
raise HTTPException(status_code=503, detail=str(type(e)))
|
85 |
+
|
86 |
+
|
87 |
@app.get("/health-mongo")
|
88 |
def health_mongo() -> str:
|
89 |
app_logger.info(f"pymongo driver version:{pymongo_version}!")
|
|
|
119 |
return JSONResponse(status_code=200, content=content_response)
|
120 |
|
121 |
|
122 |
+
@app.post("/thesaurus-wordnet")
|
123 |
+
def get_thesaurus_wordnet(body: RequestQueryThesaurusWordsapiBody | str) -> JSONResponse:
|
124 |
+
t0 = datetime.now()
|
125 |
+
app_logger.info(f"body type: {type(body)} => {body}.")
|
126 |
+
body_validated = RequestQueryThesaurusWordsapiBody.model_validate_json(body)
|
127 |
+
query = body_validated.query
|
128 |
+
app_logger.info(f"query: {type(query)} => {query}, starting get_synsets_by_word_and_language...")
|
129 |
+
use_mongo: bool = db_ok["mongo_ok"]
|
130 |
+
app_logger.info(f"query: {type(query)} => {query}, use mongo? {use_mongo}.")
|
131 |
+
if use_mongo:
|
132 |
+
try:
|
133 |
+
response = pymongo_operations_rw.get_document_by_word(query=query)
|
134 |
+
t1 = datetime.now()
|
135 |
+
duration = (t1 - t0).total_seconds()
|
136 |
+
app_logger.info(f"found local data, duration: {duration:.3f}s.")
|
137 |
+
return JSONResponse(status_code=200, content={"duration": duration, "thesaurus": response, "source": "local"})
|
138 |
+
except (PyMongoError, AssertionError) as pme:
|
139 |
+
app_logger.info(f"{pme}! Let's try the remote service...")
|
140 |
+
|
141 |
+
response = get_synsets_by_word_and_language(query, lang="eng")
|
142 |
+
t1 = datetime.now()
|
143 |
+
duration = (t1 - t0).total_seconds()
|
144 |
+
app_logger.info(f"response.status_code: {response.status_code}, duration: {duration:.3f}s.")
|
145 |
+
return JSONResponse(status_code=200, content={"duration": duration, "thesaurus": response, "source": "wordnet"})
|
146 |
+
|
147 |
+
|
148 |
@app.post("/thesaurus-wordsapi")
|
149 |
def get_thesaurus_wordsapi(body: RequestQueryThesaurusWordsapiBody | str) -> JSONResponse:
|
150 |
t0 = datetime.now()
|
my_ghost_writer/constants.py
CHANGED
@@ -20,6 +20,7 @@ IS_TESTING = bool(os.getenv('IS_TESTING', ""))
|
|
20 |
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
|
21 |
API_MODE = bool(os.getenv("API_MODE", ""))
|
22 |
N_WORDS_GRAM = int(os.getenv("N_WORDS_GRAM", 2))
|
|
|
23 |
WORDSAPI_KEY = os.getenv("WORDSAPI_KEY")
|
24 |
WORDSAPI_URL = os.getenv("WORDSAPI_URL", "https://wordsapiv1.p.rapidapi.com/words")
|
25 |
RAPIDAPI_HOST = os.getenv("RAPIDAPI_HOST", "wordsapiv1.p.rapidapi.com")
|
|
|
20 |
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
|
21 |
API_MODE = bool(os.getenv("API_MODE", ""))
|
22 |
N_WORDS_GRAM = int(os.getenv("N_WORDS_GRAM", 2))
|
23 |
+
WORDNET_LANGUAGES=(os.getenv("WORDNET_LANGUAGES", "eng,"))
|
24 |
WORDSAPI_KEY = os.getenv("WORDSAPI_KEY")
|
25 |
WORDSAPI_URL = os.getenv("WORDSAPI_URL", "https://wordsapiv1.p.rapidapi.com/words")
|
26 |
RAPIDAPI_HOST = os.getenv("RAPIDAPI_HOST", "wordsapiv1.p.rapidapi.com")
|
my_ghost_writer/thesaurus.py
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any
|
2 |
+
|
3 |
+
from nltk.corpus import wordnet31 as wn
|
4 |
+
|
5 |
+
from my_ghost_writer.type_hints import ResponseWordsAPI
|
6 |
+
|
7 |
+
|
8 |
+
def get_current_info_wordnet():
|
9 |
+
return {"languages": wn.langs(), "version": wn.get_version()}
|
10 |
+
|
11 |
+
|
12 |
+
def get_synsets_by_word_and_language(word: str, lang: str = "eng") -> ResponseWordsAPI:
|
13 |
+
results = []
|
14 |
+
for synset in wn.synsets(word, lang=lang):
|
15 |
+
# Synonyms (lemmas for this synset, excluding the input word)
|
16 |
+
synonyms = sorted(
|
17 |
+
set(
|
18 |
+
l.name().replace('_', ' ')
|
19 |
+
for l in synset.lemmas(lang=lang)
|
20 |
+
if l.name().lower() != word.lower()
|
21 |
+
)
|
22 |
+
)
|
23 |
+
# Antonyms (from lemmas)
|
24 |
+
antonyms = sorted(
|
25 |
+
set(
|
26 |
+
ant.name().replace('_', ' ')
|
27 |
+
for l in synset.lemmas(lang=lang)
|
28 |
+
for ant in l.antonyms()
|
29 |
+
)
|
30 |
+
)
|
31 |
+
# Derivationally related forms (from lemmas)
|
32 |
+
derivation = sorted(
|
33 |
+
set(
|
34 |
+
d.name().replace('_', ' ')
|
35 |
+
for l in synset.lemmas(lang=lang)
|
36 |
+
for d in l.derivationally_related_forms()
|
37 |
+
)
|
38 |
+
)
|
39 |
+
# Pertainyms (from lemmas)
|
40 |
+
pertains_to = sorted(
|
41 |
+
set(
|
42 |
+
p.name().replace('_', ' ')
|
43 |
+
for l in synset.lemmas(lang=lang)
|
44 |
+
for p in l.pertainyms()
|
45 |
+
)
|
46 |
+
)
|
47 |
+
# Synset relations
|
48 |
+
type_of = sorted(
|
49 |
+
set(
|
50 |
+
l.name().replace('_', ' ')
|
51 |
+
for h in synset.hypernyms()
|
52 |
+
for l in h.lemmas(lang=lang)
|
53 |
+
)
|
54 |
+
)
|
55 |
+
# Hyponyms (hasTypes)
|
56 |
+
has_types = sorted(
|
57 |
+
set(
|
58 |
+
l.name().replace('_', ' ')
|
59 |
+
for h in synset.hyponyms()
|
60 |
+
for l in h.lemmas(lang=lang)
|
61 |
+
)
|
62 |
+
)
|
63 |
+
# Holonyms (partOf)
|
64 |
+
part_of = sorted(
|
65 |
+
set(
|
66 |
+
l.name().replace('_', ' ')
|
67 |
+
for h in synset.member_holonyms() + synset.part_holonyms() + synset.substance_holonyms()
|
68 |
+
for l in h.lemmas(lang=lang)
|
69 |
+
)
|
70 |
+
)
|
71 |
+
# Meronyms (hasParts)
|
72 |
+
has_parts = sorted(
|
73 |
+
set(
|
74 |
+
l.name().replace('_', ' ')
|
75 |
+
for h in synset.member_meronyms() + synset.part_meronyms() + synset.substance_meronyms()
|
76 |
+
for l in h.lemmas(lang=lang)
|
77 |
+
)
|
78 |
+
)
|
79 |
+
instance_of = sorted(
|
80 |
+
set(
|
81 |
+
l.name().replace('_', ' ')
|
82 |
+
for h in synset.instance_hypernyms()
|
83 |
+
for l in h.lemmas(lang=lang)
|
84 |
+
)
|
85 |
+
)
|
86 |
+
has_instances = sorted(
|
87 |
+
set(
|
88 |
+
l.name().replace('_', ' ')
|
89 |
+
for h in synset.instance_hyponyms()
|
90 |
+
for l in h.lemmas(lang=lang)
|
91 |
+
)
|
92 |
+
)
|
93 |
+
similar_to = sorted(
|
94 |
+
set(
|
95 |
+
l.name().replace('_', ' ')
|
96 |
+
for h in synset.similar_tos()
|
97 |
+
for l in h.lemmas(lang=lang)
|
98 |
+
)
|
99 |
+
)
|
100 |
+
also = sorted(
|
101 |
+
set(
|
102 |
+
l.name().replace('_', ' ')
|
103 |
+
for h in synset.also_sees()
|
104 |
+
for l in h.lemmas(lang=lang)
|
105 |
+
)
|
106 |
+
)
|
107 |
+
entails = sorted(
|
108 |
+
set(
|
109 |
+
l.name().replace('_', ' ')
|
110 |
+
for h in synset.entailments()
|
111 |
+
for l in h.lemmas(lang=lang)
|
112 |
+
)
|
113 |
+
)
|
114 |
+
causes = sorted(
|
115 |
+
set(
|
116 |
+
l.name().replace('_', ' ')
|
117 |
+
for h in synset.causes()
|
118 |
+
for l in h.lemmas(lang=lang)
|
119 |
+
)
|
120 |
+
)
|
121 |
+
verb_groups = sorted(
|
122 |
+
set(
|
123 |
+
l.name().replace('_', ' ')
|
124 |
+
for h in synset.verb_groups()
|
125 |
+
for l in h.lemmas(lang=lang)
|
126 |
+
)
|
127 |
+
)
|
128 |
+
has_substances = sorted(
|
129 |
+
set(
|
130 |
+
l.name().replace('_', ' ')
|
131 |
+
for h in synset.substance_meronyms()
|
132 |
+
for l in h.lemmas(lang=lang)
|
133 |
+
)
|
134 |
+
)
|
135 |
+
in_category = sorted(
|
136 |
+
set(
|
137 |
+
l.name().replace('_', ' ')
|
138 |
+
for h in synset.topic_domains()
|
139 |
+
for l in h.lemmas(lang=lang)
|
140 |
+
)
|
141 |
+
)
|
142 |
+
usage_of = sorted(
|
143 |
+
set(
|
144 |
+
l.name().replace('_', ' ')
|
145 |
+
for h in synset.usage_domains()
|
146 |
+
for l in h.lemmas(lang=lang)
|
147 |
+
)
|
148 |
+
)
|
149 |
+
obj = {
|
150 |
+
"definition": synset.definition(lang=lang),
|
151 |
+
}
|
152 |
+
if synonyms:
|
153 |
+
obj["synonyms"] = synonyms
|
154 |
+
if type_of:
|
155 |
+
obj["typeOf"] = type_of
|
156 |
+
if has_types:
|
157 |
+
obj["hasTypes"] = has_types
|
158 |
+
if part_of:
|
159 |
+
obj["partOf"]: part_of
|
160 |
+
if has_parts:
|
161 |
+
obj["hasParts"]: has_parts
|
162 |
+
if antonyms:
|
163 |
+
obj["antonyms"] = antonyms
|
164 |
+
if derivation:
|
165 |
+
obj["derivation"] = derivation
|
166 |
+
if pertains_to:
|
167 |
+
obj["pertainsTo"] = pertains_to
|
168 |
+
if instance_of:
|
169 |
+
obj["instanceOf"] = instance_of
|
170 |
+
if has_instances:
|
171 |
+
obj["hasInstances"] = has_instances
|
172 |
+
if similar_to:
|
173 |
+
obj["similarTo"] = similar_to
|
174 |
+
if also:
|
175 |
+
obj["also"] = also
|
176 |
+
if entails:
|
177 |
+
obj["entails"] = entails
|
178 |
+
if has_substances:
|
179 |
+
obj["hasSubstances"] = has_substances
|
180 |
+
if in_category:
|
181 |
+
obj["inCategory"] = in_category
|
182 |
+
if usage_of:
|
183 |
+
obj["usageOf"] = usage_of
|
184 |
+
if causes:
|
185 |
+
obj["causes"] = causes
|
186 |
+
if verb_groups:
|
187 |
+
obj["verbGroups"] = verb_groups
|
188 |
+
results.append(obj)
|
189 |
+
return {
|
190 |
+
"word": word,
|
191 |
+
"results": results
|
192 |
+
}
|
193 |
+
|
194 |
+
|
195 |
+
if __name__ == '__main__':
|
196 |
+
res = {}
|
197 |
+
for w in ["dog", "spider", "look", "tree"]:
|
198 |
+
oo = get_synsets_by_word_and_language(w, lang="eng")
|
199 |
+
res[w] = oo
|
200 |
+
pass
|
my_ghost_writer/type_hints.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from typing import TypedDict
|
2 |
from pydantic import BaseModel
|
3 |
|
4 |
|
@@ -45,6 +45,34 @@ class WordStem(TypedDict):
|
|
45 |
offsets_array: list[OffsetArray]
|
46 |
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
RequestTextRowsList = list[InputTextRow]
|
49 |
RequestTextRowsParentList = list[InputTextRowWithParent]
|
50 |
ResponseTextRowsDict = tuple[int, dict[str, WordStem]]
|
|
|
|
1 |
+
from typing import TypedDict, Optional
|
2 |
from pydantic import BaseModel
|
3 |
|
4 |
|
|
|
45 |
offsets_array: list[OffsetArray]
|
46 |
|
47 |
|
48 |
+
class ResultWordsAPI(TypedDict):
|
49 |
+
definition: str
|
50 |
+
synonyms: Optional[list[str]]
|
51 |
+
typeOf: Optional[list[str]]
|
52 |
+
hasTypes: Optional[list[str]]
|
53 |
+
partOf: Optional[list[str]]
|
54 |
+
hasParts: Optional[list[str]]
|
55 |
+
antonyms: Optional[list[str]]
|
56 |
+
derivation: Optional[list[str]]
|
57 |
+
pertainsTo: Optional[list[str]]
|
58 |
+
instanceOf: Optional[list[str]]
|
59 |
+
hasInstances: Optional[list[str]]
|
60 |
+
similarTo: Optional[list[str]]
|
61 |
+
also: Optional[list[str]]
|
62 |
+
entails: Optional[list[str]]
|
63 |
+
hasSubstances: Optional[list[str]]
|
64 |
+
inCategory: Optional[list[str]]
|
65 |
+
usageOf: Optional[list[str]]
|
66 |
+
causes: Optional[list[str]]
|
67 |
+
verbGroups: Optional[list[str]]
|
68 |
+
|
69 |
+
|
70 |
+
class ResponseWordsAPI(TypedDict):
|
71 |
+
word: str
|
72 |
+
results: list[ResultWordsAPI]
|
73 |
+
|
74 |
+
|
75 |
RequestTextRowsList = list[InputTextRow]
|
76 |
RequestTextRowsParentList = list[InputTextRowWithParent]
|
77 |
ResponseTextRowsDict = tuple[int, dict[str, WordStem]]
|
78 |
+
#ResponseWordsAPI = dict[str, str | list[str]]
|
tests/events/expected_get_synsets_by_word_and_language_dog.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"word": "dog", "results": [{"definition": "a member of the genus Canis (probably descended from the common wolf) that has been domesticated by man since prehistoric times; occurs in many breeds", "synonyms": ["Canis familiaris", "domestic dog"], "typeOf": ["canid", "canine", "domestic animal", "domesticated animal"], "hasTypes": ["Belgian griffon", "Brussels griffon", "Great Pyrenees", "Leonberg", "Mexican hairless", "Newfoundland", "Newfoundland dog", "Welsh corgi", "barker", "basenji", "bow-wow", "carriage dog", "coach dog", "corgi", "cur", "dalmatian", "doggie", "doggy", "griffon", "hunting dog", "lapdog", "mongrel", "mutt", "pooch", "poodle", "poodle dog", "pug", "pug-dog", "puppy", "spitz", "toy", "toy dog", "working dog"]}, {"definition": "a dull unattractive unpleasant girl or woman", "synonyms": ["frump"], "typeOf": ["disagreeable woman", "unpleasant woman"], "derivation": ["frumpy"]}, {"definition": "informal term for a man", "typeOf": ["blighter", "bloke", "chap", "cuss", "fella", "feller", "fellow", "gent", "lad"]}, {"definition": "someone who is morally reprehensible", "synonyms": ["blackguard", "bounder", "cad", "heel", "hound"], "typeOf": ["scoundrel", "villain"], "hasTypes": ["perisher"], "derivation": ["blackguardly"]}, {"definition": "a smooth-textured sausage of minced beef or pork usually smoked; often served on a bread roll", "synonyms": ["frank", "frankfurter", "hot dog", "hotdog", "weenie", "wiener", "wienerwurst"], "typeOf": ["sausage"], "hasTypes": ["Vienna sausage"]}, {"definition": "a hinged catch that fits into a notch of a ratchet to move a wheel forward or prevent it from moving backward", "synonyms": ["click", "detent", "pawl"], "typeOf": ["catch", "stop"]}, {"definition": "metal supports for logs in a fireplace", "synonyms": ["andiron", "dog-iron", "firedog"], "typeOf": ["support"]}, {"definition": "go after with the intent to catch", "synonyms": ["chase", "chase after", "give chase", "go after", "tag", "tail", "track", "trail"], "typeOf": ["follow", "pursue"], "hasTypes": ["hound", "hunt", "quest", "run down", "trace", "tree"], "derivation": ["chase", "chaser", "tag", "tail", "tailing", "track", "tracker", "tracking", "trailing"]}]}
|
tests/events/expected_get_synsets_by_word_and_language_look.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"word": "look", "results": [{"definition": "the feelings expressed on a person's face", "synonyms": ["aspect", "expression", "face", "facial expression"], "typeOf": ["countenance", "visage"], "hasTypes": ["leer", "light", "spark", "sparkle", "twinkle"], "derivation": ["look"]}, {"definition": "the act of directing the eyes toward something and perceiving it visually", "synonyms": ["looking", "looking at"], "typeOf": ["perception", "sensing"], "hasTypes": ["coup d'oeil", "dekko", "evil eye", "glance", "glimpse", "lookout", "observance", "observation", "outlook", "peek", "peep", "rubber-necking", "scrutiny", "sight", "sightseeing", "squint", "stare", "survey", "view", "watching"], "derivation": ["look"]}, {"definition": "physical appearance", "typeOf": ["appearance", "visual aspect"], "derivation": ["look"]}, {"definition": "the general atmosphere of a place or situation and the effect that it has on people", "synonyms": ["feel", "feeling", "flavor", "flavour", "smell", "spirit", "tone"], "typeOf": ["ambiance", "ambience", "atmosphere"], "hasTypes": ["Hollywood", "Zeitgeist"], "derivation": ["feel", "look", "spirit", "spiritize"]}, {"definition": "perceive with attention; direct one's gaze towards", "hasTypes": ["admire", "consider", "eye", "eyeball", "gape", "gawk", "gawp", "gaze", "get a load", "give the eye", "give the glad eye", "give the once over", "glance", "glint", "gloat", "goggle", "have a look", "leer", "look around", "look away", "look back", "look backward", "ogle", "peek", "peep", "peer", "regard", "squint", "stare", "take a look"], "derivation": ["look", "looker"], "entails": ["see"]}, {"definition": "give a certain impression or have a certain outward aspect", "synonyms": ["appear", "seem"], "typeOf": ["be"], "hasTypes": ["beam", "come across", "cut", "feel", "gleam", "glint", "glisten", "glitter", "glow", "jump", "jump out", "leap out", "lift", "loom", "make", "pass off", "radiate", "rear", "rise", "shine", "sound", "stand out", "stick out"], "derivation": ["appearance", "look"]}, {"definition": "have a certain outward or facial expression", "typeOf": ["be"], "hasTypes": ["squint"], "derivation": ["look"]}, {"definition": "search or seek", "synonyms": ["search"], "typeOf": ["examine", "see"], "hasTypes": ["cruise", "horn in", "hunt", "intrude", "nose", "poke", "prospect", "pry"], "derivation": ["search", "searcher"]}, {"definition": "be oriented in a certain direction, often with respect to another reference point; be opposite to", "synonyms": ["face", "front"], "typeOf": ["lie"], "hasTypes": ["confront"], "antonyms": ["back"], "derivation": ["front", "frontage"], "verbGroups": ["face"]}, {"definition": "take charge of or deal with", "synonyms": ["attend", "see", "take care"], "typeOf": ["care", "give care"], "hasTypes": ["minister", "tend"], "derivation": ["attention"]}, {"definition": "convey by one's expression", "typeOf": ["convey"], "derivation": ["look"]}, {"definition": "look forward to the probable occurrence of", "synonyms": ["await", "expect", "wait"], "hasTypes": ["anticipate", "expect", "hang on", "hold on", "hold the line", "look for", "look forward", "look to"], "derivation": ["expectancy", "expectant", "expectation", "waiter"], "verbGroups": ["anticipate", "expect"]}, {"definition": "accord in appearance with", "typeOf": ["agree", "check", "correspond", "fit", "gibe", "jibe", "match", "tally"]}, {"definition": "have faith or confidence in", "synonyms": ["bank", "bet", "calculate", "count", "depend", "reckon", "rely", "swear"], "typeOf": ["trust"], "derivation": ["dependency", "reliance", "reliant"]}]}
|
tests/events/expected_get_synsets_by_word_and_language_power.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"word": "power", "results": [{"definition": "possession of controlling influence", "synonyms": ["powerfulness"], "typeOf": ["quality"], "hasTypes": ["chokehold", "control", "discretion", "disposal", "effectiveness", "effectivity", "effectuality", "effectualness", "free will", "influence", "interest", "interestingness", "irresistibility", "irresistibleness", "jurisdiction", "legal power", "persuasiveness", "potency", "preponderance", "puissance", "repellant", "repellent", "stranglehold", "strength", "sway", "throttlehold", "valence", "valency", "veto"], "antonyms": ["powerlessness"], "derivation": ["powerful"]}, {"definition": "(physics) the rate of doing work; measured in watts (= joules/second)", "typeOf": ["physical phenomenon"], "hasTypes": ["electric power", "electrical power", "waterpower", "wattage"], "derivation": ["power"], "inCategory": ["natural philosophy", "physics"]}, {"definition": "possession of the qualities (especially mental qualities) required to do something or get something done", "synonyms": ["ability"], "typeOf": ["cognition", "knowledge", "noesis"], "hasTypes": ["accomplishment", "acquirement", "acquisition", "aptitude", "attainment", "bilingualism", "capacity", "creative thinking", "creativeness", "creativity", "faculty", "hand", "intelligence", "know-how", "leadership", "mental ability", "mental faculty", "module", "originality", "science", "skill", "superior skill"], "antonyms": ["inability"], "derivation": ["able"]}, {"definition": "(of a government or government official) holding an office means being in power", "synonyms": ["office"], "typeOf": ["state"], "hasTypes": ["executive clemency", "war power"], "derivation": ["official", "officiate"], "inCategory": ["administration", "governance", "governing", "government", "government activity"]}, {"definition": "one possessing or exercising power or influence or authority", "synonyms": ["force"], "typeOf": ["causal agency", "causal agent", "cause"], "hasTypes": ["Moloch", "influence", "juggernaut", "steamroller"], "derivation": ["force"]}, {"definition": "a mathematical notation indicating the number of times a quantity is multiplied by itself", "synonyms": ["exponent", "index"], "typeOf": ["mathematical notation"], "hasTypes": ["degree", "log", "logarithm"], "derivation": ["exponential"]}, {"definition": "physical strength", "synonyms": ["might", "mightiness"], "typeOf": ["strength"], "derivation": ["mighty"]}, {"definition": "a state powerful enough to influence events throughout the world", "synonyms": ["great power", "major power", "superpower", "world power"], "typeOf": ["body politic", "commonwealth", "country", "land", "nation", "res publica", "state"], "hasTypes": ["hegemon"]}, {"definition": "energy made available by the flow of electric charge through a conductor", "synonyms": ["electrical energy", "electricity"], "typeOf": ["energy", "free energy"], "hasTypes": ["AC", "DC", "alternating current", "alternating electric current", "direct current", "direct electric current", "signal"], "derivation": ["electric", "electrify"]}, {"definition": "a very wealthy or powerful businessman", "synonyms": ["baron", "big businessman", "business leader", "king", "magnate", "mogul", "top executive", "tycoon"], "typeOf": ["businessman", "man of affairs"], "hasTypes": ["oil tycoon"]}, {"definition": "supply the force or power for the functioning of", "typeOf": ["cater", "ply", "provide", "supply"], "hasTypes": ["drive"], "derivation": ["power"]}]}
|
tests/events/expected_get_synsets_by_word_and_language_term.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"word": "term", "results": [{"definition": "a word or expression used for some particular thing", "typeOf": ["word"], "hasTypes": ["referent"], "derivation": ["term"]}, {"definition": "a limited period of time", "typeOf": ["period", "period of time", "time period"], "hasTypes": ["academic session", "academic term", "incumbency", "prison term", "school term", "sentence", "session", "tenure", "term of office", "time"]}, {"definition": "(usually plural) a statement of what is required as part of an agreement", "synonyms": ["condition", "strings"], "typeOf": ["statement"], "derivation": ["condition"], "usageOf": ["plural", "plural form"]}, {"definition": "any distinct quantity contained in a polynomial", "typeOf": ["quantity"]}, {"definition": "one of the substantive phrases in a logical proposition", "typeOf": ["constituent", "grammatical constituent"], "hasTypes": ["categorem", "categoreme", "major term", "middle term", "minor term", "predicate", "referent", "relatum", "subject"]}, {"definition": "the end of gestation or point at which birth is imminent", "synonyms": ["full term"], "typeOf": ["point", "point in time"]}, {"definition": "(architecture) a statue or a human bust or an animal carved out of the top of a square pillar; originally used as a boundary marker in ancient Rome", "synonyms": ["terminal figure", "terminus"], "typeOf": ["statue"], "inCategory": ["architecture"]}, {"definition": "name formally or designate with a term", "typeOf": ["be known as", "call", "know as", "name"], "derivation": ["term"]}]}
|
tests/events/look_wordsapi_response.json
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"word": "example",
|
3 |
+
"results": [
|
4 |
+
{
|
5 |
+
"definition": "a representative form or pattern",
|
6 |
+
"partOfSpeech": "noun",
|
7 |
+
"synonyms": [
|
8 |
+
"model"
|
9 |
+
],
|
10 |
+
"typeOf": [
|
11 |
+
"representation",
|
12 |
+
"internal representation",
|
13 |
+
"mental representation"
|
14 |
+
],
|
15 |
+
"hasTypes": [
|
16 |
+
"prefiguration",
|
17 |
+
"archetype",
|
18 |
+
"epitome",
|
19 |
+
"guide",
|
20 |
+
"holotype",
|
21 |
+
"image",
|
22 |
+
"loadstar",
|
23 |
+
"lodestar",
|
24 |
+
"microcosm",
|
25 |
+
"original",
|
26 |
+
"paradigm",
|
27 |
+
"pilot",
|
28 |
+
"prototype",
|
29 |
+
"template",
|
30 |
+
"templet",
|
31 |
+
"type specimen"
|
32 |
+
],
|
33 |
+
"derivation": [
|
34 |
+
"exemplify"
|
35 |
+
],
|
36 |
+
"examples": [
|
37 |
+
"I profited from his example"
|
38 |
+
]
|
39 |
+
},
|
40 |
+
{
|
41 |
+
"definition": "something to be imitated",
|
42 |
+
"partOfSpeech": "noun",
|
43 |
+
"synonyms": [
|
44 |
+
"exemplar",
|
45 |
+
"good example",
|
46 |
+
"model"
|
47 |
+
],
|
48 |
+
"typeOf": [
|
49 |
+
"ideal"
|
50 |
+
],
|
51 |
+
"hasTypes": [
|
52 |
+
"pacemaker",
|
53 |
+
"pattern",
|
54 |
+
"beauty",
|
55 |
+
"prodigy",
|
56 |
+
"beaut",
|
57 |
+
"pacesetter"
|
58 |
+
],
|
59 |
+
"derivation": [
|
60 |
+
"exemplify",
|
61 |
+
"exemplary"
|
62 |
+
]
|
63 |
+
},
|
64 |
+
{
|
65 |
+
"definition": "an occurrence of something",
|
66 |
+
"partOfSpeech": "noun",
|
67 |
+
"synonyms": [
|
68 |
+
"case",
|
69 |
+
"instance"
|
70 |
+
],
|
71 |
+
"typeOf": [
|
72 |
+
"happening",
|
73 |
+
"natural event",
|
74 |
+
"occurrence",
|
75 |
+
"occurrent"
|
76 |
+
],
|
77 |
+
"hasTypes": [
|
78 |
+
"clip",
|
79 |
+
"mortification",
|
80 |
+
"piece",
|
81 |
+
"time",
|
82 |
+
"humiliation",
|
83 |
+
"bit"
|
84 |
+
],
|
85 |
+
"derivation": [
|
86 |
+
"exemplify"
|
87 |
+
],
|
88 |
+
"examples": [
|
89 |
+
"but there is always the famous example of the Smiths"
|
90 |
+
]
|
91 |
+
},
|
92 |
+
{
|
93 |
+
"definition": "an item of information that is typical of a class or group",
|
94 |
+
"partOfSpeech": "noun",
|
95 |
+
"synonyms": [
|
96 |
+
"illustration",
|
97 |
+
"instance",
|
98 |
+
"representative"
|
99 |
+
],
|
100 |
+
"typeOf": [
|
101 |
+
"information"
|
102 |
+
],
|
103 |
+
"hasTypes": [
|
104 |
+
"excuse",
|
105 |
+
"apology",
|
106 |
+
"specimen",
|
107 |
+
"case in point",
|
108 |
+
"sample",
|
109 |
+
"exception",
|
110 |
+
"quintessence",
|
111 |
+
"precedent"
|
112 |
+
],
|
113 |
+
"derivation": [
|
114 |
+
"exemplify",
|
115 |
+
"exemplary"
|
116 |
+
],
|
117 |
+
"examples": [
|
118 |
+
"this patient provides a typical example of the syndrome",
|
119 |
+
"there is an example on page 10"
|
120 |
+
]
|
121 |
+
},
|
122 |
+
{
|
123 |
+
"definition": "punishment intended as a warning to others",
|
124 |
+
"partOfSpeech": "noun",
|
125 |
+
"synonyms": [
|
126 |
+
"deterrent example",
|
127 |
+
"lesson",
|
128 |
+
"object lesson"
|
129 |
+
],
|
130 |
+
"typeOf": [
|
131 |
+
"monition",
|
132 |
+
"admonition",
|
133 |
+
"word of advice",
|
134 |
+
"warning"
|
135 |
+
],
|
136 |
+
"derivation": [
|
137 |
+
"exemplary"
|
138 |
+
],
|
139 |
+
"examples": [
|
140 |
+
"they decided to make an example of him"
|
141 |
+
]
|
142 |
+
},
|
143 |
+
{
|
144 |
+
"definition": "a task performed or problem solved in order to develop skill or understanding",
|
145 |
+
"partOfSpeech": "noun",
|
146 |
+
"synonyms": [
|
147 |
+
"exercise"
|
148 |
+
],
|
149 |
+
"typeOf": [
|
150 |
+
"lesson"
|
151 |
+
],
|
152 |
+
"examples": [
|
153 |
+
"you must work the examples at the end of each chapter in the textbook"
|
154 |
+
]
|
155 |
+
}
|
156 |
+
],
|
157 |
+
"syllables": {
|
158 |
+
"count": 3,
|
159 |
+
"list": [
|
160 |
+
"ex",
|
161 |
+
"am",
|
162 |
+
"ple"
|
163 |
+
]
|
164 |
+
},
|
165 |
+
"pronunciation": {
|
166 |
+
"all": "ɪɡ'zæmpəl"
|
167 |
+
},
|
168 |
+
"frequency": 4.67
|
169 |
+
}
|
tests/events/thesaurus-wordnet.http
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@domain = http://localhost:7860
|
2 |
+
|
3 |
+
### Thesaurus WordNet Query
|
4 |
+
POST {{domain}}/thesaurus-wordnet
|
5 |
+
Content-Type: text/plain;charset=UTF-8
|
6 |
+
|
7 |
+
{"query": "dog"}
|
8 |
+
|
9 |
+
> {%
|
10 |
+
client.log("Status:", response.status);
|
11 |
+
if (response.status >= 400) {
|
12 |
+
client.log("Error:", response.body);
|
13 |
+
} else {
|
14 |
+
client.log("Response:", response.body);
|
15 |
+
}
|
16 |
+
%}
|
tests/events/thesaurus-wordsapi.http
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@domain = http://localhost:7860
|
2 |
+
|
3 |
+
### Thesaurus WordsAPI Query (with browser-like headers)
|
4 |
+
POST {{domain}}/thesaurus-wordsapi
|
5 |
+
Content-Type: text/plain;charset=UTF-8
|
6 |
+
|
7 |
+
{"query":"look"}
|
8 |
+
|
9 |
+
> {%
|
10 |
+
client.log("Status:", response.status);
|
11 |
+
if (response.status >= 400) {
|
12 |
+
client.log("Error:", response.body);
|
13 |
+
} else {
|
14 |
+
client.log("Response:", response.body);
|
15 |
+
}
|
16 |
+
%}
|
tests/test_thesaurus_wordnet.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import unittest
|
3 |
+
|
4 |
+
from tests import EVENTS_FOLDER
|
5 |
+
|
6 |
+
|
7 |
+
def assert_get_synsets_by_word_and_language(cls, q):
|
8 |
+
from my_ghost_writer.thesaurus import get_synsets_by_word_and_language
|
9 |
+
|
10 |
+
response = get_synsets_by_word_and_language(q, lang="eng")
|
11 |
+
cls.assertEqual(list(response.keys()), ['word', 'results'])
|
12 |
+
cls.assertEqual(response["word"], q)
|
13 |
+
cls.assertIsInstance(response["results"], list)
|
14 |
+
results = response["results"]
|
15 |
+
for result in results:
|
16 |
+
for k, v in result.items():
|
17 |
+
cls.assertIsInstance(k, str)
|
18 |
+
try:
|
19 |
+
if k == "definition":
|
20 |
+
cls.assertIsInstance(v, str)
|
21 |
+
else:
|
22 |
+
cls.assertIsInstance(v, list)
|
23 |
+
except AssertionError as ae:
|
24 |
+
print(k, v, ae)
|
25 |
+
for s in v:
|
26 |
+
cls.assertIsInstance(s, str)
|
27 |
+
with open(EVENTS_FOLDER / f"expected_get_synsets_by_word_and_language_{q}.json", "r") as src:
|
28 |
+
# json.dump(response, src)
|
29 |
+
expected_response = json.load(src)
|
30 |
+
cls.assertEqual(response, expected_response)
|
31 |
+
|
32 |
+
|
33 |
+
class TestThesaurusWordnet(unittest.TestCase):
|
34 |
+
def test_get_current_info_wordnet(self):
|
35 |
+
from my_ghost_writer.thesaurus import get_current_info_wordnet
|
36 |
+
|
37 |
+
current_info = get_current_info_wordnet()
|
38 |
+
self.assertEqual(list(current_info.keys()), ['languages', 'version'])
|
39 |
+
languages = current_info["languages"]
|
40 |
+
self.assertIn("eng", languages)
|
41 |
+
self.assertIsInstance(languages, list)
|
42 |
+
self.assertIsInstance(current_info["version"], str)
|
43 |
+
self.assertGreaterEqual(len(languages), 1)
|
44 |
+
|
45 |
+
def test_get_synsets_by_word_and_language(self):
|
46 |
+
assert_get_synsets_by_word_and_language(self, "dog")
|
47 |
+
assert_get_synsets_by_word_and_language(self, "look")
|
48 |
+
assert_get_synsets_by_word_and_language(self, "power")
|
49 |
+
assert_get_synsets_by_word_and_language(self, "term")
|