pygpt-net 2.6.37__py3-none-any.whl → 2.6.38__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 +7 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/controller/chat/handler/anthropic_stream.py +0 -2
- pygpt_net/controller/chat/handler/worker.py +6 -2
- pygpt_net/controller/debug/debug.py +6 -6
- pygpt_net/controller/model/importer.py +9 -2
- pygpt_net/controller/plugins/plugins.py +11 -3
- pygpt_net/controller/presets/presets.py +2 -2
- pygpt_net/core/ctx/bag.py +7 -2
- pygpt_net/core/ctx/reply.py +17 -2
- pygpt_net/core/db/viewer.py +19 -34
- pygpt_net/core/render/plain/pid.py +12 -1
- pygpt_net/core/render/web/body.py +1 -5
- pygpt_net/core/tabs/tab.py +24 -1
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/item/assistant.py +51 -2
- pygpt_net/item/attachment.py +21 -20
- pygpt_net/item/calendar_note.py +19 -2
- pygpt_net/item/ctx.py +115 -2
- pygpt_net/item/index.py +9 -2
- pygpt_net/item/mode.py +9 -6
- pygpt_net/item/model.py +20 -3
- pygpt_net/item/notepad.py +14 -2
- pygpt_net/item/preset.py +42 -2
- pygpt_net/item/prompt.py +8 -2
- pygpt_net/plugin/cmd_files/plugin.py +2 -2
- pygpt_net/provider/api/anthropic/tools.py +1 -1
- pygpt_net/provider/api/google/realtime/client.py +2 -2
- pygpt_net/provider/core/attachment/json_file.py +2 -2
- pygpt_net/tools/text_editor/tool.py +4 -1
- pygpt_net/tools/text_editor/ui/dialogs.py +1 -1
- pygpt_net/ui/dialog/db.py +177 -59
- pygpt_net/ui/dialog/dictionary.py +57 -59
- pygpt_net/ui/dialog/editor.py +3 -2
- pygpt_net/ui/dialog/image.py +1 -1
- pygpt_net/ui/dialog/logger.py +3 -2
- pygpt_net/ui/dialog/models.py +14 -12
- pygpt_net/ui/dialog/plugins.py +26 -20
- pygpt_net/ui/layout/ctx/ctx_list.py +3 -4
- pygpt_net/ui/layout/toolbox/__init__.py +2 -2
- pygpt_net/ui/layout/toolbox/assistants.py +8 -9
- pygpt_net/ui/layout/toolbox/presets.py +2 -2
- pygpt_net/ui/main.py +9 -4
- pygpt_net/ui/widget/element/labels.py +2 -2
- pygpt_net/ui/widget/textarea/editor.py +0 -4
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/METADATA +9 -2
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/RECORD +51 -51
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
2.6.38 (2025-09-05)
|
|
2
|
+
|
|
3
|
+
- Fixed: Detection of chunk type in Ollama.
|
|
4
|
+
- Fixed: Import of models with existing IDs.
|
|
5
|
+
- Fixed: Updating Assistants UI list after create new Assistant.
|
|
6
|
+
- Refactor and optimization.
|
|
7
|
+
|
|
1
8
|
2.6.37 (2025-09-05)
|
|
2
9
|
|
|
3
10
|
- Fixed: Function parameters sanitization in the Google Gen AI SDK.
|
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.38"
|
|
17
17
|
__build__ = "2025-09-05"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
|
@@ -154,8 +154,6 @@ def process_anthropic_chunk(ctx, core, state, chunk) -> Optional[str]:
|
|
|
154
154
|
state.usage_payload["out"] = out_tok
|
|
155
155
|
delta = getattr(chunk, "delta", None)
|
|
156
156
|
stop_reason = getattr(delta, "stop_reason", None) if delta else None
|
|
157
|
-
if stop_reason == "tool_use":
|
|
158
|
-
state.force_func_call = True
|
|
159
157
|
except Exception:
|
|
160
158
|
pass
|
|
161
159
|
return None
|
|
@@ -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.09.
|
|
9
|
+
# Updated Date: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import io
|
|
@@ -16,6 +16,7 @@ from typing import Optional, Literal, Any
|
|
|
16
16
|
from enum import Enum
|
|
17
17
|
|
|
18
18
|
from PySide6.QtCore import QObject, Signal, Slot, QRunnable
|
|
19
|
+
from openai.types.chat import ChatCompletionChunk
|
|
19
20
|
|
|
20
21
|
from pygpt_net.core.events import RenderEvent
|
|
21
22
|
from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
@@ -262,6 +263,10 @@ class StreamWorker(QRunnable):
|
|
|
262
263
|
if not hasattr(chunk, "type") and not hasattr(chunk, "candidates"):
|
|
263
264
|
return ChunkType.LLAMA_CHAT
|
|
264
265
|
|
|
266
|
+
# fallback: OpenAI ChatCompletionChunk not caught above
|
|
267
|
+
if isinstance(chunk, ChatCompletionChunk):
|
|
268
|
+
return ChunkType.API_CHAT
|
|
269
|
+
|
|
265
270
|
return ChunkType.RAW
|
|
266
271
|
|
|
267
272
|
def _append_response(
|
|
@@ -344,7 +349,6 @@ class StreamWorker(QRunnable):
|
|
|
344
349
|
calls = xai_stream.xai_extract_tool_calls(state.xai_last_response)
|
|
345
350
|
if calls:
|
|
346
351
|
state.tool_calls = calls
|
|
347
|
-
state.force_func_call = True
|
|
348
352
|
except Exception:
|
|
349
353
|
pass
|
|
350
354
|
|
|
@@ -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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from datetime import datetime
|
|
@@ -31,6 +31,7 @@ class Debug(QObject):
|
|
|
31
31
|
self.is_logger = False # logger window opened
|
|
32
32
|
self.is_app_log = False # app log window opened
|
|
33
33
|
self.allow_level_change = False # allow changing log level
|
|
34
|
+
self._ids = None
|
|
34
35
|
|
|
35
36
|
def update(self):
|
|
36
37
|
"""Update debug"""
|
|
@@ -100,12 +101,11 @@ class Debug(QObject):
|
|
|
100
101
|
|
|
101
102
|
:param all: update all debug windows
|
|
102
103
|
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
for id in self.
|
|
104
|
+
if self._ids is None:
|
|
105
|
+
self._ids = self.window.controller.dialogs.debug.get_ids()
|
|
106
|
+
for id in self._ids:
|
|
106
107
|
if self.window.controller.dialogs.debug.is_active(id):
|
|
107
|
-
|
|
108
|
-
self.window.controller.dialogs.debug.update_worker(id)
|
|
108
|
+
self.window.controller.dialogs.debug.update_worker(id)
|
|
109
109
|
|
|
110
110
|
def post_setup(self):
|
|
111
111
|
"""Post setup debug"""
|
|
@@ -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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -503,7 +503,7 @@ class Importer:
|
|
|
503
503
|
return models
|
|
504
504
|
else:
|
|
505
505
|
for model in ollama_models:
|
|
506
|
-
name = model.get('name')
|
|
506
|
+
name = model.get('name')
|
|
507
507
|
m = self.window.core.models.create_empty(append=False)
|
|
508
508
|
m.id = name
|
|
509
509
|
m.name = name
|
|
@@ -541,6 +541,13 @@ class Importer:
|
|
|
541
541
|
base_models[key] = copy.deepcopy(self.pending[key])
|
|
542
542
|
base_models[key].imported = True
|
|
543
543
|
added = True
|
|
544
|
+
else:
|
|
545
|
+
# add provider suffix - to key
|
|
546
|
+
new_key = f"{key}-{self.provider}"
|
|
547
|
+
if new_key not in base_models:
|
|
548
|
+
base_models[new_key] = copy.deepcopy(self.pending[key])
|
|
549
|
+
base_models[new_key].imported = True
|
|
550
|
+
added = True
|
|
544
551
|
for key in list(self.removed.keys()):
|
|
545
552
|
if key in base_models:
|
|
546
553
|
del base_models[key]
|
|
@@ -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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import List, Dict, Any, Optional
|
|
@@ -34,6 +34,8 @@ class Plugins:
|
|
|
34
34
|
self.settings = Settings(window)
|
|
35
35
|
self.presets = Presets(window)
|
|
36
36
|
self.enabled = {}
|
|
37
|
+
self._ids = None
|
|
38
|
+
self._ids_with_update = None
|
|
37
39
|
self._suspend_updates = 0
|
|
38
40
|
|
|
39
41
|
def _begin_batch(self):
|
|
@@ -316,9 +318,15 @@ class Plugins:
|
|
|
316
318
|
def on_post_update(self):
|
|
317
319
|
"""Called on post update"""
|
|
318
320
|
pm = self.window.core.plugins
|
|
319
|
-
|
|
321
|
+
if self._ids is None:
|
|
322
|
+
self._ids = pm.get_ids()
|
|
323
|
+
if self._ids_with_update is None:
|
|
324
|
+
self._ids_with_update = [pid for pid in self._ids if hasattr(self.window.core.plugins.get(pid), "on_post_update")]
|
|
325
|
+
if len(self._ids_with_update) == 0:
|
|
326
|
+
return
|
|
327
|
+
for pid in self._ids_with_update:
|
|
320
328
|
if self.is_enabled(pid):
|
|
321
|
-
fn =
|
|
329
|
+
fn = pm.get(pid).on_post_update
|
|
322
330
|
if callable(fn):
|
|
323
331
|
fn()
|
|
324
332
|
|
|
@@ -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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import re
|
|
@@ -440,7 +440,7 @@ class Presets:
|
|
|
440
440
|
if preset_id and preset_id in w.core.presets.items:
|
|
441
441
|
preset = w.core.presets.items[preset_id]
|
|
442
442
|
preset.prompt = w.core.config.get('prompt')
|
|
443
|
-
w.core.presets.save(
|
|
443
|
+
w.core.presets.save(preset_id)
|
|
444
444
|
|
|
445
445
|
def select_model(self):
|
|
446
446
|
"""Select model by current preset"""
|
pygpt_net/core/ctx/bag.py
CHANGED
|
@@ -6,16 +6,21 @@
|
|
|
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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import List
|
|
13
|
+
from dataclasses import dataclass, field
|
|
13
14
|
|
|
14
15
|
from pygpt_net.item.ctx import CtxItem
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
@dataclass(slots=True)
|
|
17
19
|
class Bag:
|
|
18
|
-
|
|
20
|
+
window: object = None
|
|
21
|
+
meta: object = None
|
|
22
|
+
tab_id: int = 0
|
|
23
|
+
items: List[CtxItem] = field(default_factory=list)
|
|
19
24
|
|
|
20
25
|
def __init__(self, window=None):
|
|
21
26
|
"""
|
pygpt_net/core/ctx/reply.py
CHANGED
|
@@ -6,12 +6,14 @@
|
|
|
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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from typing import Dict, Any
|
|
12
|
+
from typing import Dict, Any, Optional
|
|
13
|
+
from dataclasses import dataclass, field
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
@dataclass(slots=True)
|
|
15
17
|
class ReplyContext:
|
|
16
18
|
|
|
17
19
|
AGENT_CONTINUE = "agent.continue"
|
|
@@ -21,6 +23,15 @@ class ReplyContext:
|
|
|
21
23
|
EXPERT_CALL = "expert.call"
|
|
22
24
|
EXPERT_RESPONSE = "expert.response"
|
|
23
25
|
|
|
26
|
+
type: Optional[object] = None
|
|
27
|
+
bridge_context: Optional[object] = None
|
|
28
|
+
ctx: Optional[object] = None
|
|
29
|
+
prev_ctx: Optional[object] = None
|
|
30
|
+
parent_id: Optional[object] = None
|
|
31
|
+
input: str = ""
|
|
32
|
+
internal: bool = False
|
|
33
|
+
cmds: list = field(default_factory=list)
|
|
34
|
+
|
|
24
35
|
def __init__(self):
|
|
25
36
|
"""Reply context"""
|
|
26
37
|
self.type = None
|
|
@@ -55,7 +66,11 @@ class ReplyContext:
|
|
|
55
66
|
data["prev_ctx"] = self.prev_ctx.to_dict()
|
|
56
67
|
return data
|
|
57
68
|
|
|
69
|
+
|
|
70
|
+
@dataclass(slots=True)
|
|
58
71
|
class Reply:
|
|
72
|
+
window: Optional[object] = None
|
|
73
|
+
|
|
59
74
|
def __init__(self, window=None):
|
|
60
75
|
"""
|
|
61
76
|
Reply core
|
pygpt_net/core/db/viewer.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:
|
|
9
|
+
# Updated Date: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -65,16 +65,13 @@ class Viewer:
|
|
|
65
65
|
limit_clause = f" LIMIT {limit} OFFSET {offset}"
|
|
66
66
|
|
|
67
67
|
params = {}
|
|
68
|
-
if search_query:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
# "column1": "value1",
|
|
76
|
-
# "column2": "value2" # AND condition
|
|
77
|
-
# }
|
|
68
|
+
if search_query is not None:
|
|
69
|
+
sq = search_query.strip()
|
|
70
|
+
if sq:
|
|
71
|
+
search_clauses = [f"{column} LIKE :search_query" for column in search_fields]
|
|
72
|
+
where_clause = f" WHERE ({' OR '.join(search_clauses)})"
|
|
73
|
+
params['search_query'] = f"%{sq}%"
|
|
74
|
+
|
|
78
75
|
if filters:
|
|
79
76
|
filter_clauses = [f"{column} = :filter_{column}" for column in filters.keys()]
|
|
80
77
|
if where_clause == "":
|
|
@@ -82,13 +79,13 @@ class Viewer:
|
|
|
82
79
|
else:
|
|
83
80
|
where_clause += f" AND ({' AND '.join(filter_clauses)})"
|
|
84
81
|
for column, value in filters.items():
|
|
85
|
-
params[f"filter_{column}"] = value
|
|
82
|
+
params[f"filter_{column}"] = value
|
|
86
83
|
|
|
87
84
|
query = f"{base_query}{where_clause}{order_clause}{limit_clause}"
|
|
88
85
|
stmt = text(query).bindparams(**params)
|
|
89
86
|
with self.database.get_db().connect() as conn:
|
|
90
87
|
result = conn.execute(stmt).fetchall()
|
|
91
|
-
return result
|
|
88
|
+
return [tuple(r) for r in result]
|
|
92
89
|
|
|
93
90
|
def count_rows(
|
|
94
91
|
self,
|
|
@@ -116,15 +113,12 @@ class Viewer:
|
|
|
116
113
|
else:
|
|
117
114
|
search_fields = tables[table]['search_fields']
|
|
118
115
|
|
|
119
|
-
if search_query:
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
if search_query is not None:
|
|
117
|
+
sq = search_query.strip()
|
|
118
|
+
if sq:
|
|
119
|
+
where_clause = f" WHERE {' OR '.join([f'{column} LIKE :search_query' for column in search_fields])}"
|
|
120
|
+
params['search_query'] = f"%{sq}%"
|
|
122
121
|
|
|
123
|
-
# apply filters
|
|
124
|
-
# filters = {
|
|
125
|
-
# "column1": "value1",
|
|
126
|
-
# "column2": "value2" # AND condition
|
|
127
|
-
# }
|
|
128
122
|
if filters:
|
|
129
123
|
filter_clauses = [f"{column} = :filter_{column}" for column in filters.keys()]
|
|
130
124
|
if where_clause == "":
|
|
@@ -132,13 +126,13 @@ class Viewer:
|
|
|
132
126
|
else:
|
|
133
127
|
where_clause += f" AND ({' AND '.join(filter_clauses)})"
|
|
134
128
|
for column, value in filters.items():
|
|
135
|
-
params[f"filter_{column}"] = value
|
|
129
|
+
params[f"filter_{column}"] = value
|
|
136
130
|
|
|
137
131
|
query = f"{base_query}{where_clause}"
|
|
138
132
|
stmt = text(query).bindparams(**params)
|
|
139
133
|
with self.database.get_db().connect() as conn:
|
|
140
134
|
count = conn.execute(stmt).scalar()
|
|
141
|
-
return count
|
|
135
|
+
return int(count) if count is not None else 0
|
|
142
136
|
|
|
143
137
|
def is_auto_backup(self) -> bool:
|
|
144
138
|
"""
|
|
@@ -154,14 +148,12 @@ class Viewer:
|
|
|
154
148
|
|
|
155
149
|
:param data: Dictionary with table and row_id keys
|
|
156
150
|
"""
|
|
157
|
-
# create backup
|
|
158
151
|
if self.is_auto_backup():
|
|
159
152
|
backup_path = self.database.make_backup()
|
|
160
153
|
if backup_path:
|
|
161
154
|
msg = f"[DB] Created DB backup: {backup_path}"
|
|
162
155
|
self.log(msg)
|
|
163
156
|
|
|
164
|
-
# delete row
|
|
165
157
|
with self.database.get_db().begin() as conn:
|
|
166
158
|
conn.execute(
|
|
167
159
|
text(f"DELETE FROM {data['table']} WHERE id = :row_id")
|
|
@@ -184,35 +176,30 @@ class Viewer:
|
|
|
184
176
|
timestamp_columns = tables[data['table']]['timestamp_columns']
|
|
185
177
|
primary_key = tables[data['table']]['primary_key']
|
|
186
178
|
|
|
187
|
-
# check JSON
|
|
188
179
|
if field in json_columns or field.endswith("_json"):
|
|
189
180
|
try:
|
|
190
|
-
value = json.dumps(json.loads(value))
|
|
181
|
+
value = json.dumps(json.loads(value))
|
|
191
182
|
except:
|
|
192
183
|
raise ValueError(f"Invalid JSON value for column {field}")
|
|
193
184
|
|
|
194
|
-
# check timestamp
|
|
195
185
|
if field in timestamp_columns or field.endswith("_ts"):
|
|
196
186
|
try:
|
|
197
187
|
value = int(value)
|
|
198
188
|
except:
|
|
199
189
|
raise ValueError(f"Invalid timestamp value for column {field}")
|
|
200
190
|
|
|
201
|
-
# check foreign id field
|
|
202
191
|
if field.endswith("_id"):
|
|
203
192
|
try:
|
|
204
193
|
value = int(value)
|
|
205
194
|
except:
|
|
206
195
|
raise ValueError(f"Invalid _id value for column {field}")
|
|
207
196
|
|
|
208
|
-
# create backup
|
|
209
197
|
if self.is_auto_backup():
|
|
210
198
|
backup_path = self.database.make_backup()
|
|
211
199
|
if backup_path:
|
|
212
200
|
msg = f"[DB] Created DB backup: {backup_path}"
|
|
213
201
|
self.log(msg)
|
|
214
202
|
|
|
215
|
-
# update row
|
|
216
203
|
with self.database.get_db().begin() as conn:
|
|
217
204
|
conn.execute(
|
|
218
205
|
text(f"UPDATE {data['table']} SET {data['field']} = :value WHERE {primary_key} = :id")
|
|
@@ -229,17 +216,15 @@ class Viewer:
|
|
|
229
216
|
:param data: Dictionary with table key
|
|
230
217
|
:param reset: Reset table sequence
|
|
231
218
|
"""
|
|
232
|
-
# create backup
|
|
233
219
|
if self.is_auto_backup():
|
|
234
220
|
backup_path = self.database.make_backup()
|
|
235
221
|
if backup_path:
|
|
236
222
|
msg = f"[DB] Created DB backup: {backup_path}"
|
|
237
223
|
self.log(msg)
|
|
238
224
|
|
|
239
|
-
# truncate table
|
|
240
225
|
with self.database.get_db().begin() as conn:
|
|
241
226
|
conn.execute(text(f"DELETE FROM {data['table']}"))
|
|
242
|
-
if reset:
|
|
227
|
+
if reset:
|
|
243
228
|
conn.execute(text(f"DELETE FROM sqlite_sequence WHERE name='{data['table']}'"))
|
|
244
229
|
msg = f"[DB] Truncated table {data['table']}"
|
|
245
230
|
else:
|
|
@@ -6,13 +6,24 @@
|
|
|
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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import io
|
|
13
|
+
from dataclasses import dataclass, field
|
|
13
14
|
|
|
15
|
+
|
|
16
|
+
@dataclass(slots=True)
|
|
14
17
|
class PidData:
|
|
15
18
|
|
|
19
|
+
pid: object = None
|
|
20
|
+
meta: object = None
|
|
21
|
+
images_appended: list = field(default_factory=list)
|
|
22
|
+
urls_appended: list = field(default_factory=list)
|
|
23
|
+
files_appended: list = field(default_factory=list)
|
|
24
|
+
_buffer: io.StringIO = field(default_factory=io.StringIO)
|
|
25
|
+
is_cmd: bool = False
|
|
26
|
+
|
|
16
27
|
def __init__(self, pid, meta=None):
|
|
17
28
|
"""Pid Data"""
|
|
18
29
|
self.pid = pid
|
|
@@ -1013,11 +1013,7 @@ class Body:
|
|
|
1013
1013
|
// - Otherwise hide the FAB to prevent overlap and noise.
|
|
1014
1014
|
let action = 'none'; // 'up' | 'down' | 'none'
|
|
1015
1015
|
if (atBottom) {
|
|
1016
|
-
|
|
1017
|
-
action = 'up';
|
|
1018
|
-
} else {
|
|
1019
|
-
action = 'none';
|
|
1020
|
-
}
|
|
1016
|
+
action = 'up';
|
|
1021
1017
|
} else {
|
|
1022
1018
|
if (dist >= SHOW_DOWN_THRESHOLD_PX) {
|
|
1023
1019
|
action = 'down';
|
pygpt_net/core/tabs/tab.py
CHANGED
|
@@ -6,13 +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.
|
|
9
|
+
# Updated Date: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from datetime import datetime
|
|
13
13
|
from typing import Dict, Any, Optional
|
|
14
|
+
from dataclasses import dataclass, field
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
@dataclass(slots=True)
|
|
16
18
|
class Tab:
|
|
17
19
|
|
|
18
20
|
# types
|
|
@@ -24,6 +26,27 @@ class Tab:
|
|
|
24
26
|
TAB_TOOL_CALENDAR = 4
|
|
25
27
|
TAB_TOOL = 100
|
|
26
28
|
|
|
29
|
+
uuid: Optional[str] = None
|
|
30
|
+
pid: Optional[int] = None
|
|
31
|
+
idx: Optional[int] = 0
|
|
32
|
+
type: Optional[int] = TAB_CHAT
|
|
33
|
+
title: Optional[str] = ""
|
|
34
|
+
icon: Optional[str] = None
|
|
35
|
+
tooltip: Optional[str] = None
|
|
36
|
+
data_id: Optional[str] = None
|
|
37
|
+
new_idx: Optional[int] = None
|
|
38
|
+
custom_name: Optional[bool] = False
|
|
39
|
+
child: Optional[Any] = None
|
|
40
|
+
parent: Optional[Any] = None
|
|
41
|
+
column_idx: Optional[int] = 0
|
|
42
|
+
tool_id: Optional[str] = None
|
|
43
|
+
on_delete: Optional[callable] = None
|
|
44
|
+
|
|
45
|
+
loaded: bool = False
|
|
46
|
+
refs: list = field(default_factory=list)
|
|
47
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
48
|
+
updated_at: datetime = field(default_factory=datetime.now)
|
|
49
|
+
|
|
27
50
|
def __init__(
|
|
28
51
|
self,
|
|
29
52
|
uuid: Optional[str] = None,
|
pygpt_net/item/assistant.py
CHANGED
|
@@ -6,16 +6,33 @@
|
|
|
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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import time
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import Optional
|
|
14
16
|
|
|
15
17
|
from pygpt_net.item.attachment import AttachmentItem
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
@dataclass(slots=True)
|
|
18
21
|
class AssistantItem:
|
|
22
|
+
id: Optional[object] = None
|
|
23
|
+
name: Optional[object] = None
|
|
24
|
+
description: Optional[object] = None
|
|
25
|
+
instructions: Optional[object] = None
|
|
26
|
+
model: Optional[object] = None
|
|
27
|
+
meta: dict = field(default_factory=dict)
|
|
28
|
+
files: dict = field(default_factory=dict)
|
|
29
|
+
attachments: dict = field(default_factory=dict)
|
|
30
|
+
vector_store: str = ""
|
|
31
|
+
tools: dict = field(default_factory=lambda: {
|
|
32
|
+
"code_interpreter": False,
|
|
33
|
+
"file_search": False,
|
|
34
|
+
"function": [],
|
|
35
|
+
})
|
|
19
36
|
|
|
20
37
|
def __init__(self):
|
|
21
38
|
"""Assistant item"""
|
|
@@ -203,7 +220,26 @@ class AssistantItem:
|
|
|
203
220
|
return self.dump()
|
|
204
221
|
|
|
205
222
|
|
|
223
|
+
@dataclass(slots=True)
|
|
206
224
|
class AssistantStoreItem:
|
|
225
|
+
id: Optional[object] = None
|
|
226
|
+
record_id: Optional[object] = None
|
|
227
|
+
uuid: Optional[object] = None
|
|
228
|
+
name: Optional[object] = None
|
|
229
|
+
description: Optional[object] = None
|
|
230
|
+
status: dict = field(default_factory=dict)
|
|
231
|
+
last_status: str = ""
|
|
232
|
+
expire_days: int = 0
|
|
233
|
+
usage_bytes: int = 0
|
|
234
|
+
bytes: int = 0
|
|
235
|
+
num_files: int = 0
|
|
236
|
+
is_thread: bool = False
|
|
237
|
+
created: int = 0
|
|
238
|
+
updated: int = 0
|
|
239
|
+
last_active: int = 0
|
|
240
|
+
last_sync: int = 0
|
|
241
|
+
file_ids: list = field(default_factory=list)
|
|
242
|
+
|
|
207
243
|
def __init__(self):
|
|
208
244
|
"""Assistant vector store item"""
|
|
209
245
|
self.id = None
|
|
@@ -300,7 +336,20 @@ class AssistantStoreItem:
|
|
|
300
336
|
return self.dump()
|
|
301
337
|
|
|
302
338
|
|
|
339
|
+
@dataclass(slots=True)
|
|
303
340
|
class AssistantFileItem:
|
|
341
|
+
id: Optional[object] = None
|
|
342
|
+
record_id: Optional[object] = None
|
|
343
|
+
name: Optional[object] = None
|
|
344
|
+
path: Optional[object] = None
|
|
345
|
+
file_id: Optional[object] = None
|
|
346
|
+
store_id: Optional[object] = None
|
|
347
|
+
thread_id: Optional[object] = None
|
|
348
|
+
uuid: Optional[object] = None
|
|
349
|
+
size: int = 0
|
|
350
|
+
created: int = 0
|
|
351
|
+
updated: int = 0
|
|
352
|
+
|
|
304
353
|
def __init__(self):
|
|
305
354
|
"""Assistant file item"""
|
|
306
355
|
self.id = None
|
|
@@ -379,4 +428,4 @@ class AssistantFileItem:
|
|
|
379
428
|
|
|
380
429
|
def __str__(self):
|
|
381
430
|
"""To string"""
|
|
382
|
-
return self.dump()
|
|
431
|
+
return self.dump()
|