pygpt-net 2.4.31__py3-none-any.whl → 2.4.33__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.
Files changed (51) hide show
  1. CHANGELOG.md +10 -0
  2. README.md +14 -4
  3. pygpt_net/CHANGELOG.txt +10 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/attachment.py +52 -1
  6. pygpt_net/controller/chat/attachment.py +109 -44
  7. pygpt_net/controller/dialogs/confirm.py +17 -1
  8. pygpt_net/core/attachments/__init__.py +11 -7
  9. pygpt_net/core/attachments/context.py +171 -34
  10. pygpt_net/core/debug/attachments.py +3 -1
  11. pygpt_net/core/debug/context.py +5 -1
  12. pygpt_net/core/idx/indexing.py +123 -15
  13. pygpt_net/core/render/markdown/pid.py +2 -1
  14. pygpt_net/core/render/plain/pid.py +2 -1
  15. pygpt_net/core/render/web/body.py +34 -12
  16. pygpt_net/core/render/web/pid.py +2 -1
  17. pygpt_net/core/render/web/renderer.py +8 -3
  18. pygpt_net/data/config/config.json +3 -3
  19. pygpt_net/data/config/models.json +3 -3
  20. pygpt_net/data/config/modes.json +3 -3
  21. pygpt_net/data/css/web.css +70 -0
  22. pygpt_net/data/css/web.dark.css +4 -1
  23. pygpt_net/data/css/web.light.css +1 -1
  24. pygpt_net/data/locale/locale.de.ini +7 -1
  25. pygpt_net/data/locale/locale.en.ini +10 -4
  26. pygpt_net/data/locale/locale.es.ini +7 -1
  27. pygpt_net/data/locale/locale.fr.ini +7 -1
  28. pygpt_net/data/locale/locale.it.ini +7 -1
  29. pygpt_net/data/locale/locale.pl.ini +7 -1
  30. pygpt_net/data/locale/locale.uk.ini +7 -1
  31. pygpt_net/data/locale/locale.zh.ini +7 -1
  32. pygpt_net/item/attachment.py +9 -1
  33. pygpt_net/plugin/cmd_code_interpreter/runner.py +2 -2
  34. pygpt_net/plugin/cmd_mouse_control/__init__.py +4 -2
  35. pygpt_net/provider/core/attachment/json_file.py +4 -1
  36. pygpt_net/provider/loaders/base.py +10 -1
  37. pygpt_net/provider/loaders/web_yt.py +19 -1
  38. pygpt_net/tools/image_viewer/ui/dialogs.py +3 -1
  39. pygpt_net/ui/dialog/url.py +29 -0
  40. pygpt_net/ui/dialogs.py +5 -1
  41. pygpt_net/ui/layout/chat/attachments.py +20 -6
  42. pygpt_net/ui/layout/chat/attachments_ctx.py +4 -3
  43. pygpt_net/ui/layout/chat/attachments_uploaded.py +8 -4
  44. pygpt_net/ui/widget/dialog/url.py +59 -0
  45. pygpt_net/ui/widget/lists/attachment.py +22 -17
  46. pygpt_net/ui/widget/textarea/url.py +43 -0
  47. {pygpt_net-2.4.31.dist-info → pygpt_net-2.4.33.dist-info}/METADATA +15 -5
  48. {pygpt_net-2.4.31.dist-info → pygpt_net-2.4.33.dist-info}/RECORD +51 -48
  49. {pygpt_net-2.4.31.dist-info → pygpt_net-2.4.33.dist-info}/LICENSE +0 -0
  50. {pygpt_net-2.4.31.dist-info → pygpt_net-2.4.33.dist-info}/WHEEL +0 -0
  51. {pygpt_net-2.4.31.dist-info → pygpt_net-2.4.33.dist-info}/entry_points.txt +0 -0
CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.4.33 (2024-11-26)
4
+
5
+ - Improved CSS and rendering of file and image lists.
6
+ - Added displaying of used attachments in the chat window.
7
+
8
+ ## 2.4.32 (2024-11-26)
9
+
10
+ - The "Add URL" option added to the "Attachments" tab allows users to include content from a given website as additional context. Currently, it only supports standard web pages and video transcription for YouTube links. More "web" options will be added in the future.
11
+ - Added UTF-8 as default in attachments content text read/write.
12
+
3
13
  ## 2.4.31 (2024-11-25)
4
14
 
5
15
  - Added an option checkbox `Auto-index on upload` in the `Attachments` tab:
README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
4
4
 
5
- Release: **2.4.31** | build: **2024.11.25** | Python: **>=3.10, <3.12**
5
+ Release: **2.4.33** | build: **2024.11.26** | Python: **>=3.10, <3.12**
6
6
 
7
7
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
8
8
  >
@@ -155,11 +155,11 @@ pip install pygpt-net
155
155
  pygpt
156
156
  ```
157
157
 
158
- ## Source Code
158
+ ## Running from GitHub source code
159
159
 
160
160
  An alternative method is to download the source code from `GitHub` and execute the application using the Python interpreter (>=3.10, <3.12).
161
161
 
162
- ### Running from GitHub source code
162
+ ### Install with pip
163
163
 
164
164
  1. Clone git repository or download .zip file:
165
165
 
@@ -187,7 +187,7 @@ pip install -r requirements.txt
187
187
  python3 run.py
188
188
  ```
189
189
 
190
- **Install with Poetry**
190
+ ### Install with Poetry
191
191
 
192
192
  1. Clone git repository or download .zip file:
193
193
 
@@ -3656,6 +3656,16 @@ may consume additional tokens that are not displayed in the main window.
3656
3656
 
3657
3657
  ## Recent changes:
3658
3658
 
3659
+ **2.4.33 (2024-11-26)**
3660
+
3661
+ - Improved CSS and rendering of file and image lists.
3662
+ - Added displaying of used attachments in the chat window.
3663
+
3664
+ **2.4.32 (2024-11-26)**
3665
+
3666
+ - The "Add URL" option added to the "Attachments" tab allows users to include content from a given website as additional context. Currently, it only supports standard web pages and video transcription for YouTube links. More "web" options will be added in the future.
3667
+ - Added UTF-8 as default in attachments content text read/write.
3668
+
3659
3669
  **2.4.31 (2024-11-25)**
3660
3670
 
3661
3671
  - Added an option checkbox `Auto-index on upload` in the `Attachments` tab:
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,13 @@
1
+ 2.4.33 (2024-11-26)
2
+
3
+ - Improved CSS and rendering of file and image lists.
4
+ - Added displaying of used attachments in the chat window.
5
+
6
+ 2.4.32 (2024-11-26)
7
+
8
+ - The "Add URL" option added to the "Attachments" tab allows users to include content from a given website as additional context. Currently, it only supports standard web pages and video transcription for YouTube links. More "web" options will be added in the future.
9
+ - Added UTF-8 as default in attachments content text read/write.
10
+
1
11
  2.4.31 (2024-11-25)
2
12
 
3
13
  - Added an option checkbox `Auto-index on upload` in the `Attachments` tab:
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: 2024.11.25 01:00:00 #
9
+ # Updated Date: 2024.11.26 05:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2024, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.4.31"
17
- __build__ = "2024.11.25"
16
+ __version__ = "2.4.33"
17
+ __build__ = "2024.11.26"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __website__ = "https://pygpt.net"
@@ -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: 2024.11.23 00:00:00 #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from datetime import datetime
14
+ from urllib.parse import urlparse
14
15
 
15
16
  from PySide6.QtGui import QImage
16
17
  from PySide6.QtWidgets import QFileDialog, QApplication
@@ -275,6 +276,38 @@ class Attachment:
275
276
  self.window.core.attachments.save()
276
277
  self.update()
277
278
 
279
+ def open_add_url(self):
280
+ """Open add attachment URL dialog"""
281
+ self.window.ui.dialog['url'].id = "attachment"
282
+ self.window.ui.dialog['url'].input.setText("")
283
+ self.window.ui.dialog['url'].current = ""
284
+ self.window.ui.dialog['url'].show()
285
+ self.window.ui.dialog['url'].input.setFocus()
286
+
287
+ def add_url(self, url: str):
288
+ """
289
+ Add URL
290
+
291
+ :param url: URL
292
+ """
293
+ if not url:
294
+ return
295
+ mode = self.window.core.config.get('mode')
296
+ try:
297
+ domain = urlparse(url).netloc
298
+ except Exception as e:
299
+ domain = os.path.basename(url)
300
+ attachment = self.window.core.attachments.new(
301
+ mode=mode,
302
+ name=domain,
303
+ path=url,
304
+ auto_save=False,
305
+ type=AttachmentItem.TYPE_URL,
306
+ )
307
+ self.window.core.attachments.save()
308
+ self.update()
309
+ self.window.ui.dialog['url'].close()
310
+
278
311
  def open_dir(self, mode: str, idx: int):
279
312
  """
280
313
  Open in directory
@@ -328,6 +361,24 @@ class Attachment:
328
361
  return ''
329
362
  return data.path
330
363
 
364
+ def get_by_idx(self, mode: str, idx: int) -> str:
365
+ """
366
+ Get attachment by index
367
+
368
+ :param mode: mode
369
+ :param idx: index
370
+ :return: path
371
+ """
372
+ file_id = self.window.core.attachments.get_id_by_idx(
373
+ mode=mode,
374
+ idx=idx,
375
+ )
376
+ data = self.window.core.attachments.get_by_id(
377
+ mode=mode,
378
+ id=file_id,
379
+ )
380
+ return data
381
+
331
382
  def has(self, mode: str) -> bool:
332
383
  """
333
384
  Return True if current mode has attachments
@@ -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.11.23 21:00:00 #
9
+ # Updated Date: 2024.11.26 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -122,59 +122,115 @@ class Attachment(QObject):
122
122
 
123
123
  for uuid in attachments:
124
124
  attachment = attachments[uuid]
125
- if not self.is_allowed(attachment.path):
126
- continue # skip not allowed files
127
- if self.window.core.filesystem.packer.is_archive(attachment.path):
128
- if self.is_verbose():
129
- print("Unpacking archive: {}".format(attachment.path))
130
- tmp_path = self.window.core.filesystem.packer.unpack(attachment.path)
131
- if tmp_path:
132
- for root, dirs, files in os.walk(tmp_path):
133
- for file in files:
134
- path = os.path.join(root, file)
135
- sub_attachment = AttachmentItem()
136
- sub_attachment.path = path
137
- sub_attachment.name = os.path.basename(path)
138
- sub_attachment.consumed = False
139
- path_relative = os.path.relpath(path, tmp_path)
140
- if self.is_allowed(str(path)):
141
- if self.is_verbose():
142
- print("Uploading unpacked from archive: {}".format(path_relative))
143
- item = self.window.core.attachments.context.upload(
144
- meta=meta,
145
- attachment=sub_attachment,
146
- prompt=prompt,
147
- real_path=attachment.path,
148
- auto_index=auto_index,
149
- )
150
- if item:
151
- item["path"] = os.path.basename(attachment.path) + "/" + path_relative
152
- item["size"] = os.path.getsize(path)
153
- if meta.additional_ctx is None:
154
- meta.additional_ctx = []
155
- meta.additional_ctx.append(item)
156
- self.uploaded = True
157
- sub_attachment.consumed = True
158
- attachment.consumed = True
159
- self.window.core.filesystem.packer.remove_tmp(tmp_path) # clean
160
- else:
161
- item = self.window.core.attachments.context.upload(
125
+ if attachment.type == AttachmentItem.TYPE_FILE:
126
+ result = self.upload_file(
127
+ attachment=attachment,
162
128
  meta=meta,
129
+ prompt=prompt,
130
+ auto_index=auto_index,
131
+ )
132
+ if result:
133
+ self.uploaded = True
134
+ elif attachment.type == AttachmentItem.TYPE_URL:
135
+ result = self.upload_web(
163
136
  attachment=attachment,
137
+ meta=meta,
164
138
  prompt=prompt,
165
- real_path=attachment.path,
166
139
  auto_index=auto_index,
167
140
  )
168
- if item:
169
- if meta.additional_ctx is None:
170
- meta.additional_ctx = []
171
- meta.additional_ctx.append(item)
172
- attachment.consumed = True # allow for deletion
141
+ if result:
173
142
  self.uploaded = True
174
143
  if self.uploaded:
175
144
  self.window.core.ctx.save(meta.id) # save meta
176
145
  return self.uploaded
177
146
 
147
+ def upload_file(
148
+ self,
149
+ attachment: AttachmentItem,
150
+ meta: CtxMeta,
151
+ prompt: str,
152
+ auto_index: bool
153
+ ) -> bool:
154
+ """
155
+ Upload file attachment
156
+
157
+ :param attachment: AttachmentItem
158
+ :param meta: CtxMeta
159
+ :param prompt: User input prompt
160
+ :param auto_index: Auto index
161
+ :return: True if uploaded
162
+ """
163
+ uploaded = False
164
+ if not self.is_allowed(attachment.path):
165
+ return False
166
+ if self.window.core.filesystem.packer.is_archive(attachment.path):
167
+ if self.is_verbose():
168
+ print("Unpacking archive: {}".format(attachment.path))
169
+ tmp_path = self.window.core.filesystem.packer.unpack(attachment.path)
170
+ if tmp_path:
171
+ for root, dirs, files in os.walk(tmp_path):
172
+ for file in files:
173
+ path = os.path.join(root, file)
174
+ sub_attachment = AttachmentItem()
175
+ sub_attachment.path = path
176
+ sub_attachment.name = os.path.basename(path)
177
+ sub_attachment.consumed = False
178
+ path_relative = os.path.relpath(path, tmp_path)
179
+ if self.is_allowed(str(path)):
180
+ if self.is_verbose():
181
+ print("Uploading unpacked from archive: {}".format(path_relative))
182
+ item = self.window.core.attachments.context.upload(
183
+ meta=meta,
184
+ attachment=sub_attachment,
185
+ prompt=prompt,
186
+ real_path=attachment.path,
187
+ auto_index=auto_index,
188
+ )
189
+ if item:
190
+ item["path"] = os.path.basename(attachment.path) + "/" + path_relative
191
+ item["size"] = os.path.getsize(path)
192
+ if meta.additional_ctx is None:
193
+ meta.additional_ctx = []
194
+ meta.additional_ctx.append(item)
195
+ uploaded = True
196
+ sub_attachment.consumed = True
197
+ attachment.consumed = True
198
+ self.window.core.filesystem.packer.remove_tmp(tmp_path) # clean
199
+ else:
200
+ item = self.window.core.attachments.context.upload(
201
+ meta=meta,
202
+ attachment=attachment,
203
+ prompt=prompt,
204
+ real_path=attachment.path,
205
+ auto_index=auto_index,
206
+ )
207
+ if item:
208
+ if meta.additional_ctx is None:
209
+ meta.additional_ctx = []
210
+ meta.additional_ctx.append(item)
211
+ attachment.consumed = True # allow for deletion
212
+ uploaded = True
213
+
214
+ return uploaded
215
+
216
+ def upload_web(
217
+ self,
218
+ attachment: AttachmentItem,
219
+ meta: CtxMeta,
220
+ prompt: str,
221
+ auto_index: bool
222
+ ) -> bool:
223
+ """
224
+ Upload web attachment
225
+
226
+ :param attachment: AttachmentItem
227
+ :param meta: CtxMeta
228
+ :param prompt: User input prompt
229
+ :param auto_index: Auto index
230
+ :return: True if uploaded
231
+ """
232
+ return self.upload_file(attachment, meta, prompt, auto_index)
233
+
178
234
  def has_context(self, meta: CtxMeta) -> bool:
179
235
  """
180
236
  Check if has additional context for attachment
@@ -218,6 +274,7 @@ class Attachment(QObject):
218
274
  if self.is_verbose():
219
275
  print("\nPreparing additional context...\nContext Mode: {}".format(self.mode))
220
276
 
277
+ self.window.core.attachments.context.reset()
221
278
  if self.mode == self.MODE_FULL_CONTEXT:
222
279
  content = self.get_full_context(ctx)
223
280
  elif self.mode == self.MODE_QUERY_CONTEXT:
@@ -225,6 +282,14 @@ class Attachment(QObject):
225
282
  elif self.mode == self.MODE_QUERY_CONTEXT_SUMMARY:
226
283
  content = self.get_context_summary(ctx)
227
284
 
285
+ # append used files and urls to context
286
+ files = self.window.core.attachments.context.get_used_files()
287
+ urls = self.window.core.attachments.context.get_used_urls()
288
+ if files:
289
+ ctx.files = files
290
+ if urls:
291
+ ctx.urls = urls
292
+
228
293
  if content:
229
294
  if self.is_verbose():
230
295
  print("\n--- Using additional context ---\n\n{}".format(content))
@@ -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.11.23 00:00:00 #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  class Confirm:
@@ -349,6 +349,18 @@ class Confirm:
349
349
  elif type == 'ctx.group':
350
350
  self.window.controller.ctx.create_group(name, id)
351
351
 
352
+ def accept_url(self, type: str, id: any, url: str):
353
+ """
354
+ Update URL provided
355
+
356
+ :param type: dialog type
357
+ :param id: dialog object id
358
+ :param url: URL
359
+ """
360
+ # add attachment
361
+ if type == 'attachment':
362
+ self.window.controller.attachment.add_url(url)
363
+
352
364
  def dismiss_rename(self):
353
365
  """Dismiss rename dialog"""
354
366
  self.window.ui.dialog['rename'].close()
@@ -356,3 +368,7 @@ class Confirm:
356
368
  def dismiss_create(self):
357
369
  """Dismiss create dialog"""
358
370
  self.window.ui.dialog['create'].close()
371
+
372
+ def dismiss_url(self):
373
+ """Dismiss url dialog"""
374
+ self.window.ui.dialog['url'].close()
@@ -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.11.23 00:00:00 #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -176,7 +176,8 @@ class Attachments:
176
176
  mode: str,
177
177
  name: str = None,
178
178
  path: str = None,
179
- auto_save: bool = True
179
+ auto_save: bool = True,
180
+ type: str = AttachmentItem.TYPE_FILE,
180
181
  ) -> AttachmentItem:
181
182
  """
182
183
  Create new attachment
@@ -185,16 +186,19 @@ class Attachments:
185
186
  :param name: name
186
187
  :param path: path
187
188
  :param auto_save: auto_save
189
+ :param type: type
188
190
  :return: AttachmentItem
189
191
  """
190
192
  # make local copy of external attachment if enabled
191
- if self.window.core.config.get("upload.store"):
192
- if not self.window.core.filesystem.in_work_dir(path):
193
- path = self.window.core.filesystem.store_upload(path)
193
+ if type == AttachmentItem.TYPE_FILE and path is not None:
194
+ if self.window.core.config.get("upload.store"):
195
+ if not self.window.core.filesystem.in_work_dir(path):
196
+ path = self.window.core.filesystem.store_upload(path)
194
197
 
195
198
  attachment = self.create()
196
199
  attachment.name = name
197
200
  attachment.path = path
201
+ attachment.type = type
198
202
 
199
203
  if mode not in self.items:
200
204
  self.items[mode] = {}
@@ -410,7 +414,7 @@ class Attachments:
410
414
  for mode in self.items:
411
415
  for id in self.items[mode]:
412
416
  attachment = self.items[mode][id]
413
- if attachment.path is not None:
417
+ if attachment.path is not None and attachment.type == AttachmentItem.TYPE_FILE:
414
418
  attachment.path = self.window.core.filesystem.to_workdir(
415
419
  attachment.path,
416
420
  )
@@ -422,7 +426,7 @@ class Attachments:
422
426
  for mode in data:
423
427
  for id in data[mode]:
424
428
  attachment = data[mode][id]
425
- if attachment.path is not None:
429
+ if attachment.path is not None and attachment.type == AttachmentItem.TYPE_FILE:
426
430
  attachment.path = self.window.core.filesystem.make_local(
427
431
  attachment.path,
428
432
  )