pygpt-net 2.4.30__py3-none-any.whl → 2.4.34__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 (126) hide show
  1. CHANGELOG.md +24 -0
  2. README.md +46 -5
  3. pygpt_net/CHANGELOG.txt +24 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/access/__init__.py +5 -5
  6. pygpt_net/controller/access/control.py +3 -2
  7. pygpt_net/controller/attachment.py +67 -1
  8. pygpt_net/controller/audio/__init__.py +34 -6
  9. pygpt_net/controller/chat/__init__.py +3 -1
  10. pygpt_net/controller/chat/attachment.py +239 -37
  11. pygpt_net/controller/chat/audio.py +99 -0
  12. pygpt_net/controller/chat/input.py +10 -3
  13. pygpt_net/controller/chat/output.py +4 -1
  14. pygpt_net/controller/chat/text.py +7 -3
  15. pygpt_net/controller/dialogs/confirm.py +17 -1
  16. pygpt_net/controller/lang/custom.py +3 -1
  17. pygpt_net/controller/mode.py +2 -1
  18. pygpt_net/controller/presets/editor.py +11 -2
  19. pygpt_net/core/access/voice.py +2 -2
  20. pygpt_net/core/agents/legacy.py +3 -1
  21. pygpt_net/core/attachments/__init__.py +11 -7
  22. pygpt_net/core/attachments/context.py +226 -44
  23. pygpt_net/core/{audio.py → audio/__init__.py} +1 -1
  24. pygpt_net/core/audio/context.py +34 -0
  25. pygpt_net/core/bridge/context.py +29 -1
  26. pygpt_net/core/ctx/__init__.py +4 -1
  27. pygpt_net/core/db/__init__.py +4 -2
  28. pygpt_net/core/debug/attachments.py +3 -1
  29. pygpt_net/core/debug/context.py +5 -1
  30. pygpt_net/core/debug/presets.py +3 -1
  31. pygpt_net/core/events/event.py +2 -1
  32. pygpt_net/core/experts/__init__.py +3 -1
  33. pygpt_net/core/idx/chat.py +28 -6
  34. pygpt_net/core/idx/indexing.py +123 -15
  35. pygpt_net/core/modes.py +3 -1
  36. pygpt_net/core/presets.py +13 -2
  37. pygpt_net/core/render/markdown/pid.py +2 -1
  38. pygpt_net/core/render/plain/pid.py +2 -1
  39. pygpt_net/core/render/web/body.py +34 -12
  40. pygpt_net/core/render/web/pid.py +2 -1
  41. pygpt_net/core/render/web/renderer.py +8 -3
  42. pygpt_net/core/tokens.py +4 -2
  43. pygpt_net/core/types/mode.py +2 -1
  44. pygpt_net/data/config/config.json +5 -3
  45. pygpt_net/data/config/models.json +190 -5
  46. pygpt_net/data/config/modes.json +11 -5
  47. pygpt_net/data/config/presets/current.audio.json +34 -0
  48. pygpt_net/data/config/settings.json +15 -1
  49. pygpt_net/data/css/web.css +70 -0
  50. pygpt_net/data/css/web.dark.css +4 -1
  51. pygpt_net/data/css/web.light.css +1 -1
  52. pygpt_net/data/locale/locale.de.ini +26 -13
  53. pygpt_net/data/locale/locale.en.ini +61 -46
  54. pygpt_net/data/locale/locale.es.ini +26 -13
  55. pygpt_net/data/locale/locale.fr.ini +28 -15
  56. pygpt_net/data/locale/locale.it.ini +26 -13
  57. pygpt_net/data/locale/locale.pl.ini +30 -17
  58. pygpt_net/data/locale/locale.uk.ini +26 -13
  59. pygpt_net/data/locale/locale.zh.ini +33 -20
  60. pygpt_net/data/locale/plugin.cmd_files.de.ini +4 -4
  61. pygpt_net/data/locale/plugin.cmd_files.en.ini +4 -4
  62. pygpt_net/data/locale/plugin.cmd_files.es.ini +4 -4
  63. pygpt_net/data/locale/plugin.cmd_files.fr.ini +4 -4
  64. pygpt_net/data/locale/plugin.cmd_files.it.ini +4 -4
  65. pygpt_net/data/locale/plugin.cmd_files.pl.ini +4 -4
  66. pygpt_net/data/locale/plugin.cmd_files.uk.ini +4 -4
  67. pygpt_net/data/locale/plugin.cmd_files.zh.ini +4 -4
  68. pygpt_net/data/locale/plugin.cmd_web.de.ini +5 -5
  69. pygpt_net/data/locale/plugin.cmd_web.en.ini +5 -5
  70. pygpt_net/data/locale/plugin.cmd_web.es.ini +5 -5
  71. pygpt_net/data/locale/plugin.cmd_web.fr.ini +5 -5
  72. pygpt_net/data/locale/plugin.cmd_web.it.ini +5 -5
  73. pygpt_net/data/locale/plugin.cmd_web.pl.ini +5 -5
  74. pygpt_net/data/locale/plugin.cmd_web.uk.ini +5 -5
  75. pygpt_net/data/locale/plugin.cmd_web.zh.ini +5 -5
  76. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +12 -12
  77. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +12 -12
  78. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +12 -12
  79. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +12 -12
  80. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +12 -12
  81. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +12 -12
  82. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +12 -12
  83. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +12 -12
  84. pygpt_net/item/attachment.py +9 -1
  85. pygpt_net/item/ctx.py +9 -1
  86. pygpt_net/item/preset.py +5 -1
  87. pygpt_net/launcher.py +3 -1
  88. pygpt_net/migrations/Version20241126170000.py +28 -0
  89. pygpt_net/migrations/__init__.py +3 -1
  90. pygpt_net/plugin/audio_input/__init__.py +11 -1
  91. pygpt_net/plugin/audio_input/worker.py +9 -1
  92. pygpt_net/plugin/audio_output/__init__.py +37 -7
  93. pygpt_net/plugin/audio_output/worker.py +38 -41
  94. pygpt_net/plugin/cmd_code_interpreter/runner.py +2 -2
  95. pygpt_net/plugin/cmd_mouse_control/__init__.py +4 -2
  96. pygpt_net/plugin/openai_dalle/__init__.py +3 -1
  97. pygpt_net/plugin/openai_vision/__init__.py +3 -1
  98. pygpt_net/provider/core/attachment/json_file.py +4 -1
  99. pygpt_net/provider/core/config/patch.py +16 -0
  100. pygpt_net/provider/core/ctx/db_sqlite/storage.py +14 -4
  101. pygpt_net/provider/core/ctx/db_sqlite/utils.py +19 -2
  102. pygpt_net/provider/core/model/patch.py +7 -1
  103. pygpt_net/provider/core/preset/json_file.py +5 -1
  104. pygpt_net/provider/gpt/__init__.py +14 -2
  105. pygpt_net/provider/gpt/audio.py +63 -0
  106. pygpt_net/provider/gpt/chat.py +76 -44
  107. pygpt_net/provider/gpt/utils.py +27 -0
  108. pygpt_net/provider/gpt/vision.py +37 -15
  109. pygpt_net/provider/loaders/base.py +10 -1
  110. pygpt_net/provider/loaders/web_yt.py +19 -1
  111. pygpt_net/tools/image_viewer/ui/dialogs.py +3 -1
  112. pygpt_net/ui/dialog/preset.py +3 -1
  113. pygpt_net/ui/dialog/url.py +29 -0
  114. pygpt_net/ui/dialogs.py +5 -1
  115. pygpt_net/ui/layout/chat/attachments.py +42 -6
  116. pygpt_net/ui/layout/chat/attachments_ctx.py +14 -4
  117. pygpt_net/ui/layout/chat/attachments_uploaded.py +8 -4
  118. pygpt_net/ui/widget/dialog/url.py +59 -0
  119. pygpt_net/ui/widget/lists/attachment.py +22 -17
  120. pygpt_net/ui/widget/lists/attachment_ctx.py +65 -3
  121. pygpt_net/ui/widget/textarea/url.py +43 -0
  122. {pygpt_net-2.4.30.dist-info → pygpt_net-2.4.34.dist-info}/METADATA +48 -7
  123. {pygpt_net-2.4.30.dist-info → pygpt_net-2.4.34.dist-info}/RECORD +126 -117
  124. {pygpt_net-2.4.30.dist-info → pygpt_net-2.4.34.dist-info}/LICENSE +0 -0
  125. {pygpt_net-2.4.30.dist-info → pygpt_net-2.4.34.dist-info}/WHEEL +0 -0
  126. {pygpt_net-2.4.30.dist-info → pygpt_net-2.4.34.dist-info}/entry_points.txt +0 -0
@@ -6,18 +6,20 @@
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
 
14
- from PySide6.QtGui import QStandardItemModel, Qt
14
+ from PySide6.QtGui import QStandardItemModel, Qt, QIcon
15
15
  from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QCheckBox, QWidget
16
16
 
17
+ from pygpt_net.item.attachment import AttachmentItem
17
18
  from pygpt_net.ui.widget.element.labels import HelpLabel
18
19
  from pygpt_net.ui.widget.lists.attachment import AttachmentList
19
20
  from pygpt_net.utils import trans
20
21
 
22
+ import pygpt_net.icons_rc
21
23
 
22
24
  class Attachments:
23
25
  def __init__(self, window=None):
@@ -38,12 +40,21 @@ class Attachments:
38
40
  self.setup_attachments()
39
41
  self.setup_buttons()
40
42
 
43
+ empty_widget = QWidget()
44
+ self.window.ui.nodes['input.attachments.options.label'] = HelpLabel(trans("attachments.options.label"))
45
+
41
46
  # buttons layout
42
47
  buttons = QHBoxLayout()
43
48
  buttons.addWidget(self.window.ui.nodes['attachments.btn.add'])
49
+ buttons.addWidget(self.window.ui.nodes['attachments.btn.add_url'])
44
50
  buttons.addWidget(self.window.ui.nodes['attachments.btn.clear'])
51
+ buttons.addWidget(empty_widget)
52
+ buttons.addWidget(self.window.ui.nodes['input.attachments.options.label'])
53
+
54
+ buttons.addWidget(self.setup_auto_index())
45
55
  buttons.addWidget(self.setup_send_clear())
46
56
  buttons.addWidget(self.setup_capture_clear())
57
+ buttons.addStretch()
47
58
 
48
59
  self.window.ui.nodes['tip.input.attachments'] = HelpLabel(trans('tip.input.attachments'), self.window)
49
60
 
@@ -88,15 +99,34 @@ class Attachments:
88
99
 
89
100
  return widget
90
101
 
102
+ def setup_auto_index(self) -> QWidget:
103
+ """
104
+ Setup auto index checkbox
105
+
106
+ :return: QWidget
107
+ """
108
+ layout = QHBoxLayout()
109
+ layout.setContentsMargins(0, 0, 0, 0)
110
+ layout.setAlignment(Qt.AlignCenter)
111
+ layout.addWidget(self.window.ui.nodes['attachments.auto_index'])
112
+
113
+ widget = QWidget()
114
+ widget.setLayout(layout)
115
+
116
+ return widget
117
+
91
118
  def setup_buttons(self):
92
119
  """
93
120
  Setup buttons
94
121
  """
95
- self.window.ui.nodes['attachments.btn.add'] = QPushButton(trans('attachments.btn.add'))
96
- self.window.ui.nodes['attachments.btn.clear'] = QPushButton(trans('attachments.btn.clear'))
122
+ self.window.ui.nodes['attachments.btn.add'] = QPushButton(QIcon(":/icons/add.svg"), trans('attachments.btn.add'))
123
+ self.window.ui.nodes['attachments.btn.add_url'] = QPushButton(QIcon(":/icons/add.svg"), trans('attachments.btn.add_url'))
124
+ self.window.ui.nodes['attachments.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments.btn.clear'))
97
125
 
98
126
  self.window.ui.nodes['attachments.btn.add'].clicked.connect(
99
127
  lambda: self.window.controller.attachment.open_add())
128
+ self.window.ui.nodes['attachments.btn.add_url'].clicked.connect(
129
+ lambda: self.window.controller.attachment.open_add_url())
100
130
  self.window.ui.nodes['attachments.btn.clear'].clicked.connect(
101
131
  lambda: self.window.controller.attachment.clear(remove_local=True))
102
132
 
@@ -110,6 +140,11 @@ class Attachments:
110
140
  lambda: self.window.controller.attachment.toggle_capture_clear(
111
141
  self.window.ui.nodes['attachments.capture_clear'].isChecked()))
112
142
 
143
+ self.window.ui.nodes['attachments.auto_index'] = QCheckBox(trans('attachments.auto_index'))
144
+ self.window.ui.nodes['attachments.auto_index'].stateChanged.connect(
145
+ lambda: self.window.controller.attachment.toggle_auto_index(
146
+ self.window.ui.nodes['attachments.auto_index'].isChecked()))
147
+
113
148
  def setup_attachments(self):
114
149
  """
115
150
  Setup attachments list
@@ -144,8 +179,9 @@ class Attachments:
144
179
  for id in data:
145
180
  path = data[id].path
146
181
  size = ""
147
- if path and os.path.exists(path):
148
- size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
182
+ if data[id].type == AttachmentItem.TYPE_FILE:
183
+ if path and os.path.exists(path):
184
+ size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
149
185
  ctx_str = ""
150
186
  if data[id].ctx:
151
187
  ctx_str = "YES"
@@ -6,19 +6,20 @@
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
 
14
14
  from PySide6 import QtCore
15
- from PySide6.QtGui import QStandardItemModel, Qt
15
+ from PySide6.QtGui import QStandardItemModel, Qt, QIcon
16
16
  from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QWidget, QRadioButton
17
17
 
18
18
  from pygpt_net.ui.widget.element.labels import HelpLabel
19
19
  from pygpt_net.ui.widget.lists.attachment_ctx import AttachmentCtxList
20
20
  from pygpt_net.utils import trans
21
21
 
22
+ import pygpt_net.icons_rc
22
23
 
23
24
  class AttachmentsCtx:
24
25
  def __init__(self, window=None):
@@ -90,7 +91,7 @@ class AttachmentsCtx:
90
91
  self.window.ui.nodes[self.id] = AttachmentCtxList(self.window)
91
92
 
92
93
  # buttons
93
- self.window.ui.nodes['attachments_ctx.btn.clear'] = QPushButton(trans('attachments_uploaded.btn.clear'))
94
+ self.window.ui.nodes['attachments_ctx.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments_uploaded.btn.clear'))
94
95
  self.window.ui.nodes['attachments_ctx.btn.clear'].clicked.connect(
95
96
  lambda: self.window.controller.chat.attachment.clear()
96
97
  )
@@ -105,11 +106,12 @@ class AttachmentsCtx:
105
106
  :param parent: parent widget
106
107
  :return: QStandardItemModel
107
108
  """
108
- model = QStandardItemModel(0, 4, parent)
109
+ model = QStandardItemModel(0, 5, parent)
109
110
  model.setHeaderData(0, Qt.Horizontal, trans('attachments.header.name'))
110
111
  model.setHeaderData(1, Qt.Horizontal, trans('attachments.header.path'))
111
112
  model.setHeaderData(2, Qt.Horizontal, trans('attachments.header.size'))
112
113
  model.setHeaderData(3, Qt.Horizontal, trans('attachments.header.length'))
114
+ model.setHeaderData(4, Qt.Horizontal, trans('attachments.header.idx'))
113
115
  return model
114
116
 
115
117
  def update(self, data):
@@ -121,6 +123,7 @@ class AttachmentsCtx:
121
123
  self.window.ui.models[self.id].removeRows(0, self.window.ui.models[self.id].rowCount())
122
124
  i = 0
123
125
  for item in data:
126
+ indexed = False
124
127
  name = "No name"
125
128
  if 'name' in item:
126
129
  name = item['name']
@@ -136,6 +139,12 @@ class AttachmentsCtx:
136
139
  length = str(item['length'])
137
140
  if 'tokens' in item:
138
141
  length += ' / ~' + str(item['tokens'])
142
+ if 'indexed' in item and item['indexed']:
143
+ indexed = True
144
+
145
+ idx_str = ""
146
+ if indexed:
147
+ idx_str = trans("attachments.ctx.indexed")
139
148
 
140
149
  if os.path.exists(path):
141
150
  size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
@@ -149,4 +158,5 @@ class AttachmentsCtx:
149
158
  self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 1), path)
150
159
  self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 2), size)
151
160
  self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 3), length)
161
+ self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 4), idx_str)
152
162
  i += 1
@@ -12,7 +12,7 @@
12
12
  import os
13
13
 
14
14
  from PySide6 import QtCore
15
- from PySide6.QtGui import QStandardItemModel, Qt
15
+ from PySide6.QtGui import QStandardItemModel, Qt, QIcon
16
16
  from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QCheckBox, QLabel, QWidget
17
17
 
18
18
  from pygpt_net.ui.widget.element.button import SyncButton
@@ -20,6 +20,7 @@ from pygpt_net.ui.widget.element.labels import HelpLabel
20
20
  from pygpt_net.ui.widget.lists.uploaded import UploadedFileList
21
21
  from pygpt_net.utils import trans
22
22
 
23
+ import pygpt_net.icons_rc
23
24
 
24
25
  class AttachmentsUploaded:
25
26
  def __init__(self, window=None):
@@ -38,10 +39,11 @@ class AttachmentsUploaded:
38
39
  :return: QVBoxLayout
39
40
  """
40
41
  self.setup_attachments()
42
+ empty_widget = QWidget()
41
43
 
42
- self.window.ui.nodes['attachments_uploaded.sync.tip'] = QLabel(trans('attachments_uploaded.sync.tip'))
44
+ self.window.ui.nodes['attachments_uploaded.sync.tip'] = HelpLabel(trans('attachments_uploaded.sync.tip'))
45
+ self.window.ui.nodes['attachments_uploaded.sync.tip'].setWordWrap(False)
43
46
  self.window.ui.nodes['attachments_uploaded.sync.tip'].setAlignment(Qt.AlignCenter)
44
- empty_widget = QWidget()
45
47
 
46
48
  self.window.ui.nodes['tip.input.attachments.uploaded'] = HelpLabel(trans('tip.input.attachments.uploaded'),
47
49
  self.window)
@@ -52,6 +54,8 @@ class AttachmentsUploaded:
52
54
  buttons_layout.addWidget(self.window.ui.nodes['attachments_uploaded.btn.clear'])
53
55
  buttons_layout.addWidget(empty_widget)
54
56
  buttons_layout.addWidget(self.window.ui.nodes['attachments_uploaded.sync.tip'])
57
+ buttons_layout.addStretch()
58
+
55
59
 
56
60
  # layout
57
61
  layout = QVBoxLayout()
@@ -70,7 +74,7 @@ class AttachmentsUploaded:
70
74
 
71
75
  # buttons
72
76
  self.window.ui.nodes['attachments_uploaded.btn.sync'] = SyncButton(trans('attachments_uploaded.btn.sync'), self.window)
73
- self.window.ui.nodes['attachments_uploaded.btn.clear'] = QPushButton(trans('attachments_uploaded.btn.clear'))
77
+ self.window.ui.nodes['attachments_uploaded.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments_uploaded.btn.clear'))
74
78
  self.window.ui.nodes['attachments_uploaded.btn.clear'].clicked.connect(
75
79
  lambda: self.window.controller.assistant.files.clear()
76
80
  )
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
+ # ================================================== #
11
+
12
+ from PySide6.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton
13
+
14
+ from pygpt_net.ui.widget.element.labels import HelpLabel
15
+ from pygpt_net.utils import trans
16
+ from pygpt_net.ui.widget.textarea.url import UrlInput
17
+
18
+
19
+ class UrlDialog(QDialog):
20
+ def __init__(self, window=None, id=None):
21
+ """
22
+ Url dialog
23
+
24
+ :param window: main window
25
+ :param id: info window id
26
+ """
27
+ super(UrlDialog, self).__init__(window)
28
+ self.window = window
29
+ self.id = id
30
+ self.current = None
31
+ self.input = UrlInput(window, id)
32
+ self.input.setMinimumWidth(400)
33
+
34
+ self.window.ui.nodes['dialog.url.btn.update'] = QPushButton(trans('dialog.url.update'))
35
+ self.window.ui.nodes['dialog.url.btn.update'].clicked.connect(
36
+ lambda: self.window.controller.dialogs.confirm.accept_url(
37
+ self.id,
38
+ self.window.ui.dialog['url'].current,
39
+ self.input.text()),
40
+ )
41
+
42
+ self.window.ui.nodes['dialog.url.btn.dismiss'] = QPushButton(trans('dialog.url.dismiss'))
43
+ self.window.ui.nodes['dialog.url.btn.dismiss'].clicked.connect(
44
+ lambda: self.window.controller.dialogs.confirm.dismiss_url())
45
+
46
+ bottom = QHBoxLayout()
47
+ bottom.addWidget(self.window.ui.nodes['dialog.url.btn.dismiss'])
48
+ bottom.addWidget(self.window.ui.nodes['dialog.url.btn.update'])
49
+
50
+ self.window.ui.nodes['dialog.url.label'] = QLabel(trans("dialog.url.title"))
51
+ self.window.ui.nodes['dialog.url.tip'] = HelpLabel(trans("dialog.url.tip"))
52
+
53
+ layout = QVBoxLayout()
54
+ layout.addWidget(self.window.ui.nodes['dialog.url.label'])
55
+ layout.addWidget(self.input)
56
+ layout.addWidget(self.window.ui.nodes['dialog.url.tip'])
57
+ layout.addLayout(bottom)
58
+
59
+ self.setLayout(layout)
@@ -6,13 +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: 2024.11.23 00:00:00 #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
13
13
  from PySide6.QtGui import QAction, QIcon, QResizeEvent, QImage
14
14
  from PySide6.QtWidgets import QMenu, QApplication, QHeaderView
15
15
 
16
+ from pygpt_net.item.attachment import AttachmentItem
16
17
  from pygpt_net.ui.widget.lists.base import BaseList
17
18
  from pygpt_net.utils import trans
18
19
  import pygpt_net.icons_rc
@@ -91,9 +92,12 @@ class AttachmentList(BaseList):
91
92
  idx = item.row()
92
93
  preview_actions = []
93
94
  path = None
95
+ attachment = None
94
96
 
95
97
  if idx >= 0:
96
- path = self.window.controller.attachment.get_path_by_idx(mode, idx)
98
+ attachment = self.window.controller.attachment.get_by_idx(mode, idx)
99
+ if attachment:
100
+ path = attachment.path
97
101
  preview_actions = []
98
102
  if self.window.core.filesystem.actions.has_preview(path):
99
103
  preview_actions = self.window.core.filesystem.actions.get_preview(self, path)
@@ -116,21 +120,22 @@ class AttachmentList(BaseList):
116
120
  lambda: self.action_delete(event))
117
121
 
118
122
  menu = QMenu(self)
119
- if idx >= 0 and preview_actions:
120
- for action in preview_actions:
121
- menu.addAction(action)
122
- menu.addAction(actions['open'])
123
- menu.addAction(actions['open_dir'])
124
-
125
- if idx >= 0:
126
- if self.window.core.filesystem.actions.has_use(path):
127
- use_actions = self.window.core.filesystem.actions.get_use(self, path)
128
- use_menu = QMenu(trans('action.use'), self)
129
- for action in use_actions:
130
- use_menu.addAction(action)
131
- menu.addMenu(use_menu)
132
-
133
- menu.addAction(actions['rename'])
123
+ if attachment and attachment.type == AttachmentItem.TYPE_FILE:
124
+ if idx >= 0 and preview_actions:
125
+ for action in preview_actions:
126
+ menu.addAction(action)
127
+
128
+ menu.addAction(actions['open'])
129
+ menu.addAction(actions['open_dir'])
130
+ if idx >= 0:
131
+ if self.window.core.filesystem.actions.has_use(path):
132
+ use_actions = self.window.core.filesystem.actions.get_use(self, path)
133
+ use_menu = QMenu(trans('action.use'), self)
134
+ for action in use_actions:
135
+ use_menu.addAction(action)
136
+ menu.addMenu(use_menu)
137
+
138
+ menu.addAction(actions['rename'])
134
139
  menu.addAction(actions['delete'])
135
140
 
136
141
  if idx >= 0:
@@ -85,18 +85,47 @@ class AttachmentCtxList(BaseList):
85
85
  """
86
86
  actions = {}
87
87
 
88
+ item = self.indexAt(event.pos())
89
+ idx = item.row()
90
+
91
+ has_file = False
92
+ has_src = False
93
+ has_dest = False
94
+
95
+ if idx >= 0:
96
+ has_file = self.window.controller.chat.attachment.has_file_by_idx(idx)
97
+ has_src = self.window.controller.chat.attachment.has_src_by_idx(idx)
98
+ has_dest = self.window.controller.chat.attachment.has_dest_by_idx(idx)
99
+
100
+ actions['open'] = QAction(QIcon(":/icons/view.svg"), trans('action.open'), self)
101
+ actions['open'].triggered.connect(
102
+ lambda: self.action_open(event)
103
+ )
104
+ actions['open_dir_src'] = QAction(QIcon(":/icons/folder.svg"), trans('action.open_dir_src'), self)
105
+ actions['open_dir_src'].triggered.connect(
106
+ lambda: self.action_open_dir_src(event)
107
+ )
108
+ actions['open_dir_dest'] = QAction(QIcon(":/icons/folder.svg"), trans('action.open_dir_storage'), self)
109
+ actions['open_dir_dest'].triggered.connect(
110
+ lambda: self.action_open_dir_dest(event)
111
+ )
112
+
88
113
  actions['delete'] = QAction(QIcon(":/icons/delete.svg"), trans('action.delete'), self)
89
114
  actions['delete'].triggered.connect(
90
115
  lambda: self.action_delete(event)
91
116
  )
92
117
 
93
118
  menu = QMenu(self)
119
+ if has_file:
120
+ menu.addAction(actions['open'])
121
+ if has_src:
122
+ menu.addAction(actions['open_dir_src'])
123
+ if has_dest:
124
+ menu.addAction(actions['open_dir_dest'])
94
125
  menu.addAction(actions['delete'])
95
126
 
96
- item = self.indexAt(event.pos())
97
- idx = item.row()
98
127
  if idx >= 0:
99
- self.window.controller.assistant.files.select(item.row())
128
+ self.window.controller.chat.attachment.select(item.row())
100
129
  menu.exec_(event.globalPos())
101
130
 
102
131
  def action_delete(self, event):
@@ -109,3 +138,36 @@ class AttachmentCtxList(BaseList):
109
138
  idx = item.row()
110
139
  if idx >= 0:
111
140
  self.window.controller.chat.attachment.delete_by_idx(idx)
141
+
142
+ def action_open(self, event):
143
+ """
144
+ Open action handler
145
+
146
+ :param event: mouse event
147
+ """
148
+ item = self.indexAt(event.pos())
149
+ idx = item.row()
150
+ if idx >= 0:
151
+ self.window.controller.chat.attachment.open_by_idx(idx)
152
+
153
+ def action_open_dir_src(self, event):
154
+ """
155
+ Open source directory action handler
156
+
157
+ :param event: mouse event
158
+ """
159
+ item = self.indexAt(event.pos())
160
+ idx = item.row()
161
+ if idx >= 0:
162
+ self.window.controller.chat.attachment.open_dir_src_by_idx(idx)
163
+
164
+ def action_open_dir_dest(self, event):
165
+ """
166
+ Open destination directory action handler
167
+
168
+ :param event: mouse event
169
+ """
170
+ item = self.indexAt(event.pos())
171
+ idx = item.row()
172
+ if idx >= 0:
173
+ self.window.controller.chat.attachment.open_dir_dest_by_idx(idx)
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2024.11.26 02:00:00 #
10
+ # ================================================== #
11
+
12
+ from PySide6 import QtCore
13
+ from PySide6.QtWidgets import QLineEdit
14
+
15
+
16
+ class UrlInput(QLineEdit):
17
+ def __init__(self, window=None, id=None):
18
+ """
19
+ Url dialog input
20
+
21
+ :param window: main window
22
+ :param id: info window id
23
+ """
24
+ super(UrlInput, self).__init__(window)
25
+
26
+ self.window = window
27
+ self.id = id
28
+
29
+ def keyPressEvent(self, event):
30
+ """
31
+ Key press event
32
+
33
+ :param event: key event
34
+ """
35
+ super(UrlInput, self).keyPressEvent(event)
36
+
37
+ # save on Enter
38
+ if event.key() == QtCore.Qt.Key_Return or event.key() == QtCore.Qt.Key_Enter:
39
+ self.window.controller.dialogs.confirm.accept_url(
40
+ self.window.ui.dialog['url'].id,
41
+ self.window.ui.dialog['url'].current,
42
+ self.text(),
43
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pygpt-net
3
- Version: 2.4.30
3
+ Version: 2.4.34
4
4
  Summary: Desktop AI Assistant powered by models: OpenAI o1, GPT-4o, GPT-4, GPT-4 Vision, GPT-3.5, DALL-E 3, Llama 3, Mistral, Gemini, Claude, Bielik, and other models supported by Langchain, Llama Index, and Ollama. Features include chatbot, text completion, image generation, vision analysis, speech-to-text, internet access, file handling, command execution and more.
5
5
  Home-page: https://pygpt.net
6
6
  License: MIT
@@ -66,7 +66,7 @@ Requires-Dist: llama-index-vector-stores-pinecone (>=0.1.3,<0.2.0)
66
66
  Requires-Dist: llama-index-vector-stores-redis (>=0.1.2,<0.2.0)
67
67
  Requires-Dist: mss (>=9.0.2,<10.0.0)
68
68
  Requires-Dist: nbconvert (>=7.16.1,<8.0.0)
69
- Requires-Dist: openai (>=1.41.0,<1.60.0)
69
+ Requires-Dist: openai (>=1.55.1,<1.60.0)
70
70
  Requires-Dist: opencv-python (>=4.9.0.80,<5.0.0.0)
71
71
  Requires-Dist: packaging (>=23.2,<24.0)
72
72
  Requires-Dist: pandas (>=2.2.0,<3.0.0)
@@ -92,7 +92,7 @@ Description-Content-Type: text/markdown
92
92
 
93
93
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
94
94
 
95
- Release: **2.4.30** | build: **2024.11.25** | Python: **>=3.10, <3.12**
95
+ Release: **2.4.34** | build: **2024.11.26** | Python: **>=3.10, <3.12**
96
96
 
97
97
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
98
98
  >
@@ -245,11 +245,11 @@ pip install pygpt-net
245
245
  pygpt
246
246
  ```
247
247
 
248
- ## Source Code
248
+ ## Running from GitHub source code
249
249
 
250
250
  An alternative method is to download the source code from `GitHub` and execute the application using the Python interpreter (>=3.10, <3.12).
251
251
 
252
- ### Running from GitHub source code
252
+ ### Install with pip
253
253
 
254
254
  1. Clone git repository or download .zip file:
255
255
 
@@ -277,7 +277,7 @@ pip install -r requirements.txt
277
277
  python3 run.py
278
278
  ```
279
279
 
280
- **Install with Poetry**
280
+ ### Install with Poetry
281
281
 
282
282
  1. Clone git repository or download .zip file:
283
283
 
@@ -446,7 +446,7 @@ This mode in **PyGPT** mirrors `ChatGPT`, allowing you to chat with models such
446
446
 
447
447
  The main part of the interface is a chat window where conversations appear. Right below that is where you type your messages. On the right side of the screen, there's a section to set up or change your system prompts. You can also save these setups as presets to quickly switch between different models or tasks.
448
448
 
449
- Above where you type your messages, the interface shows you the number of tokens your message will use up as you type it – this helps to keep track of usage. There's also a feature to upload files in this area. Go to the `Files` tab to manage your uploads or add attachments to send to the OpenAI API (but this makes effect only in `Assisant` and `Vision` modes).
449
+ Above where you type your messages, the interface shows you the number of tokens your message will use up as you type it – this helps to keep track of usage. There's also a feature to upload files in this area. Go to the `Attachments` tab to manage your uploads or add attachments to send to the OpenAI API (but this makes effect only in `Assisant` and `Vision` modes).
450
450
 
451
451
  ![v2_mode_chat](https://github.com/szczyglis-dev/py-gpt/assets/61396542/f573ee22-8539-4259-b180-f97e54bc0d94)
452
452
 
@@ -464,6 +464,17 @@ Plugin allows you to generate images in Chat mode:
464
464
 
465
465
  ![v3_img_chat](https://github.com/szczyglis-dev/py-gpt/assets/61396542/c288a4b3-c932-4201-b5a3-8452aea49817)
466
466
 
467
+
468
+ ## Chat with Audio
469
+
470
+ 2024-11-26: currently in beta.
471
+
472
+ This mode works like the Chat mode but with native support for audio input and output using a multimodal model - `gpt-4o-audio`. In this mode, audio input and output are directed to and from the model directly, without the use of external plugins. This enables faster and better audio communication.
473
+
474
+ More info: https://platform.openai.com/docs/guides/audio/quickstart
475
+
476
+ **INFO:** The execution of commands and tools in this mode is temporarily unavailable.
477
+
467
478
  ## Completion
468
479
 
469
480
  This mode provides in-depth access to a broader range of capabilities offered by Large Language Models (LLMs). While it maintains a chat-like interface for user interaction, it introduces additional settings and functional richness beyond typical chat exchanges. Users can leverage this mode to prompt models for complex text completions, role-play dialogues between different characters, perform text analysis, and execute a variety of other sophisticated tasks. It supports any model provided by the OpenAI API as well as other models through `Langchain`.
@@ -1187,6 +1198,10 @@ The content from the uploaded attachments will be used in the current conversati
1187
1198
 
1188
1199
  **Note:** Only text files from the list above are included in the additional context. Images will not be included in the context but will be used by the vision model in real-time. Adding image files to the context will be available in future versions.
1189
1200
 
1201
+ **Uploading larger files and auto-index:**
1202
+
1203
+ To use the `Query only` mode, the file must be indexed in the vector database. This occurs automatically at the time of upload if the `Auto-index on upload` option in the `Attachments` tab is enabled. When uploading large files, such indexing might take a while - therefore, if you are using the `Full context` option, which does not use the index, you can disable the `Auto-index` option to speed up the upload of the attachment. In this case, it will only be indexed when the `Query only` option is called for the first time, and until then, attachment will be available in the form of `Full context` and `Summary`.
1204
+
1190
1205
  ## Files (download, code generation)
1191
1206
 
1192
1207
  **PyGPT** enables the automatic download and saving of files created by the model. This is carried out in the background, with the files being saved to an `data` folder located within the user's working directory. To view or manage these files, users can navigate to the `Files` tab which features a file browser for this specific directory. Here, users have the interface to handle all files sent by the AI.
@@ -1655,6 +1670,8 @@ Python code to a file, which the `Code Interpreter` can execute it and return it
1655
1670
  - `Files I/O` - provides access to the local filesystem, enabling GPT to read and write files,
1656
1671
  as well as list and create directories.
1657
1672
 
1673
+ - `System (OS)` - allows you to create and execute custom commands on your system.
1674
+
1658
1675
  - `Mouse and Keyboard` - provides the ability to control the mouse and keyboard by the model.
1659
1676
 
1660
1677
  - `Web Search` - provides the ability to connect to the Web, search web pages for current data, and index external content using Llama-index data loaders.
@@ -3742,6 +3759,30 @@ may consume additional tokens that are not displayed in the main window.
3742
3759
 
3743
3760
  ## Recent changes:
3744
3761
 
3762
+ **2.4.34 (2024-11-26)**
3763
+
3764
+ - Added a new mode: `Chat with Audio`, with built-in multimodal support for audio input/output. Currently in `beta`, the execution of commands and tools in this mode is temporarily unavailable.
3765
+ - Added new models: `gpt-4o-audio-preview`, `gpt-4o-2024-11-20`, `chatgpt-4o-latest`.
3766
+ - Force disabled integration with the native system menu.
3767
+
3768
+ **2.4.33 (2024-11-26)**
3769
+
3770
+ - Improved CSS and rendering of file and image lists.
3771
+ - Added displaying of used attachments in the chat window.
3772
+
3773
+ **2.4.32 (2024-11-26)**
3774
+
3775
+ - 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.
3776
+ - Added UTF-8 as default in attachments content text read/write.
3777
+
3778
+ **2.4.31 (2024-11-25)**
3779
+
3780
+ - Added an option checkbox `Auto-index on upload` in the `Attachments` tab:
3781
+
3782
+ **Tip:** To use the `Query only` mode, the file must be indexed in the vector database. This occurs automatically at the time of upload if the `Auto-index on upload` option in the `Attachments` tab is enabled. When uploading large files, such indexing might take a while - therefore, if you are using the `Full context` option, which does not use the index, you can disable the `Auto-index` option to speed up the upload of the attachment. In this case, it will only be indexed when the `Query only` option is called for the first time, and until then, attachment will be available in the form of `Full context` and `Summary`.
3783
+
3784
+ - Added context menu options in `Uploaded attachments` tab: `Open`, `Open Source directory` and `Open Storage directory`.
3785
+
3745
3786
  **2.4.30 (2024-11-25)**
3746
3787
 
3747
3788
  - Added instruction to model about mapped data directory in both legacy and IPython code interepreter.