import json
import MeCab
import re
import requests
request_url = "http://127.0.0.1:19633"
request_timeout = 10
# Generate Hiragana and Katakana characters
hiragana = tuple(chr(i) for i in range(12353, 12436)) # \u3041 - \u3094
katakana = tuple(chr(i) for i in range(12450, 12532)) # \u30A2 - \u30F4
punctuation = tuple(chr(i) for i in range(65281, 65382))
# Combine both into one tuple
all_kana = hiragana + katakana + punctuation + (' ', 'ー', '・')
KANJI_RE = re.compile(r"[\u4E00-\u9FFF]")
def katakana_to_hiragana(text: str) -> str:
return "".join(
chr(ord(ch) - 0x60) if 0x30A1 <= ord(ch) <= 0x30F6 else ch
for ch in text
)
# def get_node_reading(node) -> str:
# features = node.feature.split(",")
# print()
# if len(features) >= 8 and features[7] != "*":
# return katakana_to_hiragana(features[7])
# return node.surface
def has_kanji(text: str) -> bool:
return bool(KANJI_RE.search(text))
def get_node_reading(node) -> str:
features = node.feature.split(",")
## These depend on what dictionary is being used.
if len(features) > 6 and features[6] != "*":
return katakana_to_hiragana(features[6])
return node.surface
def annotate_phrase(text: str) -> str:
tagger = MeCab.Tagger()
node = tagger.parseToNode(text)
vocab = ()
parts = []
# 漢字
furi = []
while node:
surface = node.surface
if surface:
vocab += (surface,)
if has_kanji(surface):
reading = get_node_reading(node)
parts.append(f"{surface}({reading})")
furi.append(f"{surface}")
else:
parts.append(surface)
furi.append(surface)
node = node.next
return {'reading':("".join(parts)),'vocab':vocab,"furigana":("".join(furi))}
def elide(text: str) -> str:
elide_max_length = 100
if len(text) > elide_max_length:
return text[:100] + "..."
return text
def anki_fields_term(term : str) -> dict:
params = {
"text": term,
"type": "term",
"markers": ["audio", "cloze-body-kana", "conjugation", "expression", "furigana", "furigana-plain", "glossary", "glossary-brief", "glossary-no-dictionary", "glossary-first", "glossary-first-brief", "glossary-first-no-dictionary", "part-of-speech", "phonetic-transcriptions", "pitch-accents", "pitch-accent-graphs", "pitch-accent-graphs-jj", "pitch-accent-positions", "pitch-accent-categories", "reading", "tags", "clipboard-image", "clipboard-text", "cloze-body", "cloze-prefix", "cloze-suffix", "dictionary", "dictionary-alias", "document-title", "frequencies", "frequency-harmonic-rank", "frequency-harmonic-occurrence", "frequency-average-rank", "frequency-average-occurrence", "screenshot", "search-query", "popup-selection-text", "sentence", "sentence-furigana", "sentence-furigana-plain", "url"],
"maxEntries": 1,
"includeMedia": False,
}
response = requests.post(request_url + "/ankiFields", json = params, timeout = request_timeout)
return json.loads(response.text)
def term_entries(term :str) -> dict:
#print("Requesting termEntries:")
params = {
"term": term,
"maxEntries": 1,
"includeMedia": False,
}
response = requests.post(request_url + "/termEntries", json = params, timeout = request_timeout)
return json.loads(response.text)
# perhaps set up a filter parameter.
def flatten_string(node):
if isinstance(node,str):
yield node
elif isinstance(node, list):
for item in node:
yield from flatten_string(item)
elif isinstance(node,dict):
if isinstance(node.get("content"), str):
yield node["content"]
else:
for v in node.values():
yield from flatten_string(v)
def extract_text_by_type(node, target_type):
if isinstance(node,dict):
data = node.get("data")
if isinstance(data,dict) and data.get("content") == target_type:
yield from flatten_string(node.get("content"))
#yield from ",".join(node.get("content"))
for value in node.values():
yield from extract_text_by_type(value, target_type)
elif isinstance(node,list):
for item in node:
yield from extract_text_by_type(item,target_type)
def get_glossary(word :str) -> list:
glossary = list()
dict_items = term_entries(word)
entry = next(iter(dict_items.get("dictionaryEntries",[])),None)
if entry:
definition = next(iter(entry.get("definitions",[])),None)
if definition:
def_entry = next(iter(definition.get("entries", [])),None)
if def_entry:
glossary.extend( list(extract_text_by_type(def_entry, "glossary")) )
return glossary[:2]
#print(annotate_phrase("私は学校へ行きます"))
with open("dump2.json", "r", encoding="utf-16") as f:
dump = json.load(f)
vocab_dict = {}
## A micab phrase based word parser
for cd in dump:
print(dump[cd]['name_J'])
# node = tagger.parseToNode(dump[cd]['name_J'])
# while node:
# # node.surface is the word; node.feature contains POS tags
# if node.surface:
# print(f"{node.surface}\t{node.feature}")
# node = node.next
anottated = annotate_phrase(dump[cd]['name_J'])
if anottated['reading'] != dump[cd]['name_J']:
#print(anottated['reading'])
dump[cd]['kana'] = anottated['reading']
dump[cd]['furi'] = anottated['furigana']
cd_nm = dump[cd]['name_J']
if (anottated.get('vocab')):
dump[cd]['glossary_Name_J'] = {}
for word in anottated['vocab']:
# Skip punctuation words hopefully
if len(word) == 1 and has_kanji(word) == False:
continue
if vocab_dict.get(word) is None:
vocab_dict[word] = {
'Def.': "; ".join(get_glossary(word)),
'count': 0,
'Examples': (cd_nm,)
}
else:
vocab_dict[word]['count'] = vocab_dict[word]['count'] + 1
if cd_nm not in vocab_dict[word]['Examples']:
vocab_dict[word]['Examples'] += (cd_nm,)
if vocab_dict.get(word) and dump[cd]['glossary_Name_J'].get(word) is None:
dump[cd]['glossary_Name_J'][word] = vocab_dict[word]['Def.']
#append(f"{word}: {vocab_dict[word]['Def.']}")
print()
phrase = dump[cd]['desc_J']
anottated = annotate_phrase(phrase)
if anottated['reading'] != phrase:
#print(anottated['reading'])
dump[cd]['desc_kana'] = anottated['reading']
dump[cd]['desc_Furi'] = anottated['furigana']
if (anottated.get('vocab')):
dump[cd]['glossary_Desc_J'] = {}
for word in anottated['vocab']:
if len(word) == 1 and has_kanji(word) == False:
continue
if vocab_dict.get(word) is None:
vocab_dict[word] = {
'Def.': "; ".join(get_glossary(word)),
'count': 0,
'Examples': (cd_nm,)
}
else:
vocab_dict[word]['count'] = vocab_dict[word]['count'] + 1
if len(vocab_dict[word]['Examples']) < 5:
if cd_nm not in vocab_dict[word]['Examples']:
vocab_dict[word]['Examples'] += (cd_nm,)
if vocab_dict.get(word) and dump[cd]['glossary_Desc_J'].get(word) is None:
dump[cd]['glossary_Desc_J'][word] = vocab_dict[word]['Def.']
vocab_dict = sorted(vocab_dict.items(), key= lambda x: x[1]['count'], reverse=True)
with open("dump-withFuri.json", "w", encoding="utf-16") as outfile:
json.dump(dump, outfile, ensure_ascii=False, indent=2)
#with open("dump-vocab.json", "w", encoding="utf-16") as outfile:
# json.dump(vocab_dict, outfile, ensure_ascii=False, indent=2)