Skip to content

Commit

Permalink
Add support for example sentences in cards
Browse files Browse the repository at this point in the history
Implemented functionality to include example sentences from a Japanese sentence library. Updated configuration and UI to handle example sentences.
  • Loading branch information
kit-nya committed Aug 24, 2024
1 parent 0b5addf commit 89c5732
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 4 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import kanji_furi
from . import kanji_furi, sentence_examples
4 changes: 3 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Binary file added dicts/sentences.pickle
Binary file not shown.
46 changes: 45 additions & 1 deletion kanji_furi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -247,16 +255,34 @@ 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"))
text_def.setText(config.get(SETTING_MEANING_FIELD, "not_set"))
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()
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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


Expand Down Expand Up @@ -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__)
Expand Down
4 changes: 3 additions & 1 deletion meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
99 changes: 99 additions & 0 deletions sentence_examples.py
Original file line number Diff line number Diff line change
@@ -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 "<br>".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

0 comments on commit 89c5732

Please sign in to comment.