pygpt-net 2.6.32__py3-none-any.whl → 2.6.34__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.
- pygpt_net/CHANGELOG.txt +12 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/assistant/batch.py +14 -4
- pygpt_net/controller/assistant/files.py +1 -0
- pygpt_net/controller/assistant/store.py +195 -1
- pygpt_net/controller/camera/camera.py +1 -1
- pygpt_net/controller/chat/attachment.py +2 -0
- pygpt_net/controller/chat/common.py +50 -46
- pygpt_net/controller/config/placeholder.py +95 -75
- pygpt_net/controller/dialogs/confirm.py +3 -1
- pygpt_net/controller/media/media.py +11 -3
- pygpt_net/controller/painter/common.py +227 -10
- pygpt_net/controller/painter/painter.py +4 -12
- pygpt_net/core/assistants/files.py +18 -0
- pygpt_net/core/camera/camera.py +38 -93
- pygpt_net/core/camera/worker.py +430 -0
- pygpt_net/core/filesystem/url.py +3 -0
- pygpt_net/core/render/web/body.py +65 -9
- pygpt_net/core/text/utils.py +3 -0
- pygpt_net/data/config/config.json +234 -221
- pygpt_net/data/config/models.json +179 -180
- pygpt_net/data/config/settings.json +10 -5
- pygpt_net/data/locale/locale.de.ini +8 -6
- pygpt_net/data/locale/locale.en.ini +9 -5
- pygpt_net/data/locale/locale.es.ini +8 -6
- pygpt_net/data/locale/locale.fr.ini +8 -6
- pygpt_net/data/locale/locale.it.ini +8 -6
- pygpt_net/data/locale/locale.pl.ini +8 -6
- pygpt_net/data/locale/locale.uk.ini +8 -6
- pygpt_net/data/locale/locale.zh.ini +8 -6
- pygpt_net/item/assistant.py +13 -1
- pygpt_net/provider/api/google/__init__.py +32 -23
- pygpt_net/provider/api/openai/store.py +45 -1
- pygpt_net/provider/llms/google.py +4 -0
- pygpt_net/ui/dialog/assistant_store.py +213 -203
- pygpt_net/ui/layout/chat/input.py +3 -3
- pygpt_net/ui/widget/draw/painter.py +458 -75
- pygpt_net/ui/widget/option/combo.py +5 -1
- pygpt_net/ui/widget/textarea/input.py +273 -3
- {pygpt_net-2.6.32.dist-info → pygpt_net-2.6.34.dist-info}/METADATA +14 -2
- {pygpt_net-2.6.32.dist-info → pygpt_net-2.6.34.dist-info}/RECORD +44 -43
- {pygpt_net-2.6.32.dist-info → pygpt_net-2.6.34.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.32.dist-info → pygpt_net-2.6.34.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.32.dist-info → pygpt_net-2.6.34.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
2.6.34 (2025-09-03)
|
|
2
|
+
|
|
3
|
+
- Added auto-resizing for input.
|
|
4
|
+
- Added file management to the OpenAI Vector Stores tool.
|
|
5
|
+
- Implemented removal of script tags when exporting HTML.
|
|
6
|
+
- Enabled maintaining custom resolution in Painter.
|
|
7
|
+
|
|
8
|
+
2.6.33 (2025-09-02)
|
|
9
|
+
|
|
10
|
+
- Added a "crop" option, auto-resize canvas, and layer support to Painter.
|
|
11
|
+
- Improved video capture from the camera.
|
|
12
|
+
|
|
1
13
|
2.6.32 (2025-09-02)
|
|
2
14
|
|
|
3
15
|
- Added video generation and support for Google Veo 3 models.
|
pygpt_net/__init__.py
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.09.
|
|
9
|
+
# Updated Date: 2025.09.03 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
__author__ = "Marcin Szczygliński"
|
|
13
13
|
__copyright__ = "Copyright 2025, Marcin Szczygliński"
|
|
14
14
|
__credits__ = ["Marcin Szczygliński"]
|
|
15
15
|
__license__ = "MIT"
|
|
16
|
-
__version__ = "2.6.
|
|
17
|
-
__build__ = "2025-09-
|
|
16
|
+
__version__ = "2.6.34"
|
|
17
|
+
__build__ = "2025-09-03"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
|
20
20
|
__report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.09.02 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional, Any
|
|
13
13
|
|
|
14
|
+
from PySide6.QtCore import QTimer
|
|
14
15
|
from PySide6.QtWidgets import QFileDialog, QApplication
|
|
15
16
|
|
|
16
17
|
from pygpt_net.utils import trans
|
|
@@ -526,6 +527,15 @@ class Batch:
|
|
|
526
527
|
msg=msg,
|
|
527
528
|
)
|
|
528
529
|
|
|
530
|
+
def refresh_delayed(self, ms: int = 1000):
|
|
531
|
+
"""
|
|
532
|
+
Refresh UI after delay
|
|
533
|
+
|
|
534
|
+
:param ms: milliseconds to wait
|
|
535
|
+
"""
|
|
536
|
+
self.window.update_status("Refreshing status...")
|
|
537
|
+
QTimer.singleShot(ms, lambda: self.window.controller.assistant.store.refresh_status())
|
|
538
|
+
|
|
529
539
|
def upload(self, force: bool = False):
|
|
530
540
|
"""
|
|
531
541
|
Upload files to vector store
|
|
@@ -548,10 +558,10 @@ class Batch:
|
|
|
548
558
|
|
|
549
559
|
:param num: number of uploaded files
|
|
550
560
|
"""
|
|
551
|
-
self.window.controller.assistant.files.update()
|
|
552
|
-
self.window.controller.assistant.store.refresh_status()
|
|
561
|
+
self.window.controller.assistant.files.update()
|
|
553
562
|
self.window.update_status("OK. Uploaded files: " + str(num) + ".")
|
|
554
563
|
self.window.ui.dialogs.alert("OK. Uploaded files: " + str(num) + ".")
|
|
564
|
+
self.refresh_delayed(1500)
|
|
555
565
|
|
|
556
566
|
def handle_uploaded_files_failed(self, error: Any):
|
|
557
567
|
"""
|
|
@@ -562,7 +572,7 @@ class Batch:
|
|
|
562
572
|
self.window.core.debug.log(error)
|
|
563
573
|
print("Error uploading files")
|
|
564
574
|
self.window.controller.assistant.files.update()
|
|
565
|
-
self.
|
|
575
|
+
self.refresh_delayed(1500)
|
|
566
576
|
self.window.update_status("Error uploading files.")
|
|
567
577
|
self.window.ui.dialogs.alert(error)
|
|
568
578
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.09.02 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -14,6 +14,8 @@ import json
|
|
|
14
14
|
from typing import Optional
|
|
15
15
|
|
|
16
16
|
from PySide6.QtWidgets import QApplication
|
|
17
|
+
from PySide6.QtGui import QStandardItem
|
|
18
|
+
from PySide6.QtCore import Qt, QTimer
|
|
17
19
|
|
|
18
20
|
from pygpt_net.item.assistant import AssistantStoreItem
|
|
19
21
|
from pygpt_net.utils import trans
|
|
@@ -57,6 +59,8 @@ class VectorStore:
|
|
|
57
59
|
"value": "",
|
|
58
60
|
},
|
|
59
61
|
}
|
|
62
|
+
# Mapping of current files list rows to file IDs
|
|
63
|
+
self._files_row_to_id = []
|
|
60
64
|
|
|
61
65
|
def get_options(self) -> dict:
|
|
62
66
|
"""
|
|
@@ -147,6 +151,8 @@ class VectorStore:
|
|
|
147
151
|
self.current = None # reset if not exists
|
|
148
152
|
self.window.controller.config.load_options(self.id, options)
|
|
149
153
|
|
|
154
|
+
self.update_files_list()
|
|
155
|
+
|
|
150
156
|
def refresh_status(self):
|
|
151
157
|
"""Reload store status"""
|
|
152
158
|
if self.current is not None: # TODO: reset on profile reload
|
|
@@ -157,6 +163,7 @@ class VectorStore:
|
|
|
157
163
|
self.refresh_store(store)
|
|
158
164
|
self.window.update_status(trans('status.assistant.saved'))
|
|
159
165
|
self.update() # update stores list in assistant dialog
|
|
166
|
+
self.update_files_list()
|
|
160
167
|
|
|
161
168
|
def refresh_store(
|
|
162
169
|
self,
|
|
@@ -200,6 +207,8 @@ class VectorStore:
|
|
|
200
207
|
self.refresh_store(store)
|
|
201
208
|
self.window.update_status(trans('status.assistant.saved'))
|
|
202
209
|
self.update()
|
|
210
|
+
if self.current == store_id:
|
|
211
|
+
self.update_files_list()
|
|
203
212
|
|
|
204
213
|
def update_current(self):
|
|
205
214
|
"""Update current store"""
|
|
@@ -220,6 +229,13 @@ class VectorStore:
|
|
|
220
229
|
option["value"] = store.expire_days
|
|
221
230
|
self.window.controller.config.apply(self.id, "expire_days", option)
|
|
222
231
|
|
|
232
|
+
def save_btn(self):
|
|
233
|
+
"""Save vector store editor and close dialog"""
|
|
234
|
+
self.window.update_status("Saving...")
|
|
235
|
+
self.save()
|
|
236
|
+
self.refresh_status()
|
|
237
|
+
self.window.update_status("Saved.")
|
|
238
|
+
|
|
223
239
|
def save(self, persist: bool = True):
|
|
224
240
|
"""
|
|
225
241
|
Save vector store editor
|
|
@@ -258,6 +274,7 @@ class VectorStore:
|
|
|
258
274
|
self.update() # update stores list in assistant dialog
|
|
259
275
|
self.window.update_status(trans("info.settings.saved"))
|
|
260
276
|
self.restore_selection()
|
|
277
|
+
self.update_files_list()
|
|
261
278
|
|
|
262
279
|
def reload_items(self):
|
|
263
280
|
"""Reload list items"""
|
|
@@ -281,6 +298,7 @@ class VectorStore:
|
|
|
281
298
|
self.save(persist=False)
|
|
282
299
|
self.current = self.get_by_tab_idx(idx)
|
|
283
300
|
self.init()
|
|
301
|
+
self.update_files_list()
|
|
284
302
|
|
|
285
303
|
def new(self):
|
|
286
304
|
"""Create new vector store"""
|
|
@@ -305,6 +323,7 @@ class VectorStore:
|
|
|
305
323
|
self.init()
|
|
306
324
|
self.restore_selection()
|
|
307
325
|
self.refresh_by_store_id(store.id)
|
|
326
|
+
self.update_files_list()
|
|
308
327
|
|
|
309
328
|
def delete_by_idx(
|
|
310
329
|
self,
|
|
@@ -357,6 +376,7 @@ class VectorStore:
|
|
|
357
376
|
self.update() # update stores list in assistant dialog
|
|
358
377
|
self.init()
|
|
359
378
|
self.restore_selection()
|
|
379
|
+
self.update_files_list()
|
|
360
380
|
else:
|
|
361
381
|
self.window.update_status(trans('status.error'))
|
|
362
382
|
except Exception as e:
|
|
@@ -469,6 +489,7 @@ class VectorStore:
|
|
|
469
489
|
"""Update vector store editor"""
|
|
470
490
|
self.reload_items()
|
|
471
491
|
self.window.controller.assistant.editor.update_store_list() # update stores list in assistant dialog
|
|
492
|
+
self.update_files_list()
|
|
472
493
|
|
|
473
494
|
def set_hide_thread(self, state: bool):
|
|
474
495
|
"""
|
|
@@ -478,3 +499,176 @@ class VectorStore:
|
|
|
478
499
|
"""
|
|
479
500
|
self.window.core.config.set("assistant.store.hide_threads", state)
|
|
480
501
|
self.update()
|
|
502
|
+
|
|
503
|
+
# ==================== Files ====================
|
|
504
|
+
|
|
505
|
+
def update_files_list(self):
|
|
506
|
+
"""
|
|
507
|
+
Update files list view for the current store based on local DB.
|
|
508
|
+
This method does not hit the API; it reflects local state.
|
|
509
|
+
"""
|
|
510
|
+
model_id = 'assistant.store.files.list'
|
|
511
|
+
if 'assistant.store.files.list' not in self.window.ui.models:
|
|
512
|
+
return # files panel not initialized yet
|
|
513
|
+
model = self.window.ui.models[model_id]
|
|
514
|
+
try:
|
|
515
|
+
model.removeRows(0, model.rowCount())
|
|
516
|
+
except Exception:
|
|
517
|
+
pass
|
|
518
|
+
|
|
519
|
+
self._files_row_to_id = []
|
|
520
|
+
|
|
521
|
+
if self.current is None:
|
|
522
|
+
return
|
|
523
|
+
|
|
524
|
+
files_db = self.window.core.assistants.files
|
|
525
|
+
if files_db is None:
|
|
526
|
+
return
|
|
527
|
+
|
|
528
|
+
# Resolve store files collection from DB
|
|
529
|
+
try:
|
|
530
|
+
store_files = files_db.get_by_store_or_thread(self.current, None) or {}
|
|
531
|
+
except Exception as e:
|
|
532
|
+
self.window.core.debug.log(e)
|
|
533
|
+
store_files = {}
|
|
534
|
+
|
|
535
|
+
i = 0
|
|
536
|
+
for file_id, file_obj in store_files.items():
|
|
537
|
+
if isinstance(file_obj, dict):
|
|
538
|
+
data = file_obj
|
|
539
|
+
else:
|
|
540
|
+
data = {}
|
|
541
|
+
for key in ('id', 'file_id', 'name', 'filename', 'bytes', 'size', 'usage_bytes', 'status'):
|
|
542
|
+
try:
|
|
543
|
+
if hasattr(file_obj, key):
|
|
544
|
+
data[key] = getattr(file_obj, key)
|
|
545
|
+
except Exception:
|
|
546
|
+
pass
|
|
547
|
+
if not data and hasattr(file_obj, 'to_dict'):
|
|
548
|
+
try:
|
|
549
|
+
data = file_obj.to_dict()
|
|
550
|
+
except Exception:
|
|
551
|
+
data = {}
|
|
552
|
+
|
|
553
|
+
# Choose display name
|
|
554
|
+
name = data.get('filename') or data.get('name') or file_id
|
|
555
|
+
# Choose size
|
|
556
|
+
size_val = None
|
|
557
|
+
for k in ('bytes', 'size', 'usage_bytes'):
|
|
558
|
+
if data.get(k) is not None:
|
|
559
|
+
size_val = data.get(k)
|
|
560
|
+
break
|
|
561
|
+
|
|
562
|
+
# Human-readable size if possible
|
|
563
|
+
size_txt = ""
|
|
564
|
+
try:
|
|
565
|
+
if size_val:
|
|
566
|
+
size_txt = self.window.core.filesystem.sizeof_fmt(int(size_val))
|
|
567
|
+
except Exception:
|
|
568
|
+
pass
|
|
569
|
+
|
|
570
|
+
extra = []
|
|
571
|
+
if size_txt:
|
|
572
|
+
extra.append(size_txt)
|
|
573
|
+
if data.get('status'):
|
|
574
|
+
extra.append(str(data.get('status')))
|
|
575
|
+
label = name
|
|
576
|
+
if extra:
|
|
577
|
+
label += " ({})".format(", ".join(extra))
|
|
578
|
+
|
|
579
|
+
item = QStandardItem(label)
|
|
580
|
+
item.setEditable(False)
|
|
581
|
+
item.setData(file_id, Qt.UserRole)
|
|
582
|
+
model.setItem(i, 0, item)
|
|
583
|
+
self._files_row_to_id.append(data['file_id'] if 'file_id' in data else file_id)
|
|
584
|
+
i += 1
|
|
585
|
+
|
|
586
|
+
def delete_file_by_idx(self, idx: int, force: bool = False):
|
|
587
|
+
"""
|
|
588
|
+
Delete a single file from the current store by row index in files list.
|
|
589
|
+
This uses API to remove the file from a remote store, then triggers async re-import
|
|
590
|
+
of files for the current store to keep the local DB in sync.
|
|
591
|
+
|
|
592
|
+
:param idx: row index in files list
|
|
593
|
+
:param force: force delete without confirmation
|
|
594
|
+
"""
|
|
595
|
+
if self.current is None:
|
|
596
|
+
self.window.ui.dialogs.alert("Please select vector store first.")
|
|
597
|
+
return
|
|
598
|
+
|
|
599
|
+
if not force:
|
|
600
|
+
self.window.ui.dialogs.confirm(
|
|
601
|
+
type='assistant.file.delete',
|
|
602
|
+
id=idx,
|
|
603
|
+
msg=trans('confirm.assistant.store.file.delete'),
|
|
604
|
+
)
|
|
605
|
+
return
|
|
606
|
+
|
|
607
|
+
model_id = 'assistant.store.files.list'
|
|
608
|
+
if model_id not in self.window.ui.models:
|
|
609
|
+
return
|
|
610
|
+
if idx < 0 or idx >= len(self._files_row_to_id):
|
|
611
|
+
return
|
|
612
|
+
|
|
613
|
+
file_id = self._files_row_to_id[idx]
|
|
614
|
+
if not file_id:
|
|
615
|
+
return
|
|
616
|
+
|
|
617
|
+
# Update UI state
|
|
618
|
+
self.window.update_status(trans('status.sending'))
|
|
619
|
+
QApplication.processEvents()
|
|
620
|
+
|
|
621
|
+
try:
|
|
622
|
+
api = self.window.core.api.openai.store
|
|
623
|
+
removed = False
|
|
624
|
+
|
|
625
|
+
# Prefer store-scoped removal if available
|
|
626
|
+
if hasattr(api, 'remove_store_file'):
|
|
627
|
+
try:
|
|
628
|
+
api.remove_store_file(self.current, file_id)
|
|
629
|
+
removed = True
|
|
630
|
+
except Exception as e:
|
|
631
|
+
self.window.core.debug.log(e)
|
|
632
|
+
|
|
633
|
+
# Fallback: remove by file_id only
|
|
634
|
+
if not removed and hasattr(api, 'remove_file'):
|
|
635
|
+
try:
|
|
636
|
+
api.remove_file(file_id)
|
|
637
|
+
removed = True
|
|
638
|
+
except Exception as e:
|
|
639
|
+
self.window.core.debug.log(e)
|
|
640
|
+
|
|
641
|
+
if not removed:
|
|
642
|
+
raise RuntimeError("Remove file API not available.")
|
|
643
|
+
|
|
644
|
+
# Remove from local DB
|
|
645
|
+
try:
|
|
646
|
+
self.window.core.assistants.files.delete_by_file_id(file_id)
|
|
647
|
+
except Exception as e:
|
|
648
|
+
self.window.core.debug.log(e)
|
|
649
|
+
|
|
650
|
+
# Optimistic UI update: remove row from the model immediately
|
|
651
|
+
try:
|
|
652
|
+
self.window.ui.models[model_id].removeRow(idx)
|
|
653
|
+
# also update index map
|
|
654
|
+
try:
|
|
655
|
+
del self._files_row_to_id[idx]
|
|
656
|
+
except Exception:
|
|
657
|
+
pass
|
|
658
|
+
except Exception:
|
|
659
|
+
pass
|
|
660
|
+
|
|
661
|
+
# Trigger re-import for the current store to refresh local DB and UI elsewhere
|
|
662
|
+
try:
|
|
663
|
+
self.window.update_status("Refreshing status...")
|
|
664
|
+
QTimer.singleShot(1000, lambda: self.window.controller.assistant.store.refresh_status())
|
|
665
|
+
except Exception as e:
|
|
666
|
+
self.window.core.debug.log(e)
|
|
667
|
+
|
|
668
|
+
self.window.update_status(trans('status.deleted'))
|
|
669
|
+
|
|
670
|
+
except Exception as e:
|
|
671
|
+
self.window.update_status(trans('status.error'))
|
|
672
|
+
self.window.ui.dialogs.alert("Failed to delete file: {}".format(e))
|
|
673
|
+
self.window.core.debug.log(e)
|
|
674
|
+
self.update_files_list()
|
|
@@ -18,7 +18,7 @@ from PySide6.QtCore import Slot, QObject
|
|
|
18
18
|
from PySide6.QtGui import QImage, QPixmap, Qt
|
|
19
19
|
|
|
20
20
|
from pygpt_net.core.events import AppEvent, KernelEvent
|
|
21
|
-
from pygpt_net.core.camera import CaptureWorker
|
|
21
|
+
from pygpt_net.core.camera.worker import CaptureWorker
|
|
22
22
|
from pygpt_net.core.types import MODE_ASSISTANT
|
|
23
23
|
from pygpt_net.utils import trans
|
|
24
24
|
|
|
@@ -126,6 +126,8 @@ class Attachment(QObject):
|
|
|
126
126
|
self.uploaded = False
|
|
127
127
|
auto_index = self.window.core.config.get("attachments_auto_index", False)
|
|
128
128
|
attachments = self.window.core.attachments.get_all(mode, only_files=True)
|
|
129
|
+
if self.mode != self.MODE_QUERY_CONTEXT:
|
|
130
|
+
auto_index = False # disable auto index for full context and summary modes
|
|
129
131
|
|
|
130
132
|
if self.is_verbose() and len(attachments) > 0:
|
|
131
133
|
print(f"\nUploading attachments...\nWork Mode: {mode}")
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
-
from typing import Any
|
|
14
13
|
|
|
15
14
|
from PySide6.QtGui import QTextCursor
|
|
16
15
|
from PySide6.QtWidgets import QFileDialog, QApplication
|
|
@@ -34,42 +33,45 @@ class Common:
|
|
|
34
33
|
|
|
35
34
|
def setup(self):
|
|
36
35
|
"""Set up UI"""
|
|
36
|
+
nodes = self.window.ui.nodes
|
|
37
|
+
config = self.window.core.config
|
|
38
|
+
|
|
37
39
|
# stream mode
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
+
if config.get('stream'):
|
|
41
|
+
nodes['input.stream'].setChecked(True)
|
|
40
42
|
else:
|
|
41
|
-
|
|
43
|
+
nodes['input.stream'].setChecked(False)
|
|
42
44
|
|
|
43
45
|
# send clear
|
|
44
|
-
if
|
|
45
|
-
|
|
46
|
+
if config.get('send_clear'):
|
|
47
|
+
nodes['input.send_clear'].setChecked(True)
|
|
46
48
|
else:
|
|
47
|
-
|
|
49
|
+
nodes['input.send_clear'].setChecked(False)
|
|
48
50
|
|
|
49
51
|
# send with enter/shift/disabled
|
|
50
|
-
mode =
|
|
52
|
+
mode = config.get('send_mode')
|
|
51
53
|
if mode == 2:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
nodes['input.send_shift_enter'].setChecked(True)
|
|
55
|
+
nodes['input.send_enter'].setChecked(False)
|
|
56
|
+
nodes['input.send_none'].setChecked(False)
|
|
55
57
|
elif mode == 1:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
nodes['input.send_enter'].setChecked(True)
|
|
59
|
+
nodes['input.send_shift_enter'].setChecked(False)
|
|
60
|
+
nodes['input.send_none'].setChecked(False)
|
|
59
61
|
elif mode == 0:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
nodes['input.send_enter'].setChecked(False)
|
|
63
|
+
nodes['input.send_shift_enter'].setChecked(False)
|
|
64
|
+
nodes['input.send_none'].setChecked(True)
|
|
63
65
|
|
|
64
66
|
# cmd enabled
|
|
65
|
-
if
|
|
66
|
-
|
|
67
|
+
if config.get('cmd'):
|
|
68
|
+
nodes['cmd.enabled'].setChecked(True)
|
|
67
69
|
else:
|
|
68
|
-
|
|
70
|
+
nodes['cmd.enabled'].setChecked(False)
|
|
69
71
|
|
|
70
72
|
# output timestamps
|
|
71
|
-
is_timestamp =
|
|
72
|
-
|
|
73
|
+
is_timestamp = config.get('output_timestamp')
|
|
74
|
+
nodes['output.timestamp'].setChecked(is_timestamp)
|
|
73
75
|
if is_timestamp:
|
|
74
76
|
data = {
|
|
75
77
|
"initialized": self.initialized,
|
|
@@ -78,22 +80,22 @@ class Common:
|
|
|
78
80
|
self.window.dispatch(event)
|
|
79
81
|
|
|
80
82
|
# raw (plain) output
|
|
81
|
-
plain =
|
|
82
|
-
|
|
83
|
+
plain = config.get('render.plain')
|
|
84
|
+
nodes['output.raw'].setChecked(plain)
|
|
83
85
|
if plain:
|
|
84
|
-
|
|
85
|
-
for pid in
|
|
86
|
+
nodes['output.timestamp'].setVisible(True)
|
|
87
|
+
for pid in nodes['output']:
|
|
86
88
|
try:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
nodes['output'][pid].setVisible(False)
|
|
90
|
+
nodes['output_plain'][pid].setVisible(True)
|
|
89
91
|
except Exception as e:
|
|
90
92
|
pass
|
|
91
93
|
else:
|
|
92
|
-
|
|
93
|
-
for pid in
|
|
94
|
+
nodes['output.timestamp'].setVisible(False)
|
|
95
|
+
for pid in nodes['output']:
|
|
94
96
|
try:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
nodes['output'][pid].setVisible(True)
|
|
98
|
+
nodes['output_plain'][pid].setVisible(False)
|
|
97
99
|
except Exception as e:
|
|
98
100
|
pass
|
|
99
101
|
|
|
@@ -101,7 +103,7 @@ class Common:
|
|
|
101
103
|
self.window.dispatch(event) # switch renderer if needed
|
|
102
104
|
|
|
103
105
|
# set focus to input
|
|
104
|
-
|
|
106
|
+
nodes['input'].setFocus()
|
|
105
107
|
self.initialized = True
|
|
106
108
|
|
|
107
109
|
def append_to_input(
|
|
@@ -115,8 +117,9 @@ class Common:
|
|
|
115
117
|
:param text: text to append
|
|
116
118
|
:param separator: text separator
|
|
117
119
|
"""
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
node = self.window.ui.nodes['input']
|
|
121
|
+
prev_text = node.toPlainText()
|
|
122
|
+
cur = node.textCursor()
|
|
120
123
|
cur.movePosition(QTextCursor.End)
|
|
121
124
|
text = str(text).strip()
|
|
122
125
|
if prev_text.strip() != "":
|
|
@@ -128,8 +131,8 @@ class Common:
|
|
|
128
131
|
if sep: # New line if LF
|
|
129
132
|
cur.insertBlock()
|
|
130
133
|
cur.movePosition(QTextCursor.End) # Move cursor to end of text
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
node.setTextCursor(cur) # Update visible cursor
|
|
135
|
+
node.setFocus() # Set focus to input
|
|
133
136
|
|
|
134
137
|
# update tokens counter
|
|
135
138
|
self.window.controller.ui.update_tokens()
|
|
@@ -176,18 +179,19 @@ class Common:
|
|
|
176
179
|
|
|
177
180
|
:param value: True if enabled
|
|
178
181
|
"""
|
|
182
|
+
nodes = self.window.ui.nodes
|
|
179
183
|
if value == 0:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
nodes['input.send_none'].setChecked(True)
|
|
185
|
+
nodes['input.send_shift_enter'].setChecked(False)
|
|
186
|
+
nodes['input.send_enter'].setChecked(False)
|
|
183
187
|
elif value == 1:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
nodes['input.send_enter'].setChecked(True)
|
|
189
|
+
nodes['input.send_shift_enter'].setChecked(False)
|
|
190
|
+
nodes['input.send_none'].setChecked(False)
|
|
187
191
|
elif value == 2:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
nodes['input.send_shift_enter'].setChecked(True)
|
|
193
|
+
nodes['input.send_enter'].setChecked(False)
|
|
194
|
+
nodes['input.send_none'].setChecked(False)
|
|
191
195
|
self.window.core.config.set('send_mode', value)
|
|
192
196
|
|
|
193
197
|
def focus_input(self):
|