pygpt-net 2.4.42__py3-none-any.whl → 2.4.45__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 (71) hide show
  1. CHANGELOG.md +15 -0
  2. README.md +21 -2
  3. pygpt_net/CHANGELOG.txt +15 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/attachment.py +31 -3
  6. pygpt_net/controller/chat/attachment.py +37 -36
  7. pygpt_net/controller/config/placeholder.py +6 -4
  8. pygpt_net/controller/idx/common.py +7 -3
  9. pygpt_net/controller/lang/mapping.py +32 -9
  10. pygpt_net/core/attachments/__init__.py +7 -2
  11. pygpt_net/core/attachments/context.py +52 -34
  12. pygpt_net/core/db/__init__.py +2 -1
  13. pygpt_net/core/debug/attachments.py +1 -0
  14. pygpt_net/core/idx/__init__.py +8 -3
  15. pygpt_net/core/idx/indexing.py +24 -7
  16. pygpt_net/core/idx/ui/__init__.py +22 -0
  17. pygpt_net/core/idx/ui/loaders.py +217 -0
  18. pygpt_net/data/config/config.json +4 -4
  19. pygpt_net/data/config/models.json +3 -3
  20. pygpt_net/data/config/modes.json +3 -3
  21. pygpt_net/data/config/settings.json +5 -5
  22. pygpt_net/data/css/style.css +1 -0
  23. pygpt_net/data/locale/locale.de.ini +4 -4
  24. pygpt_net/data/locale/locale.en.ini +11 -9
  25. pygpt_net/data/locale/locale.es.ini +4 -4
  26. pygpt_net/data/locale/locale.fr.ini +4 -4
  27. pygpt_net/data/locale/locale.it.ini +4 -4
  28. pygpt_net/data/locale/locale.pl.ini +4 -4
  29. pygpt_net/data/locale/locale.uk.ini +4 -4
  30. pygpt_net/data/locale/locale.zh.ini +4 -4
  31. pygpt_net/data/locale/plugin.mailer.en.ini +5 -5
  32. pygpt_net/item/attachment.py +5 -1
  33. pygpt_net/item/ctx.py +99 -2
  34. pygpt_net/migrations/Version20241215110000.py +25 -0
  35. pygpt_net/migrations/__init__.py +3 -1
  36. pygpt_net/plugin/cmd_files/__init__.py +3 -2
  37. pygpt_net/provider/core/attachment/json_file.py +4 -1
  38. pygpt_net/provider/core/config/patch.py +12 -0
  39. pygpt_net/provider/core/ctx/db_sqlite/storage.py +50 -7
  40. pygpt_net/provider/core/ctx/db_sqlite/utils.py +29 -5
  41. pygpt_net/provider/loaders/base.py +14 -0
  42. pygpt_net/provider/loaders/hub/google/gmail.py +2 -2
  43. pygpt_net/provider/loaders/hub/yt/base.py +5 -0
  44. pygpt_net/provider/loaders/web_database.py +13 -5
  45. pygpt_net/provider/loaders/web_github_issues.py +18 -1
  46. pygpt_net/provider/loaders/web_github_repo.py +10 -0
  47. pygpt_net/provider/loaders/web_google_calendar.py +9 -1
  48. pygpt_net/provider/loaders/web_google_docs.py +6 -1
  49. pygpt_net/provider/loaders/web_google_drive.py +10 -1
  50. pygpt_net/provider/loaders/web_google_gmail.py +5 -3
  51. pygpt_net/provider/loaders/web_google_keep.py +5 -1
  52. pygpt_net/provider/loaders/web_google_sheets.py +5 -1
  53. pygpt_net/provider/loaders/web_microsoft_onedrive.py +15 -1
  54. pygpt_net/provider/loaders/web_page.py +4 -2
  55. pygpt_net/provider/loaders/web_rss.py +3 -1
  56. pygpt_net/provider/loaders/web_sitemap.py +9 -3
  57. pygpt_net/provider/loaders/web_twitter.py +4 -2
  58. pygpt_net/provider/loaders/web_yt.py +17 -2
  59. pygpt_net/provider/vector_stores/ctx_attachment.py +1 -1
  60. pygpt_net/tools/indexer/__init__.py +8 -40
  61. pygpt_net/tools/indexer/ui/web.py +33 -80
  62. pygpt_net/ui/layout/ctx/ctx_list.py +86 -18
  63. pygpt_net/ui/widget/dialog/url.py +162 -14
  64. pygpt_net/ui/widget/element/group.py +15 -2
  65. pygpt_net/ui/widget/lists/context.py +23 -9
  66. pygpt_net/utils.py +1 -1
  67. {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.45.dist-info}/METADATA +22 -3
  68. {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.45.dist-info}/RECORD +71 -68
  69. {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.45.dist-info}/LICENSE +0 -0
  70. {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.45.dist-info}/WHEEL +0 -0
  71. {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.45.dist-info}/entry_points.txt +0 -0
CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.4.45 (2024-12-16)
4
+
5
+ - Enhanced web data loaders UI.
6
+
7
+ ## 2.4.44 (2024-12-16)
8
+
9
+ - Enhanced web data loaders.
10
+ - Web loaders have been added to attachments, allowing external web content to be attached to context via the "+Web" button in the Attachments tab.
11
+ - Improved handling of attachments in groups and added an attachment icon when a group contains attachments.
12
+
13
+ ## 2.4.43 (2024-12-15)
14
+
15
+ - Fix: Bug on attachment upload.
16
+ - Added: Attachments uploaded in groups are now available for all contexts in the group (beta).
17
+
3
18
  ## 2.4.42 (2024-12-15)
4
19
 
5
20
  - Added Mailer plugin, which allows sending and retrieving emails from the server, and reading them. It currently supports only SMTP.
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.42** | build: **2024.12.15** | Python: **>=3.10, <3.12**
5
+ Release: **2.4.45** | build: **2024.12.16** | Python: **>=3.10, <3.12**
6
6
 
7
7
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
8
8
  >
@@ -785,6 +785,8 @@ You can use your own files (for example, to analyze them) during any conversatio
785
785
 
786
786
  **PyGPT** makes it simple for users to upload files and send them to the model for tasks like analysis, similar to attaching files in `ChatGPT`. There's a separate `Attachments` tab next to the text input area specifically for managing file uploads.
787
787
 
788
+ **Tip: Attachments uploaded in group are available in all contexts in group**.
789
+
788
790
  ![v2_file_input](https://github.com/user-attachments/assets/db8467b6-2d07-4e20-a795-430fc09443a7)
789
791
 
790
792
  You can use attachments to provide additional context to the conversation. Uploaded files will be converted into text using loaders from LlamaIndex, and then embedded into the vector store. You can upload any file format supported by the application through LlamaIndex. Supported formats include:
@@ -3260,8 +3262,10 @@ Allowed additional keyword arguments for built-in data loaders (Web and external
3260
3262
 
3261
3263
  **SQL Database** (web_database)
3262
3264
 
3263
- - `engine` - str, default: `None`
3264
3265
  - `uri` - str, default: `None`
3266
+
3267
+ You can provide a single URI in the form of: `{scheme}://{user}:{password}@{host}:{port}/{dbname}`, or you can provide each field manually:
3268
+
3265
3269
  - `scheme` - str, default: `None`
3266
3270
  - `host` - str, default: `None`
3267
3271
  - `port` - str, default: `None`
@@ -3934,6 +3938,21 @@ may consume additional tokens that are not displayed in the main window.
3934
3938
 
3935
3939
  ## Recent changes:
3936
3940
 
3941
+ **2.4.45 (2024-12-16)**
3942
+
3943
+ - Enhanced web data loaders UI.
3944
+
3945
+ **2.4.44 (2024-12-16)**
3946
+
3947
+ - Enhanced web data loaders.
3948
+ - Web loaders have been added to attachments, allowing external web content to be attached to context via the "+Web" button in the Attachments tab.
3949
+ - Improved handling of attachments in groups and added an attachment icon when a group contains attachments.
3950
+
3951
+ **2.4.43 (2024-12-15)**
3952
+
3953
+ - Fix: Bug on attachment upload.
3954
+ - Added: Attachments uploaded in groups are now available for all contexts in the group (beta).
3955
+
3937
3956
  **2.4.42 (2024-12-15)**
3938
3957
 
3939
3958
  - Added Mailer plugin, which allows sending and retrieving emails from the server, and reading them. It currently supports only SMTP.
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,18 @@
1
+ 2.4.45 (2024-12-16)
2
+
3
+ - Enhanced web data loaders UI.
4
+
5
+ 2.4.44 (2024-12-16)
6
+
7
+ - Enhanced web data loaders.
8
+ - Web loaders have been added to attachments, allowing external web content to be attached to context via the "+Web" button in the Attachments tab.
9
+ - Improved handling of attachments in groups and added an attachment icon when a group contains attachments.
10
+
11
+ 2.4.43 (2024-12-15)
12
+
13
+ - Fix: Bug on attachment upload.
14
+ - Added: Attachments uploaded in groups are now available for all contexts in the group (beta).
15
+
1
16
  2.4.42 (2024-12-15)
2
17
 
3
18
  - Added Mailer plugin, which allows sending and retrieving emails from the server, and reading them. It currently supports only SMTP.
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.12.15 04:00:00 #
9
+ # Updated Date: 2024.12.16 02: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.42"
17
- __build__ = "2024.12.15"
16
+ __version__ = "2.4.45"
17
+ __build__ = "2024.12.16"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __website__ = "https://pygpt.net"
@@ -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: 2024.12.16 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -293,10 +293,38 @@ class Attachment:
293
293
  def open_add_url(self):
294
294
  """Open add attachment URL dialog"""
295
295
  self.window.ui.dialog['url'].id = "attachment"
296
- self.window.ui.dialog['url'].input.setText("")
297
296
  self.window.ui.dialog['url'].current = ""
297
+ self.window.ui.dialog['url'].init()
298
+ self.window.ui.dialog['url'].resize(800, 400)
298
299
  self.window.ui.dialog['url'].show()
299
- self.window.ui.dialog['url'].input.setFocus()
300
+
301
+ def attach_url(self):
302
+ """Attach attachment URL"""
303
+ result, loader, input_params, input_config = self.window.core.idx.ui.loaders.handle_options(
304
+ self.window.ui.nodes["dialog.url.loader"],
305
+ "dialog.url.loader.option",
306
+ "dialog.url.loader.config",
307
+ )
308
+ extra = {
309
+ "loader": loader,
310
+ "input_params": input_params,
311
+ "input_config": input_config,
312
+ }
313
+ provider = self.window.core.idx.indexing.get_loader(loader)
314
+ if provider:
315
+ mode = self.window.core.config.get('mode')
316
+ name = provider.get_external_id(input_params)
317
+ attachment = self.window.core.attachments.new(
318
+ mode=mode,
319
+ name=name,
320
+ path=name,
321
+ auto_save=False,
322
+ type=AttachmentItem.TYPE_URL,
323
+ extra=extra,
324
+ )
325
+ self.window.core.attachments.save()
326
+ self.update()
327
+ self.window.ui.dialog['url'].close()
300
328
 
301
329
  def add_url(self, url: str):
302
330
  """
@@ -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: 2024.12.16 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -180,7 +180,7 @@ class Attachment(QObject):
180
180
  if tmp_path:
181
181
  for root, dirs, files in os.walk(tmp_path):
182
182
  for file in files:
183
- path = os.path.join(root, file)
183
+ path = str(os.path.join(root, file))
184
184
  sub_attachment = AttachmentItem()
185
185
  sub_attachment.path = path
186
186
  sub_attachment.name = os.path.basename(path)
@@ -197,11 +197,9 @@ class Attachment(QObject):
197
197
  auto_index=auto_index,
198
198
  )
199
199
  if item:
200
- item["path"] = os.path.basename(attachment.path) + "/" + path_relative
200
+ item["path"] = os.path.basename(attachment.path) + "/" + str(path_relative)
201
201
  item["size"] = os.path.getsize(path)
202
- if meta.additional_ctx is None:
203
- meta.additional_ctx = []
204
- meta.additional_ctx.append(item)
202
+ self.append_to_meta(meta, item)
205
203
  uploaded = True
206
204
  sub_attachment.consumed = True
207
205
  attachment.consumed = True
@@ -215,14 +213,27 @@ class Attachment(QObject):
215
213
  auto_index=auto_index,
216
214
  )
217
215
  if item:
218
- if meta.additional_ctx is None:
219
- meta.additional_ctx = []
220
- meta.additional_ctx.append(item)
216
+ self.append_to_meta(meta, item)
221
217
  attachment.consumed = True # allow for deletion
222
218
  uploaded = True
223
-
224
219
  return uploaded
225
220
 
221
+ def append_to_meta(self, meta: CtxMeta, item: Dict[str, Any]):
222
+ """
223
+ Append item to meta
224
+
225
+ :param meta: CtxMeta instance
226
+ :param item: Attachment item
227
+ """
228
+ if meta.group:
229
+ if meta.group.additional_ctx is None:
230
+ meta.group.additional_ctx = []
231
+ meta.group.additional_ctx.append(item)
232
+ return
233
+ if meta.additional_ctx is None:
234
+ meta.additional_ctx = []
235
+ meta.additional_ctx.append(item)
236
+
226
237
  def upload_web(
227
238
  self,
228
239
  attachment: AttachmentItem,
@@ -248,9 +259,9 @@ class Attachment(QObject):
248
259
  :param meta: CtxMeta
249
260
  :return: True if has context
250
261
  """
251
- if meta is None or meta.additional_ctx is None:
262
+ if meta is None:
252
263
  return False
253
- return len(meta.additional_ctx) > 0
264
+ return meta.has_additional_ctx()
254
265
 
255
266
  def current_has_context(self) -> bool:
256
267
  """
@@ -306,18 +317,6 @@ class Attachment(QObject):
306
317
  return "====================================\nADDITIONAL CONTEXT FROM ATTACHMENT(s): {}".format(content)
307
318
  return ""
308
319
 
309
- def get_uploaded_attachments(
310
- self,
311
- meta: CtxMeta
312
- ) -> List[Dict[str, Any]]:
313
- """
314
- Get uploaded attachments for meta
315
-
316
- :param meta: CtxMeta instance
317
- :return: List of attachments
318
- """
319
- return meta.additional_ctx
320
-
321
320
  def update(self):
322
321
  """Update attachments list"""
323
322
  mode = self.window.core.config.get("mode")
@@ -334,7 +333,7 @@ class Attachment(QObject):
334
333
  :param meta: CtxMeta instance
335
334
  """
336
335
  # update list of attachments
337
- if meta is None or meta.additional_ctx is None:
336
+ if meta is None or not meta.has_additional_ctx():
338
337
  items = []
339
338
  else:
340
339
  items = self.window.core.attachments.context.get_all(meta)
@@ -347,7 +346,7 @@ class Attachment(QObject):
347
346
 
348
347
  :param meta: CtxMeta instance
349
348
  """
350
- if meta is None or meta.additional_ctx is None:
349
+ if meta is None or not meta.has_additional_ctx():
351
350
  num_files = 0
352
351
  else:
353
352
  num_files = self.window.core.attachments.context.count(meta)
@@ -402,13 +401,14 @@ class Attachment(QObject):
402
401
  )
403
402
  return
404
403
  meta = self.window.core.ctx.get_current_meta()
405
- if meta is None or meta.additional_ctx is None:
404
+ if meta is None or not meta.has_additional_ctx():
406
405
  return
407
406
  items = self.window.core.attachments.context.get_all(meta)
408
407
  if idx < len(items):
409
408
  item = items[idx]
410
409
  self.window.core.attachments.context.delete(meta, item, delete_files=remove_local)
411
410
  self.update_list(meta)
411
+ self.window.controller.ctx.update()
412
412
 
413
413
  def clear(
414
414
  self,
@@ -432,10 +432,11 @@ class Attachment(QObject):
432
432
  return
433
433
 
434
434
  meta = self.window.core.ctx.get_current_meta()
435
- if meta is None or meta.additional_ctx is None:
435
+ if meta is None or not meta.has_additional_ctx():
436
436
  return
437
437
  self.window.core.attachments.context.clear(meta, delete_files=remove_local)
438
438
  self.update_list(meta)
439
+ self.window.controller.ctx.update()
439
440
 
440
441
  def select(self, idx: int):
441
442
  """
@@ -452,7 +453,7 @@ class Attachment(QObject):
452
453
  :param idx: Index on list
453
454
  """
454
455
  meta = self.window.core.ctx.get_current_meta()
455
- if meta is None or meta.additional_ctx is None:
456
+ if meta is None or not meta.has_additional_ctx():
456
457
  return
457
458
  items = self.window.core.attachments.context.get_all(meta)
458
459
  if idx < len(items):
@@ -471,7 +472,7 @@ class Attachment(QObject):
471
472
  :param idx: Index on list
472
473
  """
473
474
  meta = self.window.core.ctx.get_current_meta()
474
- if meta is None or meta.additional_ctx is None:
475
+ if meta is None or not meta.has_additional_ctx():
475
476
  return
476
477
  items = self.window.core.attachments.context.get_all(meta)
477
478
  if idx < len(items):
@@ -491,7 +492,7 @@ class Attachment(QObject):
491
492
  :param idx: Index on list
492
493
  """
493
494
  meta = self.window.core.ctx.get_current_meta()
494
- if meta is None or meta.additional_ctx is None:
495
+ if meta is None or not meta.has_additional_ctx():
495
496
  return
496
497
  items = self.window.core.attachments.context.get_all(meta)
497
498
  if idx < len(items):
@@ -510,7 +511,7 @@ class Attachment(QObject):
510
511
  :return: True if has file
511
512
  """
512
513
  meta = self.window.core.ctx.get_current_meta()
513
- if meta is None or meta.additional_ctx is None:
514
+ if meta is None or not meta.has_additional_ctx():
514
515
  return False
515
516
  items = self.window.core.attachments.context.get_all(meta)
516
517
  if idx < len(items):
@@ -529,7 +530,7 @@ class Attachment(QObject):
529
530
  :return: True if has source directory
530
531
  """
531
532
  meta = self.window.core.ctx.get_current_meta()
532
- if meta is None or meta.additional_ctx is None:
533
+ if meta is None or not meta.has_additional_ctx():
533
534
  return False
534
535
  items = self.window.core.attachments.context.get_all(meta)
535
536
  if idx < len(items):
@@ -549,7 +550,7 @@ class Attachment(QObject):
549
550
  :return: True if has destination directory
550
551
  """
551
552
  meta = self.window.core.ctx.get_current_meta()
552
- if meta is None or meta.additional_ctx is None:
553
+ if meta is None or not meta.has_additional_ctx():
553
554
  return False
554
555
  items = self.window.core.attachments.context.get_all(meta)
555
556
  if idx < len(items):
@@ -570,10 +571,10 @@ class Attachment(QObject):
570
571
  meta = self.window.core.ctx.get_current_meta()
571
572
  if meta is None:
572
573
  return 0
573
- if meta.additional_ctx is None:
574
+ if not meta.has_additional_ctx():
574
575
  return 0
575
576
  tokens = 0
576
- for item in meta.additional_ctx:
577
+ for item in meta.get_additional_ctx():
577
578
  if "tokens" in item:
578
579
  try:
579
580
  tokens += int(item["tokens"])
@@ -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 18:00:00 #
9
+ # Updated Date: 2024.12.16 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict, Any, List
@@ -279,7 +279,8 @@ class Placeholder:
279
279
  modes = self.window.core.agents.legacy.get_allowed_modes()
280
280
  data = []
281
281
  for id in modes:
282
- data.append({id: id}) # TODO: name
282
+ name = trans(f"mode.{id}")
283
+ data.append({id: name})
283
284
  return data
284
285
 
285
286
  def get_idx(self) -> List[Dict[str, str]]:
@@ -291,8 +292,9 @@ class Placeholder:
291
292
  indexes = self.window.core.idx.get_idx_ids()
292
293
  data = []
293
294
  data.append({'_': '---'})
294
- for id in indexes:
295
- data.append({id: id})
295
+ for item in indexes:
296
+ for k, v in item.items():
297
+ data.append({k: v})
296
298
  return data
297
299
 
298
300
  def get_syntax_styles(self) -> List[Dict[str, str]]:
@@ -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: 2024.12.16 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import List, Dict
@@ -50,13 +50,17 @@ class Common:
50
50
  ext_str = " (" + ", ".join(loader.extensions) + ")"
51
51
  # name = "(File) " + loader.name + ext_str # TODO: implement option names
52
52
  data.append({
53
- id: id
53
+ id: loader.name
54
54
  })
55
+ # sort by name
56
+ data = sorted(data, key=lambda x: list(x.values())[0])
55
57
  # web
56
58
  if "web" in loader.type:
57
59
  id = "web_" + id
58
60
  # name = "(Web) " + loader.name # TODO: implement option names
59
61
  data.append({
60
- id: id
62
+ id: loader.name
61
63
  })
64
+ # sort by name
65
+ data = sorted(data, key=lambda x: list(x.values())[0])
62
66
  return data
@@ -34,42 +34,66 @@ class Mapping:
34
34
  # nodes labels
35
35
  for k in self.mapping['nodes']:
36
36
  if k in self.window.ui.nodes:
37
- self.window.ui.nodes[k].setText(trans(self.mapping['nodes'][k]))
37
+ try:
38
+ self.window.ui.nodes[k].setText(trans(self.mapping['nodes'][k]))
39
+ except:
40
+ pass
38
41
 
39
42
  # menu title
40
43
  for k in self.mapping['menu.title']:
41
44
  if k in self.window.ui.menu:
42
- self.window.ui.menu[k].setTitle(trans(self.mapping['menu.title'][k]))
45
+ try:
46
+ self.window.ui.menu[k].setTitle(trans(self.mapping['menu.title'][k]))
47
+ except:
48
+ pass
43
49
 
44
50
  # menu text
45
51
  for k in self.mapping['menu.text']:
46
52
  if k in self.window.ui.menu:
47
- self.window.ui.menu[k].setText(trans(self.mapping['menu.text'][k]))
53
+ try:
54
+ self.window.ui.menu[k].setText(trans(self.mapping['menu.text'][k]))
55
+ except:
56
+ pass
48
57
 
49
58
  # menu tooltip
50
59
  for k in self.mapping['menu.tooltip']:
51
60
  if k in self.window.ui.menu:
52
- self.window.ui.menu[k].setToolTip(trans(self.mapping['menu.tooltip'][k]))
61
+ try:
62
+ self.window.ui.menu[k].setToolTip(trans(self.mapping['menu.tooltip'][k]))
63
+ except:
64
+ pass
53
65
 
54
66
  # dialog title
55
67
  for k in self.mapping['dialog.title']:
56
68
  if k in self.window.ui.dialog:
57
- self.window.ui.dialog[k].setWindowTitle(trans(self.mapping['dialog.title'][k]))
69
+ try:
70
+ self.window.ui.dialog[k].setWindowTitle(trans(self.mapping['dialog.title'][k]))
71
+ except:
72
+ pass
58
73
 
59
74
  # tooltip
60
75
  for k in self.mapping['tooltip']:
61
76
  if k in self.window.ui.nodes:
62
- self.window.ui.nodes[k].setToolTip(trans(self.mapping['tooltip'][k]))
77
+ try:
78
+ self.window.ui.nodes[k].setToolTip(trans(self.mapping['tooltip'][k]))
79
+ except:
80
+ pass
63
81
 
64
82
  # placeholder
65
83
  for k in self.mapping['placeholder']:
66
84
  if k in self.window.ui.nodes:
67
- self.window.ui.nodes[k].setPlaceholderText(trans(self.mapping['placeholder'][k]))
85
+ try:
86
+ self.window.ui.nodes[k].setPlaceholderText(trans(self.mapping['placeholder'][k]))
87
+ except:
88
+ pass
68
89
 
69
90
  # menu tab tools
70
91
  for k in self.window.controller.tools.get_tab_tools():
71
92
  if k in self.window.ui.menu:
72
- self.window.ui.menu[k].setText(trans("output.tab." + self.window.controller.tools.get_tab_tools()[k][0]))
93
+ try:
94
+ self.window.ui.menu[k].setText(trans("output.tab." + self.window.controller.tools.get_tab_tools()[k][0]))
95
+ except:
96
+ pass
73
97
 
74
98
  def get_mapping(self) -> Dict[str, Dict[str, str]]:
75
99
  """
@@ -313,7 +337,6 @@ class Mapping:
313
337
  nodes['tool.indexer.file.options.replace'] = 'tool.indexer.option.replace'
314
338
  nodes['tool.indexer.web.loader.label'] = 'tool.indexer.tab.web.loader'
315
339
  nodes['tool.indexer.web.options.label'] = 'tool.indexer.tab.web.source'
316
- nodes['tool.indexer.web.config.label'] = 'tool.indexer.tab.web.cfg'
317
340
  nodes['tool.indexer.web.options.replace'] = 'tool.indexer.option.replace'
318
341
  nodes['tool.indexer.file.header.tip'] = 'tool.indexer.tab.files.tip'
319
342
  nodes['tool.indexer.web.header.tip'] = 'tool.indexer.tab.web.tip'
@@ -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: 2024.12.16 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -161,7 +161,7 @@ class Attachments:
161
161
  if meta is None:
162
162
  return []
163
163
  attachments = []
164
- for attachment in meta.additional_ctx:
164
+ for attachment in meta.get_additional_ctx():
165
165
  item = AttachmentItem()
166
166
  if 'uuid' not in attachment:
167
167
  continue
@@ -187,6 +187,7 @@ class Attachments:
187
187
  path: Optional[str] = None,
188
188
  auto_save: bool = True,
189
189
  type: str = AttachmentItem.TYPE_FILE,
190
+ extra: Optional[dict] = None
190
191
  ) -> AttachmentItem:
191
192
  """
192
193
  Create new attachment
@@ -196,6 +197,7 @@ class Attachments:
196
197
  :param path: path
197
198
  :param auto_save: auto_save
198
199
  :param type: type
200
+ :param extra: extra data
199
201
  :return: AttachmentItem
200
202
  """
201
203
  # make local copy of external attachment if enabled
@@ -209,6 +211,9 @@ class Attachments:
209
211
  attachment.path = path
210
212
  attachment.type = type
211
213
 
214
+ if extra is not None:
215
+ attachment.extra = extra
216
+
212
217
  if mode not in self.items:
213
218
  self.items[mode] = {}
214
219