Anchor-annotator 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
anchor/settings.py CHANGED
@@ -116,6 +116,8 @@ class AnchorSettings(QtCore.QSettings):
116
116
  CLUSTERING_DISTANCE_THRESHOLD = "anchor/clustering/distance_threshold"
117
117
  CLUSTERING_METRIC = "anchor/clustering/metric"
118
118
 
119
+ PLOT_THREAD_COUNT = "anchor/plot/max_thread_count"
120
+
119
121
  PITCH_MAX_TIME = "anchor/pitch/max_time"
120
122
  PITCH_MIN_F0 = "anchor/pitch/min_f0"
121
123
  PITCH_MAX_F0 = "anchor/pitch/max_f0"
@@ -218,6 +220,7 @@ class AnchorSettings(QtCore.QSettings):
218
220
  AnchorSettings.TIER_TRANSCRIBED_WORDS_VISIBLE: True,
219
221
  AnchorSettings.TIER_TRANSCRIBED_PHONES_VISIBLE: True,
220
222
  AnchorSettings.THEME_PRESET: "MFA",
223
+ AnchorSettings.PLOT_THREAD_COUNT: 10,
221
224
  }
222
225
  self.default_values.update(self.mfa_theme)
223
226
  self.border_radius = 5
@@ -264,9 +267,10 @@ class AnchorSettings(QtCore.QSettings):
264
267
  super(AnchorSettings, self).value(arg__1, self.default_values[arg__1])
265
268
  )
266
269
  elif "color" in arg__1:
267
- value = QtGui.QColor(
268
- super(AnchorSettings, self).value(arg__1, self.default_values[arg__1])
269
- )
270
+ value = super(AnchorSettings, self).value(arg__1, self.default_values[arg__1])
271
+ if value is None:
272
+ value = self.default_values[arg__1]
273
+ value = QtGui.QColor(value)
270
274
  elif "keybind" in arg__1:
271
275
  value = QtGui.QKeySequence(
272
276
  super(AnchorSettings, self).value(arg__1, self.default_values[arg__1])
@@ -319,6 +323,8 @@ class AnchorSettings(QtCore.QSettings):
319
323
 
320
324
  def set_theme(self, theme):
321
325
  for k, v in theme.items():
326
+ if v is None:
327
+ continue
322
328
  self.setValue(k, v)
323
329
  self.sync()
324
330
  self.themeUpdated.emit()
@@ -909,7 +915,7 @@ class AnchorSettings(QtCore.QSettings):
909
915
  }}
910
916
  QToolButton:checked {{
911
917
  color: {active_color};
912
- background-color: {active_background_color};
918
+ background-color: {hover_background_color};
913
919
  border-color: {active_border_color};
914
920
  }}
915
921
  QPushButton:disabled, QToolButton:disabled {{
anchor/ui_main_window.py CHANGED
@@ -262,6 +262,8 @@ class Ui_MainWindow(object):
262
262
  self.segmentUtteranceAct.setIcon(icon6)
263
263
  self.openCorpusManagerAct = QAction(MainWindow)
264
264
  self.openCorpusManagerAct.setObjectName("openCorpusManagerAct")
265
+ self.verifyTranscriptsAct = QAction(MainWindow)
266
+ self.verifyTranscriptsAct.setObjectName("verifyTranscriptsAct")
265
267
  self.centralwidget = QWidget(MainWindow)
266
268
  self.centralwidget.setObjectName("centralwidget")
267
269
  self.verticalLayout_4 = QVBoxLayout(self.centralwidget)
@@ -663,6 +665,14 @@ class Ui_MainWindow(object):
663
665
  QCoreApplication.translate("MainWindow", "Manage corpora and models", None)
664
666
  )
665
667
  # endif // QT_CONFIG(tooltip)
668
+ self.verifyTranscriptsAct.setText(
669
+ QCoreApplication.translate("MainWindow", "Verify transcripts", None)
670
+ )
671
+ # if QT_CONFIG(tooltip)
672
+ self.verifyTranscriptsAct.setToolTip(
673
+ QCoreApplication.translate("MainWindow", "Verify transcripts", None)
674
+ )
675
+ # endif // QT_CONFIG(tooltip)
666
676
  self.menuCorpus.setTitle(QCoreApplication.translate("MainWindow", "Corpus", None))
667
677
  self.loadRecentCorpusMenu.setTitle(
668
678
  QCoreApplication.translate("MainWindow", "Load a recent corpus", None)
anchor/undo.py CHANGED
@@ -427,28 +427,26 @@ class UpdateUtteranceTextCommand(FileCommand):
427
427
  "UpdateUtteranceTextCommand", "Update utterance text"
428
428
  )
429
429
  )
430
+ self.tokenizer = self.corpus_model.corpus.get_tokenizer(
431
+ self.corpus_model.corpus.get_dict_id_for_speaker(
432
+ self.corpus_model.get_speaker_name(self.speaker_id)
433
+ )
434
+ )
430
435
 
431
- def _redo(self, session) -> None:
432
- oovs = set()
433
- for w in self.new_text.split():
434
- if not self.corpus_model.dictionary_model.check_word(w, self.speaker_id):
435
- oovs.add(w)
436
- self.utterance.text = self.new_text
437
- self.utterance.normalized_text = self.new_text # FIXME: Update this
436
+ def _process_text(self, session, text: str):
437
+ self.utterance.text = text
438
+ normalized_text, normalized_character_text, oovs = self.tokenizer(text)
439
+ self.utterance.normalized_text = normalized_text
440
+ self.utterance.normalized_character_text = normalized_character_text
438
441
  self.utterance.oovs = " ".join(oovs)
439
- self.utterance.ignored = not self.new_text
442
+ self.utterance.ignored = not text
440
443
  session.merge(self.utterance)
441
444
 
445
+ def _redo(self, session) -> None:
446
+ self._process_text(session, self.new_text)
447
+
442
448
  def _undo(self, session) -> None:
443
- oovs = set()
444
- for w in self.new_text.split():
445
- if not self.corpus_model.dictionary_model.check_word(w, self.speaker_id):
446
- oovs.add(w)
447
- self.utterance.text = self.old_text
448
- self.utterance.normalized_text = self.old_text # FIXME: Update this
449
- self.utterance.oovs = " ".join(oovs)
450
- self.utterance.ignored = not self.old_text
451
- session.merge(self.utterance)
449
+ self._process_text(session, self.old_text)
452
450
 
453
451
  def id(self) -> int:
454
452
  return 1
@@ -767,7 +765,9 @@ class AddPronunciationCommand(DictionaryCommand):
767
765
 
768
766
  def _redo(self, session) -> None:
769
767
  if self.word_id is None:
770
- self.word_id = session.query(Word.id).filter(Word.word == self.word).first()[0]
768
+ q = session.query(Word.id).filter(Word.word == self.word).first()
769
+ if q is not None:
770
+ self.word_id = q[0]
771
771
  if self.word_id is None:
772
772
  self.word_id = session.query(sqlalchemy.func.max(Word.id)).scalar() + 1
773
773
  word_mapping_id = (
anchor/widgets.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  import re
5
+ import time
5
6
  import typing
6
7
  from typing import TYPE_CHECKING, Optional
7
8
 
@@ -93,13 +94,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
93
94
  self.fade_in_anim.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
94
95
  self.fade_in_anim.setKeyValueAt(0.1, 0.1)
95
96
 
96
- self.fade_out_anim = QtCore.QPropertyAnimation(self._audio_output, b"volume")
97
- self.fade_out_anim.setDuration(5)
98
- self.fade_out_anim.setStartValue(self._audio_output.volume())
99
- self.fade_out_anim.setEndValue(0)
100
- self.fade_out_anim.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
101
- self.fade_out_anim.setKeyValueAt(0.1, self._audio_output.volume())
102
- self.fade_out_anim.finished.connect(super().pause)
103
97
  self.file_path = None
104
98
  self.set_volume(self.settings.value(self.settings.VOLUME))
105
99
 
@@ -113,6 +107,12 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
113
107
  def play(self) -> None:
114
108
  if self.startTime() is None:
115
109
  return
110
+ if self.mediaStatus() not in {
111
+ QtMultimedia.QMediaPlayer.MediaStatus.BufferedMedia,
112
+ QtMultimedia.QMediaPlayer.MediaStatus.LoadedMedia,
113
+ QtMultimedia.QMediaPlayer.MediaStatus.EndOfMedia,
114
+ }:
115
+ return
116
116
  fade_in = self.settings.value(self.settings.ENABLE_FADE)
117
117
  if fade_in:
118
118
  self._audio_output.setVolume(0.1)
@@ -167,7 +167,7 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
167
167
  if selection_model is None:
168
168
  return
169
169
  self.selection_model = selection_model
170
- self.selection_model.fileChanged.connect(self.loadNewFile)
170
+ self.selection_model.fileChanged.connect(self.load_new_file)
171
171
  self.selection_model.viewChanged.connect(self.update_times)
172
172
  self.selection_model.selectionAudioChanged.connect(self.update_selection_times)
173
173
 
@@ -175,24 +175,23 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
175
175
  self.settings.setValue(self.settings.VOLUME, volume)
176
176
  if self.audioOutput() is None:
177
177
  return
178
- linearVolume = QtMultimedia.QtAudio.convertVolume(
178
+ linearVolume = QtMultimedia.QAudio.convertVolume(
179
179
  volume / 100.0,
180
- QtMultimedia.QtAudio.VolumeScale.LogarithmicVolumeScale,
181
- QtMultimedia.QtAudio.VolumeScale.LinearVolumeScale,
180
+ QtMultimedia.QAudio.VolumeScale.LogarithmicVolumeScale,
181
+ QtMultimedia.QAudio.VolumeScale.LinearVolumeScale,
182
182
  )
183
183
  self.audioOutput().setVolume(linearVolume)
184
184
  self.fade_in_anim.setEndValue(linearVolume)
185
- self.fade_out_anim.setStartValue(linearVolume)
186
185
 
187
186
  def volume(self) -> int:
188
187
  if self.audioOutput() is None:
189
188
  return 100
190
189
  volume = self.audioOutput().volume()
191
190
  volume = int(
192
- QtMultimedia.QtAudio.convertVolume(
191
+ QtMultimedia.QAudio.convertVolume(
193
192
  volume,
194
- QtMultimedia.QtAudio.VolumeScale.LinearVolumeScale,
195
- QtMultimedia.QtAudio.VolumeScale.LogarithmicVolumeScale,
193
+ QtMultimedia.QAudio.VolumeScale.LinearVolumeScale,
194
+ QtMultimedia.QAudio.VolumeScale.LogarithmicVolumeScale,
196
195
  )
197
196
  * 100
198
197
  )
@@ -211,9 +210,13 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
211
210
  self.stop()
212
211
  self.setCurrentTime(self.startTime())
213
212
 
214
- def loadNewFile(self, *args):
215
- self.audioReady.emit(False)
216
- self.stop()
213
+ def load_new_file(self, *args):
214
+ if self.playbackState() in {
215
+ QtMultimedia.QMediaPlayer.PlaybackState.PlayingState,
216
+ QtMultimedia.QMediaPlayer.PlaybackState.PausedState,
217
+ }:
218
+ self.stop()
219
+ time.sleep(0.1)
217
220
  try:
218
221
  new_file = self.selection_model.model().file.sound_file.sound_file_path
219
222
  except Exception:
@@ -227,8 +230,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
227
230
  self.setSource(QtCore.QUrl())
228
231
  return
229
232
  self.setSource(f"file:///{new_file}")
230
- self.setPosition(0)
231
- self.audioReady.emit(True)
232
233
 
233
234
  def currentTime(self):
234
235
  pos = self.position()
@@ -1063,21 +1064,72 @@ class SearchBox(ClearableField):
1063
1064
 
1064
1065
  def __init__(self, *args):
1065
1066
  super().__init__(*args)
1067
+ settings = AnchorSettings()
1066
1068
  self.returnPressed.connect(self.activate)
1067
1069
  self.setObjectName("search_box")
1068
1070
 
1069
1071
  self.clear_action.triggered.connect(self.returnPressed.emit)
1070
1072
 
1071
- regex_icon = QtGui.QIcon.fromTheme("edit-regex")
1073
+ regex_icon = QtGui.QIcon()
1074
+ word_icon = QtGui.QIcon()
1075
+ case_icon = QtGui.QIcon()
1076
+ if (
1077
+ settings.theme_preset == "Native"
1078
+ and QtGui.QGuiApplication.styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark
1079
+ ):
1080
+ regex_icon.addFile(
1081
+ ":icons/anchor_dark/actions/edit-regex.svg",
1082
+ mode=QtGui.QIcon.Mode.Normal,
1083
+ state=QtGui.QIcon.State.Off,
1084
+ )
1085
+ word_icon.addFile(
1086
+ ":icons/anchor_dark/actions/edit-word.svg",
1087
+ mode=QtGui.QIcon.Mode.Normal,
1088
+ state=QtGui.QIcon.State.Off,
1089
+ )
1090
+ case_icon.addFile(
1091
+ ":icons/anchor_dark/actions/edit-case.svg",
1092
+ mode=QtGui.QIcon.Mode.Normal,
1093
+ state=QtGui.QIcon.State.Off,
1094
+ )
1095
+ else:
1096
+ regex_icon.addFile(
1097
+ ":icons/anchor_light/actions/edit-regex.svg",
1098
+ mode=QtGui.QIcon.Mode.Normal,
1099
+ state=QtGui.QIcon.State.Off,
1100
+ )
1101
+ word_icon.addFile(
1102
+ ":icons/anchor_light/actions/edit-word.svg",
1103
+ mode=QtGui.QIcon.Mode.Normal,
1104
+ state=QtGui.QIcon.State.Off,
1105
+ )
1106
+ case_icon.addFile(
1107
+ ":icons/anchor_light/actions/edit-case.svg",
1108
+ mode=QtGui.QIcon.Mode.Normal,
1109
+ state=QtGui.QIcon.State.Off,
1110
+ )
1111
+ regex_icon.addFile(
1112
+ ":icons/edit-regex-checked.svg",
1113
+ mode=QtGui.QIcon.Mode.Normal,
1114
+ state=QtGui.QIcon.State.On,
1115
+ )
1116
+ word_icon.addFile(
1117
+ ":icons/edit-word-checked.svg",
1118
+ mode=QtGui.QIcon.Mode.Normal,
1119
+ state=QtGui.QIcon.State.On,
1120
+ )
1121
+ case_icon.addFile(
1122
+ ":icons/edit-case-checked.svg",
1123
+ mode=QtGui.QIcon.Mode.Normal,
1124
+ state=QtGui.QIcon.State.On,
1125
+ )
1072
1126
 
1073
1127
  self.regex_action = QtGui.QAction(icon=regex_icon, parent=self)
1074
1128
  self.regex_action.setCheckable(True)
1075
1129
 
1076
- word_icon = QtGui.QIcon.fromTheme("edit-word")
1077
1130
  self.word_action = QtGui.QAction(icon=word_icon, parent=self)
1078
1131
  self.word_action.setCheckable(True)
1079
1132
 
1080
- case_icon = QtGui.QIcon.fromTheme("edit-case")
1081
1133
  self.case_action = QtGui.QAction(icon=case_icon, parent=self)
1082
1134
  self.case_action.setCheckable(True)
1083
1135
 
@@ -1108,7 +1160,7 @@ class SearchBox(ClearableField):
1108
1160
  def query(self) -> TextFilterQuery:
1109
1161
  filter = TextFilterQuery(
1110
1162
  super().text(),
1111
- self.regex_action.isChecked() or self.word_action.isChecked(),
1163
+ self.regex_action.isChecked(),
1112
1164
  self.word_action.isChecked(),
1113
1165
  self.case_action.isChecked(),
1114
1166
  )
@@ -2063,7 +2115,7 @@ class OovTableView(AnchorTableView):
2063
2115
 
2064
2116
  def generate_context_menu(self, location):
2065
2117
  menu = QtWidgets.QMenu()
2066
- # menu.setStyleSheet(self.settings.menu_style_sheet)
2118
+ menu.setStyleSheet(self.settings.menu_style_sheet)
2067
2119
  menu.addAction(self.add_pronunciation_action)
2068
2120
  menu.exec_(self.mapToGlobal(location))
2069
2121
 
@@ -2122,7 +2174,7 @@ class DictionaryTableView(AnchorTableView):
2122
2174
 
2123
2175
  def generate_context_menu(self, location):
2124
2176
  menu = QtWidgets.QMenu()
2125
- # menu.setStyleSheet(self.settings.menu_style_sheet)
2177
+ menu.setStyleSheet(self.settings.menu_style_sheet)
2126
2178
  menu.addAction(self.add_pronunciation_action)
2127
2179
  menu.addSeparator()
2128
2180
  menu.addAction(self.delete_words_action)
@@ -2205,8 +2257,7 @@ class SpeakerTableView(AnchorTableView):
2205
2257
  | QtWidgets.QAbstractItemView.EditTrigger.DoubleClicked
2206
2258
  )
2207
2259
  self.speaker_model: SpeakerModel = None
2208
- self.view_delegate = ButtonDelegate(":magnifying-glass.svg", self)
2209
- self.delete_delegate = ButtonDelegate(":expand.svg", self)
2260
+ self.view_delegate = ButtonDelegate("edit-find", self)
2210
2261
  self.edit_delegate = EditableDelegate(self)
2211
2262
  self.speaker_delegate = SpeakerViewDelegate(self)
2212
2263
  self.setItemDelegateForColumn(1, self.speaker_delegate)
@@ -2500,7 +2551,7 @@ class ButtonDelegate(QtWidgets.QStyledItemDelegate):
2500
2551
  options = QtWidgets.QStyleOptionViewItem(option)
2501
2552
  options.rect = QtCore.QRect(x, y, self.settings.icon_size, self.settings.icon_size)
2502
2553
  self.initStyleOption(options, index)
2503
- icon = QtGui.QIcon(self.icon_path)
2554
+ icon = QtGui.QIcon.fromTheme(self.icon_path)
2504
2555
  icon.paint(painter, options.rect, QtCore.Qt.AlignmentFlag.AlignCenter)
2505
2556
 
2506
2557
  painter.restore()
@@ -2899,9 +2950,13 @@ class AlignmentWidget(QtWidgets.QWidget):
2899
2950
  def __init__(self, *args):
2900
2951
  super().__init__(*args)
2901
2952
  self.button = QtWidgets.QToolButton()
2902
- layout = QtWidgets.QFormLayout()
2953
+ self.verify_button = QtWidgets.QToolButton()
2954
+ form_layout = QtWidgets.QFormLayout()
2955
+ button_layout = QtWidgets.QHBoxLayout()
2956
+ layout = QtWidgets.QVBoxLayout()
2903
2957
  self.acoustic_model_label = QtWidgets.QLabel("Not loaded")
2904
2958
  self.dictionary_label = QtWidgets.QLabel("Not loaded")
2959
+ self.interjection_word_label = QtWidgets.QLabel("Not loaded")
2905
2960
  self.fine_tune_check = QtWidgets.QCheckBox()
2906
2961
  self.beam = QtWidgets.QSpinBox()
2907
2962
  self.beam.setMinimum(6)
@@ -2914,14 +2969,18 @@ class AlignmentWidget(QtWidgets.QWidget):
2914
2969
  self.silence_boost = ThresholdWidget()
2915
2970
  self.silence_boost.setText("1.0")
2916
2971
  self.cutoff_check = QtWidgets.QCheckBox()
2917
- layout.addRow(QtWidgets.QLabel("Acoustic model"), self.acoustic_model_label)
2918
- layout.addRow(QtWidgets.QLabel("Dictionary"), self.dictionary_label)
2919
- layout.addRow(QtWidgets.QLabel("Beam"), self.beam)
2920
- layout.addRow(QtWidgets.QLabel("Retry beam"), self.retry_beam)
2921
- layout.addRow(QtWidgets.QLabel("Silence boost factor"), self.silence_boost)
2922
- layout.addRow(QtWidgets.QLabel("Fine tune"), self.fine_tune_check)
2923
- layout.addRow(QtWidgets.QLabel("Cutoff modeling"), self.cutoff_check)
2924
- layout.addWidget(self.button)
2972
+ form_layout.addRow(QtWidgets.QLabel("Acoustic model"), self.acoustic_model_label)
2973
+ form_layout.addRow(QtWidgets.QLabel("Dictionary"), self.dictionary_label)
2974
+ form_layout.addRow(QtWidgets.QLabel("Beam"), self.beam)
2975
+ form_layout.addRow(QtWidgets.QLabel("Retry beam"), self.retry_beam)
2976
+ form_layout.addRow(QtWidgets.QLabel("Silence boost factor"), self.silence_boost)
2977
+ form_layout.addRow(QtWidgets.QLabel("Fine tune"), self.fine_tune_check)
2978
+ form_layout.addRow(QtWidgets.QLabel("Cutoff modeling"), self.cutoff_check)
2979
+ form_layout.addRow(QtWidgets.QLabel("Interjection words"), self.interjection_word_label)
2980
+ layout.addLayout(form_layout)
2981
+ button_layout.addWidget(self.button)
2982
+ button_layout.addWidget(self.verify_button)
2983
+ layout.addLayout(button_layout)
2925
2984
  self.text = QtWidgets.QTextEdit()
2926
2985
  self.text.setReadOnly(True)
2927
2986
  layout.addWidget(self.text)
@@ -2930,6 +2989,10 @@ class AlignmentWidget(QtWidgets.QWidget):
2930
2989
 
2931
2990
  def refresh(self):
2932
2991
  validate_enabled = True
2992
+ num_interjection_words = self.corpus_model.get_interjection_count()
2993
+ self.interjection_word_label.setText(str(num_interjection_words))
2994
+ if self.verify_button.defaultAction() is not None:
2995
+ self.verify_button.defaultAction().setEnabled(num_interjection_words > 0)
2933
2996
  if self.corpus_model.has_dictionary:
2934
2997
  self.dictionary_label.setText(self.corpus_model.corpus.dictionary_model.name)
2935
2998
  else:
@@ -2948,6 +3011,7 @@ class AlignmentWidget(QtWidgets.QWidget):
2948
3011
  self.refresh()
2949
3012
  self.corpus_model.dictionaryChanged.connect(self.refresh)
2950
3013
  self.corpus_model.acousticModelChanged.connect(self.refresh)
3014
+ self.corpus_model.corpusLoaded.connect(self.refresh)
2951
3015
 
2952
3016
  def parameters(self):
2953
3017
  return {
@@ -3228,6 +3292,7 @@ class SpeakerWidget(QtWidgets.QWidget):
3228
3292
  session.query(Speaker.id).filter(Speaker.name == speaker_id).first()
3229
3293
  )
3230
3294
  if actual_speaker_id is None:
3295
+ self.speaker_model.set_speaker_filter(speaker_id)
3231
3296
  return
3232
3297
  self.speaker_dropdown.completions[speaker_id] = actual_speaker_id[0]
3233
3298
  speaker_id = actual_speaker_id[0]