supervertaler 1.9.163__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 +48473 -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 +1911 -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 +351 -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 +1176 -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.163.dist-info/METADATA +906 -0
- supervertaler-1.9.163.dist-info/RECORD +85 -0
- supervertaler-1.9.163.dist-info/WHEEL +5 -0
- supervertaler-1.9.163.dist-info/entry_points.txt +2 -0
- supervertaler-1.9.163.dist-info/licenses/LICENSE +21 -0
- supervertaler-1.9.163.dist-info/top_level.txt +2 -0
modules/superbrowser.py
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
=============================================================================
|
|
4
|
+
MODULE: Superbrowser - Multi-Chat AI Browser
|
|
5
|
+
=============================================================================
|
|
6
|
+
Display multiple AI chat pages side by side in a single interface.
|
|
7
|
+
Supports ChatGPT, Claude, and Gemini in a three-column resizable layout.
|
|
8
|
+
|
|
9
|
+
Author: Michael Beijer
|
|
10
|
+
Date: November 18, 2025
|
|
11
|
+
Version: 1.0.0
|
|
12
|
+
=============================================================================
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import shutil
|
|
17
|
+
from PyQt6.QtCore import QUrl, Qt
|
|
18
|
+
from PyQt6.QtWidgets import (
|
|
19
|
+
QWidget, QHBoxLayout, QVBoxLayout, QLabel,
|
|
20
|
+
QSplitter, QPushButton, QLineEdit, QComboBox,
|
|
21
|
+
QGroupBox, QFormLayout
|
|
22
|
+
)
|
|
23
|
+
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
|
24
|
+
from PyQt6.QtWebEngineCore import QWebEngineProfile
|
|
25
|
+
from PyQt6.QtGui import QPalette, QColor
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _clear_corrupted_cache(storage_path: str):
|
|
29
|
+
"""
|
|
30
|
+
Clear potentially corrupted Chromium cache folders.
|
|
31
|
+
These can cause 'wrong file structure on disk' errors on startup.
|
|
32
|
+
"""
|
|
33
|
+
problematic_dirs = [
|
|
34
|
+
os.path.join(storage_path, "Shared Dictionary"),
|
|
35
|
+
os.path.join(storage_path, "cache", "Shared Dictionary"),
|
|
36
|
+
]
|
|
37
|
+
for dir_path in problematic_dirs:
|
|
38
|
+
if os.path.exists(dir_path):
|
|
39
|
+
try:
|
|
40
|
+
shutil.rmtree(dir_path)
|
|
41
|
+
except Exception:
|
|
42
|
+
pass # Silently ignore - may be in use
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ChatColumn(QWidget):
|
|
46
|
+
"""A column containing a chat interface with web browser"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, title, url, header_color, parent=None, user_data_path=None):
|
|
49
|
+
super().__init__(parent)
|
|
50
|
+
self.title = title
|
|
51
|
+
self.url = url
|
|
52
|
+
self.header_color = header_color
|
|
53
|
+
self.user_data_path = user_data_path # Store user data path
|
|
54
|
+
self.init_ui()
|
|
55
|
+
|
|
56
|
+
def init_ui(self):
|
|
57
|
+
"""Initialize the chat column UI"""
|
|
58
|
+
layout = QVBoxLayout()
|
|
59
|
+
layout.setContentsMargins(0, 0, 0, 0)
|
|
60
|
+
layout.setSpacing(0)
|
|
61
|
+
|
|
62
|
+
# Tiny header label with provider name
|
|
63
|
+
header = QLabel(self.title)
|
|
64
|
+
header.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
65
|
+
header.setStyleSheet(f"""
|
|
66
|
+
QLabel {{
|
|
67
|
+
background-color: {self.header_color};
|
|
68
|
+
color: white;
|
|
69
|
+
padding: 0px;
|
|
70
|
+
margin: 0px;
|
|
71
|
+
font-weight: bold;
|
|
72
|
+
font-size: 9px;
|
|
73
|
+
max-height: 20px;
|
|
74
|
+
min-height: 20px;
|
|
75
|
+
}}
|
|
76
|
+
""")
|
|
77
|
+
|
|
78
|
+
# URL bar for navigation
|
|
79
|
+
url_layout = QHBoxLayout()
|
|
80
|
+
url_layout.setContentsMargins(1, 1, 1, 1)
|
|
81
|
+
|
|
82
|
+
self.url_input = QLineEdit()
|
|
83
|
+
self.url_input.setText(self.url)
|
|
84
|
+
self.url_input.setPlaceholderText("Enter URL...")
|
|
85
|
+
self.url_input.returnPressed.connect(self.load_url)
|
|
86
|
+
|
|
87
|
+
reload_btn = QPushButton("↻")
|
|
88
|
+
reload_btn.setMaximumWidth(40)
|
|
89
|
+
reload_btn.setToolTip("Reload page")
|
|
90
|
+
reload_btn.clicked.connect(self.reload_page)
|
|
91
|
+
|
|
92
|
+
home_btn = QPushButton("⌂")
|
|
93
|
+
home_btn.setMaximumWidth(40)
|
|
94
|
+
home_btn.setToolTip("Go to home URL")
|
|
95
|
+
home_btn.clicked.connect(self.go_home)
|
|
96
|
+
|
|
97
|
+
url_layout.addWidget(self.url_input)
|
|
98
|
+
url_layout.addWidget(reload_btn)
|
|
99
|
+
url_layout.addWidget(home_btn)
|
|
100
|
+
|
|
101
|
+
# Web view with persistent profile
|
|
102
|
+
# Create or use persistent profile to save cookies and session data
|
|
103
|
+
profile_name = f"superbrowser_{self.title.lower()}"
|
|
104
|
+
self.profile = QWebEngineProfile(profile_name, self)
|
|
105
|
+
|
|
106
|
+
# Set persistent storage path using user_data_path from parent
|
|
107
|
+
if self.user_data_path:
|
|
108
|
+
storage_path = os.path.join(str(self.user_data_path), "superbrowser_profiles", profile_name)
|
|
109
|
+
else:
|
|
110
|
+
# Fallback to script directory if user_data_path not provided
|
|
111
|
+
dev_mode_marker = os.path.join(os.path.dirname(__file__), "..", ".supervertaler.local")
|
|
112
|
+
base_folder = "user_data_private" if os.path.exists(dev_mode_marker) else "user_data"
|
|
113
|
+
storage_path = os.path.join(os.path.dirname(__file__), "..", base_folder, "superbrowser_profiles", profile_name)
|
|
114
|
+
os.makedirs(storage_path, exist_ok=True)
|
|
115
|
+
|
|
116
|
+
# Clear potentially corrupted cache to prevent Chromium errors
|
|
117
|
+
_clear_corrupted_cache(storage_path)
|
|
118
|
+
|
|
119
|
+
self.profile.setPersistentStoragePath(storage_path)
|
|
120
|
+
self.profile.setCachePath(os.path.join(storage_path, "cache"))
|
|
121
|
+
|
|
122
|
+
# Enable persistent cookies
|
|
123
|
+
self.profile.setPersistentCookiesPolicy(QWebEngineProfile.PersistentCookiesPolicy.AllowPersistentCookies)
|
|
124
|
+
|
|
125
|
+
# Create web view with this profile
|
|
126
|
+
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
|
127
|
+
from PyQt6.QtWebEngineCore import QWebEnginePage
|
|
128
|
+
|
|
129
|
+
page = QWebEnginePage(self.profile, self)
|
|
130
|
+
self.web_view = QWebEngineView()
|
|
131
|
+
self.web_view.setPage(page)
|
|
132
|
+
self.web_view.setUrl(QUrl(self.url))
|
|
133
|
+
|
|
134
|
+
# Update URL bar when page changes
|
|
135
|
+
self.web_view.urlChanged.connect(self.update_url_bar)
|
|
136
|
+
|
|
137
|
+
# Add to layout (tiny header, URL bar, then browser)
|
|
138
|
+
layout.addWidget(header)
|
|
139
|
+
layout.addLayout(url_layout)
|
|
140
|
+
layout.addWidget(self.web_view)
|
|
141
|
+
|
|
142
|
+
self.setLayout(layout)
|
|
143
|
+
|
|
144
|
+
def load_url(self):
|
|
145
|
+
"""Load URL from input field"""
|
|
146
|
+
url_text = self.url_input.text().strip()
|
|
147
|
+
if not url_text.startswith(('http://', 'https://')):
|
|
148
|
+
url_text = 'https://' + url_text
|
|
149
|
+
self.web_view.setUrl(QUrl(url_text))
|
|
150
|
+
|
|
151
|
+
def reload_page(self):
|
|
152
|
+
"""Reload the current page"""
|
|
153
|
+
self.web_view.reload()
|
|
154
|
+
|
|
155
|
+
def go_home(self):
|
|
156
|
+
"""Go back to the home URL"""
|
|
157
|
+
self.web_view.setUrl(QUrl(self.url))
|
|
158
|
+
|
|
159
|
+
def update_url_bar(self, url):
|
|
160
|
+
"""Update URL bar when page changes"""
|
|
161
|
+
self.url_input.setText(url.toString())
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class SuperbrowserWidget(QWidget):
|
|
165
|
+
"""
|
|
166
|
+
Superbrowser - Multi-Chat AI Browser Widget
|
|
167
|
+
|
|
168
|
+
Displays multiple AI chat interfaces side by side for easy comparison
|
|
169
|
+
and concurrent interaction with different AI models.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
def __init__(self, parent=None, user_data_path=None):
|
|
173
|
+
super().__init__(parent)
|
|
174
|
+
self.parent_window = parent
|
|
175
|
+
self.user_data_path = user_data_path # Store user data path for profiles
|
|
176
|
+
|
|
177
|
+
# Default URLs for AI chat interfaces
|
|
178
|
+
self.chatgpt_url = "https://chatgpt.com/"
|
|
179
|
+
self.claude_url = "https://claude.ai/"
|
|
180
|
+
self.gemini_url = "https://gemini.google.com/"
|
|
181
|
+
|
|
182
|
+
self.init_ui()
|
|
183
|
+
|
|
184
|
+
def init_ui(self):
|
|
185
|
+
"""Initialize the Superbrowser UI"""
|
|
186
|
+
main_layout = QVBoxLayout()
|
|
187
|
+
main_layout.setContentsMargins(5, 5, 5, 5)
|
|
188
|
+
main_layout.setSpacing(5)
|
|
189
|
+
|
|
190
|
+
# Compact title bar with toggle button
|
|
191
|
+
title_bar_layout = QHBoxLayout()
|
|
192
|
+
title_bar_layout.setContentsMargins(0, 0, 0, 0)
|
|
193
|
+
|
|
194
|
+
title_label = QLabel("🌐 Superbrowser - Multi-Chat AI Browser")
|
|
195
|
+
title_label.setStyleSheet("""
|
|
196
|
+
QLabel {
|
|
197
|
+
font-size: 12px;
|
|
198
|
+
font-weight: bold;
|
|
199
|
+
color: #2c3e50;
|
|
200
|
+
padding: 3px;
|
|
201
|
+
}
|
|
202
|
+
""")
|
|
203
|
+
|
|
204
|
+
description = QLabel(
|
|
205
|
+
"View and interact with ChatGPT, Claude, and Gemini side by side. "
|
|
206
|
+
"Perfect for comparing responses or maintaining multiple conversation threads."
|
|
207
|
+
)
|
|
208
|
+
description.setWordWrap(True)
|
|
209
|
+
description.setStyleSheet("color: #7f8c8d; padding: 3px; font-size: 10px;")
|
|
210
|
+
|
|
211
|
+
# Toggle button for configuration section
|
|
212
|
+
self.toggle_config_btn = QPushButton("▼ Hide Configuration")
|
|
213
|
+
self.toggle_config_btn.setMaximumWidth(150)
|
|
214
|
+
self.toggle_config_btn.setStyleSheet("""
|
|
215
|
+
QPushButton {
|
|
216
|
+
background-color: #3498db;
|
|
217
|
+
color: white;
|
|
218
|
+
border: none;
|
|
219
|
+
padding: 4px 8px;
|
|
220
|
+
font-size: 10px;
|
|
221
|
+
border-radius: 3px;
|
|
222
|
+
}
|
|
223
|
+
QPushButton:hover {
|
|
224
|
+
background-color: #2980b9;
|
|
225
|
+
}
|
|
226
|
+
""")
|
|
227
|
+
self.toggle_config_btn.clicked.connect(self.toggle_configuration)
|
|
228
|
+
|
|
229
|
+
title_bar_layout.addWidget(title_label)
|
|
230
|
+
title_bar_layout.addWidget(description, stretch=1)
|
|
231
|
+
title_bar_layout.addWidget(self.toggle_config_btn)
|
|
232
|
+
|
|
233
|
+
main_layout.addLayout(title_bar_layout)
|
|
234
|
+
|
|
235
|
+
# URL Configuration section (collapsible)
|
|
236
|
+
self.config_group = QGroupBox("🔧 Configuration")
|
|
237
|
+
self.config_group.setStyleSheet("QGroupBox { font-size: 10px; font-weight: bold; }")
|
|
238
|
+
config_layout = QFormLayout()
|
|
239
|
+
|
|
240
|
+
self.chatgpt_url_input = QLineEdit(self.chatgpt_url)
|
|
241
|
+
self.chatgpt_url_input.setStyleSheet("font-size: 10px;")
|
|
242
|
+
self.claude_url_input = QLineEdit(self.claude_url)
|
|
243
|
+
self.claude_url_input.setStyleSheet("font-size: 10px;")
|
|
244
|
+
self.gemini_url_input = QLineEdit(self.gemini_url)
|
|
245
|
+
self.gemini_url_input.setStyleSheet("font-size: 10px;")
|
|
246
|
+
|
|
247
|
+
config_layout.addRow("ChatGPT URL:", self.chatgpt_url_input)
|
|
248
|
+
config_layout.addRow("Claude URL:", self.claude_url_input)
|
|
249
|
+
config_layout.addRow("Gemini URL:", self.gemini_url_input)
|
|
250
|
+
|
|
251
|
+
update_btn = QPushButton("Update URLs")
|
|
252
|
+
update_btn.setStyleSheet("font-size: 10px; padding: 3px;")
|
|
253
|
+
update_btn.clicked.connect(self.update_urls)
|
|
254
|
+
config_layout.addRow("", update_btn)
|
|
255
|
+
|
|
256
|
+
self.config_group.setLayout(config_layout)
|
|
257
|
+
self.config_group.setMaximumHeight(150)
|
|
258
|
+
main_layout.addWidget(self.config_group)
|
|
259
|
+
|
|
260
|
+
# Splitter for resizable columns
|
|
261
|
+
splitter = QSplitter(Qt.Orientation.Horizontal)
|
|
262
|
+
splitter.setHandleWidth(3)
|
|
263
|
+
|
|
264
|
+
# Create chat columns - pass user_data_path for profile storage
|
|
265
|
+
self.chatgpt_column = ChatColumn("ChatGPT", self.chatgpt_url, "#10a37f", self, user_data_path=self.user_data_path)
|
|
266
|
+
self.claude_column = ChatColumn("Claude", self.claude_url, "#c17c4f", self, user_data_path=self.user_data_path)
|
|
267
|
+
self.gemini_column = ChatColumn("Gemini", self.gemini_url, "#4285f4", self, user_data_path=self.user_data_path)
|
|
268
|
+
|
|
269
|
+
# Add columns to splitter
|
|
270
|
+
splitter.addWidget(self.chatgpt_column)
|
|
271
|
+
splitter.addWidget(self.claude_column)
|
|
272
|
+
splitter.addWidget(self.gemini_column)
|
|
273
|
+
|
|
274
|
+
# Set equal sizes for all columns
|
|
275
|
+
splitter.setSizes([600, 600, 600])
|
|
276
|
+
|
|
277
|
+
# Add splitter to main layout (takes most of the space)
|
|
278
|
+
main_layout.addWidget(splitter, stretch=1)
|
|
279
|
+
|
|
280
|
+
self.setLayout(main_layout)
|
|
281
|
+
|
|
282
|
+
def toggle_configuration(self):
|
|
283
|
+
"""Toggle visibility of configuration section"""
|
|
284
|
+
if self.config_group.isVisible():
|
|
285
|
+
self.config_group.setVisible(False)
|
|
286
|
+
self.toggle_config_btn.setText("▶ Show Configuration")
|
|
287
|
+
else:
|
|
288
|
+
self.config_group.setVisible(True)
|
|
289
|
+
self.toggle_config_btn.setText("▼ Hide Configuration")
|
|
290
|
+
|
|
291
|
+
def update_urls(self):
|
|
292
|
+
"""Update the URLs for all chat columns"""
|
|
293
|
+
self.chatgpt_url = self.chatgpt_url_input.text().strip() or self.chatgpt_url
|
|
294
|
+
self.claude_url = self.claude_url_input.text().strip() or self.claude_url
|
|
295
|
+
self.gemini_url = self.gemini_url_input.text().strip() or self.gemini_url
|
|
296
|
+
|
|
297
|
+
# Update the columns
|
|
298
|
+
self.chatgpt_column.url = self.chatgpt_url
|
|
299
|
+
self.claude_column.url = self.claude_url
|
|
300
|
+
self.gemini_column.url = self.gemini_url
|
|
301
|
+
|
|
302
|
+
# Reload to new URLs
|
|
303
|
+
self.chatgpt_column.go_home()
|
|
304
|
+
self.claude_column.go_home()
|
|
305
|
+
self.gemini_column.go_home()
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
# ============================================================================
|
|
309
|
+
# STANDALONE USAGE
|
|
310
|
+
# ============================================================================
|
|
311
|
+
|
|
312
|
+
if __name__ == "__main__":
|
|
313
|
+
import sys
|
|
314
|
+
from PyQt6.QtWidgets import QApplication, QMainWindow
|
|
315
|
+
|
|
316
|
+
app = QApplication(sys.argv)
|
|
317
|
+
app.setApplicationName("Superbrowser")
|
|
318
|
+
|
|
319
|
+
# Create main window for testing
|
|
320
|
+
window = QMainWindow()
|
|
321
|
+
window.setWindowTitle("Superbrowser - Multi-Chat AI Browser")
|
|
322
|
+
window.setGeometry(100, 100, 1800, 1000)
|
|
323
|
+
|
|
324
|
+
# Create and set central widget
|
|
325
|
+
browser = SuperbrowserWidget()
|
|
326
|
+
window.setCentralWidget(browser)
|
|
327
|
+
|
|
328
|
+
window.show()
|
|
329
|
+
sys.exit(app.exec())
|