supervertaler 1.9.153__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.
Potentially problematic release.
This version of supervertaler might be problematic. Click here for more details.
- Supervertaler.py +47886 -0
- modules/__init__.py +10 -0
- modules/ai_actions.py +964 -0
- modules/ai_attachment_manager.py +343 -0
- modules/ai_file_viewer_dialog.py +210 -0
- modules/autofingers_engine.py +466 -0
- modules/cafetran_docx_handler.py +379 -0
- modules/config_manager.py +469 -0
- modules/database_manager.py +1878 -0
- modules/database_migrations.py +417 -0
- modules/dejavurtf_handler.py +779 -0
- modules/document_analyzer.py +427 -0
- modules/docx_handler.py +689 -0
- modules/encoding_repair.py +319 -0
- modules/encoding_repair_Qt.py +393 -0
- modules/encoding_repair_ui.py +481 -0
- modules/feature_manager.py +350 -0
- modules/figure_context_manager.py +340 -0
- modules/file_dialog_helper.py +148 -0
- modules/find_replace.py +164 -0
- modules/find_replace_qt.py +457 -0
- modules/glossary_manager.py +433 -0
- modules/image_extractor.py +188 -0
- modules/keyboard_shortcuts_widget.py +571 -0
- modules/llm_clients.py +1211 -0
- modules/llm_leaderboard.py +737 -0
- modules/llm_superbench_ui.py +1401 -0
- modules/local_llm_setup.py +1104 -0
- modules/model_update_dialog.py +381 -0
- modules/model_version_checker.py +373 -0
- modules/mqxliff_handler.py +638 -0
- modules/non_translatables_manager.py +743 -0
- modules/pdf_rescue_Qt.py +1822 -0
- modules/pdf_rescue_tkinter.py +909 -0
- modules/phrase_docx_handler.py +516 -0
- modules/project_home_panel.py +209 -0
- modules/prompt_assistant.py +357 -0
- modules/prompt_library.py +689 -0
- modules/prompt_library_migration.py +447 -0
- modules/quick_access_sidebar.py +282 -0
- modules/ribbon_widget.py +597 -0
- modules/sdlppx_handler.py +874 -0
- modules/setup_wizard.py +353 -0
- modules/shortcut_manager.py +932 -0
- modules/simple_segmenter.py +128 -0
- modules/spellcheck_manager.py +727 -0
- modules/statuses.py +207 -0
- modules/style_guide_manager.py +315 -0
- modules/superbench_ui.py +1319 -0
- modules/superbrowser.py +329 -0
- modules/supercleaner.py +600 -0
- modules/supercleaner_ui.py +444 -0
- modules/superdocs.py +19 -0
- modules/superdocs_viewer_qt.py +382 -0
- modules/superlookup.py +252 -0
- modules/tag_cleaner.py +260 -0
- modules/tag_manager.py +333 -0
- modules/term_extractor.py +270 -0
- modules/termbase_entry_editor.py +842 -0
- modules/termbase_import_export.py +488 -0
- modules/termbase_manager.py +1060 -0
- modules/termview_widget.py +1172 -0
- modules/theme_manager.py +499 -0
- modules/tm_editor_dialog.py +99 -0
- modules/tm_manager_qt.py +1280 -0
- modules/tm_metadata_manager.py +545 -0
- modules/tmx_editor.py +1461 -0
- modules/tmx_editor_qt.py +2784 -0
- modules/tmx_generator.py +284 -0
- modules/tracked_changes.py +900 -0
- modules/trados_docx_handler.py +430 -0
- modules/translation_memory.py +715 -0
- modules/translation_results_panel.py +2134 -0
- modules/translation_services.py +282 -0
- modules/unified_prompt_library.py +659 -0
- modules/unified_prompt_manager_qt.py +3951 -0
- modules/voice_commands.py +920 -0
- modules/voice_dictation.py +477 -0
- modules/voice_dictation_lite.py +249 -0
- supervertaler-1.9.153.dist-info/METADATA +896 -0
- supervertaler-1.9.153.dist-info/RECORD +85 -0
- supervertaler-1.9.153.dist-info/WHEEL +5 -0
- supervertaler-1.9.153.dist-info/entry_points.txt +2 -0
- supervertaler-1.9.153.dist-info/licenses/LICENSE +21 -0
- supervertaler-1.9.153.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model Update Dialog for Supervertaler
|
|
3
|
+
======================================
|
|
4
|
+
|
|
5
|
+
Dialog window that displays new LLM models detected by the version checker.
|
|
6
|
+
Allows users to easily add new models to their configuration.
|
|
7
|
+
|
|
8
|
+
Features:
|
|
9
|
+
- Shows new models grouped by provider
|
|
10
|
+
- Click to select models to add
|
|
11
|
+
- One-click "Add Selected" button
|
|
12
|
+
- Shows model details when available
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from PyQt6.QtWidgets import (
|
|
16
|
+
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
|
|
17
|
+
QCheckBox, QGroupBox, QScrollArea, QWidget, QTextEdit
|
|
18
|
+
)
|
|
19
|
+
from PyQt6.QtCore import Qt, pyqtSignal
|
|
20
|
+
from PyQt6.QtGui import QFont
|
|
21
|
+
from typing import Dict, List
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ModelUpdateDialog(QDialog):
|
|
25
|
+
"""Dialog for showing and adding new models"""
|
|
26
|
+
|
|
27
|
+
models_selected = pyqtSignal(dict) # Emits selected models by provider
|
|
28
|
+
|
|
29
|
+
def __init__(self, results: Dict, parent=None):
|
|
30
|
+
"""
|
|
31
|
+
Initialize the dialog
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
results: Results from ModelVersionChecker.check_all_providers()
|
|
35
|
+
parent: Parent widget
|
|
36
|
+
"""
|
|
37
|
+
super().__init__(parent)
|
|
38
|
+
self.results = results
|
|
39
|
+
self.selected_models = {
|
|
40
|
+
"openai": [],
|
|
41
|
+
"claude": [],
|
|
42
|
+
"gemini": []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
self.init_ui()
|
|
46
|
+
|
|
47
|
+
def init_ui(self):
|
|
48
|
+
"""Initialize the user interface"""
|
|
49
|
+
self.setWindowTitle("🆕 New LLM Models Available")
|
|
50
|
+
self.setMinimumWidth(700)
|
|
51
|
+
self.setMinimumHeight(500)
|
|
52
|
+
|
|
53
|
+
layout = QVBoxLayout()
|
|
54
|
+
|
|
55
|
+
# Header
|
|
56
|
+
header_label = QLabel("New models have been detected from LLM providers!")
|
|
57
|
+
header_font = QFont()
|
|
58
|
+
header_font.setPointSize(12)
|
|
59
|
+
header_font.setBold(True)
|
|
60
|
+
header_label.setFont(header_font)
|
|
61
|
+
layout.addWidget(header_label)
|
|
62
|
+
|
|
63
|
+
info_label = QLabel(
|
|
64
|
+
"Select the models you want to add to your Supervertaler configuration.\n"
|
|
65
|
+
"These models will be added to the respective dropdowns in Settings."
|
|
66
|
+
)
|
|
67
|
+
info_label.setWordWrap(True)
|
|
68
|
+
layout.addWidget(info_label)
|
|
69
|
+
|
|
70
|
+
# Scroll area for model groups
|
|
71
|
+
scroll = QScrollArea()
|
|
72
|
+
scroll.setWidgetResizable(True)
|
|
73
|
+
scroll_widget = QWidget()
|
|
74
|
+
scroll_layout = QVBoxLayout(scroll_widget)
|
|
75
|
+
|
|
76
|
+
# Track if we have any new models
|
|
77
|
+
has_new_models = False
|
|
78
|
+
|
|
79
|
+
# OpenAI models
|
|
80
|
+
if self.results.get("openai", {}).get("new_models"):
|
|
81
|
+
has_new_models = True
|
|
82
|
+
openai_group = self._create_provider_group(
|
|
83
|
+
"OpenAI",
|
|
84
|
+
self.results["openai"]["new_models"],
|
|
85
|
+
"openai"
|
|
86
|
+
)
|
|
87
|
+
scroll_layout.addWidget(openai_group)
|
|
88
|
+
|
|
89
|
+
# Claude models
|
|
90
|
+
if self.results.get("claude", {}).get("new_models"):
|
|
91
|
+
has_new_models = True
|
|
92
|
+
claude_group = self._create_provider_group(
|
|
93
|
+
"Anthropic Claude",
|
|
94
|
+
self.results["claude"]["new_models"],
|
|
95
|
+
"claude"
|
|
96
|
+
)
|
|
97
|
+
scroll_layout.addWidget(claude_group)
|
|
98
|
+
|
|
99
|
+
# Gemini models
|
|
100
|
+
if self.results.get("gemini", {}).get("new_models"):
|
|
101
|
+
has_new_models = True
|
|
102
|
+
gemini_group = self._create_provider_group(
|
|
103
|
+
"Google Gemini",
|
|
104
|
+
self.results["gemini"]["new_models"],
|
|
105
|
+
"gemini"
|
|
106
|
+
)
|
|
107
|
+
scroll_layout.addWidget(gemini_group)
|
|
108
|
+
|
|
109
|
+
# Show errors if any
|
|
110
|
+
error_text = []
|
|
111
|
+
for provider in ["openai", "claude", "gemini"]:
|
|
112
|
+
error = self.results.get(provider, {}).get("error")
|
|
113
|
+
if error and "No API key" not in error:
|
|
114
|
+
error_text.append(f"❌ {provider.capitalize()}: {error}")
|
|
115
|
+
|
|
116
|
+
if error_text:
|
|
117
|
+
error_box = QGroupBox("⚠️ Errors")
|
|
118
|
+
error_layout = QVBoxLayout()
|
|
119
|
+
error_label = QLabel("\n".join(error_text))
|
|
120
|
+
error_label.setWordWrap(True)
|
|
121
|
+
error_label.setStyleSheet("color: #d32f2f;")
|
|
122
|
+
error_layout.addWidget(error_label)
|
|
123
|
+
error_box.setLayout(error_layout)
|
|
124
|
+
scroll_layout.addWidget(error_box)
|
|
125
|
+
|
|
126
|
+
scroll_layout.addStretch()
|
|
127
|
+
scroll.setWidget(scroll_widget)
|
|
128
|
+
layout.addWidget(scroll)
|
|
129
|
+
|
|
130
|
+
# Buttons
|
|
131
|
+
button_layout = QHBoxLayout()
|
|
132
|
+
|
|
133
|
+
if has_new_models:
|
|
134
|
+
select_all_btn = QPushButton("Select All")
|
|
135
|
+
select_all_btn.clicked.connect(self._select_all)
|
|
136
|
+
button_layout.addWidget(select_all_btn)
|
|
137
|
+
|
|
138
|
+
deselect_all_btn = QPushButton("Deselect All")
|
|
139
|
+
deselect_all_btn.clicked.connect(self._deselect_all)
|
|
140
|
+
button_layout.addWidget(deselect_all_btn)
|
|
141
|
+
|
|
142
|
+
button_layout.addStretch()
|
|
143
|
+
|
|
144
|
+
if has_new_models:
|
|
145
|
+
add_btn = QPushButton("Add Selected Models")
|
|
146
|
+
add_btn.setStyleSheet("""
|
|
147
|
+
QPushButton {
|
|
148
|
+
background-color: #4CAF50;
|
|
149
|
+
color: white;
|
|
150
|
+
font-weight: bold;
|
|
151
|
+
padding: 8px 16px;
|
|
152
|
+
border-radius: 4px;
|
|
153
|
+
}
|
|
154
|
+
QPushButton:hover {
|
|
155
|
+
background-color: #45a049;
|
|
156
|
+
}
|
|
157
|
+
""")
|
|
158
|
+
add_btn.clicked.connect(self._add_selected)
|
|
159
|
+
button_layout.addWidget(add_btn)
|
|
160
|
+
|
|
161
|
+
close_btn = QPushButton("Close")
|
|
162
|
+
close_btn.clicked.connect(self.reject)
|
|
163
|
+
button_layout.addWidget(close_btn)
|
|
164
|
+
|
|
165
|
+
layout.addLayout(button_layout)
|
|
166
|
+
|
|
167
|
+
self.setLayout(layout)
|
|
168
|
+
|
|
169
|
+
def _create_provider_group(self, provider_name: str, models: List[str], provider_key: str) -> QGroupBox:
|
|
170
|
+
"""
|
|
171
|
+
Create a group box for a provider's models
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
provider_name: Display name (e.g., "OpenAI")
|
|
175
|
+
models: List of model IDs
|
|
176
|
+
provider_key: Key for tracking selections ("openai", "claude", "gemini")
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
QGroupBox with checkboxes for each model
|
|
180
|
+
"""
|
|
181
|
+
group = QGroupBox(f"🤖 {provider_name} ({len(models)} new model{'s' if len(models) != 1 else ''})")
|
|
182
|
+
layout = QVBoxLayout()
|
|
183
|
+
|
|
184
|
+
# Create checkbox for each model
|
|
185
|
+
for model in models:
|
|
186
|
+
checkbox = CheckmarkCheckBox(model)
|
|
187
|
+
checkbox.setChecked(True) # Pre-select all by default
|
|
188
|
+
checkbox.stateChanged.connect(
|
|
189
|
+
lambda state, m=model, p=provider_key: self._on_model_toggled(p, m, state)
|
|
190
|
+
)
|
|
191
|
+
layout.addWidget(checkbox)
|
|
192
|
+
|
|
193
|
+
# Add model to selected by default
|
|
194
|
+
if model not in self.selected_models[provider_key]:
|
|
195
|
+
self.selected_models[provider_key].append(model)
|
|
196
|
+
|
|
197
|
+
group.setLayout(layout)
|
|
198
|
+
return group
|
|
199
|
+
|
|
200
|
+
def _on_model_toggled(self, provider: str, model: str, state: int):
|
|
201
|
+
"""Handle checkbox toggle"""
|
|
202
|
+
if state == Qt.CheckState.Checked.value:
|
|
203
|
+
if model not in self.selected_models[provider]:
|
|
204
|
+
self.selected_models[provider].append(model)
|
|
205
|
+
else:
|
|
206
|
+
if model in self.selected_models[provider]:
|
|
207
|
+
self.selected_models[provider].remove(model)
|
|
208
|
+
|
|
209
|
+
def _select_all(self):
|
|
210
|
+
"""Select all checkboxes"""
|
|
211
|
+
for checkbox in self.findChildren(QCheckBox):
|
|
212
|
+
checkbox.setChecked(True)
|
|
213
|
+
|
|
214
|
+
def _deselect_all(self):
|
|
215
|
+
"""Deselect all checkboxes"""
|
|
216
|
+
for checkbox in self.findChildren(QCheckBox):
|
|
217
|
+
checkbox.setChecked(False)
|
|
218
|
+
|
|
219
|
+
def _add_selected(self):
|
|
220
|
+
"""Emit signal with selected models and close dialog"""
|
|
221
|
+
# Only include providers with selected models
|
|
222
|
+
selected = {
|
|
223
|
+
provider: models
|
|
224
|
+
for provider, models in self.selected_models.items()
|
|
225
|
+
if models
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if selected:
|
|
229
|
+
self.models_selected.emit(selected)
|
|
230
|
+
self.accept()
|
|
231
|
+
else:
|
|
232
|
+
# No models selected
|
|
233
|
+
self.reject()
|
|
234
|
+
|
|
235
|
+
def get_selected_models(self) -> Dict[str, List[str]]:
|
|
236
|
+
"""Get the selected models"""
|
|
237
|
+
return {
|
|
238
|
+
provider: models
|
|
239
|
+
for provider, models in self.selected_models.items()
|
|
240
|
+
if models
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class NoNewModelsDialog(QDialog):
|
|
245
|
+
"""Simple dialog shown when no new models are found"""
|
|
246
|
+
|
|
247
|
+
def __init__(self, last_check: str = None, parent=None):
|
|
248
|
+
"""
|
|
249
|
+
Initialize dialog
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
last_check: ISO format timestamp of last check
|
|
253
|
+
parent: Parent widget
|
|
254
|
+
"""
|
|
255
|
+
super().__init__(parent)
|
|
256
|
+
self.last_check = last_check
|
|
257
|
+
self.init_ui()
|
|
258
|
+
|
|
259
|
+
def init_ui(self):
|
|
260
|
+
"""Initialize UI"""
|
|
261
|
+
self.setWindowTitle("✅ No New Models")
|
|
262
|
+
self.setMinimumWidth(400)
|
|
263
|
+
|
|
264
|
+
layout = QVBoxLayout()
|
|
265
|
+
|
|
266
|
+
# Icon and message
|
|
267
|
+
label = QLabel("✅ No new LLM models detected")
|
|
268
|
+
font = QFont()
|
|
269
|
+
font.setPointSize(12)
|
|
270
|
+
font.setBold(True)
|
|
271
|
+
label.setFont(font)
|
|
272
|
+
layout.addWidget(label)
|
|
273
|
+
|
|
274
|
+
info_label = QLabel(
|
|
275
|
+
"Your Supervertaler is up to date with the latest models from:\n"
|
|
276
|
+
"• OpenAI (GPT-4, GPT-5, o1, o3)\n"
|
|
277
|
+
"• Anthropic (Claude Sonnet, Haiku, Opus)\n"
|
|
278
|
+
"• Google (Gemini 2.5, Gemini 3)"
|
|
279
|
+
)
|
|
280
|
+
info_label.setWordWrap(True)
|
|
281
|
+
layout.addWidget(info_label)
|
|
282
|
+
|
|
283
|
+
if self.last_check:
|
|
284
|
+
from datetime import datetime
|
|
285
|
+
try:
|
|
286
|
+
check_time = datetime.fromisoformat(self.last_check)
|
|
287
|
+
time_str = check_time.strftime("%Y-%m-%d %H:%M")
|
|
288
|
+
last_check_label = QLabel(f"Last checked: {time_str}")
|
|
289
|
+
last_check_label.setStyleSheet("color: #666; font-style: italic;")
|
|
290
|
+
layout.addWidget(last_check_label)
|
|
291
|
+
except:
|
|
292
|
+
pass
|
|
293
|
+
|
|
294
|
+
layout.addStretch()
|
|
295
|
+
|
|
296
|
+
# Close button
|
|
297
|
+
close_btn = QPushButton("OK")
|
|
298
|
+
close_btn.clicked.connect(self.accept)
|
|
299
|
+
layout.addWidget(close_btn)
|
|
300
|
+
|
|
301
|
+
self.setLayout(layout)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class CheckmarkCheckBox(QCheckBox):
|
|
305
|
+
"""Custom checkbox with green background and white checkmark when checked"""
|
|
306
|
+
|
|
307
|
+
def __init__(self, text="", parent=None):
|
|
308
|
+
super().__init__(text, parent)
|
|
309
|
+
self.setCheckable(True)
|
|
310
|
+
self.setEnabled(True)
|
|
311
|
+
self.setStyleSheet("""
|
|
312
|
+
QCheckBox {
|
|
313
|
+
font-size: 9pt;
|
|
314
|
+
spacing: 6px;
|
|
315
|
+
}
|
|
316
|
+
QCheckBox::indicator {
|
|
317
|
+
width: 16px;
|
|
318
|
+
height: 16px;
|
|
319
|
+
border: 2px solid #999;
|
|
320
|
+
border-radius: 3px;
|
|
321
|
+
background-color: white;
|
|
322
|
+
}
|
|
323
|
+
QCheckBox::indicator:checked {
|
|
324
|
+
background-color: #4CAF50;
|
|
325
|
+
border-color: #4CAF50;
|
|
326
|
+
}
|
|
327
|
+
QCheckBox::indicator:hover {
|
|
328
|
+
border-color: #666;
|
|
329
|
+
}
|
|
330
|
+
QCheckBox::indicator:checked:hover {
|
|
331
|
+
background-color: #45a049;
|
|
332
|
+
border-color: #45a049;
|
|
333
|
+
}
|
|
334
|
+
""")
|
|
335
|
+
|
|
336
|
+
def paintEvent(self, event):
|
|
337
|
+
"""Override paint event to draw white checkmark when checked"""
|
|
338
|
+
super().paintEvent(event)
|
|
339
|
+
|
|
340
|
+
if self.isChecked():
|
|
341
|
+
from PyQt6.QtWidgets import QStyleOptionButton
|
|
342
|
+
from PyQt6.QtGui import QPainter, QPen, QColor
|
|
343
|
+
from PyQt6.QtCore import QPointF, Qt
|
|
344
|
+
|
|
345
|
+
opt = QStyleOptionButton()
|
|
346
|
+
self.initStyleOption(opt)
|
|
347
|
+
indicator_rect = self.style().subElementRect(
|
|
348
|
+
self.style().SubElement.SE_CheckBoxIndicator,
|
|
349
|
+
opt,
|
|
350
|
+
self
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
if indicator_rect.isValid():
|
|
354
|
+
painter = QPainter(self)
|
|
355
|
+
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
|
356
|
+
pen_width = max(2.0, min(indicator_rect.width(), indicator_rect.height()) * 0.12)
|
|
357
|
+
painter.setPen(QPen(QColor(255, 255, 255), pen_width, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
|
|
358
|
+
painter.setBrush(QColor(255, 255, 255))
|
|
359
|
+
|
|
360
|
+
x = indicator_rect.x()
|
|
361
|
+
y = indicator_rect.y()
|
|
362
|
+
w = indicator_rect.width()
|
|
363
|
+
h = indicator_rect.height()
|
|
364
|
+
|
|
365
|
+
padding = min(w, h) * 0.15
|
|
366
|
+
x += padding
|
|
367
|
+
y += padding
|
|
368
|
+
w -= padding * 2
|
|
369
|
+
h -= padding * 2
|
|
370
|
+
|
|
371
|
+
check_x1 = x + w * 0.10
|
|
372
|
+
check_y1 = y + h * 0.50
|
|
373
|
+
check_x2 = x + w * 0.35
|
|
374
|
+
check_y2 = y + h * 0.70
|
|
375
|
+
check_x3 = x + w * 0.90
|
|
376
|
+
check_y3 = y + h * 0.25
|
|
377
|
+
|
|
378
|
+
painter.drawLine(QPointF(check_x2, check_y2), QPointF(check_x3, check_y3))
|
|
379
|
+
painter.drawLine(QPointF(check_x1, check_y1), QPointF(check_x2, check_y2))
|
|
380
|
+
|
|
381
|
+
painter.end()
|