supervertaler 1.9.195__py3-none-any.whl → 1.9.197__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 +233 -53
- modules/llm_clients.py +58 -33
- modules/unified_prompt_manager_qt.py +22 -1
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/METADATA +1 -1
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/RECORD +9 -9
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.195.dist-info → supervertaler-1.9.197.dist-info}/top_level.txt +0 -0
Supervertaler.py
CHANGED
|
@@ -32,7 +32,7 @@ License: MIT
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
# Version Information.
|
|
35
|
-
__version__ = "1.9.
|
|
35
|
+
__version__ = "1.9.197"
|
|
36
36
|
__phase__ = "0.9"
|
|
37
37
|
__release_date__ = "2026-02-02"
|
|
38
38
|
__edition__ = "Qt"
|
|
@@ -391,10 +391,10 @@ def runs_to_tagged_text(paragraphs) -> str:
|
|
|
391
391
|
def strip_formatting_tags(text: str) -> str:
|
|
392
392
|
"""
|
|
393
393
|
Remove HTML formatting tags from text, leaving plain text.
|
|
394
|
-
|
|
394
|
+
|
|
395
395
|
Args:
|
|
396
396
|
text: Text with HTML tags like <b>, </b>, <i>, </i>, <u>, </u>
|
|
397
|
-
|
|
397
|
+
|
|
398
398
|
Returns:
|
|
399
399
|
Plain text without tags
|
|
400
400
|
"""
|
|
@@ -403,6 +403,77 @@ def strip_formatting_tags(text: str) -> str:
|
|
|
403
403
|
return re.sub(r'</?[biu]>', '', text)
|
|
404
404
|
|
|
405
405
|
|
|
406
|
+
def strip_outer_wrapping_tags(text: str) -> tuple:
|
|
407
|
+
"""
|
|
408
|
+
Strip outer wrapping tags from text if the entire segment is wrapped in a single tag pair.
|
|
409
|
+
|
|
410
|
+
This handles structural tags like <li-o>...</li-o>, <p>...</p>, <td>...</td>, etc.
|
|
411
|
+
Inner formatting tags like <b>...</b> are preserved.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
text: Text that may be wrapped in outer structural tags
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
Tuple of (stripped_text, tag_name) where tag_name is the outer tag that was stripped,
|
|
418
|
+
or (original_text, None) if no outer wrapping tag was found
|
|
419
|
+
|
|
420
|
+
Examples:
|
|
421
|
+
"<li-o>Hello <b>world</b></li-o>" -> ("Hello <b>world</b>", "li-o")
|
|
422
|
+
"<p>Simple text</p>" -> ("Simple text", "p")
|
|
423
|
+
"No tags here" -> ("No tags here", None)
|
|
424
|
+
"<b>Bold text</b>" -> ("<b>Bold text</b>", None) # <b> is formatting, not structural
|
|
425
|
+
"""
|
|
426
|
+
import re
|
|
427
|
+
|
|
428
|
+
if not text or not text.strip():
|
|
429
|
+
return (text, None)
|
|
430
|
+
|
|
431
|
+
text = text.strip()
|
|
432
|
+
|
|
433
|
+
# Structural tags that wrap entire segments (not inline formatting)
|
|
434
|
+
structural_tags = {
|
|
435
|
+
'li-o', 'li-b', 'li', 'p', 'td', 'th', 'tr', 'div', 'span',
|
|
436
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'title', 'caption',
|
|
437
|
+
'blockquote', 'pre', 'code', 'dt', 'dd', 'header', 'footer',
|
|
438
|
+
'article', 'section', 'aside', 'nav', 'main', 'figure', 'figcaption'
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
# Pattern to match opening tag at start: <tag> or <tag attr="...">
|
|
442
|
+
opening_pattern = r'^<([a-zA-Z][a-zA-Z0-9-]*)(?:\s+[^>]*)?>(.*)$'
|
|
443
|
+
opening_match = re.match(opening_pattern, text, re.DOTALL)
|
|
444
|
+
|
|
445
|
+
if not opening_match:
|
|
446
|
+
return (text, None)
|
|
447
|
+
|
|
448
|
+
tag_name = opening_match.group(1).lower()
|
|
449
|
+
rest = opening_match.group(2)
|
|
450
|
+
|
|
451
|
+
# Only strip structural tags, not inline formatting like <b>, <i>, <u>, <em>, <strong>
|
|
452
|
+
if tag_name not in structural_tags:
|
|
453
|
+
return (text, None)
|
|
454
|
+
|
|
455
|
+
# Check if text ends with matching closing tag
|
|
456
|
+
closing_pattern = rf'^(.*)</{re.escape(tag_name)}>$'
|
|
457
|
+
closing_match = re.match(closing_pattern, rest, re.DOTALL | re.IGNORECASE)
|
|
458
|
+
|
|
459
|
+
if not closing_match:
|
|
460
|
+
return (text, None)
|
|
461
|
+
|
|
462
|
+
inner_content = closing_match.group(1)
|
|
463
|
+
|
|
464
|
+
# Verify this is truly a wrapping pair (no other occurrences of this tag inside)
|
|
465
|
+
# Count opening and closing tags of this type in the inner content
|
|
466
|
+
inner_opening_count = len(re.findall(rf'<{re.escape(tag_name)}(?:\s+[^>]*)?>',
|
|
467
|
+
inner_content, re.IGNORECASE))
|
|
468
|
+
inner_closing_count = len(re.findall(rf'</{re.escape(tag_name)}>', inner_content, re.IGNORECASE))
|
|
469
|
+
|
|
470
|
+
# If there are nested tags of the same type, don't strip
|
|
471
|
+
if inner_opening_count > 0 or inner_closing_count > 0:
|
|
472
|
+
return (text, None)
|
|
473
|
+
|
|
474
|
+
return (inner_content, tag_name)
|
|
475
|
+
|
|
476
|
+
|
|
406
477
|
def has_formatting_tags(text: str) -> bool:
|
|
407
478
|
"""
|
|
408
479
|
Check if text contains any formatting tags.
|
|
@@ -6222,7 +6293,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
6222
6293
|
self.enable_alternating_row_colors = True # Enable alternating row colors by default
|
|
6223
6294
|
self.even_row_color = '#FFFFFF' # White for even rows
|
|
6224
6295
|
self.odd_row_color = '#F0F0F0' # Light gray for odd rows
|
|
6225
|
-
|
|
6296
|
+
|
|
6297
|
+
# Hide outer wrapping tags in grid display (e.g. <li-o>...</li-o>)
|
|
6298
|
+
self.hide_outer_wrapping_tags = False # Disabled by default
|
|
6299
|
+
|
|
6226
6300
|
# Termbase highlight style settings
|
|
6227
6301
|
self.termbase_highlight_style = 'semibold' # 'background', 'dotted', or 'semibold'
|
|
6228
6302
|
self.termbase_dotted_color = '#808080' # Medium gray for dotted underline (more visible)
|
|
@@ -17690,14 +17764,41 @@ class SupervertalerQt(QMainWindow):
|
|
|
17690
17764
|
|
|
17691
17765
|
grid_group.setLayout(grid_layout)
|
|
17692
17766
|
layout.addWidget(grid_group)
|
|
17693
|
-
|
|
17694
|
-
#
|
|
17695
|
-
|
|
17767
|
+
|
|
17768
|
+
# Grid Display Options section
|
|
17769
|
+
grid_display_group = QGroupBox("📊 Grid Display Options")
|
|
17770
|
+
grid_display_layout = QVBoxLayout()
|
|
17771
|
+
|
|
17772
|
+
grid_display_info = QLabel(
|
|
17773
|
+
"Configure how content is displayed in the translation grid."
|
|
17774
|
+
)
|
|
17775
|
+
grid_display_info.setStyleSheet("font-size: 8pt; padding: 8px; border-radius: 2px;")
|
|
17776
|
+
grid_display_info.setWordWrap(True)
|
|
17777
|
+
grid_display_layout.addWidget(grid_display_info)
|
|
17778
|
+
|
|
17779
|
+
# Hide wrapping tags checkbox
|
|
17780
|
+
hide_wrapping_tags_layout = QHBoxLayout()
|
|
17781
|
+
hide_wrapping_tags_check = CheckmarkCheckBox("Hide outer wrapping tags in grid (e.g. <li-o>...</li-o>)")
|
|
17782
|
+
hide_wrapping_tags_check.setChecked(font_settings.get('hide_outer_wrapping_tags', False))
|
|
17783
|
+
hide_wrapping_tags_check.setToolTip(
|
|
17784
|
+
"When enabled, structural tags that wrap the entire segment (like <li-o>, <p>, <td>) are hidden in the grid.\n"
|
|
17785
|
+
"The segment type is already shown in the Type column, so this reduces visual clutter.\n"
|
|
17786
|
+
"Inner formatting tags like <b>bold</b> are still shown.\n"
|
|
17787
|
+
"This affects the Source column display only - the Target column keeps tags for editing."
|
|
17788
|
+
)
|
|
17789
|
+
hide_wrapping_tags_layout.addWidget(hide_wrapping_tags_check)
|
|
17790
|
+
hide_wrapping_tags_layout.addStretch()
|
|
17791
|
+
grid_display_layout.addLayout(hide_wrapping_tags_layout)
|
|
17792
|
+
|
|
17793
|
+
grid_display_group.setLayout(grid_display_layout)
|
|
17794
|
+
layout.addWidget(grid_display_group)
|
|
17795
|
+
|
|
17796
|
+
# Match Panel & Tag Colors section
|
|
17797
|
+
results_group = QGroupBox("📋 Match Panel && Tag Colors")
|
|
17696
17798
|
results_layout = QVBoxLayout()
|
|
17697
17799
|
|
|
17698
17800
|
results_size_info = QLabel(
|
|
17699
|
-
"Set
|
|
17700
|
-
"You can also adjust these using View menu → Translation Results Pane."
|
|
17801
|
+
"Set font sizes for the Match Panel (TM/termbase matches) and tag colors."
|
|
17701
17802
|
)
|
|
17702
17803
|
results_size_info.setStyleSheet("font-size: 8pt; padding: 8px; border-radius: 2px;")
|
|
17703
17804
|
results_size_info.setWordWrap(True)
|
|
@@ -17737,7 +17838,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
17737
17838
|
show_tags_layout.addWidget(show_tags_check)
|
|
17738
17839
|
show_tags_layout.addStretch()
|
|
17739
17840
|
results_layout.addLayout(show_tags_layout)
|
|
17740
|
-
|
|
17841
|
+
|
|
17741
17842
|
# Tag highlight color picker
|
|
17742
17843
|
tag_color_layout = QHBoxLayout()
|
|
17743
17844
|
tag_color_layout.addWidget(QLabel("Tag Highlight Color:"))
|
|
@@ -18295,7 +18396,8 @@ class SupervertalerQt(QMainWindow):
|
|
|
18295
18396
|
grid_font_spin, match_font_spin, compare_font_spin, show_tags_check, tag_color_btn,
|
|
18296
18397
|
alt_colors_check, even_color_btn, odd_color_btn, invisible_char_color_btn, grid_font_family_combo,
|
|
18297
18398
|
termview_font_family_combo, termview_font_spin, termview_bold_check,
|
|
18298
|
-
border_color_btn, border_thickness_spin, badge_text_color_btn, tabs_above_check
|
|
18399
|
+
border_color_btn, border_thickness_spin, badge_text_color_btn, tabs_above_check,
|
|
18400
|
+
hide_wrapping_tags_check
|
|
18299
18401
|
)
|
|
18300
18402
|
|
|
18301
18403
|
save_btn.clicked.connect(save_view_settings_with_scale)
|
|
@@ -18307,14 +18409,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
18307
18409
|
|
|
18308
18410
|
def _create_voice_dictation_settings_tab(self):
|
|
18309
18411
|
"""Create Supervoice Settings tab content with Voice Commands"""
|
|
18310
|
-
from PyQt6.QtWidgets import (QGroupBox, QPushButton, QComboBox, QSpinBox,
|
|
18412
|
+
from PyQt6.QtWidgets import (QGroupBox, QPushButton, QComboBox, QSpinBox,
|
|
18311
18413
|
QTableWidget, QTableWidgetItem, QHeaderView,
|
|
18312
|
-
QAbstractItemView, QCheckBox)
|
|
18414
|
+
QAbstractItemView, QCheckBox, QSplitter)
|
|
18415
|
+
from modules.keyboard_shortcuts_widget import CheckmarkCheckBox
|
|
18313
18416
|
|
|
18314
18417
|
tab = QWidget()
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18418
|
+
main_layout = QVBoxLayout(tab)
|
|
18419
|
+
main_layout.setContentsMargins(20, 20, 20, 20)
|
|
18420
|
+
main_layout.setSpacing(15)
|
|
18318
18421
|
|
|
18319
18422
|
# Load current dictation settings
|
|
18320
18423
|
dictation_settings = self.load_dictation_settings()
|
|
@@ -18327,19 +18430,33 @@ class SupervertalerQt(QMainWindow):
|
|
|
18327
18430
|
header_info.setTextFormat(Qt.TextFormat.RichText)
|
|
18328
18431
|
header_info.setStyleSheet("font-size: 9pt; color: #444; padding: 10px; background-color: #E3F2FD; border-radius: 4px;")
|
|
18329
18432
|
header_info.setWordWrap(True)
|
|
18330
|
-
|
|
18433
|
+
main_layout.addWidget(header_info)
|
|
18331
18434
|
|
|
18332
|
-
# ===== Voice Commands
|
|
18333
|
-
|
|
18334
|
-
|
|
18435
|
+
# ===== Two-column layout: Left = Settings, Right = Voice Commands Table =====
|
|
18436
|
+
columns_layout = QHBoxLayout()
|
|
18437
|
+
columns_layout.setSpacing(15)
|
|
18335
18438
|
|
|
18336
|
-
#
|
|
18337
|
-
|
|
18439
|
+
# --- LEFT COLUMN: Settings ---
|
|
18440
|
+
left_column = QVBoxLayout()
|
|
18441
|
+
left_column.setSpacing(15)
|
|
18442
|
+
|
|
18443
|
+
# Enable voice commands checkbox (green checkmark style)
|
|
18444
|
+
voice_cmd_enabled = CheckmarkCheckBox("Enable voice commands (spoken phrases trigger actions)")
|
|
18338
18445
|
voice_cmd_enabled.setChecked(dictation_settings.get('voice_commands_enabled', True))
|
|
18339
18446
|
voice_cmd_enabled.setToolTip("When enabled, spoken phrases like 'confirm' or 'next segment' will execute commands instead of being inserted as text")
|
|
18340
|
-
|
|
18447
|
+
left_column.addWidget(voice_cmd_enabled)
|
|
18341
18448
|
self.voice_commands_enabled_checkbox = voice_cmd_enabled
|
|
18342
18449
|
|
|
18450
|
+
# Create a layout variable for settings sections to be added below
|
|
18451
|
+
layout = left_column
|
|
18452
|
+
|
|
18453
|
+
# --- RIGHT COLUMN: Voice Commands Table ---
|
|
18454
|
+
right_column = QVBoxLayout()
|
|
18455
|
+
right_column.setSpacing(10)
|
|
18456
|
+
|
|
18457
|
+
commands_group = QGroupBox("🗣️ Voice Commands (Talon-style)")
|
|
18458
|
+
commands_layout = QVBoxLayout()
|
|
18459
|
+
|
|
18343
18460
|
commands_info = QLabel(
|
|
18344
18461
|
"Voice commands let you control Supervertaler by voice. Say a phrase to execute an action.\n"
|
|
18345
18462
|
"If no command matches, the spoken text is inserted as dictation."
|
|
@@ -18358,38 +18475,47 @@ class SupervertalerQt(QMainWindow):
|
|
|
18358
18475
|
self.voice_commands_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
|
|
18359
18476
|
self.voice_commands_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
18360
18477
|
self.voice_commands_table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
|
18361
|
-
self.voice_commands_table.setMinimumHeight(
|
|
18362
|
-
|
|
18363
|
-
|
|
18478
|
+
self.voice_commands_table.setMinimumHeight(350)
|
|
18479
|
+
|
|
18364
18480
|
# Populate table with current commands
|
|
18365
18481
|
self._populate_voice_commands_table()
|
|
18366
18482
|
commands_layout.addWidget(self.voice_commands_table)
|
|
18367
18483
|
|
|
18368
18484
|
# Command buttons
|
|
18369
18485
|
cmd_btn_layout = QHBoxLayout()
|
|
18370
|
-
|
|
18371
|
-
add_cmd_btn = QPushButton("➕ Add
|
|
18486
|
+
|
|
18487
|
+
add_cmd_btn = QPushButton("➕ Add")
|
|
18372
18488
|
add_cmd_btn.clicked.connect(self._add_voice_command)
|
|
18373
18489
|
cmd_btn_layout.addWidget(add_cmd_btn)
|
|
18374
|
-
|
|
18375
|
-
edit_cmd_btn = QPushButton("✏️ Edit
|
|
18490
|
+
|
|
18491
|
+
edit_cmd_btn = QPushButton("✏️ Edit")
|
|
18376
18492
|
edit_cmd_btn.clicked.connect(self._edit_voice_command)
|
|
18377
18493
|
cmd_btn_layout.addWidget(edit_cmd_btn)
|
|
18378
|
-
|
|
18379
|
-
remove_cmd_btn = QPushButton("🗑️ Remove
|
|
18494
|
+
|
|
18495
|
+
remove_cmd_btn = QPushButton("🗑️ Remove")
|
|
18380
18496
|
remove_cmd_btn.clicked.connect(self._remove_voice_command)
|
|
18381
18497
|
cmd_btn_layout.addWidget(remove_cmd_btn)
|
|
18382
|
-
|
|
18498
|
+
|
|
18383
18499
|
cmd_btn_layout.addStretch()
|
|
18384
|
-
|
|
18385
|
-
reset_cmd_btn = QPushButton("🔄 Reset
|
|
18500
|
+
|
|
18501
|
+
reset_cmd_btn = QPushButton("🔄 Reset")
|
|
18386
18502
|
reset_cmd_btn.clicked.connect(self._reset_voice_commands)
|
|
18387
18503
|
cmd_btn_layout.addWidget(reset_cmd_btn)
|
|
18388
|
-
|
|
18504
|
+
|
|
18389
18505
|
commands_layout.addLayout(cmd_btn_layout)
|
|
18390
18506
|
|
|
18391
18507
|
commands_group.setLayout(commands_layout)
|
|
18392
|
-
|
|
18508
|
+
right_column.addWidget(commands_group)
|
|
18509
|
+
right_column.addStretch()
|
|
18510
|
+
|
|
18511
|
+
# Add columns to the two-column layout
|
|
18512
|
+
left_widget = QWidget()
|
|
18513
|
+
left_widget.setLayout(left_column)
|
|
18514
|
+
right_widget = QWidget()
|
|
18515
|
+
right_widget.setLayout(right_column)
|
|
18516
|
+
|
|
18517
|
+
columns_layout.addWidget(left_widget, stretch=1)
|
|
18518
|
+
columns_layout.addWidget(right_widget, stretch=1)
|
|
18393
18519
|
|
|
18394
18520
|
# ===== Always-On Mode Section =====
|
|
18395
18521
|
alwayson_group = QGroupBox("🎧 Always-On Listening Mode")
|
|
@@ -18552,7 +18678,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
18552
18678
|
ahk_group.setLayout(ahk_layout)
|
|
18553
18679
|
layout.addWidget(ahk_group)
|
|
18554
18680
|
|
|
18555
|
-
#
|
|
18681
|
+
# Add stretch to left column to push content up
|
|
18682
|
+
layout.addStretch()
|
|
18683
|
+
|
|
18684
|
+
# Add two-column layout to main layout
|
|
18685
|
+
main_layout.addLayout(columns_layout, stretch=1)
|
|
18686
|
+
|
|
18687
|
+
# Save button (full width, below the two columns)
|
|
18556
18688
|
save_btn = QPushButton("💾 Save Supervoice Settings")
|
|
18557
18689
|
save_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 10px; border: none; outline: none;")
|
|
18558
18690
|
save_btn.clicked.connect(lambda: self._save_voice_settings(
|
|
@@ -18561,15 +18693,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
18561
18693
|
lang_combo.currentText(),
|
|
18562
18694
|
voice_cmd_enabled.isChecked()
|
|
18563
18695
|
))
|
|
18564
|
-
|
|
18696
|
+
main_layout.addWidget(save_btn)
|
|
18565
18697
|
|
|
18566
18698
|
# Store references
|
|
18567
18699
|
self.dictation_model_combo = model_combo
|
|
18568
18700
|
self.dictation_duration_spin = duration_spin
|
|
18569
18701
|
self.dictation_lang_combo = lang_combo
|
|
18570
18702
|
|
|
18571
|
-
layout.addStretch()
|
|
18572
|
-
|
|
18573
18703
|
return tab
|
|
18574
18704
|
|
|
18575
18705
|
def _populate_voice_commands_table(self):
|
|
@@ -20198,7 +20328,8 @@ class SupervertalerQt(QMainWindow):
|
|
|
20198
20328
|
def _save_view_settings_from_ui(self, grid_spin, match_spin, compare_spin, show_tags_check=None, tag_color_btn=None,
|
|
20199
20329
|
alt_colors_check=None, even_color_btn=None, odd_color_btn=None, invisible_char_color_btn=None,
|
|
20200
20330
|
grid_font_family_combo=None, termview_font_family_combo=None, termview_font_spin=None, termview_bold_check=None,
|
|
20201
|
-
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None
|
|
20331
|
+
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None,
|
|
20332
|
+
hide_wrapping_tags_check=None):
|
|
20202
20333
|
"""Save view settings from UI"""
|
|
20203
20334
|
# CRITICAL: Suppress TM saves during view settings update
|
|
20204
20335
|
# Grid operations (setStyleSheet, rehighlight, etc.) can trigger textChanged events
|
|
@@ -20211,7 +20342,8 @@ class SupervertalerQt(QMainWindow):
|
|
|
20211
20342
|
grid_spin, match_spin, compare_spin, show_tags_check, tag_color_btn,
|
|
20212
20343
|
alt_colors_check, even_color_btn, odd_color_btn, invisible_char_color_btn,
|
|
20213
20344
|
grid_font_family_combo, termview_font_family_combo, termview_font_spin, termview_bold_check,
|
|
20214
|
-
border_color_btn, border_thickness_spin, badge_text_color_btn, tabs_above_check
|
|
20345
|
+
border_color_btn, border_thickness_spin, badge_text_color_btn, tabs_above_check,
|
|
20346
|
+
hide_wrapping_tags_check
|
|
20215
20347
|
)
|
|
20216
20348
|
finally:
|
|
20217
20349
|
self._suppress_target_change_handlers = previous_suppression
|
|
@@ -20219,16 +20351,18 @@ class SupervertalerQt(QMainWindow):
|
|
|
20219
20351
|
def _save_view_settings_from_ui_impl(self, grid_spin, match_spin, compare_spin, show_tags_check=None, tag_color_btn=None,
|
|
20220
20352
|
alt_colors_check=None, even_color_btn=None, odd_color_btn=None, invisible_char_color_btn=None,
|
|
20221
20353
|
grid_font_family_combo=None, termview_font_family_combo=None, termview_font_spin=None, termview_bold_check=None,
|
|
20222
|
-
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None
|
|
20354
|
+
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None,
|
|
20355
|
+
hide_wrapping_tags_check=None):
|
|
20223
20356
|
"""Implementation of save view settings (called with TM saves suppressed)"""
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20357
|
+
# Load existing settings first to preserve all values, then update with new ones
|
|
20358
|
+
general_settings = self.load_general_settings()
|
|
20359
|
+
general_settings.update({
|
|
20360
|
+
'auto_propagate_exact_matches': self.auto_propagate_exact_matches,
|
|
20227
20361
|
'grid_font_size': grid_spin.value(),
|
|
20228
20362
|
'results_match_font_size': match_spin.value(),
|
|
20229
20363
|
'results_compare_font_size': compare_spin.value(),
|
|
20230
|
-
'enable_tm_termbase_matching': self.enable_tm_matching
|
|
20231
|
-
}
|
|
20364
|
+
'enable_tm_termbase_matching': self.enable_tm_matching
|
|
20365
|
+
})
|
|
20232
20366
|
|
|
20233
20367
|
# Add tabs above grid setting if provided
|
|
20234
20368
|
if tabs_above_check is not None:
|
|
@@ -20268,7 +20402,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
20268
20402
|
if invisible_char_color:
|
|
20269
20403
|
general_settings['invisible_char_color'] = invisible_char_color
|
|
20270
20404
|
self.invisible_char_color = invisible_char_color
|
|
20271
|
-
|
|
20405
|
+
|
|
20406
|
+
# Add hide outer wrapping tags setting if provided
|
|
20407
|
+
if hide_wrapping_tags_check is not None:
|
|
20408
|
+
general_settings['hide_outer_wrapping_tags'] = hide_wrapping_tags_check.isChecked()
|
|
20409
|
+
self.hide_outer_wrapping_tags = hide_wrapping_tags_check.isChecked()
|
|
20410
|
+
|
|
20272
20411
|
# Add focus border settings if provided
|
|
20273
20412
|
if border_color_btn is not None:
|
|
20274
20413
|
border_color = border_color_btn.property('selected_color')
|
|
@@ -20432,7 +20571,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
20432
20571
|
self.refresh_grid_tag_colors()
|
|
20433
20572
|
# Also refresh row colors
|
|
20434
20573
|
self.apply_alternating_row_colors()
|
|
20435
|
-
|
|
20574
|
+
|
|
20575
|
+
# Refresh source column if hide_outer_wrapping_tags setting changed
|
|
20576
|
+
if hide_wrapping_tags_check is not None and hasattr(self, 'table') and self.table is not None:
|
|
20577
|
+
self._refresh_source_column_display()
|
|
20578
|
+
|
|
20436
20579
|
self.log("✓ View settings saved and applied")
|
|
20437
20580
|
# Use explicit QMessageBox instance to ensure proper dialog closing
|
|
20438
20581
|
msg = QMessageBox(self)
|
|
@@ -29773,8 +29916,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
29773
29916
|
self.table.setItem(row, 1, type_item)
|
|
29774
29917
|
|
|
29775
29918
|
# Source - Use read-only QTextEdit widget for easy text selection
|
|
29919
|
+
# Strip outer wrapping tags if setting is enabled (display only, data unchanged)
|
|
29920
|
+
source_for_display = segment.source
|
|
29921
|
+
if self.hide_outer_wrapping_tags:
|
|
29922
|
+
stripped, _ = strip_outer_wrapping_tags(segment.source)
|
|
29923
|
+
source_for_display = stripped
|
|
29776
29924
|
# Apply invisible character replacements for display only
|
|
29777
|
-
source_display_text = self.apply_invisible_replacements(
|
|
29925
|
+
source_display_text = self.apply_invisible_replacements(source_for_display)
|
|
29778
29926
|
source_editor = ReadOnlyGridTextEditor(source_display_text, self.table, row)
|
|
29779
29927
|
|
|
29780
29928
|
# Initialize empty termbase matches (will be populated lazily on segment selection or by background worker)
|
|
@@ -29793,6 +29941,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
29793
29941
|
self.table.setItem(row, 2, source_item)
|
|
29794
29942
|
|
|
29795
29943
|
# Target - Use editable QTextEdit widget for easy text selection and editing
|
|
29944
|
+
# Note: We don't strip wrapping tags from target cells since users edit them directly
|
|
29796
29945
|
# Apply invisible character replacements for display (will be reversed when saving)
|
|
29797
29946
|
target_display_text = self.apply_invisible_replacements(segment.target)
|
|
29798
29947
|
target_editor = EditableGridTextEditor(target_display_text, self.table, row, self.table)
|
|
@@ -31730,7 +31879,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
31730
31879
|
self.enable_alternating_row_colors = settings.get('enable_alternating_row_colors', True)
|
|
31731
31880
|
self.even_row_color = settings.get('even_row_color', '#FFFFFF')
|
|
31732
31881
|
self.odd_row_color = settings.get('odd_row_color', '#F0F0F0')
|
|
31733
|
-
|
|
31882
|
+
|
|
31883
|
+
# Load hide outer wrapping tags setting
|
|
31884
|
+
self.hide_outer_wrapping_tags = settings.get('hide_outer_wrapping_tags', False)
|
|
31885
|
+
|
|
31734
31886
|
# Load termbase highlight style settings
|
|
31735
31887
|
self.termbase_highlight_style = settings.get('termbase_highlight_style', 'semibold')
|
|
31736
31888
|
self.termbase_dotted_color = settings.get('termbase_dotted_color', '#808080')
|
|
@@ -37377,6 +37529,34 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37377
37529
|
# during load_segments_to_grid when creating cell widgets
|
|
37378
37530
|
self.load_segments_to_grid()
|
|
37379
37531
|
|
|
37532
|
+
def _refresh_source_column_display(self):
|
|
37533
|
+
"""Refresh source column to reflect hide_outer_wrapping_tags setting"""
|
|
37534
|
+
if not hasattr(self, 'table') or not self.table:
|
|
37535
|
+
return
|
|
37536
|
+
if not hasattr(self, 'current_project') or not self.current_project:
|
|
37537
|
+
return
|
|
37538
|
+
|
|
37539
|
+
# Update each source cell with potentially stripped tags
|
|
37540
|
+
for row in range(self.table.rowCount()):
|
|
37541
|
+
if row >= len(self.current_project.segments):
|
|
37542
|
+
continue
|
|
37543
|
+
|
|
37544
|
+
segment = self.current_project.segments[row]
|
|
37545
|
+
source_widget = self.table.cellWidget(row, 2)
|
|
37546
|
+
|
|
37547
|
+
if source_widget and hasattr(source_widget, 'setPlainText'):
|
|
37548
|
+
# Calculate display text with or without outer wrapping tags
|
|
37549
|
+
source_for_display = segment.source
|
|
37550
|
+
if self.hide_outer_wrapping_tags:
|
|
37551
|
+
stripped, _ = strip_outer_wrapping_tags(segment.source)
|
|
37552
|
+
source_for_display = stripped
|
|
37553
|
+
source_display_text = self.apply_invisible_replacements(source_for_display)
|
|
37554
|
+
source_widget.setPlainText(source_display_text)
|
|
37555
|
+
|
|
37556
|
+
# Re-apply highlighting
|
|
37557
|
+
if hasattr(source_widget, 'highlighter'):
|
|
37558
|
+
source_widget.highlighter.rehighlight()
|
|
37559
|
+
|
|
37380
37560
|
def apply_invisible_replacements(self, text):
|
|
37381
37561
|
"""Apply invisible character replacements to text based on settings"""
|
|
37382
37562
|
if not hasattr(self, 'invisible_display_settings'):
|
modules/llm_clients.py
CHANGED
|
@@ -594,18 +594,20 @@ class LLMClient:
|
|
|
594
594
|
context: Optional[str] = None,
|
|
595
595
|
custom_prompt: Optional[str] = None,
|
|
596
596
|
max_tokens: Optional[int] = None,
|
|
597
|
-
images: Optional[List] = None
|
|
597
|
+
images: Optional[List] = None,
|
|
598
|
+
system_prompt: Optional[str] = None
|
|
598
599
|
) -> str:
|
|
599
600
|
"""
|
|
600
601
|
Translate text using configured LLM
|
|
601
|
-
|
|
602
|
+
|
|
602
603
|
Args:
|
|
603
604
|
text: Text to translate
|
|
604
605
|
source_lang: Source language code
|
|
605
606
|
target_lang: Target language code
|
|
606
607
|
context: Optional context for translation
|
|
607
608
|
custom_prompt: Optional custom prompt (overrides default simple prompt)
|
|
608
|
-
|
|
609
|
+
system_prompt: Optional system prompt for AI behavior context
|
|
610
|
+
|
|
609
611
|
Returns:
|
|
610
612
|
Translated text
|
|
611
613
|
"""
|
|
@@ -615,30 +617,30 @@ class LLMClient:
|
|
|
615
617
|
else:
|
|
616
618
|
# Build prompt
|
|
617
619
|
prompt = f"Translate the following text from {source_lang} to {target_lang}:\n\n{text}"
|
|
618
|
-
|
|
620
|
+
|
|
619
621
|
if context:
|
|
620
622
|
prompt = f"Context: {context}\n\n{prompt}"
|
|
621
|
-
|
|
623
|
+
|
|
622
624
|
# Log warning if images provided but model doesn't support vision
|
|
623
625
|
if images and not self.model_supports_vision(self.provider, self.model):
|
|
624
626
|
print(f"⚠️ Warning: Model {self.model} doesn't support vision. Images will be ignored.")
|
|
625
627
|
images = None # Don't pass to API
|
|
626
|
-
|
|
628
|
+
|
|
627
629
|
# Call appropriate provider
|
|
628
630
|
if self.provider == "openai":
|
|
629
|
-
return self._call_openai(prompt, max_tokens=max_tokens, images=images)
|
|
631
|
+
return self._call_openai(prompt, max_tokens=max_tokens, images=images, system_prompt=system_prompt)
|
|
630
632
|
elif self.provider == "claude":
|
|
631
|
-
return self._call_claude(prompt, max_tokens=max_tokens, images=images)
|
|
633
|
+
return self._call_claude(prompt, max_tokens=max_tokens, images=images, system_prompt=system_prompt)
|
|
632
634
|
elif self.provider == "gemini":
|
|
633
|
-
return self._call_gemini(prompt, max_tokens=max_tokens, images=images)
|
|
635
|
+
return self._call_gemini(prompt, max_tokens=max_tokens, images=images, system_prompt=system_prompt)
|
|
634
636
|
elif self.provider == "ollama":
|
|
635
|
-
return self._call_ollama(prompt, max_tokens=max_tokens)
|
|
637
|
+
return self._call_ollama(prompt, max_tokens=max_tokens, system_prompt=system_prompt)
|
|
636
638
|
else:
|
|
637
639
|
raise ValueError(f"Unsupported provider: {self.provider}")
|
|
638
640
|
|
|
639
|
-
def _call_openai(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None) -> str:
|
|
641
|
+
def _call_openai(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None, system_prompt: Optional[str] = None) -> str:
|
|
640
642
|
"""Call OpenAI API with GPT-5/o1/o3 reasoning model support and vision capability"""
|
|
641
|
-
print(f"🔵 _call_openai START: model={self.model}, prompt_len={len(prompt)}, max_tokens={max_tokens}, images={len(images) if images else 0}")
|
|
643
|
+
print(f"🔵 _call_openai START: model={self.model}, prompt_len={len(prompt)}, max_tokens={max_tokens}, images={len(images) if images else 0}, has_system={bool(system_prompt)}")
|
|
642
644
|
|
|
643
645
|
try:
|
|
644
646
|
from openai import OpenAI
|
|
@@ -686,10 +688,16 @@ class LLMClient:
|
|
|
686
688
|
# Standard text-only format
|
|
687
689
|
content = prompt
|
|
688
690
|
|
|
691
|
+
# Build messages list
|
|
692
|
+
messages = []
|
|
693
|
+
if system_prompt:
|
|
694
|
+
messages.append({"role": "system", "content": system_prompt})
|
|
695
|
+
messages.append({"role": "user", "content": content})
|
|
696
|
+
|
|
689
697
|
# Build API call parameters
|
|
690
698
|
api_params = {
|
|
691
699
|
"model": self.model,
|
|
692
|
-
"messages":
|
|
700
|
+
"messages": messages,
|
|
693
701
|
"timeout": timeout_seconds
|
|
694
702
|
}
|
|
695
703
|
|
|
@@ -742,7 +750,7 @@ class LLMClient:
|
|
|
742
750
|
print(f" Response: {e.response}")
|
|
743
751
|
raise # Re-raise to be caught by calling code
|
|
744
752
|
|
|
745
|
-
def _call_claude(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None) -> str:
|
|
753
|
+
def _call_claude(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None, system_prompt: Optional[str] = None) -> str:
|
|
746
754
|
"""Call Anthropic Claude API with vision support"""
|
|
747
755
|
try:
|
|
748
756
|
import anthropic
|
|
@@ -786,12 +794,19 @@ class LLMClient:
|
|
|
786
794
|
# Standard text-only format
|
|
787
795
|
content = prompt
|
|
788
796
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
797
|
+
# Build API call parameters
|
|
798
|
+
api_params = {
|
|
799
|
+
"model": self.model,
|
|
800
|
+
"max_tokens": tokens_to_use,
|
|
801
|
+
"messages": [{"role": "user", "content": content}],
|
|
802
|
+
"timeout": timeout_seconds # Explicit timeout
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
# Add system prompt if provided (Claude uses 'system' parameter, not a message)
|
|
806
|
+
if system_prompt:
|
|
807
|
+
api_params["system"] = system_prompt
|
|
808
|
+
|
|
809
|
+
response = client.messages.create(**api_params)
|
|
795
810
|
|
|
796
811
|
translation = response.content[0].text.strip()
|
|
797
812
|
|
|
@@ -800,7 +815,7 @@ class LLMClient:
|
|
|
800
815
|
|
|
801
816
|
return translation
|
|
802
817
|
|
|
803
|
-
def _call_gemini(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None) -> str:
|
|
818
|
+
def _call_gemini(self, prompt: str, max_tokens: Optional[int] = None, images: Optional[List] = None, system_prompt: Optional[str] = None) -> str:
|
|
804
819
|
"""Call Google Gemini API with vision support"""
|
|
805
820
|
try:
|
|
806
821
|
import google.generativeai as genai
|
|
@@ -809,10 +824,15 @@ class LLMClient:
|
|
|
809
824
|
raise ImportError(
|
|
810
825
|
"Google AI library not installed. Install with: pip install google-generativeai pillow"
|
|
811
826
|
)
|
|
812
|
-
|
|
827
|
+
|
|
813
828
|
genai.configure(api_key=self.api_key)
|
|
814
|
-
|
|
815
|
-
|
|
829
|
+
|
|
830
|
+
# Gemini supports system instructions via GenerativeModel parameter
|
|
831
|
+
if system_prompt:
|
|
832
|
+
model = genai.GenerativeModel(self.model, system_instruction=system_prompt)
|
|
833
|
+
else:
|
|
834
|
+
model = genai.GenerativeModel(self.model)
|
|
835
|
+
|
|
816
836
|
# Build content (text + optional images)
|
|
817
837
|
if images:
|
|
818
838
|
# Gemini format: list with prompt text followed by PIL Image objects
|
|
@@ -823,7 +843,7 @@ class LLMClient:
|
|
|
823
843
|
else:
|
|
824
844
|
# Standard text-only
|
|
825
845
|
content = prompt
|
|
826
|
-
|
|
846
|
+
|
|
827
847
|
response = model.generate_content(content)
|
|
828
848
|
translation = response.text.strip()
|
|
829
849
|
|
|
@@ -832,20 +852,21 @@ class LLMClient:
|
|
|
832
852
|
|
|
833
853
|
return translation
|
|
834
854
|
|
|
835
|
-
def _call_ollama(self, prompt: str, max_tokens: Optional[int] = None) -> str:
|
|
855
|
+
def _call_ollama(self, prompt: str, max_tokens: Optional[int] = None, system_prompt: Optional[str] = None) -> str:
|
|
836
856
|
"""
|
|
837
857
|
Call local Ollama server for translation.
|
|
838
|
-
|
|
858
|
+
|
|
839
859
|
Ollama provides a simple REST API compatible with local LLM inference.
|
|
840
860
|
Models run entirely on the user's computer - no API keys, no internet required.
|
|
841
|
-
|
|
861
|
+
|
|
842
862
|
Args:
|
|
843
863
|
prompt: The full prompt to send
|
|
844
864
|
max_tokens: Maximum tokens to generate (default: 4096)
|
|
845
|
-
|
|
865
|
+
system_prompt: Optional system prompt for AI behavior context
|
|
866
|
+
|
|
846
867
|
Returns:
|
|
847
868
|
Translated text
|
|
848
|
-
|
|
869
|
+
|
|
849
870
|
Raises:
|
|
850
871
|
ConnectionError: If Ollama is not running
|
|
851
872
|
ValueError: If model is not available
|
|
@@ -866,13 +887,17 @@ class LLMClient:
|
|
|
866
887
|
print(f"🟠 _call_ollama START: model={self.model}, prompt_len={len(prompt)}, max_tokens={tokens_to_use}")
|
|
867
888
|
print(f"🟠 Ollama endpoint: {endpoint}")
|
|
868
889
|
|
|
890
|
+
# Build messages list
|
|
891
|
+
messages = []
|
|
892
|
+
if system_prompt:
|
|
893
|
+
messages.append({"role": "system", "content": system_prompt})
|
|
894
|
+
messages.append({"role": "user", "content": prompt})
|
|
895
|
+
|
|
869
896
|
# Build request payload
|
|
870
897
|
# Using /api/chat for chat-style interaction (better for translation prompts)
|
|
871
898
|
payload = {
|
|
872
899
|
"model": self.model,
|
|
873
|
-
"messages":
|
|
874
|
-
{"role": "user", "content": prompt}
|
|
875
|
-
],
|
|
900
|
+
"messages": messages,
|
|
876
901
|
"stream": False, # Get complete response at once
|
|
877
902
|
"options": {
|
|
878
903
|
"temperature": 0.3, # Low temperature for consistent translations
|
|
@@ -3795,6 +3795,26 @@ Output complete ACTION."""
|
|
|
3795
3795
|
from PyQt6.QtWidgets import QApplication
|
|
3796
3796
|
QApplication.processEvents()
|
|
3797
3797
|
|
|
3798
|
+
# System prompt that explains the ACTION format to the AI
|
|
3799
|
+
ai_system_prompt = """You are an AI assistant for Supervertaler, a professional translation workbench.
|
|
3800
|
+
|
|
3801
|
+
You can execute actions using a special format. When you need to create, modify, or manage prompts, output ACTION blocks in this EXACT format:
|
|
3802
|
+
|
|
3803
|
+
ACTION:function_name PARAMS:{"param1": "value1", "param2": "value2"}
|
|
3804
|
+
|
|
3805
|
+
Available actions:
|
|
3806
|
+
- create_prompt: Create a new prompt. Required params: name, content. Optional: folder, description, activate
|
|
3807
|
+
- update_prompt: Update an existing prompt. Required params: name. Optional: content, folder, description
|
|
3808
|
+
- delete_prompt: Delete a prompt. Required params: name
|
|
3809
|
+
- list_prompts: List all prompts. Optional params: folder
|
|
3810
|
+
- activate_prompt: Set a prompt as active. Required params: name
|
|
3811
|
+
|
|
3812
|
+
IMPORTANT:
|
|
3813
|
+
1. Output ONLY the ACTION block when asked to create/modify prompts - no explanatory text
|
|
3814
|
+
2. The ACTION must be on a single line (PARAMS JSON can be multiline if needed)
|
|
3815
|
+
3. Use valid JSON for PARAMS (double quotes for strings, escape special characters)
|
|
3816
|
+
4. Do not wrap in code fences or add any markdown formatting"""
|
|
3817
|
+
|
|
3798
3818
|
# Call LLM using translate method with custom prompt
|
|
3799
3819
|
# The translate method accepts a custom_prompt parameter that we can use for any text generation
|
|
3800
3820
|
self.log_message("[AI Assistant] Calling LLM translate method...")
|
|
@@ -3802,7 +3822,8 @@ Output complete ACTION."""
|
|
|
3802
3822
|
text="", # Empty text since we're using custom_prompt
|
|
3803
3823
|
source_lang="en",
|
|
3804
3824
|
target_lang="en",
|
|
3805
|
-
custom_prompt=prompt
|
|
3825
|
+
custom_prompt=prompt,
|
|
3826
|
+
system_prompt=ai_system_prompt
|
|
3806
3827
|
)
|
|
3807
3828
|
|
|
3808
3829
|
# Log the response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supervertaler
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.197
|
|
4
4
|
Summary: Professional AI-enhanced translation workbench with multi-LLM support, glossary system, TM, spellcheck, voice commands, and PyQt6 interface. Batteries included (core).
|
|
5
5
|
Home-page: https://supervertaler.com
|
|
6
6
|
Author: Michael Beijer
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Supervertaler.py,sha256=
|
|
1
|
+
Supervertaler.py,sha256=YdvLAgY__whrP8VBodeeVh70BXurnBlJ4PpFrFUkXdk,2387857
|
|
2
2
|
modules/__init__.py,sha256=G58XleS-EJ2sX4Kehm-3N2m618_W2Es0Kg8CW_eBG7g,327
|
|
3
3
|
modules/ai_actions.py,sha256=i5MJcM-7Y6CAvKUwxmxrVHeoZAVtAP7aRDdWM5KLkO0,33877
|
|
4
4
|
modules/ai_attachment_manager.py,sha256=juZlrW3UPkIkcnj0SREgOQkQROLf0fcu3ShZcKXMxsI,11361
|
|
@@ -23,7 +23,7 @@ modules/find_replace_qt.py,sha256=z06yyjOCmpYBrCzZcCv68VK-2o6pjfFCPtbr9o95XH8,18
|
|
|
23
23
|
modules/glossary_manager.py,sha256=JDxY9RAGcv-l6Nms4FH7CNDucZdY1TI4WTzyylAuj24,16437
|
|
24
24
|
modules/image_extractor.py,sha256=HI6QHnpkjO35GHzTXbzazYdjoHZPFD44WAa4JGa9bAw,8332
|
|
25
25
|
modules/keyboard_shortcuts_widget.py,sha256=H489eknMDJkYusri1hQYr5MT-NhkVoHWdx9k_NMTr68,26411
|
|
26
|
-
modules/llm_clients.py,sha256=
|
|
26
|
+
modules/llm_clients.py,sha256=q-E9PnmtAuN8LWs_EKlMV4sXN5Jx2L57kfKCTk9X-24,50012
|
|
27
27
|
modules/llm_leaderboard.py,sha256=MQ-RbjlE10-CdgVHwoVXzXlCuUfulZ839FaF6dKlt1M,29139
|
|
28
28
|
modules/llm_superbench_ui.py,sha256=lmzsL8lt0KzFw-z8De1zb49Emnv7f1dZv_DJmoQz0bQ,60212
|
|
29
29
|
modules/local_llm_setup.py,sha256=33y-D_LKzkn2w8ejyjeKaovf_An6xQ98mKISoqe-Qjc,42661
|
|
@@ -76,13 +76,13 @@ modules/translation_memory.py,sha256=LnG8csZNL2GTHXT4zk0uecJEtvRc-MKwv7Pt7EX3s7s
|
|
|
76
76
|
modules/translation_results_panel.py,sha256=OWqzV9xmJOi8NGCi3h42nq-qE7-v6WStjQWRsghCVbQ,92044
|
|
77
77
|
modules/translation_services.py,sha256=lyVpWuZK1wtVtYZMDMdLoq1DHBoSaeAnp-Yejb0TlVQ,10530
|
|
78
78
|
modules/unified_prompt_library.py,sha256=96u4WlMwnmmhD4uNJHZ-qVQj8v9_8dA2AVCWpBcwTrg,26006
|
|
79
|
-
modules/unified_prompt_manager_qt.py,sha256=
|
|
79
|
+
modules/unified_prompt_manager_qt.py,sha256=y7xAIM9X7f1afXGE1tOcAc5EY7BKFy53Rgqi3fFzKmQ,173374
|
|
80
80
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
81
81
|
modules/voice_dictation.py,sha256=QmitXfkG-vRt5hIQATjphHdhXfqmwhzcQcbXB6aRzIg,16386
|
|
82
82
|
modules/voice_dictation_lite.py,sha256=jorY0BmWE-8VczbtGrWwt1zbnOctMoSlWOsQrcufBcc,9423
|
|
83
|
-
supervertaler-1.9.
|
|
84
|
-
supervertaler-1.9.
|
|
85
|
-
supervertaler-1.9.
|
|
86
|
-
supervertaler-1.9.
|
|
87
|
-
supervertaler-1.9.
|
|
88
|
-
supervertaler-1.9.
|
|
83
|
+
supervertaler-1.9.197.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
84
|
+
supervertaler-1.9.197.dist-info/METADATA,sha256=6_J_jdwGKZ-MCwIJODfkHTxXjhBHY7Wf5pK-xDMbQwU,5725
|
|
85
|
+
supervertaler-1.9.197.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
86
|
+
supervertaler-1.9.197.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
87
|
+
supervertaler-1.9.197.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
88
|
+
supervertaler-1.9.197.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|