diff --git a/__init__.py b/__init__.py index 4e4b264..0ab2884 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -from . import kanji_furi +from . import kanji_furi, sentence_examples \ No newline at end of file diff --git a/config.json b/config.json index 1a71da3..a688222 100644 --- a/config.json +++ b/config.json @@ -4,5 +4,7 @@ "kanji_field": "Front", "kana_field": "Reading", "type_field": "WordType", - "number_of_defs": 3 + "number_of_defs": 3, + "number_of_sentences": 5, + "sentence_field": "Examples" } \ No newline at end of file diff --git a/dicts/sentences.pickle b/dicts/sentences.pickle new file mode 100644 index 0000000..d2f99a0 Binary files /dev/null and b/dicts/sentences.pickle differ diff --git a/kanji_furi.py b/kanji_furi.py index 0a0dfe3..d19954f 100644 --- a/kanji_furi.py +++ b/kanji_furi.py @@ -10,12 +10,16 @@ from anki.notes import Note from aqt import gui_hooks, qconnect, mw +from . import sentence_examples + SETTING_SRC_FIELD = "kanji_field" SETTING_FURI_DEST_FIELD = "furigana_field" SETTING_KANA_DEST_FIELD = "kana_field" SETTING_TYPE_DEST_FIELD = "type_field" SETTING_MEANING_FIELD = "definition_field" SETTING_NUM_DEFS = "number_of_defs" +SETTING_NUM_SENTENCES = "number_of_sentences" +SETTING_SENTENCE_DEST_FIELD = "sentence_field" # This is used to prevent excessive lookups previous_srcTxt = None @@ -186,6 +190,10 @@ def on_focus_lost(changed: bool, note: Note, current_field_index: int) -> bool: if insert_if_empty(fields, note, SETTING_TYPE_DEST_FIELD, parts_of_speech_conversion(jmdict_info.get("parts_of_speech_values", ""))): changed = True + if config.get(SETTING_SENTENCE_DEST_FIELD) in fields: + sentence_num = config[SETTING_NUM_SENTENCES] + if insert_if_empty(fields, note, SETTING_SENTENCE_DEST_FIELD, jsl.find_example_sentences_by_word_formatted(src_txt, sentence_num)): + changed = True return changed @@ -247,9 +255,24 @@ def settings_dialog(): box_def_nums.addWidget(label_def_nums) box_def_nums.addWidget(text_def_nums) + box_sentence = QHBoxLayout() + label_sentence = QLabel("Example Sentence field:") + text_sentence = QLineEdit("") + text_sentence.setMinimumWidth(200) + box_sentence.addWidget(label_sentence) + box_sentence.addWidget(text_sentence) + + box_sentc_nums = QHBoxLayout() + label_sentc_nums = QLabel("Number of Sentences:") + text_sentc_nums = QSpinBox() + text_sentc_nums.setMinimumWidth(200) + box_sentc_nums.addWidget(label_sentc_nums) + box_sentc_nums.addWidget(text_sentc_nums) + ok = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok) cancel = QDialogButtonBox(QDialogButtonBox.StandardButton.Cancel) + def init_configui(): text_query.setText(config.get(SETTING_SRC_FIELD, "not_set")) text_furigana.setText(config.get(SETTING_FURI_DEST_FIELD, "not_set")) @@ -257,6 +280,9 @@ def init_configui(): text_kana.setText(config.get(SETTING_KANA_DEST_FIELD, "not_set")) text_type.setText(config.get(SETTING_TYPE_DEST_FIELD, "WordType")) text_def_nums.setValue(config.get(SETTING_NUM_DEFS, 5)) + text_sentence.setText(config.get(SETTING_SENTENCE_DEST_FIELD, "Examples")) + text_sentc_nums.setValue(config.get(SETTING_NUM_SENTENCES, 5)) + def save_config(): config[SETTING_SRC_FIELD] = text_query.text() @@ -265,9 +291,12 @@ def save_config(): config[SETTING_KANA_DEST_FIELD] = text_kana.text() config[SETTING_TYPE_DEST_FIELD] = text_type.text() config[SETTING_NUM_DEFS] = text_def_nums.value() + config[SETTING_SENTENCE_DEST_FIELD] = text_sentence.text() + config[SETTING_NUM_SENTENCES] = text_sentc_nums.value() mw.addonManager.writeConfig(__name__, config) dialog.close() + def layout_everything(): layout = QVBoxLayout() dialog.setLayout(layout) @@ -278,6 +307,8 @@ def layout_everything(): layout.addLayout(box_def) layout.addLayout(box_type) layout.addLayout(box_def_nums) + layout.addLayout(box_sentence) + layout.addLayout(box_sentc_nums) layout.addWidget(ok) layout.addWidget(cancel) @@ -299,7 +330,7 @@ def init_menu(): def get_field_names_array(): array = [config.get(SETTING_SRC_FIELD), config.get(SETTING_FURI_DEST_FIELD), config.get(SETTING_KANA_DEST_FIELD), - config.get(SETTING_TYPE_DEST_FIELD), config.get(SETTING_MEANING_FIELD)] + config.get(SETTING_TYPE_DEST_FIELD), config.get(SETTING_MEANING_FIELD), config.get(SETTING_SENTENCE_DEST_FIELD)] return array @@ -350,6 +381,19 @@ def editor_button_setup(buttons, editor): with open(data_file, "wb") as file: pickle.dump(dict_data, file) +# Begin Section for example sentences +sentences_pickle_file = 'sentences.pickle' +if os.path.isfile(os.path.join(dicts_path + sentences_pickle_file)): + jsl = sentence_examples.JapaneseSentenceLib() + jsl.load_pickle_file(os.path.join(dicts_path + sentences_pickle_file)) +else: + jsl = sentence_examples.JapaneseSentenceLib() + # Won't include these in the release... However... can be downloaded from the following. + # https://tatoeba.org/en/downloads + jsl.load_sentences_from_file(os.path.join(dicts_path + 'jpn_sentences_detailed.tsv')) + jsl.load_sentence_rating_data(os.path.join(dicts_path + 'users_sentences.csv')) + jsl.save_pickle_file(os.path.join(dicts_path + sentences_pickle_file)) + # Create config variable config = mw.addonManager.getConfig(__name__) diff --git a/meta.json b/meta.json index 3aeb703..0d13d62 100644 --- a/meta.json +++ b/meta.json @@ -5,6 +5,8 @@ "kanji_field": "Front", "kana_field": "Reading", "type_field": "WordType", - "number_of_defs": 3 + "number_of_defs": 3, + "number_of_sentences": 5, + "sentence_field": "Examples" } } \ No newline at end of file diff --git a/sentence_examples.py b/sentence_examples.py new file mode 100644 index 0000000..b016418 --- /dev/null +++ b/sentence_examples.py @@ -0,0 +1,99 @@ +import csv +import pickle +from datetime import datetime + +class JapaneseSentenceLib: + def __init__(self): + self.sentences = {} + + # Data locations... + # Sentence id [tab] Lang [tab] Text [tab] Username [tab] Date added [tab] Date last modified + def load_sentences_from_file(self, filepath): + with open(filepath, 'r') as file: + reader = csv.reader(file, delimiter='\t') + for line in reader: + add_sentence = Sentence(line) + self.sentences[int(add_sentence.id)] = add_sentence + + def find_example_sentences_by_word(self, word, limit = 10): + sentences = [] + for sentence in self.sentences.values(): + if word in sentence.text: + sentences.append(sentence) + + sentences = sorted(sentences, key=lambda x: x.date_added) + if len(sentences) > limit: + return sentences[:limit] + return sentences + + def find_example_sentences_by_word_formatted(self, word, limit = 10): + sentences = self.find_example_sentences_by_word(word, limit) + output_str_ary = [] + for sentence in sentences: + output_str_ary.append(sentence.text) + return "
".join(output_str_ary) + + def load_sentence_rating_data(self, file): + with open(file, 'r') as file: + reader = csv.reader(file, delimiter='\t') + for line in reader: + sentence = self.get_sentence_by_id(line[1]) + if sentence: + if line[2] == '1': + sentence.add_positive_rating() + elif line[2] == '0': + sentence.add_undecided_rating() + elif line[2] == '-1': + sentence.add_negative_rating() + + def get_sentence_by_id(self, id): + if int(id) in self.sentences: + return self.sentences[int(id)] + return None + + def save_pickle_file(self, data_file): + with open(data_file, 'wb') as file: + pickle.dump(self.sentences, file) + + def load_pickle_file(self, data_file): + with open(data_file, 'rb') as file: + self.sentences = pickle.load(file) + +class Sentence: + def __init__(self, data): + self.id = data[0] + self.lang = data[1] + self.text = data[2] + self.username = data[3] + self.date_added = data[4] + self.date_modified = data[5] + # Fixes up the ones without an added date + if self.date_added == '\\N': + self.date_added = self.date_modified + if self.date_modified == '\\N': + self.date_modified = self.date_added + if self.date_added in ['0000-00-00 00:00:00', '\\N']: + self.date_added = '2008-01-26 18:04:24' + if self.date_modified in ['0000-00-00 00:00:00', '\\N']: + self.date_modified = '2008-01-26 18:04:24' + self.date_modified = datetime.strptime(self.date_modified, '%Y-%m-%d %H:%M:%S') + self.date_added = datetime.strptime(self.date_added, '%Y-%m-%d %H:%M:%S') + self.total_ratings = 0 + self.positive_rating = 0 + self.negative_rating = 0 + + def add_positive_rating(self): + self.positive_rating = self.positive_rating + 1 + self.total_ratings = self.total_ratings + 1 + + def add_undecided_rating(self): + self.total_ratings = self.total_ratings + 1 + + def add_negative_rating(self): + self.negative_rating = self.negative_rating + 1 + self.total_ratings = self.total_ratings + 1 + + def get_rating_percentage(self): + if self.total_ratings == 0: + return 100 + return self.positive_rating / self.total_ratings * 100 \ No newline at end of file