pygpt-net 2.6.47__py3-none-any.whl → 2.6.48__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 +4 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/app_core.py +39 -39
- pygpt_net/controller/__init__.py +72 -62
- pygpt_net/controller/ctx/common.py +0 -7
- pygpt_net/controller/ctx/ctx.py +172 -6
- pygpt_net/controller/ctx/extra.py +3 -3
- pygpt_net/controller/settings/editor.py +3 -1
- pygpt_net/controller/theme/common.py +8 -2
- pygpt_net/controller/ui/tabs.py +6 -37
- pygpt_net/core/ctx/ctx.py +79 -26
- pygpt_net/core/tabs/tabs.py +57 -10
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/data/css/web-blocks.css +256 -270
- pygpt_net/data/css/web-chatgpt.css +276 -301
- pygpt_net/data/css/web-chatgpt_wide.css +286 -294
- pygpt_net/provider/core/config/patch.py +9 -0
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +19 -5
- pygpt_net/ui/__init__.py +9 -14
- pygpt_net/ui/layout/chat/chat.py +2 -2
- pygpt_net/ui/layout/ctx/ctx_list.py +71 -1
- pygpt_net/ui/widget/lists/base.py +32 -1
- pygpt_net/ui/widget/lists/context.py +45 -2
- {pygpt_net-2.6.47.dist-info → pygpt_net-2.6.48.dist-info}/METADATA +6 -2
- {pygpt_net-2.6.47.dist-info → pygpt_net-2.6.48.dist-info}/RECORD +29 -29
- {pygpt_net-2.6.47.dist-info → pygpt_net-2.6.48.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.47.dist-info → pygpt_net-2.6.48.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.47.dist-info → pygpt_net-2.6.48.dist-info}/entry_points.txt +0 -0
pygpt_net/core/ctx/ctx.py
CHANGED
|
@@ -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.15 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -1003,7 +1003,7 @@ class Ctx:
|
|
|
1003
1003
|
for item in reversed(history_items):
|
|
1004
1004
|
num = from_ctx(item, mode, model)
|
|
1005
1005
|
new_total = tokens + num
|
|
1006
|
-
if
|
|
1006
|
+
if 0 < max_tokens < new_total:
|
|
1007
1007
|
break
|
|
1008
1008
|
tokens = new_total
|
|
1009
1009
|
context_tokens += num
|
|
@@ -1240,49 +1240,102 @@ class Ctx:
|
|
|
1240
1240
|
return len(self.filters_labels) < num_all
|
|
1241
1241
|
|
|
1242
1242
|
def load_meta(self):
|
|
1243
|
-
"""Load ctx list
|
|
1244
|
-
|
|
1243
|
+
"""Load ctx list: pinned and grouped unlimited; ungrouped not pinned paginated directly in SQL."""
|
|
1244
|
+
# base package size (per page)
|
|
1245
|
+
base_limit = 0
|
|
1245
1246
|
if self.window.core.config.has('ctx.records.limit'):
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1247
|
+
try:
|
|
1248
|
+
base_limit = int(self.window.core.config.get('ctx.records.limit') or 0)
|
|
1249
|
+
except Exception:
|
|
1250
|
+
base_limit = 0
|
|
1251
|
+
|
|
1252
|
+
# total loaded (persisted); fallback to base when missing
|
|
1253
|
+
try:
|
|
1254
|
+
loaded_total = int(self.window.core.config.get('ctx.records.limit.total') or 0)
|
|
1255
|
+
except Exception:
|
|
1256
|
+
loaded_total = 0
|
|
1257
|
+
if loaded_total <= 0:
|
|
1258
|
+
loaded_total = base_limit
|
|
1259
|
+
|
|
1260
|
+
# Common filters (labels etc.)
|
|
1261
|
+
common_filters = self.get_parsed_filters()
|
|
1262
|
+
|
|
1263
|
+
# If explicit filters target a narrow subset (legacy path), keep old behavior
|
|
1264
|
+
if "is_important" in self.filters or "indexed_ts" in self.filters:
|
|
1265
|
+
limit = 0 if base_limit == 0 else loaded_total
|
|
1266
|
+
self.meta = self.provider.get_meta(
|
|
1255
1267
|
search_string=self.search_string,
|
|
1256
1268
|
order_by='updated_ts',
|
|
1257
1269
|
order_direction='DESC',
|
|
1258
|
-
limit=
|
|
1259
|
-
|
|
1270
|
+
limit=limit,
|
|
1271
|
+
offset=0,
|
|
1272
|
+
filters=common_filters,
|
|
1260
1273
|
search_content=self.is_search_content(),
|
|
1261
1274
|
)
|
|
1275
|
+
return
|
|
1262
1276
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1277
|
+
# 1) Pinned (important) – unlimited
|
|
1278
|
+
filters_pinned = self.get_parsed_filters()
|
|
1279
|
+
filters_pinned['is_important'] = {"mode": "=", "value": 1}
|
|
1280
|
+
meta_pinned = self.provider.get_meta(
|
|
1281
|
+
search_string=self.search_string,
|
|
1282
|
+
order_by='updated_ts',
|
|
1283
|
+
order_direction='DESC',
|
|
1284
|
+
limit=0,
|
|
1285
|
+
offset=0,
|
|
1286
|
+
filters=filters_pinned,
|
|
1287
|
+
search_content=self.is_search_content(),
|
|
1288
|
+
)
|
|
1289
|
+
|
|
1290
|
+
# 2) Grouped – unlimited
|
|
1291
|
+
filters_grouped = self.get_parsed_filters()
|
|
1292
|
+
filters_grouped['group_id'] = {"mode": ">", "value": 0}
|
|
1293
|
+
meta_grouped = self.provider.get_meta(
|
|
1294
|
+
search_string=self.search_string,
|
|
1295
|
+
order_by='updated_ts',
|
|
1296
|
+
order_direction='DESC',
|
|
1297
|
+
limit=0,
|
|
1298
|
+
offset=0,
|
|
1299
|
+
filters=filters_grouped,
|
|
1300
|
+
search_content=self.is_search_content(),
|
|
1301
|
+
)
|
|
1302
|
+
|
|
1303
|
+
# 3) Ungrouped & not pinned – paginate directly in SQL
|
|
1304
|
+
# If base_limit == 0 -> unlimited (no paging)
|
|
1305
|
+
filters_ungrp = self.get_parsed_filters()
|
|
1306
|
+
filters_ungrp['is_important'] = {"mode": "=", "value": 0}
|
|
1307
|
+
filters_ungrp['group_id'] = {"mode": "NULL_OR_ZERO", "value": 0} # special mode handled in Storage
|
|
1308
|
+
|
|
1309
|
+
if base_limit <= 0:
|
|
1310
|
+
meta_ungrouped = self.provider.get_meta(
|
|
1265
1311
|
search_string=self.search_string,
|
|
1266
1312
|
order_by='updated_ts',
|
|
1267
1313
|
order_direction='DESC',
|
|
1268
|
-
limit=
|
|
1269
|
-
|
|
1314
|
+
limit=0, # unlimited
|
|
1315
|
+
offset=0,
|
|
1316
|
+
filters=filters_ungrp,
|
|
1270
1317
|
search_content=self.is_search_content(),
|
|
1271
1318
|
)
|
|
1272
|
-
|
|
1273
|
-
self.meta = {**meta_pinned, **meta_unpinned}
|
|
1274
|
-
|
|
1275
1319
|
else:
|
|
1276
|
-
|
|
1277
|
-
|
|
1320
|
+
# Always take the top-N ungrouped newest items directly from DB
|
|
1321
|
+
take = max(0, int(loaded_total or 0))
|
|
1322
|
+
meta_ungrouped = self.provider.get_meta(
|
|
1278
1323
|
search_string=self.search_string,
|
|
1279
1324
|
order_by='updated_ts',
|
|
1280
1325
|
order_direction='DESC',
|
|
1281
|
-
limit=
|
|
1282
|
-
|
|
1326
|
+
limit=take,
|
|
1327
|
+
offset=0,
|
|
1328
|
+
filters=filters_ungrp,
|
|
1283
1329
|
search_content=self.is_search_content(),
|
|
1284
1330
|
)
|
|
1285
1331
|
|
|
1332
|
+
# Compose final dict with deterministic order: pinned -> grouped -> ungrouped
|
|
1333
|
+
combined = {}
|
|
1334
|
+
combined.update(meta_pinned)
|
|
1335
|
+
combined.update(meta_grouped)
|
|
1336
|
+
combined.update(meta_ungrouped)
|
|
1337
|
+
self.meta = combined
|
|
1338
|
+
|
|
1286
1339
|
def load_tmp_meta(self, meta_id: int):
|
|
1287
1340
|
"""
|
|
1288
1341
|
Load tmp meta
|
pygpt_net/core/tabs/tabs.py
CHANGED
|
@@ -13,7 +13,9 @@ import uuid
|
|
|
13
13
|
from datetime import datetime
|
|
14
14
|
from typing import Optional, Any, Dict, Tuple, Union
|
|
15
15
|
|
|
16
|
+
from PySide6.QtCore import QUrl
|
|
16
17
|
from PySide6.QtGui import QIcon
|
|
18
|
+
from PySide6.QtWebEngineCore import QWebEnginePage
|
|
17
19
|
from PySide6.QtWidgets import QVBoxLayout, QWidget, QLayout
|
|
18
20
|
|
|
19
21
|
from pygpt_net.ui.widget.tabs.body import TabBody
|
|
@@ -234,20 +236,38 @@ class Tabs:
|
|
|
234
236
|
tab.icon = self.icons[tab.type]
|
|
235
237
|
|
|
236
238
|
if tab.type == Tab.TAB_CHAT: # chat
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
try:
|
|
240
|
+
self.add_chat(tab)
|
|
241
|
+
self.window.core.ctx.output.mapping[tab.pid] = tab.data_id # restore pid => meta.id mapping
|
|
242
|
+
self.window.core.ctx.output.last_pids[tab.data_id] = tab.pid
|
|
243
|
+
self.window.core.ctx.output.last_pid = tab.pid
|
|
244
|
+
except Exception as e:
|
|
245
|
+
print("Error restoring chat tab:", e)
|
|
241
246
|
elif tab.type == Tab.TAB_NOTEPAD: # notepad
|
|
242
|
-
|
|
247
|
+
try:
|
|
248
|
+
self.add_notepad(tab)
|
|
249
|
+
except Exception as e:
|
|
250
|
+
print("Error restoring notepad tab:", e)
|
|
243
251
|
elif tab.type == Tab.TAB_FILES: # files
|
|
244
|
-
|
|
252
|
+
try:
|
|
253
|
+
self.add_tool_explorer(tab)
|
|
254
|
+
except Exception as e:
|
|
255
|
+
print("Error restoring explorer tab:", e)
|
|
245
256
|
elif tab.type == Tab.TAB_TOOL_PAINTER: # painter
|
|
246
|
-
|
|
257
|
+
try:
|
|
258
|
+
self.add_tool_painter(tab)
|
|
259
|
+
except Exception as e:
|
|
260
|
+
print("Error restoring painter tab:", e)
|
|
247
261
|
elif tab.type == Tab.TAB_TOOL_CALENDAR: # calendar
|
|
248
|
-
|
|
262
|
+
try:
|
|
263
|
+
self.add_tool_calendar(tab)
|
|
264
|
+
except Exception as e:
|
|
265
|
+
print("Error restoring calendar tab:", e)
|
|
249
266
|
elif tab.type == Tab.TAB_TOOL: # custom tools, id 100+
|
|
250
|
-
|
|
267
|
+
try:
|
|
268
|
+
self.add_tool(tab)
|
|
269
|
+
except Exception as e:
|
|
270
|
+
print("Error restoring tool tab:", e)
|
|
251
271
|
|
|
252
272
|
self.pids[tab.pid] = tab
|
|
253
273
|
self.last_pid = self.get_max_pid()
|
|
@@ -277,8 +297,35 @@ class Tabs:
|
|
|
277
297
|
tab = self.get_tab_by_pid(pid)
|
|
278
298
|
if tab is None:
|
|
279
299
|
return
|
|
300
|
+
try:
|
|
301
|
+
if tab.type == Tab.TAB_CHAT:
|
|
302
|
+
node = self.window.ui.nodes['output'].get(tab.pid)
|
|
303
|
+
if node:
|
|
304
|
+
node.hide()
|
|
305
|
+
p = node.page()
|
|
306
|
+
p.triggerAction(QWebEnginePage.Stop)
|
|
307
|
+
p.setUrl(QUrl("about:blank"))
|
|
308
|
+
p.history().clear()
|
|
309
|
+
p.setLifecycleState(QWebEnginePage.LifecycleState.Discarded)
|
|
310
|
+
tab.delete_ref(node)
|
|
311
|
+
layout = tab.child.layout()
|
|
312
|
+
layout.removeWidget(node)
|
|
313
|
+
self.window.ui.nodes['output'].pop(pid, None)
|
|
314
|
+
node.on_delete()
|
|
315
|
+
node_plain = self.window.ui.nodes['output_plain'].get(tab.pid)
|
|
316
|
+
if node_plain:
|
|
317
|
+
tab.delete_ref(node_plain)
|
|
318
|
+
layout = tab.child.layout()
|
|
319
|
+
layout.removeWidget(node_plain)
|
|
320
|
+
self.window.ui.nodes['output_plain'].pop(pid, None)
|
|
321
|
+
node_plain.on_delete()
|
|
322
|
+
|
|
323
|
+
if tab.type in (Tab.TAB_CHAT, Tab.TAB_NOTEPAD, Tab.TAB_TOOL):
|
|
324
|
+
tab.cleanup() # unload assigned data from memory
|
|
325
|
+
|
|
326
|
+
except Exception as e:
|
|
327
|
+
print(f"Error unloading tab {pid}: {e}")
|
|
280
328
|
|
|
281
|
-
tab.cleanup() # unload assigned data from memory
|
|
282
329
|
column_idx = tab.column_idx
|
|
283
330
|
self.window.ui.layout.get_tabs_by_idx(column_idx).removeTab(tab.idx)
|
|
284
331
|
del self.pids[pid]
|