supervertaler 1.9.174__py3-none-any.whl → 1.9.176b0__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.
- Supervertaler.py +503 -27
- modules/database_migrations.py +54 -7
- modules/termbase_manager.py +105 -1
- modules/unified_prompt_library.py +2 -2
- modules/unified_prompt_manager_qt.py +35 -18
- supervertaler-1.9.176b0.dist-info/METADATA +151 -0
- {supervertaler-1.9.174.dist-info → supervertaler-1.9.176b0.dist-info}/RECORD +11 -11
- supervertaler-1.9.174.dist-info/METADATA +0 -939
- {supervertaler-1.9.174.dist-info → supervertaler-1.9.176b0.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.174.dist-info → supervertaler-1.9.176b0.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.174.dist-info → supervertaler-1.9.176b0.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.174.dist-info → supervertaler-1.9.176b0.dist-info}/top_level.txt +0 -0
modules/database_migrations.py
CHANGED
|
@@ -186,9 +186,13 @@ def run_all_migrations(db_manager) -> bool:
|
|
|
186
186
|
# Migration 3: Add display_order and forbidden fields to synonyms
|
|
187
187
|
if not migrate_synonym_fields(db_manager):
|
|
188
188
|
success = False
|
|
189
|
-
|
|
189
|
+
|
|
190
|
+
# Migration 4: Add ai_inject field to termbases
|
|
191
|
+
if not migrate_termbase_ai_inject(db_manager):
|
|
192
|
+
success = False
|
|
193
|
+
|
|
190
194
|
print("="*60)
|
|
191
|
-
|
|
195
|
+
|
|
192
196
|
return success
|
|
193
197
|
|
|
194
198
|
|
|
@@ -221,18 +225,26 @@ def check_and_migrate(db_manager) -> bool:
|
|
|
221
225
|
|
|
222
226
|
# Check if synonyms table exists
|
|
223
227
|
cursor.execute("""
|
|
224
|
-
SELECT name FROM sqlite_master
|
|
228
|
+
SELECT name FROM sqlite_master
|
|
225
229
|
WHERE type='table' AND name='termbase_synonyms'
|
|
226
230
|
""")
|
|
227
231
|
needs_synonyms_table = cursor.fetchone() is None
|
|
228
|
-
|
|
232
|
+
|
|
233
|
+
# Check if termbases table has ai_inject column
|
|
234
|
+
cursor.execute("PRAGMA table_info(termbases)")
|
|
235
|
+
termbase_columns = {row[1] for row in cursor.fetchall()}
|
|
236
|
+
needs_ai_inject = 'ai_inject' not in termbase_columns
|
|
237
|
+
|
|
229
238
|
if needs_migration:
|
|
230
239
|
print(f"⚠️ Migration needed - missing columns: {', '.join([c for c in ['project', 'client', 'term_uuid', 'note'] if c not in columns])}")
|
|
231
|
-
|
|
240
|
+
|
|
232
241
|
if needs_synonyms_table:
|
|
233
242
|
print("⚠️ Migration needed - termbase_synonyms table missing")
|
|
234
|
-
|
|
235
|
-
if
|
|
243
|
+
|
|
244
|
+
if needs_ai_inject:
|
|
245
|
+
print("⚠️ Migration needed - termbases.ai_inject column missing")
|
|
246
|
+
|
|
247
|
+
if needs_migration or needs_synonyms_table or needs_ai_inject:
|
|
236
248
|
success = run_all_migrations(db_manager)
|
|
237
249
|
if success:
|
|
238
250
|
# Generate UUIDs for terms that don't have them
|
|
@@ -316,6 +328,41 @@ def migrate_synonym_fields(db_manager) -> bool:
|
|
|
316
328
|
return False
|
|
317
329
|
|
|
318
330
|
|
|
331
|
+
def migrate_termbase_ai_inject(db_manager) -> bool:
|
|
332
|
+
"""
|
|
333
|
+
Add ai_inject column to termbases table.
|
|
334
|
+
When enabled, the termbase's terms will be injected into LLM translation prompts.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
db_manager: DatabaseManager instance
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
True if migration successful
|
|
341
|
+
"""
|
|
342
|
+
try:
|
|
343
|
+
cursor = db_manager.cursor
|
|
344
|
+
|
|
345
|
+
# Check which columns exist
|
|
346
|
+
cursor.execute("PRAGMA table_info(termbases)")
|
|
347
|
+
columns = {row[1] for row in cursor.fetchall()}
|
|
348
|
+
|
|
349
|
+
if 'ai_inject' not in columns:
|
|
350
|
+
print("📊 Adding 'ai_inject' column to termbases...")
|
|
351
|
+
cursor.execute("ALTER TABLE termbases ADD COLUMN ai_inject BOOLEAN DEFAULT 0")
|
|
352
|
+
db_manager.connection.commit()
|
|
353
|
+
print(" ✓ Column 'ai_inject' added successfully")
|
|
354
|
+
else:
|
|
355
|
+
print("✅ termbases.ai_inject column already exists")
|
|
356
|
+
|
|
357
|
+
return True
|
|
358
|
+
|
|
359
|
+
except Exception as e:
|
|
360
|
+
print(f"❌ ai_inject migration failed: {e}")
|
|
361
|
+
import traceback
|
|
362
|
+
traceback.print_exc()
|
|
363
|
+
return False
|
|
364
|
+
|
|
365
|
+
|
|
319
366
|
def generate_missing_uuids(db_manager) -> bool:
|
|
320
367
|
"""
|
|
321
368
|
Generate UUIDs for any termbase terms that don't have them.
|
modules/termbase_manager.py
CHANGED
|
@@ -409,7 +409,111 @@ class TermbaseManager:
|
|
|
409
409
|
except Exception as e:
|
|
410
410
|
self.log(f"✗ Error setting termbase read_only: {e}")
|
|
411
411
|
return False
|
|
412
|
-
|
|
412
|
+
|
|
413
|
+
def get_termbase_ai_inject(self, termbase_id: int) -> bool:
|
|
414
|
+
"""Get whether termbase terms should be injected into LLM prompts"""
|
|
415
|
+
try:
|
|
416
|
+
cursor = self.db_manager.cursor
|
|
417
|
+
cursor.execute("SELECT ai_inject FROM termbases WHERE id = ?", (termbase_id,))
|
|
418
|
+
result = cursor.fetchone()
|
|
419
|
+
return bool(result[0]) if result and result[0] else False
|
|
420
|
+
except Exception as e:
|
|
421
|
+
self.log(f"✗ Error getting termbase ai_inject: {e}")
|
|
422
|
+
return False
|
|
423
|
+
|
|
424
|
+
def set_termbase_ai_inject(self, termbase_id: int, ai_inject: bool) -> bool:
|
|
425
|
+
"""Set whether termbase terms should be injected into LLM prompts"""
|
|
426
|
+
try:
|
|
427
|
+
cursor = self.db_manager.cursor
|
|
428
|
+
cursor.execute("""
|
|
429
|
+
UPDATE termbases SET ai_inject = ? WHERE id = ?
|
|
430
|
+
""", (1 if ai_inject else 0, termbase_id))
|
|
431
|
+
self.db_manager.connection.commit()
|
|
432
|
+
status = "enabled" if ai_inject else "disabled"
|
|
433
|
+
self.log(f"✓ AI injection {status} for termbase {termbase_id}")
|
|
434
|
+
return True
|
|
435
|
+
except Exception as e:
|
|
436
|
+
self.log(f"✗ Error setting termbase ai_inject: {e}")
|
|
437
|
+
return False
|
|
438
|
+
|
|
439
|
+
def get_ai_inject_termbases(self, project_id: Optional[int] = None) -> List[Dict]:
|
|
440
|
+
"""
|
|
441
|
+
Get all termbases with ai_inject enabled that are active for the given project.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
project_id: Project ID (0 or None for global)
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
List of termbase dictionaries with all terms
|
|
448
|
+
"""
|
|
449
|
+
try:
|
|
450
|
+
cursor = self.db_manager.cursor
|
|
451
|
+
proj_id = project_id if project_id else 0
|
|
452
|
+
|
|
453
|
+
cursor.execute("""
|
|
454
|
+
SELECT t.id, t.name, t.source_lang, t.target_lang
|
|
455
|
+
FROM termbases t
|
|
456
|
+
LEFT JOIN termbase_activation ta ON t.id = ta.termbase_id AND ta.project_id = ?
|
|
457
|
+
WHERE t.ai_inject = 1
|
|
458
|
+
AND (ta.is_active = 1 OR (t.is_global = 1 AND ta.is_active IS NULL))
|
|
459
|
+
ORDER BY ta.priority ASC, t.name ASC
|
|
460
|
+
""", (proj_id,))
|
|
461
|
+
|
|
462
|
+
termbases = []
|
|
463
|
+
for row in cursor.fetchall():
|
|
464
|
+
termbases.append({
|
|
465
|
+
'id': row[0],
|
|
466
|
+
'name': row[1],
|
|
467
|
+
'source_lang': row[2],
|
|
468
|
+
'target_lang': row[3]
|
|
469
|
+
})
|
|
470
|
+
return termbases
|
|
471
|
+
except Exception as e:
|
|
472
|
+
self.log(f"✗ Error getting AI inject termbases: {e}")
|
|
473
|
+
return []
|
|
474
|
+
|
|
475
|
+
def get_ai_inject_terms(self, project_id: Optional[int] = None) -> List[Dict]:
|
|
476
|
+
"""
|
|
477
|
+
Get all terms from AI-inject-enabled termbases for the given project.
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
project_id: Project ID (0 or None for global)
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
List of term dictionaries with source_term, target_term, forbidden, termbase_name
|
|
484
|
+
"""
|
|
485
|
+
try:
|
|
486
|
+
# First get all AI-inject termbases
|
|
487
|
+
ai_termbases = self.get_ai_inject_termbases(project_id)
|
|
488
|
+
if not ai_termbases:
|
|
489
|
+
return []
|
|
490
|
+
|
|
491
|
+
all_terms = []
|
|
492
|
+
cursor = self.db_manager.cursor
|
|
493
|
+
|
|
494
|
+
for tb in ai_termbases:
|
|
495
|
+
cursor.execute("""
|
|
496
|
+
SELECT source_term, target_term, forbidden, priority
|
|
497
|
+
FROM termbase_terms
|
|
498
|
+
WHERE termbase_id = ?
|
|
499
|
+
ORDER BY priority ASC, source_term ASC
|
|
500
|
+
""", (tb['id'],))
|
|
501
|
+
|
|
502
|
+
for row in cursor.fetchall():
|
|
503
|
+
all_terms.append({
|
|
504
|
+
'source_term': row[0],
|
|
505
|
+
'target_term': row[1],
|
|
506
|
+
'forbidden': bool(row[2]) if row[2] else False,
|
|
507
|
+
'priority': row[3] or 99,
|
|
508
|
+
'termbase_name': tb['name']
|
|
509
|
+
})
|
|
510
|
+
|
|
511
|
+
self.log(f"📚 Retrieved {len(all_terms)} terms from {len(ai_termbases)} AI-inject glossar{'y' if len(ai_termbases) == 1 else 'ies'}")
|
|
512
|
+
return all_terms
|
|
513
|
+
except Exception as e:
|
|
514
|
+
self.log(f"✗ Error getting AI inject terms: {e}")
|
|
515
|
+
return []
|
|
516
|
+
|
|
413
517
|
def set_termbase_priority(self, termbase_id: int, project_id: int, priority: int) -> bool:
|
|
414
518
|
"""
|
|
415
519
|
Set manual priority for a termbase in a specific project.
|
|
@@ -367,7 +367,7 @@ class UnifiedPromptLibrary:
|
|
|
367
367
|
|
|
368
368
|
self.active_primary_prompt = self.prompts[relative_path]['content']
|
|
369
369
|
self.active_primary_prompt_path = relative_path
|
|
370
|
-
self.log(f"✓ Set
|
|
370
|
+
self.log(f"✓ Set custom prompt: {self.prompts[relative_path].get('name', relative_path)}")
|
|
371
371
|
return True
|
|
372
372
|
|
|
373
373
|
def set_external_primary_prompt(self, file_path: str) -> Tuple[bool, str]:
|
|
@@ -399,7 +399,7 @@ class UnifiedPromptLibrary:
|
|
|
399
399
|
self.active_primary_prompt = content
|
|
400
400
|
self.active_primary_prompt_path = f"[EXTERNAL] {file_path}"
|
|
401
401
|
|
|
402
|
-
self.log(f"✓ Set external
|
|
402
|
+
self.log(f"✓ Set external custom prompt: {display_name}")
|
|
403
403
|
return True, display_name
|
|
404
404
|
|
|
405
405
|
def attach_prompt(self, relative_path: str) -> bool:
|
|
@@ -1566,9 +1566,9 @@ class UnifiedPromptManagerQt:
|
|
|
1566
1566
|
|
|
1567
1567
|
layout.addWidget(mode_frame)
|
|
1568
1568
|
|
|
1569
|
-
#
|
|
1569
|
+
# Custom Prompt
|
|
1570
1570
|
primary_layout = QHBoxLayout()
|
|
1571
|
-
primary_label = QLabel("
|
|
1571
|
+
primary_label = QLabel("Custom Prompt ⭐:")
|
|
1572
1572
|
primary_label.setFont(QFont("Segoe UI", 9, QFont.Weight.Bold))
|
|
1573
1573
|
primary_layout.addWidget(primary_label)
|
|
1574
1574
|
|
|
@@ -2210,8 +2210,8 @@ class UnifiedPromptManagerQt:
|
|
|
2210
2210
|
if data['type'] == 'prompt':
|
|
2211
2211
|
path = data['path']
|
|
2212
2212
|
|
|
2213
|
-
# Set as
|
|
2214
|
-
action_primary = menu.addAction("⭐ Set as
|
|
2213
|
+
# Set as custom prompt
|
|
2214
|
+
action_primary = menu.addAction("⭐ Set as Custom Prompt")
|
|
2215
2215
|
action_primary.triggered.connect(lambda: self._set_primary_prompt(path))
|
|
2216
2216
|
|
|
2217
2217
|
# Attach/detach
|
|
@@ -2493,7 +2493,7 @@ class UnifiedPromptManagerQt:
|
|
|
2493
2493
|
self.library.active_primary_prompt_path = None
|
|
2494
2494
|
self.primary_prompt_label.setText("[None selected]")
|
|
2495
2495
|
self.primary_prompt_label.setStyleSheet("color: #999;")
|
|
2496
|
-
self.log_message("✓ Cleared
|
|
2496
|
+
self.log_message("✓ Cleared custom prompt")
|
|
2497
2497
|
|
|
2498
2498
|
def _load_external_primary_prompt(self):
|
|
2499
2499
|
"""Load an external prompt file (not in library) as primary"""
|
|
@@ -2787,7 +2787,7 @@ class UnifiedPromptManagerQt:
|
|
|
2787
2787
|
composition_parts.append(f"📏 Total prompt length: {len(combined):,} characters")
|
|
2788
2788
|
|
|
2789
2789
|
if self.library.active_primary_prompt:
|
|
2790
|
-
composition_parts.append(f"✓
|
|
2790
|
+
composition_parts.append(f"✓ Custom prompt attached")
|
|
2791
2791
|
|
|
2792
2792
|
if self.library.attached_prompts:
|
|
2793
2793
|
composition_parts.append(f"✓ {len(self.library.attached_prompts)} additional prompt(s) attached")
|
|
@@ -2993,49 +2993,66 @@ If the text refers to figures (e.g., 'Figure 1A'), relevant images may be provid
|
|
|
2993
2993
|
|
|
2994
2994
|
# === Prompt Composition (for translation) ===
|
|
2995
2995
|
|
|
2996
|
-
def build_final_prompt(self, source_text: str, source_lang: str, target_lang: str,
|
|
2996
|
+
def build_final_prompt(self, source_text: str, source_lang: str, target_lang: str,
|
|
2997
|
+
mode: str = None, glossary_terms: list = None) -> str:
|
|
2997
2998
|
"""
|
|
2998
2999
|
Build final prompt for translation using 2-layer architecture:
|
|
2999
3000
|
1. System Prompt (auto-selected by mode)
|
|
3000
3001
|
2. Combined prompts from library (primary + attached)
|
|
3001
|
-
|
|
3002
|
+
3. Glossary terms (optional, injected before translation delimiter)
|
|
3003
|
+
|
|
3002
3004
|
Args:
|
|
3003
3005
|
source_text: Text to translate
|
|
3004
3006
|
source_lang: Source language
|
|
3005
3007
|
target_lang: Target language
|
|
3006
3008
|
mode: Override mode (if None, uses self.current_mode)
|
|
3007
|
-
|
|
3009
|
+
glossary_terms: Optional list of term dicts with 'source_term' and 'target_term' keys
|
|
3010
|
+
|
|
3008
3011
|
Returns:
|
|
3009
3012
|
Complete prompt ready for LLM
|
|
3010
3013
|
"""
|
|
3011
3014
|
if mode is None:
|
|
3012
3015
|
mode = self.current_mode
|
|
3013
|
-
|
|
3016
|
+
|
|
3014
3017
|
# Layer 1: System Prompt
|
|
3015
3018
|
system_template = self.get_system_template(mode)
|
|
3016
|
-
|
|
3019
|
+
|
|
3017
3020
|
# Replace placeholders in system prompt
|
|
3018
3021
|
system_template = system_template.replace("{{SOURCE_LANGUAGE}}", source_lang)
|
|
3019
3022
|
system_template = system_template.replace("{{TARGET_LANGUAGE}}", target_lang)
|
|
3020
3023
|
system_template = system_template.replace("{{SOURCE_TEXT}}", source_text)
|
|
3021
|
-
|
|
3024
|
+
|
|
3022
3025
|
# Layer 2: Library prompts (primary + attached)
|
|
3023
3026
|
library_prompts = ""
|
|
3024
|
-
|
|
3027
|
+
|
|
3025
3028
|
if self.library.active_primary_prompt:
|
|
3026
|
-
library_prompts += "\n\n#
|
|
3029
|
+
library_prompts += "\n\n# CUSTOM PROMPT\n\n"
|
|
3027
3030
|
library_prompts += self.library.active_primary_prompt
|
|
3028
|
-
|
|
3031
|
+
|
|
3029
3032
|
for attached_content in self.library.attached_prompts:
|
|
3030
3033
|
library_prompts += "\n\n# ADDITIONAL INSTRUCTIONS\n\n"
|
|
3031
3034
|
library_prompts += attached_content
|
|
3032
|
-
|
|
3035
|
+
|
|
3033
3036
|
# Combine
|
|
3034
3037
|
final_prompt = system_template + library_prompts
|
|
3035
|
-
|
|
3038
|
+
|
|
3039
|
+
# Glossary injection (if terms provided)
|
|
3040
|
+
if glossary_terms:
|
|
3041
|
+
final_prompt += "\n\n# GLOSSARY\n\n"
|
|
3042
|
+
final_prompt += "Use these approved terms in your translation:\n\n"
|
|
3043
|
+
for term in glossary_terms:
|
|
3044
|
+
source_term = term.get('source_term', '')
|
|
3045
|
+
target_term = term.get('target_term', '')
|
|
3046
|
+
if source_term and target_term:
|
|
3047
|
+
# Mark forbidden terms
|
|
3048
|
+
if term.get('forbidden'):
|
|
3049
|
+
final_prompt += f"- {source_term} → ⚠️ DO NOT USE: {target_term}\n"
|
|
3050
|
+
else:
|
|
3051
|
+
final_prompt += f"- {source_term} → {target_term}\n"
|
|
3052
|
+
|
|
3036
3053
|
# Add translation delimiter
|
|
3037
3054
|
final_prompt += "\n\n**YOUR TRANSLATION (provide ONLY the translated text, no numbering or labels):**\n"
|
|
3038
|
-
|
|
3055
|
+
|
|
3039
3056
|
return final_prompt
|
|
3040
3057
|
|
|
3041
3058
|
# ============================================================================
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: supervertaler
|
|
3
|
+
Version: 1.9.176b0
|
|
4
|
+
Summary: Professional AI-enhanced translation workbench with multi-LLM support, glossary system, TM, spellcheck, voice commands, and PyQt6 interface. Batteries included (core).
|
|
5
|
+
Home-page: https://supervertaler.com
|
|
6
|
+
Author: Michael Beijer
|
|
7
|
+
Author-email: Michael Beijer <info@michaelbeijer.co.uk>
|
|
8
|
+
Maintainer-email: Michael Beijer <info@michaelbeijer.co.uk>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Project-URL: Homepage, https://supervertaler.com
|
|
11
|
+
Project-URL: Repository, https://github.com/michaelbeijer/Supervertaler.git
|
|
12
|
+
Project-URL: Bug Tracker, https://github.com/michaelbeijer/Supervertaler/issues
|
|
13
|
+
Project-URL: Changelog, https://github.com/michaelbeijer/Supervertaler/blob/main/CHANGELOG.md
|
|
14
|
+
Project-URL: Documentation, https://github.com/michaelbeijer/Supervertaler/blob/main/AGENTS.md
|
|
15
|
+
Project-URL: Author Website, https://michaelbeijer.co.uk
|
|
16
|
+
Keywords: translation,CAT,CAT-tool,AI,LLM,GPT,Claude,Gemini,Ollama,glossary,termbase,translation-memory,TM,PyQt6,localization,memoQ,Trados,SDLPPX,XLIFF,voice-commands,spellcheck
|
|
17
|
+
Classifier: Development Status :: 4 - Beta
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
24
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
25
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
26
|
+
Classifier: Topic :: Office/Business
|
|
27
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
28
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: PyQt6>=6.5.0
|
|
33
|
+
Requires-Dist: PyQt6-WebEngine>=6.5.0
|
|
34
|
+
Requires-Dist: python-docx>=0.8.11
|
|
35
|
+
Requires-Dist: openpyxl>=3.1.0
|
|
36
|
+
Requires-Dist: Pillow>=10.0.0
|
|
37
|
+
Requires-Dist: lxml>=4.9.0
|
|
38
|
+
Requires-Dist: openai>=1.0.0
|
|
39
|
+
Requires-Dist: anthropic>=0.7.0
|
|
40
|
+
Requires-Dist: google-generativeai>=0.3.0
|
|
41
|
+
Requires-Dist: requests>=2.28.0
|
|
42
|
+
Requires-Dist: markitdown>=0.0.1
|
|
43
|
+
Requires-Dist: sacrebleu>=2.3.1
|
|
44
|
+
Requires-Dist: pyperclip>=1.8.2
|
|
45
|
+
Requires-Dist: chardet>=5.0.0
|
|
46
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
47
|
+
Requires-Dist: markdown>=3.4.0
|
|
48
|
+
Requires-Dist: pyspellchecker>=0.7.0
|
|
49
|
+
Requires-Dist: sounddevice>=0.4.6
|
|
50
|
+
Requires-Dist: numpy>=1.24.0
|
|
51
|
+
Requires-Dist: PyMuPDF>=1.23.0
|
|
52
|
+
Requires-Dist: boto3>=1.28.0
|
|
53
|
+
Requires-Dist: deepl>=1.15.0
|
|
54
|
+
Requires-Dist: spylls>=0.1.7
|
|
55
|
+
Requires-Dist: keyboard>=0.13.5; platform_system == "Windows"
|
|
56
|
+
Requires-Dist: ahk>=1.0.0; platform_system == "Windows"
|
|
57
|
+
Requires-Dist: pyautogui>=0.9.54; platform_system == "Windows"
|
|
58
|
+
Requires-Dist: psutil>=5.9.0
|
|
59
|
+
Provides-Extra: local-whisper
|
|
60
|
+
Requires-Dist: openai-whisper>=20230314; extra == "local-whisper"
|
|
61
|
+
Provides-Extra: voice
|
|
62
|
+
Provides-Extra: web
|
|
63
|
+
Provides-Extra: pdf
|
|
64
|
+
Provides-Extra: mt
|
|
65
|
+
Provides-Extra: hunspell
|
|
66
|
+
Provides-Extra: windows
|
|
67
|
+
Provides-Extra: core
|
|
68
|
+
Provides-Extra: all
|
|
69
|
+
Dynamic: author
|
|
70
|
+
Dynamic: home-page
|
|
71
|
+
Dynamic: license-file
|
|
72
|
+
Dynamic: requires-python
|
|
73
|
+
|
|
74
|
+
# Supervertaler
|
|
75
|
+
|
|
76
|
+
[](https://pypi.org/project/Supervertaler/)
|
|
77
|
+
[](https://www.python.org/downloads/)
|
|
78
|
+
[](https://opensource.org/licenses/MIT)
|
|
79
|
+
|
|
80
|
+
**Professional AI-enhanced translation workbench** with multi-LLM support (GPT-4, Claude, Gemini, Ollama), translation memory, glossary management, and seamless CAT tool integration (memoQ, Trados, CafeTran, Phrase, Déjà Vu).
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install supervertaler
|
|
88
|
+
supervertaler
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or run from source:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/michaelbeijer/Supervertaler.git
|
|
95
|
+
cd Supervertaler
|
|
96
|
+
pip install -r requirements.txt
|
|
97
|
+
python Supervertaler.py
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Key Features
|
|
103
|
+
|
|
104
|
+
- **Multi-LLM AI Translation** - OpenAI GPT-4/5, Anthropic Claude, Google Gemini, Local Ollama
|
|
105
|
+
- **Translation Memory** - Fuzzy matching TM with TMX import/export
|
|
106
|
+
- **Glossary System** - Priority-based term highlighting with forbidden term marking
|
|
107
|
+
- **Superlookup** - Unified concordance search across TM, glossaries, MT, and web resources
|
|
108
|
+
- **CAT Tool Integration** - memoQ XLIFF, Trados SDLPPX/SDLRPX, CafeTran, Phrase, Déjà Vu X3
|
|
109
|
+
- **Voice Commands** - Hands-free translation with OpenAI Whisper
|
|
110
|
+
- **Document Support** - DOCX, bilingual DOCX, PDF, Markdown, plain text
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Documentation
|
|
115
|
+
|
|
116
|
+
| Resource | Description |
|
|
117
|
+
|----------|-------------|
|
|
118
|
+
| [Online Manual](https://supervertaler.gitbook.io/superdocs/) | Quick start, guides, and troubleshooting |
|
|
119
|
+
| [Changelog](CHANGELOG.md) | Complete version history |
|
|
120
|
+
| [Keyboard Shortcuts](docs/guides/KEYBOARD_SHORTCUTS.md) | Shortcut reference |
|
|
121
|
+
| [FAQ](FAQ.md) | Common questions |
|
|
122
|
+
| [Website](https://supervertaler.com) | Project homepage |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
- Python 3.10+
|
|
129
|
+
- PyQt6
|
|
130
|
+
- Windows, macOS, or Linux
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Contributing
|
|
135
|
+
|
|
136
|
+
- [Report bugs](https://github.com/michaelbeijer/Supervertaler/issues)
|
|
137
|
+
- [Request features](https://github.com/michaelbeijer/Supervertaler/discussions)
|
|
138
|
+
- [Contributing guide](CONTRIBUTING.md)
|
|
139
|
+
- [Stargazers](https://github.com/michaelbeijer/Supervertaler/stargazers) - See who's starred the project
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## About
|
|
144
|
+
|
|
145
|
+
**Supervertaler** is maintained by [Michael Beijer](https://michaelbeijer.co.uk), a professional translator with 30 years of experience in technical and patent translation.
|
|
146
|
+
|
|
147
|
+
**License:** MIT - Free for personal and commercial use.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
**Current Version:** See [CHANGELOG.md](CHANGELOG.md) for the latest release notes.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Supervertaler.py,sha256=
|
|
1
|
+
Supervertaler.py,sha256=ABqaS7k80j4w3EiJr52ogQVIJRAFFOD3NpaeDbzWX6k,2318994
|
|
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
|
|
@@ -7,7 +7,7 @@ modules/autofingers_engine.py,sha256=eJ7tBi7YJvTToe5hYTfnyGXB-qme_cHrOPZibaoR2Xw
|
|
|
7
7
|
modules/cafetran_docx_handler.py,sha256=_F7Jh0WPVaDnMhdxEsVSXuD1fN9r-S_V6i0gr86Pdfc,14076
|
|
8
8
|
modules/config_manager.py,sha256=MkPY3xVFgFDkcwewLREg4BfyKueO0OJkT1cTLxehcjM,17894
|
|
9
9
|
modules/database_manager.py,sha256=FecvNLJa_mw0PZld8-LozUSSgtAq6wDZ8Mhq_u2aiA0,82563
|
|
10
|
-
modules/database_migrations.py,sha256=
|
|
10
|
+
modules/database_migrations.py,sha256=tndJ4wV_2JBfPggMgO1tQRwdfRFZ9zwvADllCZE9CCk,15663
|
|
11
11
|
modules/dejavurtf_handler.py,sha256=8NZPPYtHga40SZCypHjPoJPmZTvm9rD-eEUUab7mjtg,28156
|
|
12
12
|
modules/document_analyzer.py,sha256=t1rVvqLaTcpQTEja228C7zZnh8dXshK4wA9t1E9aGVk,19524
|
|
13
13
|
modules/docx_handler.py,sha256=jSlZs5tollJnsnIA80buEXLfZBunp_GQ9lCtFZPUnBs,34053
|
|
@@ -58,7 +58,7 @@ modules/tag_manager.py,sha256=g66S0JSxdguN9AhWzZG3hsIz87Ul51wQ3c2wOCTZVSk,12789
|
|
|
58
58
|
modules/term_extractor.py,sha256=qPvKNCVXFTGEGwXNvvC0cfCmdb5c3WhzE38EOgKdKUI,11253
|
|
59
59
|
modules/termbase_entry_editor.py,sha256=iWO9CgLjMomGAqBXDsGAX7TFJvDOp2s_taS4gBL1rZY,35818
|
|
60
60
|
modules/termbase_import_export.py,sha256=16IAY04IS_rgt0GH5UOUzUI5NoqAli4JMfMquxmFBm0,23552
|
|
61
|
-
modules/termbase_manager.py,sha256
|
|
61
|
+
modules/termbase_manager.py,sha256=7KXEFab6y0o1EmFZwHs3ADklC95udVenxvrmN4XUoj0,48808
|
|
62
62
|
modules/termview_widget.py,sha256=O3ah7g-4Lb_iUctxl9sMyxh8V3A5I5PFxmy9iIH2Kgk,53484
|
|
63
63
|
modules/theme_manager.py,sha256=EOI_5pM2bXAadw08bbl92TLN-w28lbw4Zi1E8vQ-kM0,16694
|
|
64
64
|
modules/tm_editor_dialog.py,sha256=AzGwq4QW641uFJdF8DljLTRRp4FLoYX3Pe4rlTjQWNg,3517
|
|
@@ -72,14 +72,14 @@ modules/trados_docx_handler.py,sha256=VPRAQ73cUHs_SEj6x81z1PmSxfjnwPBp9P4fXeK3Kp
|
|
|
72
72
|
modules/translation_memory.py,sha256=13PDK4_kgYrWTACWBIBypOh2DvoxY9cRT8U6ulilbh4,28739
|
|
73
73
|
modules/translation_results_panel.py,sha256=DmEe0pZRSfcZFg2cWeEREK7H9vrTcPkgeuMW54Pgrys,92505
|
|
74
74
|
modules/translation_services.py,sha256=lyVpWuZK1wtVtYZMDMdLoq1DHBoSaeAnp-Yejb0TlVQ,10530
|
|
75
|
-
modules/unified_prompt_library.py,sha256=
|
|
76
|
-
modules/unified_prompt_manager_qt.py,sha256=
|
|
75
|
+
modules/unified_prompt_library.py,sha256=96u4WlMwnmmhD4uNJHZ-qVQj8v9_8dA2AVCWpBcwTrg,26006
|
|
76
|
+
modules/unified_prompt_manager_qt.py,sha256=U89UFGG-M7BLetoaLAlma0x-n8SIyx682DhSvaRnzJs,171285
|
|
77
77
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
78
78
|
modules/voice_dictation.py,sha256=QmitXfkG-vRt5hIQATjphHdhXfqmwhzcQcbXB6aRzIg,16386
|
|
79
79
|
modules/voice_dictation_lite.py,sha256=jorY0BmWE-8VczbtGrWwt1zbnOctMoSlWOsQrcufBcc,9423
|
|
80
|
-
supervertaler-1.9.
|
|
81
|
-
supervertaler-1.9.
|
|
82
|
-
supervertaler-1.9.
|
|
83
|
-
supervertaler-1.9.
|
|
84
|
-
supervertaler-1.9.
|
|
85
|
-
supervertaler-1.9.
|
|
80
|
+
supervertaler-1.9.176b0.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
81
|
+
supervertaler-1.9.176b0.dist-info/METADATA,sha256=NXnmveUpuH50y_2kAdkEavCbLiRpDYAUSIIc7YK0d-8,5727
|
|
82
|
+
supervertaler-1.9.176b0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
83
|
+
supervertaler-1.9.176b0.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
84
|
+
supervertaler-1.9.176b0.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
85
|
+
supervertaler-1.9.176b0.dist-info/RECORD,,
|