Skip to content

Commit 34d1dd8

Browse files
committed
Merge branch 'improve' into main
2 parents a74ed44 + f1441b0 commit 34d1dd8

5 files changed

Lines changed: 324 additions & 74 deletions

File tree

anylabeling/views/labeling/chatbot/chat.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from PyQt5.QtCore import (
22
QEasingCurve,
3+
QEvent,
34
QPropertyAnimation,
45
QTimer,
56
Qt,
@@ -13,6 +14,7 @@
1314
QMessageBox,
1415
QMenu,
1516
QPushButton,
17+
QScrollArea,
1618
QSizePolicy,
1719
QVBoxLayout,
1820
QTextEdit,
@@ -367,6 +369,7 @@ def _create_content_label(self, processed_content):
367369
self.original_content = processed_content
368370
web_view.page().urlChanged.connect(self.handle_external_link)
369371
web_view.setHtml(convert_markdown_to_html(processed_content))
372+
web_view.installEventFilter(self)
370373
return web_view
371374

372375
def set_action_buttons_enabled(self, enabled):
@@ -419,6 +422,27 @@ def resizeEvent(self, event):
419422
if not self.resize_in_progress:
420423
self.update_width_constraint()
421424

425+
def wheelEvent(self, event):
426+
"""Forward wheel events to parent scroll area"""
427+
parent = self.parent()
428+
while parent:
429+
if isinstance(parent, QScrollArea):
430+
parent.wheelEvent(event)
431+
return
432+
parent = parent.parent()
433+
super().wheelEvent(event)
434+
435+
def eventFilter(self, obj, event):
436+
"""Filter events to forward wheel events from QWebEngineView to scroll area"""
437+
if isinstance(obj, QWebEngineView) and event.type() == QEvent.Wheel:
438+
parent = self.parent()
439+
while parent:
440+
if isinstance(parent, QScrollArea):
441+
parent.wheelEvent(event)
442+
return True
443+
parent = parent.parent()
444+
return super().eventFilter(obj, event)
445+
422446
def copy_content_to_clipboard(self, button=None):
423447
"""Copy message content to clipboard with visual feedback"""
424448
# Copy the content to clipboard
@@ -446,8 +470,10 @@ def adjust_height_after_animation(self):
446470
self.resize_in_progress = True
447471
try:
448472
if isinstance(self.content_label, QWebEngineView):
473+
# Check if document.body exists before accessing scrollHeight
449474
self.content_label.page().runJavaScript(
450-
"document.body.scrollHeight;", self.apply_webview_height
475+
"document.body ? document.body.scrollHeight : 0;",
476+
self.apply_webview_height,
451477
)
452478
return
453479

anylabeling/views/labeling/chatbot/general.py

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from PyQt5.QtCore import (
24
Qt,
35
pyqtSignal,
@@ -9,6 +11,7 @@
911
QPushButton,
1012
QVBoxLayout,
1113
QTextEdit,
14+
QSpinBox,
1215
)
1316

1417

@@ -22,6 +25,11 @@ def __init__(self, parent=None):
2225
self.parent = parent
2326
self.setWindowTitle(self.tr("Batch Process All Images"))
2427
self.setMinimumWidth(450)
28+
29+
self.cpu_count = os.cpu_count() or 1
30+
self.max_concurrency = max(1, int(self.cpu_count * 0.95))
31+
self.default_concurrency = max(1, int(self.cpu_count * 0.8))
32+
2533
self.setup_ui()
2634

2735
def setup_ui(self):
@@ -98,6 +106,61 @@ def setup_ui(self):
98106
)
99107
dialog_layout.addWidget(self.batch_message_input)
100108

109+
# Concurrency setting
110+
settings_container = QHBoxLayout()
111+
settings_container.setContentsMargins(0, 0, 0, 0)
112+
settings_container.setSpacing(8)
113+
settings_container.addStretch()
114+
115+
concurrency_label = QLabel(self.tr("Concurrency:"))
116+
concurrency_label.setStyleSheet(
117+
"""
118+
QLabel {
119+
font-size: 12px;
120+
color: #6B7280;
121+
font-weight: 400;
122+
}
123+
"""
124+
)
125+
settings_container.addWidget(concurrency_label)
126+
127+
self.concurrency_spinbox = QSpinBox()
128+
self.concurrency_spinbox.setMinimum(1)
129+
self.concurrency_spinbox.setMaximum(self.max_concurrency)
130+
self.concurrency_spinbox.setValue(self.default_concurrency)
131+
tooltip_text = self.tr("Max: {}").format(self.max_concurrency)
132+
self.concurrency_spinbox.setToolTip(tooltip_text)
133+
self.concurrency_spinbox.setSuffix(f" / {self.max_concurrency}")
134+
self.concurrency_spinbox.setStyleSheet(
135+
"""
136+
QSpinBox {
137+
border: 1px solid #E5E7EB;
138+
border-radius: 4px;
139+
background-color: #FFFFFF;
140+
color: #1F2937;
141+
font-size: 12px;
142+
padding: 4px 8px;
143+
min-width: 80px;
144+
max-width: 80px;
145+
}
146+
QSpinBox:focus {
147+
border: 1px solid #6366F1;
148+
background-color: #F9FAFB;
149+
}
150+
QSpinBox::up-button, QSpinBox::down-button {
151+
width: 16px;
152+
border: none;
153+
background: transparent;
154+
}
155+
QSpinBox::up-button:hover, QSpinBox::down-button:hover {
156+
background-color: #F3F4F6;
157+
}
158+
"""
159+
)
160+
settings_container.addWidget(self.concurrency_spinbox)
161+
162+
dialog_layout.addLayout(settings_container)
163+
101164
# Button layout
102165
button_layout = QHBoxLayout()
103166
button_layout.setContentsMargins(0, 8, 0, 0)
@@ -178,6 +241,10 @@ def get_prompt(self):
178241
"""Get the user input prompt"""
179242
return self.batch_message_input.toPlainText().strip()
180243

244+
def get_concurrency(self):
245+
"""Get the concurrency setting"""
246+
return self.concurrency_spinbox.value()
247+
181248
def exec_(self):
182249
"""Override exec_ method to adjust position before showing the dialog"""
183250
self.adjustSize()
@@ -186,7 +253,8 @@ def exec_(self):
186253

187254
if result == QDialog.Accepted:
188255
prompt = self.get_prompt()
256+
concurrency = self.get_concurrency()
189257
if prompt:
190258
self.promptReady.emit(prompt)
191-
return prompt
192-
return ""
259+
return (prompt, concurrency)
260+
return None

0 commit comments

Comments
 (0)