pygpt-net 2.6.16__py3-none-any.whl → 2.6.17__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.
@@ -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: 2024.12.14 08:00:00 #
9
+ # Updated Date: 2025.08.21 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List, Dict
@@ -40,12 +40,9 @@ class Body:
40
40
  """
41
41
  num_str = ""
42
42
  if num is not None and num_all is not None and num_all > 1:
43
- num_str = " [{}]".format(num)
43
+ num_str = f" [{num}]"
44
44
  url, path = self.window.core.filesystem.extract_local_url(url)
45
- return """\n{prefix}{num}: {path}\n""". \
46
- format(prefix=trans('chat.prefix.img'),
47
- path=path,
48
- num=num_str)
45
+ return f"\n{trans('chat.prefix.img')}{num_str}: {path}\n"
49
46
 
50
47
  def get_url_html(
51
48
  self,
@@ -63,11 +60,8 @@ class Body:
63
60
  """
64
61
  num_str = ""
65
62
  if num is not None and num_all is not None and num_all > 1:
66
- num_str = " [{}]".format(num)
67
- return """{prefix}{num}: {url}""". \
68
- format(prefix=trans('chat.prefix.url'),
69
- url=url,
70
- num=num_str)
63
+ num_str = f" [{num}]"
64
+ return f"{trans('chat.prefix.url')}{num_str}: {url}"
71
65
 
72
66
  def get_docs_html(self, docs: List[Dict]) -> str:
73
67
  """
@@ -93,8 +87,8 @@ class Body:
93
87
  """
94
88
  doc_parts = []
95
89
  for key in doc_json:
96
- doc_parts.append("{}: {}".format(key, doc_json[key]))
97
- html_sources += "\n[{}] {}: {}".format(num, uuid, ", ".join(doc_parts))
90
+ doc_parts.append(f"{key}: {doc_json[key]}")
91
+ html_sources += f"\n[{num}] {uuid}: {', '.join(doc_parts)}"
98
92
  num += 1
99
93
  if num >= max:
100
94
  break
@@ -102,7 +96,7 @@ class Body:
102
96
  pass
103
97
 
104
98
  if html_sources != "":
105
- html += "\n----------\n{prefix}:\n".format(prefix=trans('chat.prefix.doc'))
99
+ html += f"\n----------\n{trans('chat.prefix.doc')}:\n"
106
100
  html += html_sources
107
101
  return html
108
102
 
@@ -122,9 +116,6 @@ class Body:
122
116
  """
123
117
  num_str = ""
124
118
  if num is not None and num_all is not None and num_all > 1:
125
- num_str = " [{}]".format(num)
119
+ num_str = f" [{num}]"
126
120
  url, path = self.window.core.filesystem.extract_local_url(url)
127
- return """\n{prefix}{num}: {path}\n""". \
128
- format(prefix=trans('chat.prefix.file'),
129
- path=path,
130
- num=num_str)
121
+ return f"\n{trans('chat.prefix.file')}{num_str}: {path}\n"
@@ -6,7 +6,8 @@
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.11 19:00:00 #
9
+ # Updated Date: 2025.08.21 00:00:00 #
10
+ # ================================================== #
10
11
 
11
12
  from datetime import datetime
12
13
  from typing import Optional, List
@@ -54,7 +55,7 @@ class Renderer(BaseRenderer):
54
55
  def get_pid(self, meta: CtxMeta):
55
56
  """
56
57
  Get PID for context meta
57
-
58
+
58
59
  :param meta: context PID
59
60
  """
60
61
  return self.window.core.ctx.output.get_pid(meta)
@@ -62,7 +63,7 @@ class Renderer(BaseRenderer):
62
63
  def get_or_create_pid(self, meta: CtxMeta):
63
64
  """
64
65
  Get PID for context meta and create PID data (if not exists)
65
-
66
+
66
67
  :param meta: context PID
67
68
  """
68
69
  if meta is not None:
@@ -74,7 +75,7 @@ class Renderer(BaseRenderer):
74
75
  def pid_create(self, pid, meta: CtxMeta):
75
76
  """
76
77
  Create PID data
77
-
78
+
78
79
  :param pid: PID
79
80
  :param meta: context meta
80
81
  """
@@ -98,7 +99,7 @@ class Renderer(BaseRenderer):
98
99
  ):
99
100
  """
100
101
  Render begin
101
-
102
+
102
103
  :param meta: context meta
103
104
  :param ctx: context item
104
105
  :param stream: True if it is a stream
@@ -113,7 +114,7 @@ class Renderer(BaseRenderer):
113
114
  ):
114
115
  """
115
116
  Render end
116
-
117
+
117
118
  :param meta: context meta
118
119
  :param ctx: context item
119
120
  :param stream: True if it is a stream
@@ -128,7 +129,7 @@ class Renderer(BaseRenderer):
128
129
  ):
129
130
  """
130
131
  Render end extra
131
-
132
+
132
133
  :param meta: context meta
133
134
  :param ctx: context item
134
135
  :param stream: True if it is a stream
@@ -203,12 +204,12 @@ class Renderer(BaseRenderer):
203
204
  if self.is_timestamp_enabled() and item.input_timestamp is not None:
204
205
  name = ""
205
206
  if item.input_name is not None and item.input_name != "":
206
- name = item.input_name + " "
207
+ name = f"{item.input_name} "
207
208
  ts = datetime.fromtimestamp(item.input_timestamp)
208
209
  hour = ts.strftime("%H:%M:%S")
209
- text = '{}{} > {}'.format(name, hour, item.input)
210
+ text = f"{name}{hour} > {item.input}"
210
211
  else:
211
- text = "> {}".format(item.input)
212
+ text = f"> {item.input}"
212
213
  self.append_raw(meta, item, text.strip())
213
214
  self.to_end(meta)
214
215
 
@@ -228,12 +229,12 @@ class Renderer(BaseRenderer):
228
229
  if self.is_timestamp_enabled() and item.output_timestamp is not None:
229
230
  name = ""
230
231
  if item.output_name is not None and item.output_name != "":
231
- name = item.output_name + " "
232
+ name = f"{item.output_name} "
232
233
  ts = datetime.fromtimestamp(item.output_timestamp)
233
234
  hour = ts.strftime("%H:%M:%S")
234
- text = '{}{} {}'.format(name, hour, item.output)
235
+ text = f"{name}{hour} {item.output}"
235
236
  else:
236
- text = "{}".format(item.output)
237
+ text = f"{item.output}"
237
238
  self.append_raw(meta, item, text.strip())
238
239
  self.to_end(meta)
239
240
 
@@ -298,7 +299,8 @@ class Renderer(BaseRenderer):
298
299
  except Exception as e:
299
300
  pass
300
301
  if urls_str:
301
- self.append_raw(meta, item, "\n" + "\n".join(urls_str))
302
+ urls_joined = "\n".join(urls_str)
303
+ self.append_raw(meta, item, f"\n{urls_joined}")
302
304
 
303
305
  if self.window.core.config.get('ctx.sources'):
304
306
  if item.doc_ids is not None and len(item.doc_ids) > 0:
@@ -341,12 +343,12 @@ class Renderer(BaseRenderer):
341
343
  if self.is_timestamp_enabled() and item.output_timestamp is not None:
342
344
  name = ""
343
345
  if item.output_name is not None and item.output_name != "":
344
- name = item.output_name + " "
346
+ name = f"{item.output_name} "
345
347
  ts = datetime.fromtimestamp(item.output_timestamp)
346
348
  hour = ts.strftime("%H:%M:%S")
347
- text_chunk = "{}{}: ".format(name, hour) + text_chunk
349
+ text_chunk = f"{name}{hour}: {text_chunk}"
348
350
 
349
- text_chunk = "\n" + text_chunk
351
+ text_chunk = f"\n{text_chunk}"
350
352
  self.append_block(meta)
351
353
  self.append_chunk_start(meta, item)
352
354
 
@@ -378,7 +380,7 @@ class Renderer(BaseRenderer):
378
380
  ):
379
381
  """
380
382
  Append and format raw text to output as plain text.
381
-
383
+
382
384
  :param meta: context meta
383
385
  :param ctx: context item
384
386
  :param text: text to append
@@ -387,7 +389,7 @@ class Renderer(BaseRenderer):
387
389
  prev_text = node.toPlainText()
388
390
  if prev_text != "":
389
391
  prev_text += "\n\n"
390
- new_text = prev_text + text.strip()
392
+ new_text = f"{prev_text}{text.strip()}"
391
393
  node.setPlainText(new_text)
392
394
  cur = node.textCursor() # Move cursor to end of text
393
395
  cur.movePosition(QTextCursor.End)
@@ -395,7 +397,7 @@ class Renderer(BaseRenderer):
395
397
  def append_chunk_start(self, meta: CtxMeta, ctx: CtxItem):
396
398
  """
397
399
  Append start of chunk to output
398
-
400
+
399
401
  :param meta: context meta
400
402
  :param ctx: context item
401
403
  """
@@ -411,7 +413,7 @@ class Renderer(BaseRenderer):
411
413
  ):
412
414
  """
413
415
  Append context item to output
414
-
416
+
415
417
  :param meta: context meta
416
418
  :param item: context item
417
419
  """
@@ -437,7 +439,7 @@ class Renderer(BaseRenderer):
437
439
  node = self.get_output_node(meta)
438
440
  cur = node.textCursor() # Move cursor to end of text
439
441
  cur.movePosition(QTextCursor.End)
440
- s = str(text) + end
442
+ s = f"{str(text)}{end}"
441
443
  while s:
442
444
  head, sep, s = s.partition("\n") # Split line at LF
443
445
  cur.insertText(head)
@@ -452,7 +454,7 @@ class Renderer(BaseRenderer):
452
454
  ) -> str:
453
455
  """
454
456
  Append timestamp to text
455
-
457
+
456
458
  :param item: context item
457
459
  :param text: input text
458
460
  :return: Text with timestamp (if enabled)
@@ -462,7 +464,7 @@ class Renderer(BaseRenderer):
462
464
  and item.input_timestamp is not None:
463
465
  ts = datetime.fromtimestamp(item.input_timestamp)
464
466
  hour = ts.strftime("%H:%M:%S")
465
- text = '{}: {}'.format(hour, text)
467
+ text = f"{hour}: {text}"
466
468
  return text
467
469
 
468
470
  def reset(self, meta: Optional[CtxMeta] = None):
@@ -518,7 +520,7 @@ class Renderer(BaseRenderer):
518
520
  ) -> ChatOutput:
519
521
  """
520
522
  Get output node for current context.
521
-
523
+
522
524
  :param meta: context meta
523
525
  :return: output node
524
526
  """
@@ -547,8 +549,6 @@ class Renderer(BaseRenderer):
547
549
  for node in self.get_all_nodes():
548
550
  try:
549
551
  node.clear()
550
- node.document().setDefaultStyleSheet("")
551
- node.setStyleSheet("")
552
552
  node.document().setMarkdown("")
553
553
  node.document().setHtml("")
554
554
  node.setPlainText("")
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.16",
4
- "app.version": "2.6.16",
5
- "updated_at": "2025-08-20T00:00:00"
3
+ "version": "2.6.17",
4
+ "app.version": "2.6.17",
5
+ "updated_at": "2025-08-21T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -179,8 +179,8 @@
179
179
  "experts.use_agent": true,
180
180
  "experts.api_use_responses": false,
181
181
  "experts.internal.api_use_responses": false,
182
- "font_size": 14,
183
- "font_size.input": 14,
182
+ "font_size": 16,
183
+ "font_size.input": 16,
184
184
  "font_size.ctx": 12,
185
185
  "font_size.toolbox": 12,
186
186
  "func_call.native": true,
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.16",
4
- "app.version": "2.6.16",
5
- "updated_at": "2025-08-20T23:07:35"
3
+ "version": "2.6.17",
4
+ "app.version": "2.6.17",
5
+ "updated_at": "2025-08-21T23:07:35"
6
6
  },
7
7
  "items": {
8
8
  "SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
pygpt_net/ui/__init__.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.01.19 03:00:00 #
9
+ # Updated Date: 2025.08.20 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -89,12 +89,6 @@ class UI:
89
89
  self.splitters['main'].addWidget(self.parts['chat']) # chat box
90
90
  self.splitters['main'].addWidget(self.parts['toolbox']) # toolbox
91
91
 
92
- # FIRST RUN: initial sizes if not set yet
93
- if not self.window.core.config.has("layout.splitters") \
94
- or self.window.core.config.get("layout.splitters") == {}\
95
- or self.window.core.config.get("license.accepted") == False:
96
- self.set_initial_size()
97
-
98
92
  # menus
99
93
  self.menus.setup()
100
94
 
@@ -107,6 +101,14 @@ class UI:
107
101
  # set window title
108
102
  self.update_title()
109
103
 
104
+ def on_show(self):
105
+ """Called after MainWindow onShow() event"""
106
+ # FIRST RUN: initial sizes if not set yet
107
+ if not self.window.core.config.has("layout.splitters") \
108
+ or self.window.core.config.get("layout.splitters") == {} \
109
+ or self.window.core.config.get("license.accepted") == False:
110
+ self.set_initial_size()
111
+
110
112
  def set_initial_size(self):
111
113
  """Set default sizes"""
112
114
  def set_initial_splitter_height():
@@ -118,19 +120,19 @@ class UI:
118
120
  self.window.ui.splitters['main.output'].setSizes([size_output, size_input])
119
121
  else:
120
122
  QTimer.singleShot(0, set_initial_splitter_height)
121
- QTimer.singleShot(0, set_initial_splitter_height)
123
+ QTimer.singleShot(10, set_initial_splitter_height)
122
124
 
123
125
  def set_initial_splitter_width():
124
126
  """Set initial splitter width"""
125
127
  total_width = self.window.ui.splitters['main'].size().width()
126
128
  if total_width > 0:
127
- size_output = int(total_width * 0.7)
129
+ size_output = int(total_width * 0.75)
128
130
  size_ctx = (total_width - size_output) / 2
129
131
  size_toolbox = (total_width - size_output) / 2
130
132
  self.window.ui.splitters['main'].setSizes([size_ctx, size_output, size_toolbox])
131
133
  else:
132
134
  QTimer.singleShot(0, set_initial_splitter_width)
133
- QTimer.singleShot(0, set_initial_splitter_width)
135
+ QTimer.singleShot(10, set_initial_splitter_width)
134
136
 
135
137
  def update_title(self):
136
138
  """Update window title"""
@@ -11,6 +11,7 @@
11
11
 
12
12
  from PySide6.QtCore import Qt
13
13
  from PySide6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QSizePolicy, QWidget, QFrame
14
+ from PySide6.QtGui import QFont
14
15
 
15
16
  from pygpt_net.ui.widget.element.labels import TitleLabel, UrlLabel
16
17
  from pygpt_net.ui.widget.option.checkbox import OptionCheckbox
@@ -57,7 +58,9 @@ class BaseConfigDialog:
57
58
  if slider and t in ('int', 'float'):
58
59
  widgets[key] = OptionSlider(self.window, id, key, option)
59
60
  else:
60
- widgets[key] = PasswordInput(self.window, id, key, option) if secret else OptionInput(self.window, id, key, option)
61
+ widgets[key] = PasswordInput(self.window, id, key, option) if secret else OptionInput(self.window,
62
+ id, key,
63
+ option)
61
64
 
62
65
  elif t == 'textarea':
63
66
  w = OptionTextarea(self.window, id, key, option)
@@ -99,20 +102,21 @@ class BaseConfigDialog:
99
102
  label = option['label']
100
103
  desc = option.get('description')
101
104
  extra = option.get('extra') or {}
102
- label_key = label + '.label'
105
+ label_key = f'{label}.label'
103
106
  nodes = self.window.ui.nodes
104
107
 
108
+ txt = trans(label)
105
109
  if extra.get('bold'):
106
- nodes[label_key] = TitleLabel(trans(label))
110
+ nodes[label_key] = TitleLabel(txt)
107
111
  else:
108
- nodes[label_key] = QLabel(trans(label))
112
+ nodes[label_key] = QLabel(txt)
109
113
  nodes[label_key].setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
110
114
  nodes[label_key].setMinimumWidth(120)
111
115
  nodes[label_key].setWordWrap(True)
112
116
 
113
117
  desc_key = None
114
118
  if desc is not None:
115
- desc_key = label + '.desc'
119
+ desc_key = f'{label}.desc'
116
120
  nodes[desc_key] = self.add_description(desc)
117
121
 
118
122
  if option.get('type') == 'textarea':
@@ -142,21 +146,22 @@ class BaseConfigDialog:
142
146
  :return: QHBoxLayout
143
147
  """
144
148
  label = option['label']
145
- label_key = label + '.label'
149
+ label_key = f'{label}.label'
146
150
  desc = option.get('description')
147
151
  extra = option.get('extra') or {}
148
152
  nodes = self.window.ui.nodes
149
153
 
154
+ txt = trans(label)
150
155
  if extra.get('bold'):
151
- nodes[label_key] = TitleLabel(trans(label))
156
+ nodes[label_key] = TitleLabel(txt)
152
157
  else:
153
- nodes[label_key] = QLabel(trans(label))
158
+ nodes[label_key] = QLabel(txt)
154
159
  nodes[label_key].setMinimumHeight(30)
155
160
  nodes[label_key].setWordWrap(True)
156
161
 
157
162
  desc_key = None
158
163
  if desc is not None:
159
- desc_key = label + '.desc'
164
+ desc_key = f'{label}.desc'
160
165
  nodes[desc_key] = self.add_description(desc)
161
166
 
162
167
  layout = QVBoxLayout()
@@ -191,7 +196,7 @@ class BaseConfigDialog:
191
196
 
192
197
  desc_key = None
193
198
  if desc is not None:
194
- desc_key = label + '.desc'
199
+ desc_key = f'{label}.desc'
195
200
  nodes[desc_key] = self.add_description(desc)
196
201
 
197
202
  urls = extra.get('urls')
@@ -114,18 +114,22 @@ class About:
114
114
  pixmap = QPixmap(path)
115
115
  logo_label.setPixmap(pixmap)
116
116
 
117
- self.window.ui.nodes['dialog.about.btn.website'] = QPushButton(QIcon(":/icons/home.svg"), trans('about.btn.website'))
118
- self.window.ui.nodes['dialog.about.btn.website'].clicked.connect(lambda: self.window.controller.dialogs.info.goto_website())
119
- self.window.ui.nodes['dialog.about.btn.website'].setCursor(Qt.PointingHandCursor)
120
- self.window.ui.nodes['dialog.about.btn.website'].setStyleSheet("font-size: 11px;")
117
+ btn_web = QPushButton(QIcon(":/icons/home.svg"), trans('about.btn.website'))
118
+ btn_web.clicked.connect(lambda: self.window.controller.dialogs.info.goto_website())
119
+ btn_web.setCursor(Qt.PointingHandCursor)
120
+ btn_web.setStyleSheet("font-size: 11px;")
121
+ self.window.ui.nodes['dialog.about.btn.website'] = btn_web
121
122
 
122
- self.window.ui.nodes['dialog.about.btn.github'] = QPushButton(QIcon(":/icons/code.svg"), trans('about.btn.github'))
123
- self.window.ui.nodes['dialog.about.btn.github'].clicked.connect(lambda: self.window.controller.dialogs.info.goto_github())
124
- self.window.ui.nodes['dialog.about.btn.github'].setCursor(Qt.PointingHandCursor)
123
+ btn_git = QPushButton(QIcon(":/icons/code.svg"), trans('about.btn.github'))
124
+ btn_git.clicked.connect(lambda: self.window.controller.dialogs.info.goto_github())
125
+ btn_git.setCursor(Qt.PointingHandCursor)
126
+ self.window.ui.nodes['dialog.about.btn.github'] = btn_git
125
127
 
126
- self.window.ui.nodes['dialog.about.btn.support'] = QPushButton(QIcon(":/icons/favorite.svg"), trans('about.btn.support'))
127
- self.window.ui.nodes['dialog.about.btn.support'].clicked.connect(lambda: self.window.controller.dialogs.info.goto_donate())
128
- self.window.ui.nodes['dialog.about.btn.support'].setCursor(Qt.PointingHandCursor)
128
+
129
+ btn_support = QPushButton(QIcon(":/icons/favorite.svg"), trans('about.btn.support'))
130
+ btn_support.clicked.connect(lambda: self.window.controller.dialogs.info.goto_donate())
131
+ btn_support.setCursor(Qt.PointingHandCursor)
132
+ self.window.ui.nodes['dialog.about.btn.support'] = btn_support
129
133
 
130
134
  buttons_layout = QHBoxLayout()
131
135
  buttons_layout.addWidget(self.window.ui.nodes['dialog.about.btn.support'])
@@ -133,10 +137,13 @@ class About:
133
137
  buttons_layout.addWidget(self.window.ui.nodes['dialog.about.btn.github'])
134
138
 
135
139
  string = self.prepare_content()
136
- self.window.ui.nodes['dialog.about.content'] = QLabel(string)
137
- self.window.ui.nodes['dialog.about.content'].setTextInteractionFlags(Qt.TextSelectableByMouse)
138
- self.window.ui.nodes['dialog.about.thanks'] = QLabel(trans('about.thanks'))
139
- self.window.ui.nodes['dialog.about.thanks'].setAlignment(Qt.AlignCenter)
140
+ content = QLabel(string)
141
+ content.setTextInteractionFlags(Qt.TextSelectableByMouse)
142
+ self.window.ui.nodes['dialog.about.content'] = content
143
+
144
+ thanks = QLabel(trans('about.thanks'))
145
+ thanks.setAlignment(Qt.AlignCenter)
146
+ self.window.ui.nodes['dialog.about.thanks'] = thanks
140
147
 
141
148
  title = QLabel("PyGPT")
142
149
  title.setContentsMargins(0, 0, 0, 0)
@@ -150,10 +157,11 @@ class About:
150
157
  )
151
158
  title.setAlignment(Qt.AlignCenter)
152
159
 
153
- self.window.ui.nodes['dialog.about.thanks.content'] = QPlainTextEdit()
154
- self.window.ui.nodes['dialog.about.thanks.content'].setReadOnly(True)
155
- self.window.ui.nodes['dialog.about.thanks.content'].setPlainText("")
156
- self.window.ui.nodes['dialog.about.thanks.content'].setStyleSheet("font-size: 11px;")
160
+ thanks_content = QPlainTextEdit()
161
+ thanks_content.setReadOnly(True)
162
+ thanks_content.setPlainText("")
163
+ thanks_content.setStyleSheet("font-size: 11px;")
164
+ self.window.ui.nodes['dialog.about.thanks.content'] = thanks_content
157
165
 
158
166
  layout = QVBoxLayout()
159
167
  layout.addWidget(logo_label)