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}{reading}") 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)