pygpt-net 2.6.2__py3-none-any.whl → 2.6.3__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 +5 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/controller/calendar/note.py +101 -126
- pygpt_net/controller/chat/render.py +20 -7
- pygpt_net/controller/ctx/common.py +3 -2
- pygpt_net/controller/ctx/ctx.py +68 -129
- pygpt_net/controller/layout/layout.py +166 -108
- pygpt_net/controller/mode/mode.py +88 -85
- pygpt_net/controller/model/model.py +73 -73
- pygpt_net/controller/plugins/plugins.py +186 -243
- pygpt_net/controller/plugins/presets.py +54 -55
- pygpt_net/controller/plugins/settings.py +54 -69
- pygpt_net/controller/presets/presets.py +292 -297
- pygpt_net/controller/theme/theme.py +72 -81
- pygpt_net/controller/ui/mode.py +2 -3
- pygpt_net/controller/ui/tabs.py +69 -90
- pygpt_net/controller/ui/ui.py +47 -56
- pygpt_net/controller/ui/vision.py +24 -23
- pygpt_net/core/render/web/body.py +183 -192
- pygpt_net/core/render/web/renderer.py +323 -370
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/ui/base/config_dialog.py +83 -101
- pygpt_net/ui/base/context_menu.py +48 -46
- pygpt_net/ui/layout/toolbox/presets.py +41 -41
- pygpt_net/ui/widget/calendar/select.py +86 -70
- pygpt_net/ui/widget/lists/attachment.py +86 -44
- pygpt_net/ui/widget/lists/base_list_combo.py +85 -33
- pygpt_net/ui/widget/lists/context.py +135 -188
- pygpt_net/ui/widget/lists/preset.py +59 -61
- {pygpt_net-2.6.2.dist-info → pygpt_net-2.6.3.dist-info}/METADATA +8 -3
- {pygpt_net-2.6.2.dist-info → pygpt_net-2.6.3.dist-info}/RECORD +35 -35
- {pygpt_net-2.6.2.dist-info → pygpt_net-2.6.3.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.2.dist-info → pygpt_net-2.6.3.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.2.dist-info → pygpt_net-2.6.3.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
pygpt_net/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@ __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.
|
|
16
|
+
__version__ = "2.6.3"
|
|
17
17
|
__build__ = "2025-08-15"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2025.08.15 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
@@ -32,29 +32,47 @@ class Note:
|
|
|
32
32
|
"""Setup calendar notes"""
|
|
33
33
|
self.counters_all = self.window.core.config.get("ctx.counters.all", True)
|
|
34
34
|
|
|
35
|
+
def _adjacent_months(self, year: int, month: int):
|
|
36
|
+
if month == 1:
|
|
37
|
+
py, pm = year - 1, 12
|
|
38
|
+
else:
|
|
39
|
+
py, pm = year, month - 1
|
|
40
|
+
if month == 12:
|
|
41
|
+
ny, nm = year + 1, 1
|
|
42
|
+
else:
|
|
43
|
+
ny, nm = year, month + 1
|
|
44
|
+
return (py, pm), (ny, nm)
|
|
45
|
+
|
|
35
46
|
def update(self):
|
|
36
47
|
"""Update on content change"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
ctrl_cal = self.window.controller.calendar
|
|
49
|
+
year = ctrl_cal.selected_year
|
|
50
|
+
month = ctrl_cal.selected_month
|
|
51
|
+
day = ctrl_cal.selected_day
|
|
40
52
|
|
|
41
53
|
if year is None or month is None or day is None:
|
|
42
54
|
return
|
|
43
55
|
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
ui_note = self.window.ui.calendar['note']
|
|
57
|
+
content = ui_note.toPlainText()
|
|
58
|
+
cal = self.window.core.calendar
|
|
59
|
+
note = cal.get_by_date(year, month, day)
|
|
46
60
|
|
|
47
|
-
|
|
61
|
+
changed = False
|
|
48
62
|
if note is None:
|
|
49
|
-
if content.strip()
|
|
63
|
+
if content.strip():
|
|
50
64
|
note = self.create(year, month, day)
|
|
51
65
|
note.content = content
|
|
52
|
-
|
|
66
|
+
cal.add(note)
|
|
67
|
+
changed = True
|
|
53
68
|
else:
|
|
54
|
-
note.content
|
|
55
|
-
|
|
69
|
+
if note.content != content:
|
|
70
|
+
note.content = content
|
|
71
|
+
cal.update(note)
|
|
72
|
+
changed = True
|
|
56
73
|
|
|
57
|
-
|
|
74
|
+
if changed:
|
|
75
|
+
self.refresh_num(year, month)
|
|
58
76
|
|
|
59
77
|
def update_content(
|
|
60
78
|
self,
|
|
@@ -69,13 +87,12 @@ class Note:
|
|
|
69
87
|
:param month: month
|
|
70
88
|
:param day: day
|
|
71
89
|
"""
|
|
90
|
+
ui_note = self.window.ui.calendar['note']
|
|
72
91
|
note = self.window.core.calendar.get_by_date(year, month, day)
|
|
73
|
-
if note is None
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
self.window.ui.calendar['note'].setPlainText(note.content)
|
|
78
|
-
self.window.ui.calendar['note'].on_update()
|
|
92
|
+
new_text = "" if note is None else note.content
|
|
93
|
+
if ui_note.toPlainText() != new_text:
|
|
94
|
+
ui_note.setPlainText(new_text)
|
|
95
|
+
ui_note.on_update()
|
|
79
96
|
|
|
80
97
|
def update_label(
|
|
81
98
|
self,
|
|
@@ -90,15 +107,13 @@ class Note:
|
|
|
90
107
|
:param month: month
|
|
91
108
|
:param day: day
|
|
92
109
|
"""
|
|
93
|
-
suffix =
|
|
94
|
-
self.window.ui.calendar['note.label'].setText(trans('calendar.note.label')
|
|
110
|
+
suffix = f"{year:04d}-{month:02d}-{day:02d}"
|
|
111
|
+
self.window.ui.calendar['note.label'].setText(f"{trans('calendar.note.label')} ({suffix})")
|
|
95
112
|
|
|
96
113
|
def update_current(self):
|
|
97
114
|
"""Update label to current selected date"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
day = self.window.ui.calendar['select'].currentDay
|
|
101
|
-
self.update_label(year, month, day)
|
|
115
|
+
select = self.window.ui.calendar['select']
|
|
116
|
+
self.update_label(select.currentYear, select.currentMonth, select.currentDay)
|
|
102
117
|
|
|
103
118
|
def update_status(
|
|
104
119
|
self,
|
|
@@ -115,16 +130,22 @@ class Note:
|
|
|
115
130
|
:param month: month
|
|
116
131
|
:param day: day
|
|
117
132
|
"""
|
|
118
|
-
|
|
133
|
+
cal = self.window.core.calendar
|
|
134
|
+
note = cal.get_by_date(year, month, day)
|
|
135
|
+
changed = False
|
|
119
136
|
if note is None:
|
|
120
137
|
note = self.create(year, month, day)
|
|
121
138
|
note.status = status
|
|
122
|
-
|
|
139
|
+
cal.add(note)
|
|
140
|
+
changed = True
|
|
123
141
|
else:
|
|
124
|
-
note.status
|
|
125
|
-
|
|
142
|
+
if note.status != status:
|
|
143
|
+
note.status = status
|
|
144
|
+
cal.update(note)
|
|
145
|
+
changed = True
|
|
126
146
|
|
|
127
|
-
|
|
147
|
+
if changed:
|
|
148
|
+
self.refresh_num(year, month)
|
|
128
149
|
|
|
129
150
|
def get_counts_around_month(
|
|
130
151
|
self,
|
|
@@ -138,27 +159,12 @@ class Note:
|
|
|
138
159
|
:param month: month
|
|
139
160
|
:return: combined counters
|
|
140
161
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
next_month_start = datetime.datetime(year, month + 1, 1)
|
|
148
|
-
|
|
149
|
-
current = self.get_ctx_counters(
|
|
150
|
-
year,
|
|
151
|
-
month,
|
|
152
|
-
)
|
|
153
|
-
last = self.get_ctx_counters(
|
|
154
|
-
last_month_start.year,
|
|
155
|
-
last_month_start.month,
|
|
156
|
-
)
|
|
157
|
-
next = self.get_ctx_counters(
|
|
158
|
-
next_month_start.year,
|
|
159
|
-
next_month_start.month,
|
|
160
|
-
)
|
|
161
|
-
return {**last, **current, **next} # combine counters
|
|
162
|
+
(ly, lm), (ny, nm) = self._adjacent_months(year, month)
|
|
163
|
+
result: Dict[str, int] = {}
|
|
164
|
+
result.update(self.get_ctx_counters(ly, lm))
|
|
165
|
+
result.update(self.get_ctx_counters(year, month))
|
|
166
|
+
result.update(self.get_ctx_counters(ny, nm))
|
|
167
|
+
return result
|
|
162
168
|
|
|
163
169
|
def get_labels_counts_around_month(
|
|
164
170
|
self,
|
|
@@ -172,27 +178,12 @@ class Note:
|
|
|
172
178
|
:param month: month
|
|
173
179
|
:return: combined counters
|
|
174
180
|
"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
next_month_start = datetime.datetime(year, month + 1, 1)
|
|
182
|
-
|
|
183
|
-
current = self.get_ctx_labels_counters(
|
|
184
|
-
year,
|
|
185
|
-
month,
|
|
186
|
-
)
|
|
187
|
-
last = self.get_ctx_labels_counters(
|
|
188
|
-
last_month_start.year,
|
|
189
|
-
last_month_start.month,
|
|
190
|
-
)
|
|
191
|
-
next = self.get_ctx_labels_counters(
|
|
192
|
-
next_month_start.year,
|
|
193
|
-
next_month_start.month,
|
|
194
|
-
)
|
|
195
|
-
return {**last, **current, **next} # combine counters
|
|
181
|
+
(ly, lm), (ny, nm) = self._adjacent_months(year, month)
|
|
182
|
+
result: Dict[str, Dict[int, int]] = {}
|
|
183
|
+
result.update(self.get_ctx_labels_counters(ly, lm))
|
|
184
|
+
result.update(self.get_ctx_labels_counters(year, month))
|
|
185
|
+
result.update(self.get_ctx_labels_counters(ny, nm))
|
|
186
|
+
return result
|
|
196
187
|
|
|
197
188
|
def get_ctx_counters(
|
|
198
189
|
self,
|
|
@@ -206,18 +197,17 @@ class Note:
|
|
|
206
197
|
:param month: month
|
|
207
198
|
:return: ctx counters
|
|
208
199
|
"""
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return self.window.core.ctx.provider.get_ctx_count_by_day(
|
|
200
|
+
ctx = self.window.core.ctx
|
|
201
|
+
if self.counters_all:
|
|
202
|
+
search_string = None
|
|
203
|
+
search_content = False
|
|
204
|
+
filters = None
|
|
205
|
+
else:
|
|
206
|
+
search_string = ctx.get_search_string()
|
|
207
|
+
search_content = ctx.is_search_content()
|
|
208
|
+
filters = ctx.get_parsed_filters()
|
|
209
|
+
|
|
210
|
+
return ctx.provider.get_ctx_count_by_day(
|
|
221
211
|
year=year,
|
|
222
212
|
month=month,
|
|
223
213
|
day=None,
|
|
@@ -238,18 +228,17 @@ class Note:
|
|
|
238
228
|
:param month: month
|
|
239
229
|
:return: ctx counters
|
|
240
230
|
"""
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return self.window.core.ctx.provider.get_ctx_labels_count_by_day(
|
|
231
|
+
ctx = self.window.core.ctx
|
|
232
|
+
if self.counters_all:
|
|
233
|
+
search_string = None
|
|
234
|
+
search_content = False
|
|
235
|
+
filters = None
|
|
236
|
+
else:
|
|
237
|
+
search_string = ctx.get_search_string()
|
|
238
|
+
search_content = ctx.is_search_content()
|
|
239
|
+
filters = ctx.get_parsed_filters()
|
|
240
|
+
|
|
241
|
+
return ctx.provider.get_ctx_labels_count_by_day(
|
|
253
242
|
year=year,
|
|
254
243
|
month=month,
|
|
255
244
|
day=None,
|
|
@@ -305,26 +294,13 @@ class Note:
|
|
|
305
294
|
:param month: month
|
|
306
295
|
:return: combined notes existence
|
|
307
296
|
"""
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
current = self.window.core.calendar.get_notes_existence_by_day(
|
|
316
|
-
year,
|
|
317
|
-
month,
|
|
318
|
-
)
|
|
319
|
-
last = self.window.core.calendar.get_notes_existence_by_day(
|
|
320
|
-
last_month_start.year,
|
|
321
|
-
last_month_start.month,
|
|
322
|
-
)
|
|
323
|
-
next = self.window.core.calendar.get_notes_existence_by_day(
|
|
324
|
-
next_month_start.year,
|
|
325
|
-
next_month_start.month,
|
|
326
|
-
)
|
|
327
|
-
return {**last, **current, **next} # combine notes existence
|
|
297
|
+
(ly, lm), (ny, nm) = self._adjacent_months(year, month)
|
|
298
|
+
cal = self.window.core.calendar
|
|
299
|
+
result: Dict[str, Dict[int, int]] = {}
|
|
300
|
+
result.update(cal.get_notes_existence_by_day(ly, lm))
|
|
301
|
+
result.update(cal.get_notes_existence_by_day(year, month))
|
|
302
|
+
result.update(cal.get_notes_existence_by_day(ny, nm))
|
|
303
|
+
return result
|
|
328
304
|
|
|
329
305
|
def refresh_num(self, year: int, month: int):
|
|
330
306
|
"""
|
|
@@ -342,6 +318,8 @@ class Note:
|
|
|
342
318
|
|
|
343
319
|
:param state: state
|
|
344
320
|
"""
|
|
321
|
+
if self.counters_all == state:
|
|
322
|
+
return
|
|
345
323
|
self.counters_all = state
|
|
346
324
|
self.window.core.config.set("ctx.counters.all", state)
|
|
347
325
|
self.window.core.config.save()
|
|
@@ -355,17 +333,14 @@ class Note:
|
|
|
355
333
|
"""
|
|
356
334
|
dt = "" # TODO: add to config append date/time
|
|
357
335
|
# dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ":\n--------------------------\n"
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
prev_text += "\n\n"
|
|
361
|
-
new_text = prev_text + dt + text.strip()
|
|
362
|
-
self.window.ui.calendar['note'].setText(new_text)
|
|
363
|
-
self.update()
|
|
364
|
-
|
|
365
|
-
# move cursor to end
|
|
366
|
-
cursor = self.window.ui.calendar['note'].textCursor()
|
|
336
|
+
editor = self.window.ui.calendar['note']
|
|
337
|
+
cursor = editor.textCursor()
|
|
367
338
|
cursor.movePosition(QTextCursor.End)
|
|
368
|
-
|
|
339
|
+
if not editor.document().isEmpty():
|
|
340
|
+
cursor.insertText("\n\n")
|
|
341
|
+
cursor.insertText(dt + text.strip())
|
|
342
|
+
editor.setTextCursor(cursor)
|
|
343
|
+
self.update()
|
|
369
344
|
|
|
370
345
|
def clear_note(self):
|
|
371
346
|
"""Clear note"""
|
|
@@ -379,4 +354,4 @@ class Note:
|
|
|
379
354
|
|
|
380
355
|
:return: notepad text
|
|
381
356
|
"""
|
|
382
|
-
return self.window.ui.calendar['note'].toPlainText()
|
|
357
|
+
return self.window.ui.calendar['note'].toPlainText()
|
|
@@ -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.08.
|
|
9
|
+
# Updated Date: 2025.08.15 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional, List
|
|
@@ -36,6 +36,7 @@ class Render:
|
|
|
36
36
|
self.web_renderer = WebRenderer(window)
|
|
37
37
|
self.engine = None
|
|
38
38
|
self.scroll = 0
|
|
39
|
+
self.renderer = None
|
|
39
40
|
|
|
40
41
|
def setup(self):
|
|
41
42
|
"""Setup render"""
|
|
@@ -86,7 +87,7 @@ class Render:
|
|
|
86
87
|
elif name == RenderEvent.STREAM_BEGIN:
|
|
87
88
|
self.stream_begin(meta, ctx)
|
|
88
89
|
elif name == RenderEvent.STREAM_APPEND:
|
|
89
|
-
self.append_chunk(meta, ctx, chunk, begin)
|
|
90
|
+
self.instance().append_chunk(meta, ctx, chunk, begin)
|
|
90
91
|
elif name == RenderEvent.STREAM_NEXT:
|
|
91
92
|
self.next_chunk(meta, ctx)
|
|
92
93
|
elif name == RenderEvent.STREAM_END:
|
|
@@ -179,7 +180,6 @@ class Render:
|
|
|
179
180
|
:param begin: if it is the beginning of the stream
|
|
180
181
|
"""
|
|
181
182
|
self.instance().append_live(meta, ctx, text_chunk, begin)
|
|
182
|
-
self.update()
|
|
183
183
|
|
|
184
184
|
def clear_live(self, meta: CtxMeta, ctx: CtxItem):
|
|
185
185
|
"""
|
|
@@ -413,7 +413,6 @@ class Render:
|
|
|
413
413
|
:param begin: if it is the beginning of the stream
|
|
414
414
|
"""
|
|
415
415
|
self.instance().append_chunk(meta, ctx, text_chunk, begin)
|
|
416
|
-
self.update()
|
|
417
416
|
|
|
418
417
|
def next_chunk(
|
|
419
418
|
self,
|
|
@@ -551,8 +550,8 @@ class Render:
|
|
|
551
550
|
|
|
552
551
|
def update(self):
|
|
553
552
|
"""On update - active"""
|
|
554
|
-
for
|
|
555
|
-
self.window.ui.nodes['output'][
|
|
553
|
+
for pid in self.window.ui.nodes['output']:
|
|
554
|
+
self.window.ui.nodes['output'][pid].on_update()
|
|
556
555
|
|
|
557
556
|
def clear(self, meta: CtxMeta):
|
|
558
557
|
"""
|
|
@@ -658,7 +657,7 @@ class Render:
|
|
|
658
657
|
pass
|
|
659
658
|
else:
|
|
660
659
|
self.window.ui.nodes['output.timestamp'].setVisible(False)
|
|
661
|
-
|
|
660
|
+
|
|
662
661
|
self.window.controller.theme.markdown.update(force=True)
|
|
663
662
|
for pid in self.window.ui.nodes['output']:
|
|
664
663
|
try:
|
|
@@ -668,12 +667,26 @@ class Render:
|
|
|
668
667
|
except Exception as e:
|
|
669
668
|
pass
|
|
670
669
|
|
|
670
|
+
# cache renderer instance
|
|
671
|
+
if self.window.core.config.get('render.plain'):
|
|
672
|
+
self.renderer = self.plaintext_renderer
|
|
673
|
+
else:
|
|
674
|
+
if self.engine == "web":
|
|
675
|
+
self.renderer = self.web_renderer
|
|
676
|
+
else:
|
|
677
|
+
self.renderer = self.markdown_renderer
|
|
678
|
+
|
|
679
|
+
self.window.controller.ctx.refresh()
|
|
680
|
+
|
|
671
681
|
def instance(self) -> BaseRenderer:
|
|
672
682
|
"""
|
|
673
683
|
Get instance of current renderer
|
|
674
684
|
|
|
675
685
|
:return: Renderer instance
|
|
676
686
|
"""
|
|
687
|
+
if self.renderer:
|
|
688
|
+
return self.renderer # return cached renderer instance
|
|
689
|
+
|
|
677
690
|
# get selected renderer
|
|
678
691
|
if self.window.core.config.get('render.plain'):
|
|
679
692
|
return self.plaintext_renderer
|
|
@@ -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.08.15 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional
|
|
13
13
|
|
|
14
|
+
from PySide6.QtCore import QTimer
|
|
14
15
|
from PySide6.QtWidgets import QApplication
|
|
15
16
|
|
|
16
17
|
from pygpt_net.core.tabs.tab import Tab
|
|
@@ -90,7 +91,7 @@ class Common:
|
|
|
90
91
|
self.window.update_status(
|
|
91
92
|
"Context duplicated, new ctx id: {}".format(new_id)
|
|
92
93
|
)
|
|
93
|
-
self.window.controller.ctx.update(no_scroll=True)
|
|
94
|
+
QTimer.singleShot(100, lambda: self.window.controller.ctx.update(no_scroll=True))
|
|
94
95
|
|
|
95
96
|
def dismiss_rename(self):
|
|
96
97
|
"""Dismiss rename dialog"""
|