pygpt-net 2.4.37__py3-none-any.whl → 2.4.41__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 (255) hide show
  1. CHANGELOG.md +29 -0
  2. README.md +44 -115
  3. pygpt_net/CHANGELOG.txt +29 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/__init__.py +7 -3
  6. pygpt_net/controller/access/control.py +1 -1
  7. pygpt_net/controller/access/voice.py +11 -5
  8. pygpt_net/controller/agent/experts.py +11 -6
  9. pygpt_net/controller/agent/legacy.py +8 -6
  10. pygpt_net/controller/agent/llama.py +4 -2
  11. pygpt_net/controller/assistant/__init__.py +9 -4
  12. pygpt_net/controller/assistant/batch.py +38 -21
  13. pygpt_net/controller/assistant/editor.py +7 -6
  14. pygpt_net/controller/assistant/files.py +23 -7
  15. pygpt_net/controller/assistant/store.py +20 -7
  16. pygpt_net/controller/assistant/threads.py +34 -8
  17. pygpt_net/controller/attachment.py +29 -10
  18. pygpt_net/controller/audio/__init__.py +25 -4
  19. pygpt_net/controller/calendar/__init__.py +23 -4
  20. pygpt_net/controller/calendar/note.py +57 -11
  21. pygpt_net/controller/camera.py +3 -2
  22. pygpt_net/controller/chat/__init__.py +5 -3
  23. pygpt_net/controller/chat/attachment.py +34 -7
  24. pygpt_net/controller/chat/command.py +4 -2
  25. pygpt_net/controller/chat/common.py +11 -4
  26. pygpt_net/controller/chat/files.py +10 -3
  27. pygpt_net/controller/chat/image.py +17 -5
  28. pygpt_net/controller/chat/input.py +10 -7
  29. pygpt_net/controller/chat/output.py +21 -6
  30. pygpt_net/controller/chat/render.py +100 -21
  31. pygpt_net/controller/chat/response.py +34 -7
  32. pygpt_net/controller/chat/stream.py +4 -2
  33. pygpt_net/controller/chat/text.py +6 -4
  34. pygpt_net/controller/command.py +11 -3
  35. pygpt_net/controller/config/__init__.py +34 -6
  36. pygpt_net/controller/config/field/checkbox.py +7 -4
  37. pygpt_net/controller/config/field/cmd.py +7 -5
  38. pygpt_net/controller/config/field/combo.py +14 -6
  39. pygpt_net/controller/config/field/dictionary.py +14 -11
  40. pygpt_net/controller/config/field/input.py +9 -6
  41. pygpt_net/controller/config/field/slider.py +11 -8
  42. pygpt_net/controller/config/field/textarea.py +8 -5
  43. pygpt_net/controller/config/placeholder.py +52 -21
  44. pygpt_net/controller/ctx/__init__.py +138 -49
  45. pygpt_net/controller/ctx/common.py +15 -4
  46. pygpt_net/controller/ctx/extra.py +11 -3
  47. pygpt_net/controller/ctx/summarizer.py +24 -5
  48. pygpt_net/controller/debug/__init__.py +27 -6
  49. pygpt_net/controller/dialogs/confirm.py +34 -7
  50. pygpt_net/controller/dialogs/debug.py +4 -2
  51. pygpt_net/controller/dialogs/info.py +7 -2
  52. pygpt_net/controller/files.py +48 -10
  53. pygpt_net/controller/finder.py +11 -5
  54. pygpt_net/controller/idx/__init__.py +10 -3
  55. pygpt_net/controller/idx/common.py +4 -2
  56. pygpt_net/controller/idx/indexer.py +25 -17
  57. pygpt_net/controller/idx/settings.py +9 -3
  58. pygpt_net/controller/kernel/__init__.py +34 -8
  59. pygpt_net/controller/kernel/reply.py +12 -3
  60. pygpt_net/controller/kernel/stack.py +5 -3
  61. pygpt_net/controller/lang/custom.py +2 -7
  62. pygpt_net/controller/lang/mapping.py +5 -3
  63. pygpt_net/controller/layout.py +2 -2
  64. pygpt_net/controller/mode.py +16 -4
  65. pygpt_net/controller/model/__init__.py +14 -3
  66. pygpt_net/controller/model/editor.py +8 -3
  67. pygpt_net/controller/notepad.py +26 -12
  68. pygpt_net/controller/painter/capture.py +23 -4
  69. pygpt_net/controller/painter/common.py +9 -7
  70. pygpt_net/controller/plugins/__init__.py +19 -5
  71. pygpt_net/controller/plugins/presets.py +15 -6
  72. pygpt_net/controller/plugins/settings.py +9 -3
  73. pygpt_net/controller/presets/__init__.py +55 -16
  74. pygpt_net/controller/presets/editor.py +26 -10
  75. pygpt_net/controller/settings/__init__.py +3 -2
  76. pygpt_net/controller/settings/editor.py +29 -7
  77. pygpt_net/controller/settings/profile.py +22 -5
  78. pygpt_net/controller/theme/__init__.py +54 -12
  79. pygpt_net/controller/theme/common.py +24 -2
  80. pygpt_net/controller/theme/markdown.py +32 -16
  81. pygpt_net/controller/theme/menu.py +26 -5
  82. pygpt_net/controller/theme/nodes.py +2 -5
  83. pygpt_net/controller/tools/__init__.py +40 -2
  84. pygpt_net/controller/ui/__init__.py +4 -6
  85. pygpt_net/controller/ui/tabs.py +363 -65
  86. pygpt_net/core/access/actions.py +6 -4
  87. pygpt_net/core/access/shortcuts.py +4 -3
  88. pygpt_net/core/access/voice.py +6 -5
  89. pygpt_net/core/agents/legacy.py +4 -2
  90. pygpt_net/core/agents/memory.py +7 -2
  91. pygpt_net/core/agents/observer/evaluation.py +15 -7
  92. pygpt_net/core/agents/provider.py +9 -4
  93. pygpt_net/core/agents/runner.py +61 -15
  94. pygpt_net/core/agents/tools.py +23 -5
  95. pygpt_net/core/assistants/__init__.py +6 -4
  96. pygpt_net/core/assistants/files.py +35 -12
  97. pygpt_net/core/assistants/store.py +20 -10
  98. pygpt_net/core/attachments/__init__.py +54 -15
  99. pygpt_net/core/attachments/context.py +92 -29
  100. pygpt_net/core/audio/__init__.py +71 -3
  101. pygpt_net/core/audio/context.py +7 -2
  102. pygpt_net/core/bridge/__init__.py +22 -6
  103. pygpt_net/core/bridge/context.py +5 -3
  104. pygpt_net/core/calendar/__init__.py +57 -11
  105. pygpt_net/core/chain/__init__.py +8 -2
  106. pygpt_net/core/chain/chat.py +10 -8
  107. pygpt_net/core/chain/completion.py +10 -7
  108. pygpt_net/core/command.py +62 -17
  109. pygpt_net/core/ctx/__init__.py +260 -58
  110. pygpt_net/core/ctx/bag.py +25 -4
  111. pygpt_net/core/ctx/container.py +28 -17
  112. pygpt_net/core/ctx/idx.py +45 -8
  113. pygpt_net/core/ctx/output.py +95 -74
  114. pygpt_net/core/ctx/reply.py +5 -2
  115. pygpt_net/core/db/__init__.py +8 -7
  116. pygpt_net/core/db/viewer.py +17 -11
  117. pygpt_net/core/debug/__init__.py +10 -9
  118. pygpt_net/core/debug/tabs.py +5 -2
  119. pygpt_net/core/docker/__init__.py +11 -5
  120. pygpt_net/core/docker/builder.py +11 -3
  121. pygpt_net/core/events/app.py +5 -3
  122. pygpt_net/core/events/base.py +11 -5
  123. pygpt_net/core/events/control.py +5 -3
  124. pygpt_net/core/events/event.py +17 -7
  125. pygpt_net/core/events/kernel.py +5 -3
  126. pygpt_net/core/events/render.py +5 -3
  127. pygpt_net/core/experts/__init__.py +5 -4
  128. pygpt_net/core/filesystem/__init__.py +52 -34
  129. pygpt_net/core/filesystem/actions.py +8 -5
  130. pygpt_net/core/filesystem/editor.py +13 -3
  131. pygpt_net/core/filesystem/types.py +12 -7
  132. pygpt_net/core/filesystem/url.py +7 -3
  133. pygpt_net/core/idx/__init__.py +34 -25
  134. pygpt_net/core/idx/chat.py +40 -16
  135. pygpt_net/core/idx/context.py +6 -2
  136. pygpt_net/core/idx/indexing.py +84 -35
  137. pygpt_net/core/idx/llm.py +11 -3
  138. pygpt_net/core/idx/metadata.py +13 -3
  139. pygpt_net/core/idx/types/ctx.py +32 -6
  140. pygpt_net/core/idx/types/external.py +41 -7
  141. pygpt_net/core/idx/types/files.py +31 -6
  142. pygpt_net/core/image.py +15 -4
  143. pygpt_net/core/llm/__init__.py +13 -3
  144. pygpt_net/core/locale.py +34 -8
  145. pygpt_net/core/models.py +4 -3
  146. pygpt_net/core/notepad.py +9 -4
  147. pygpt_net/core/plugins.py +7 -6
  148. pygpt_net/core/presets.py +19 -10
  149. pygpt_net/core/profile.py +12 -6
  150. pygpt_net/core/prompt/__init__.py +10 -3
  151. pygpt_net/core/prompt/custom.py +7 -6
  152. pygpt_net/core/prompt/template.py +9 -3
  153. pygpt_net/core/render/base.py +117 -22
  154. pygpt_net/core/render/markdown/body.py +27 -7
  155. pygpt_net/core/render/markdown/renderer.py +119 -22
  156. pygpt_net/core/render/plain/body.py +22 -5
  157. pygpt_net/core/render/plain/renderer.py +97 -21
  158. pygpt_net/core/render/web/body.py +75 -25
  159. pygpt_net/core/render/web/renderer.py +313 -63
  160. pygpt_net/core/settings.py +9 -4
  161. pygpt_net/core/tabs/__init__.py +290 -103
  162. pygpt_net/core/tabs/tab.py +17 -4
  163. pygpt_net/core/tokens.py +44 -11
  164. pygpt_net/core/updater/__init__.py +20 -7
  165. pygpt_net/core/vision/analyzer.py +29 -6
  166. pygpt_net/core/web.py +130 -2
  167. pygpt_net/data/config/config.json +15 -4
  168. pygpt_net/data/config/models.json +3 -3
  169. pygpt_net/data/config/modes.json +3 -3
  170. pygpt_net/data/config/settings.json +55 -10
  171. pygpt_net/data/config/settings_section.json +3 -0
  172. pygpt_net/data/css/style.light.css +1 -0
  173. pygpt_net/data/css/{web.css → web-blocks.css} +162 -133
  174. pygpt_net/data/css/{web.light.css → web-blocks.light.css} +7 -0
  175. pygpt_net/data/css/web-chatgpt.css +350 -0
  176. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  177. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  178. pygpt_net/data/css/web-chatgpt_wide.css +350 -0
  179. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  180. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  181. pygpt_net/data/icons/split_screen.svg +1 -0
  182. pygpt_net/data/locale/locale.de.ini +12 -0
  183. pygpt_net/data/locale/locale.en.ini +17 -2
  184. pygpt_net/data/locale/locale.es.ini +12 -0
  185. pygpt_net/data/locale/locale.fr.ini +12 -0
  186. pygpt_net/data/locale/locale.it.ini +12 -0
  187. pygpt_net/data/locale/locale.pl.ini +12 -0
  188. pygpt_net/data/locale/locale.uk.ini +12 -0
  189. pygpt_net/data/locale/locale.zh.ini +12 -0
  190. pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
  191. pygpt_net/data/locale/plugin.cmd_web.en.ini +20 -10
  192. pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
  193. pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
  194. pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
  195. pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
  196. pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
  197. pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
  198. pygpt_net/icons.qrc +1 -0
  199. pygpt_net/icons_rc.py +165 -136
  200. pygpt_net/item/ctx.py +46 -24
  201. pygpt_net/plugin/audio_input/simple.py +21 -5
  202. pygpt_net/plugin/audio_output/__init__.py +4 -1
  203. pygpt_net/plugin/base/config.py +4 -2
  204. pygpt_net/plugin/base/plugin.py +26 -6
  205. pygpt_net/plugin/base/worker.py +37 -9
  206. pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
  207. pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
  208. pygpt_net/plugin/cmd_web/__init__.py +46 -6
  209. pygpt_net/plugin/cmd_web/config.py +74 -48
  210. pygpt_net/plugin/cmd_web/websearch.py +61 -28
  211. pygpt_net/plugin/cmd_web/worker.py +79 -13
  212. pygpt_net/provider/core/config/patch.py +43 -1
  213. pygpt_net/provider/core/ctx/base.py +4 -1
  214. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +10 -1
  215. pygpt_net/provider/core/ctx/db_sqlite/storage.py +22 -1
  216. pygpt_net/provider/gpt/assistants.py +10 -9
  217. pygpt_net/provider/gpt/audio.py +3 -2
  218. pygpt_net/provider/gpt/chat.py +8 -7
  219. pygpt_net/provider/gpt/completion.py +6 -4
  220. pygpt_net/provider/gpt/image.py +9 -2
  221. pygpt_net/provider/gpt/store.py +14 -13
  222. pygpt_net/provider/gpt/vision.py +6 -5
  223. pygpt_net/tools/__init__.py +9 -1
  224. pygpt_net/tools/base.py +15 -1
  225. pygpt_net/tools/code_interpreter/__init__.py +174 -75
  226. pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
  227. pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
  228. pygpt_net/tools/html_canvas/__init__.py +78 -23
  229. pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
  230. pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
  231. pygpt_net/ui/base/context_menu.py +2 -2
  232. pygpt_net/ui/layout/chat/input.py +10 -18
  233. pygpt_net/ui/layout/chat/output.py +26 -44
  234. pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
  235. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  236. pygpt_net/ui/main.py +2 -2
  237. pygpt_net/ui/menu/config.py +7 -11
  238. pygpt_net/ui/menu/debug.py +11 -1
  239. pygpt_net/ui/menu/theme.py +9 -2
  240. pygpt_net/ui/widget/filesystem/explorer.py +2 -2
  241. pygpt_net/ui/widget/lists/context.py +27 -5
  242. pygpt_net/ui/widget/tabs/Input.py +2 -2
  243. pygpt_net/ui/widget/tabs/body.py +2 -1
  244. pygpt_net/ui/widget/tabs/layout.py +195 -0
  245. pygpt_net/ui/widget/tabs/output.py +218 -55
  246. pygpt_net/ui/widget/textarea/html.py +11 -1
  247. pygpt_net/ui/widget/textarea/output.py +10 -1
  248. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  249. pygpt_net/ui/widget/textarea/web.py +49 -9
  250. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/METADATA +45 -116
  251. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/RECORD +255 -247
  252. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  253. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/LICENSE +0 -0
  254. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/WHEEL +0 -0
  255. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/entry_points.txt +0 -0
@@ -6,29 +6,32 @@
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.11 23:00:00 #
9
+ # Updated Date: 2024.12.09 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
13
13
 
14
14
  from PySide6.QtCore import Qt
15
15
  from PySide6.QtGui import QAction, QIcon
16
- from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout, QCheckBox, QMenuBar
16
+ from PySide6.QtWidgets import QMenuBar, QVBoxLayout
17
17
 
18
- from pygpt_net.tools.html_canvas.ui.widgets import CanvasOutput, CanvasEdit
19
18
  from pygpt_net.ui.widget.dialog.base import BaseDialog
20
- from pygpt_net.ui.widget.element.labels import HelpLabel
21
- from pygpt_net.ui.widget.textarea.html import CustomWebEnginePage
22
19
  from pygpt_net.utils import trans
23
20
 
24
- class Canvas:
25
- def __init__(self, window=None):
21
+ from .widgets import ToolWidget
22
+
23
+ class Tool:
24
+ def __init__(self, window=None, tool=None):
26
25
  """
27
26
  HTML/JS canvas dialog
28
27
 
29
28
  :param window: Window instance
29
+ :param tool: Tool instance
30
30
  """
31
31
  self.window = window
32
+ self.tool = tool # tool instance
33
+ self.widget = ToolWidget(window, tool)
34
+ self.layout = None
32
35
  self.menu_bar = None
33
36
  self.menu = {}
34
37
  self.actions = {} # menu actions
@@ -45,20 +48,20 @@ class Canvas:
45
48
 
46
49
  self.actions["file.open"] = QAction(QIcon(":/icons/folder.svg"), trans("tool.html_canvas.menu.file.open"))
47
50
  self.actions["file.open"].triggered.connect(
48
- lambda: self.window.tools.get("html_canvas").open_file()
51
+ lambda: self.tool.open_file()
49
52
  )
50
53
  self.actions["file.save_as"] = QAction(QIcon(":/icons/save.svg"), trans("tool.html_canvas.menu.file.save_as"))
51
54
  self.actions["file.save_as"].triggered.connect(
52
- lambda: self.window.ui.nodes['html_canvas.output'].signals.save_as.emit(
53
- re.sub(r'\n{2,}', '\n\n', self.window.ui.nodes['html_canvas.output'].html_content), 'html')
55
+ lambda: self.widget.output.signals.save_as.emit(
56
+ re.sub(r'\n{2,}', '\n\n', self.widget.output.html_content), 'html')
54
57
  )
55
58
  self.actions["file.reload"] = QAction(QIcon(":/icons/reload.svg"), trans("tool.html_canvas.menu.file.reload"))
56
59
  self.actions["file.reload"].triggered.connect(
57
- lambda: self.window.tools.get("html_canvas").reload_output()
60
+ lambda: self.tool.reload_output()
58
61
  )
59
62
  self.actions["file.clear"] = QAction(QIcon(":/icons/close.svg"), trans("tool.html_canvas.menu.file.clear"))
60
63
  self.actions["file.clear"].triggered.connect(
61
- lambda: self.window.tools.get("html_canvas").clear()
64
+ lambda: self.tool.clear()
62
65
  )
63
66
 
64
67
  # add actions
@@ -70,61 +73,44 @@ class Canvas:
70
73
 
71
74
  def setup(self):
72
75
  """Setup canvas dialog"""
73
- self.window.ui.nodes['html_canvas.output'] = CanvasOutput(self.window)
74
- self.window.ui.nodes['html_canvas.output'].setPage(
75
- CustomWebEnginePage(self.window, self.window.ui.nodes['html_canvas.output'])
76
- )
77
- self.window.ui.nodes['html_canvas.edit'] = CanvasEdit(self.window)
78
- self.window.ui.nodes['html_canvas.edit'].setVisible(False)
79
- self.window.ui.nodes['html_canvas.edit'].textChanged.connect(
80
- lambda: self.window.tools.get("html_canvas").save_output()
81
- )
82
-
83
- # edit checkbox
84
- self.window.ui.nodes['html_canvas.btn.edit'] = QCheckBox(trans("html_canvas.btn.edit"))
85
- self.window.ui.nodes['html_canvas.btn.edit'].stateChanged.connect(
86
- lambda: self.window.tools.get("html_canvas").toggle_edit()
87
- )
88
-
89
- path = self.window.tools.get("html_canvas").get_current_path()
90
- path_label = HelpLabel(path)
91
- path_label.setMaximumHeight(30)
92
- path_label.setAlignment(Qt.AlignRight)
76
+ self.layout = self.widget.setup()
77
+ self.layout.setMenuBar(self.setup_menu()) # add menu bar
93
78
 
94
- bottom_layout = QHBoxLayout()
95
- bottom_layout.addWidget(self.window.ui.nodes['html_canvas.btn.edit'])
96
- bottom_layout.addWidget(path_label)
79
+ id = self.tool.get_dialog_id()
80
+ dialog = ToolDialog(window=self.window, tool=self.tool)
81
+ dialog.setLayout(self.layout)
82
+ dialog.setWindowTitle(trans("dialog.html_canvas.title"))
83
+ dialog.resize(800, 500)
84
+ self.window.ui.dialog[id] = dialog
97
85
 
98
- output_layout = QVBoxLayout()
99
- output_layout.addWidget(self.window.ui.nodes['html_canvas.output'])
100
- output_layout.addWidget(self.window.ui.nodes['html_canvas.edit'])
101
- output_layout.setContentsMargins(0, 0, 0, 0)
86
+ def get_widget(self) -> ToolWidget:
87
+ """
88
+ Get widget
102
89
 
103
- # connect signals
104
- self.window.ui.nodes['html_canvas.output'].signals.save_as.connect(self.window.tools.get("html_canvas").handle_save_as)
105
- self.window.ui.nodes['html_canvas.output'].signals.audio_read.connect(self.window.controller.chat.render.handle_audio_read)
90
+ :return: ToolWidget
91
+ """
92
+ return self.widget
106
93
 
107
- layout = QVBoxLayout()
108
- layout.setMenuBar(self.setup_menu()) # add menu bar
109
- layout.addLayout(output_layout)
110
- layout.addLayout(bottom_layout)
94
+ def get_tab(self) -> QVBoxLayout:
95
+ """
96
+ Get layout
111
97
 
112
- self.window.ui.dialog['html_canvas'] = CanvasDialog(self.window)
113
- self.window.ui.dialog['html_canvas'].setLayout(layout)
114
- self.window.ui.dialog['html_canvas'].setWindowTitle(trans("dialog.html_canvas.title"))
115
- self.window.ui.dialog['html_canvas'].resize(800, 500)
98
+ :return: QVBoxLayout
99
+ """
100
+ return self.layout
116
101
 
117
102
 
118
- class CanvasDialog(BaseDialog):
119
- def __init__(self, window=None, id="html_canvas"):
103
+ class ToolDialog(BaseDialog):
104
+ def __init__(self, window=None, id="html_canvas", tool=None):
120
105
  """
121
106
  HTML canvas dialog
122
107
 
123
108
  :param window: main window
124
109
  :param id: logger id
125
110
  """
126
- super(CanvasDialog, self).__init__(window, id)
111
+ super(ToolDialog, self).__init__(window, id)
127
112
  self.window = window
113
+ self.tool = tool
128
114
 
129
115
  def closeEvent(self, event):
130
116
  """
@@ -133,7 +119,7 @@ class CanvasDialog(BaseDialog):
133
119
  :param event: close event
134
120
  """
135
121
  self.cleanup()
136
- super(CanvasDialog, self).closeEvent(event)
122
+ super(ToolDialog, self).closeEvent(event)
137
123
 
138
124
  def keyPressEvent(self, event):
139
125
  """
@@ -145,14 +131,12 @@ class CanvasDialog(BaseDialog):
145
131
  self.cleanup()
146
132
  self.close() # close dialog when the Esc key is pressed.
147
133
  else:
148
- super(CanvasDialog, self).keyPressEvent(event)
134
+ super(ToolDialog, self).keyPressEvent(event)
149
135
 
150
136
  def cleanup(self):
151
- """
152
- Cleanup on close
153
- """
154
- if self.window is None:
137
+ """Cleanup on close"""
138
+ if self.window is None or self.tool is None:
155
139
  return
156
- self.window.tools.get("html_canvas").opened = False
157
- self.window.tools.get("html_canvas").close()
158
- self.window.tools.get("html_canvas").update()
140
+ self.tool.opened = False
141
+ self.tool.close()
142
+ self.tool.update()
@@ -6,13 +6,101 @@
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.11 23:00:00 #
9
+ # Updated Date: 2024.12.09 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from PySide6.QtCore import Qt, Slot, QUrl, QObject, Signal
13
+ from PySide6.QtWidgets import QVBoxLayout, QCheckBox, QHBoxLayout
14
+
15
+ from pygpt_net.ui.widget.element.labels import HelpLabel
12
16
  from pygpt_net.ui.widget.textarea.editor import BaseCodeEditor
13
- from pygpt_net.ui.widget.textarea.html import HtmlOutput
17
+ from pygpt_net.ui.widget.textarea.html import HtmlOutput, CustomWebEnginePage
14
18
 
15
19
  import pygpt_net.icons_rc
20
+ from pygpt_net.utils import trans
21
+
22
+
23
+ class ToolWidget:
24
+ def __init__(self, window=None, tool=None):
25
+ """
26
+ HTML/JS canvas widget
27
+
28
+ :param window: Window instance
29
+ :param tool: Tool instance
30
+ """
31
+ self.window = window
32
+ self.tool = tool # tool instance
33
+ self.output = None # canvas output
34
+ self.edit = None # canvas edit
35
+ self.btn_edit = None # edit checkbox
36
+
37
+ def setup(self) -> QVBoxLayout:
38
+ """
39
+ Setup widget body
40
+
41
+ :return: QVBoxLayout
42
+ """
43
+ self.output = CanvasOutput(self.window)
44
+ self.output.setPage(
45
+ CustomWebEnginePage(self.window, self.output)
46
+ )
47
+ self.edit = CanvasEdit(self.window)
48
+ self.edit.setVisible(False)
49
+ self.edit.textChanged.connect(
50
+ lambda: self.tool.save_output()
51
+ )
52
+
53
+ # edit checkbox
54
+ self.btn_edit = QCheckBox(trans("html_canvas.btn.edit"))
55
+ self.btn_edit.stateChanged.connect(
56
+ lambda: self.tool.toggle_edit(self)
57
+ )
58
+
59
+ path = self.tool.get_current_path()
60
+ path_label = HelpLabel(path)
61
+ path_label.setMaximumHeight(30)
62
+ path_label.setAlignment(Qt.AlignRight)
63
+
64
+ bottom_layout = QHBoxLayout()
65
+ bottom_layout.addWidget(self.btn_edit)
66
+ bottom_layout.addWidget(path_label)
67
+
68
+ output_layout = QVBoxLayout()
69
+ output_layout.addWidget(self.output)
70
+ output_layout.addWidget(self.edit)
71
+ output_layout.setContentsMargins(0, 0, 0, 0)
72
+
73
+ # connect signals
74
+ self.output.signals.save_as.connect(
75
+ self.tool.handle_save_as)
76
+ self.output.signals.audio_read.connect(
77
+ self.window.controller.chat.render.handle_audio_read)
78
+
79
+ self.tool.signals.update.connect(self.set_output)
80
+ self.tool.signals.reload.connect(self.load_output)
81
+
82
+ layout = QVBoxLayout()
83
+ layout.addLayout(output_layout)
84
+ layout.addLayout(bottom_layout)
85
+ return layout
86
+
87
+ @Slot(str)
88
+ def set_output(self, content: str):
89
+ """
90
+ Set output content
91
+
92
+ :param content: Content
93
+ """
94
+ self.edit.setPlainText(content)
95
+
96
+ @Slot(str)
97
+ def load_output(self, path: str):
98
+ """
99
+ Load output content
100
+
101
+ :param path: Content
102
+ """
103
+ self.output.setUrl(QUrl().fromLocalFile(path))
16
104
 
17
105
  class CanvasOutput(HtmlOutput):
18
106
  def __init__(self, window=None):
@@ -39,4 +127,9 @@ class CanvasEdit(BaseCodeEditor):
39
127
  self.min_font_size = 8
40
128
  self.setProperty('class', 'interpreter-output')
41
129
  self.default_stylesheet = ""
42
- self.setStyleSheet(self.default_stylesheet)
130
+ self.setStyleSheet(self.default_stylesheet)
131
+
132
+
133
+ class ToolSignals(QObject):
134
+ update = Signal(str) # data
135
+ reload = Signal(str) # path
@@ -6,13 +6,13 @@
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.03.25 10:00:00 #
9
+ # Updated Date: 2024.12.12 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtWidgets import QMenu
13
13
  from PySide6.QtGui import QAction, QIcon
14
14
 
15
- from pygpt_net.core.tabs import Tab
15
+ from pygpt_net.core.tabs.tab import Tab
16
16
  from pygpt_net.utils import trans
17
17
  import pygpt_net.icons_rc
18
18
 
@@ -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.12.09 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -153,14 +153,6 @@ class Input:
153
153
  """
154
154
  # header (input label + input counter)
155
155
  self.window.ui.nodes['input.label'] = HelpLabel(trans("input.label"))
156
- self.window.ui.nodes['input.counter'] = QLabel("")
157
- self.window.ui.nodes['input.counter'].setToolTip(trans('tip.tokens.input'))
158
-
159
- # inline vision
160
- self.window.ui.nodes['inline.vision'] = HelpLabel(trans('inline.vision'))
161
- self.window.ui.nodes['inline.vision'].setVisible(False)
162
- self.window.ui.nodes['inline.vision'].setContentsMargins(0, 0, 0, 0)
163
- self.window.ui.nodes['inline.vision'].setToolTip(trans('vision.checkbox.tooltip'))
164
156
 
165
157
  # plugin audio input addon
166
158
  self.window.ui.plugin_addon['audio.input'] = AudioInput(self.window)
@@ -168,10 +160,10 @@ class Input:
168
160
 
169
161
  grid = QGridLayout()
170
162
 
171
- left_layout = QHBoxLayout()
172
- left_layout.addWidget(self.window.ui.nodes['input.label'])
173
- left_layout.addWidget(self.window.ui.nodes['inline.vision'])
174
- left_layout.addStretch(1)
163
+ #left_layout = QHBoxLayout()
164
+ #left_layout.addWidget(self.window.ui.nodes['input.label'])
165
+ #left_layout.addWidget(self.window.ui.nodes['inline.vision'])
166
+ #left_layout.addStretch(1)
175
167
 
176
168
  center_layout = QHBoxLayout()
177
169
  center_layout.addStretch()
@@ -179,13 +171,13 @@ class Input:
179
171
  center_layout.addWidget(self.window.ui.plugin_addon['audio.input.btn'])
180
172
  center_layout.addStretch()
181
173
 
182
- right_layout = QHBoxLayout()
183
- right_layout.addStretch(1)
184
- right_layout.addWidget(self.window.ui.nodes['input.counter'])
174
+ #right_layout = QHBoxLayout()
175
+ #right_layout.addStretch(1)
176
+ #right_layout.addWidget(self.window.ui.nodes['input.counter'])
185
177
 
186
- grid.addLayout(left_layout, 0, 0)
178
+ #grid.addLayout(left_layout, 0, 0)
187
179
  grid.addLayout(center_layout, 0, 1, alignment=Qt.AlignCenter)
188
- grid.addLayout(right_layout, 0, 2, alignment=Qt.AlignRight)
180
+ #grid.addLayout(right_layout, 0, 2, alignment=Qt.AlignRight)
189
181
 
190
182
  grid.setContentsMargins(0, 0, 0, 0)
191
183
  return grid
@@ -6,18 +6,17 @@
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.18 00:00:00 #
9
+ # Updated Date: 2024.12.09 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
13
- from PySide6.QtGui import QIcon
14
13
  from PySide6.QtWidgets import QVBoxLayout, QLabel, QHBoxLayout, QCheckBox, QWidget, QSizePolicy, QPushButton, \
15
- QGridLayout, QSpacerItem, QWidgetItem, QLayout
14
+ QGridLayout, QWidgetItem, QLayout
16
15
 
17
16
  from pygpt_net.ui.widget.audio.output import AudioOutput
18
17
  from pygpt_net.ui.widget.element.labels import ChatStatusLabel, IconLabel, HelpLabel
19
- from pygpt_net.ui.widget.tabs.output import OutputTabs
20
- from pygpt_net.ui.widget.anims.loader import Loader, Loading
18
+ from pygpt_net.ui.widget.anims.loader import Loading
19
+ from pygpt_net.ui.widget.tabs.layout import OutputLayout
21
20
 
22
21
  from .explorer import Explorer
23
22
  from .input import Input
@@ -28,6 +27,7 @@ from pygpt_net.utils import trans
28
27
  import pygpt_net.icons_rc
29
28
 
30
29
 
30
+
31
31
  class Output:
32
32
  def __init__(self, window=None):
33
33
  """
@@ -47,46 +47,15 @@ class Output:
47
47
 
48
48
  :return: QWidget
49
49
  """
50
- # tabs
51
- self.window.ui.tabs['output'] = OutputTabs(self.window)
52
-
53
- # Create the [+] button
54
- plus_button = QPushButton(QIcon(":/icons/add.svg"), "")
55
- plus_button.setFixedSize(30, 25)
56
- plus_button.setFlat(True)
57
- plus_button.clicked.connect(self.window.controller.ui.tabs.new_tab)
58
- plus_button.setObjectName('tab-add')
59
- plus_button.setProperty('tabAdd', True)
60
- plus_button.setToolTip(trans('action.tab.add.chat'))
61
-
62
- # Add the button to the top right corner of the tab bar
63
- self.window.ui.tabs['output'].setCornerWidget(plus_button, corner=Qt.TopRightCorner)
64
-
65
- # create empty tabs
50
+ # prepare columns
51
+ self.window.ui.layout = OutputLayout(self.window)
52
+
53
+ # create empty containers for chat output
66
54
  self.window.ui.nodes['output'] = {}
67
55
  self.window.ui.nodes['output_plain'] = {}
68
56
 
69
- # connect signals
70
- self.window.ui.tabs['output'].currentChanged.connect(
71
- self.window.controller.ui.tabs.on_tab_changed
72
- )
73
- self.window.ui.tabs['output'].tabBarClicked.connect(
74
- self.window.controller.ui.tabs.on_tab_clicked
75
- )
76
- self.window.ui.tabs['output'].tabBarDoubleClicked.connect(
77
- self.window.controller.ui.tabs.on_tab_dbl_clicked
78
- )
79
- self.window.ui.tabs['output'].tabCloseRequested.connect(
80
- self.window.controller.ui.tabs.on_tab_closed
81
- )
82
-
83
- # tab bar signals
84
- self.window.ui.tabs['output'].tabBar().tabMoved.connect(
85
- self.window.controller.ui.tabs.on_tab_moved
86
- )
87
-
88
57
  layout = QVBoxLayout()
89
- layout.addWidget(self.window.ui.tabs['output'])
58
+ layout.addWidget(self.window.ui.layout)
90
59
  layout.addLayout(self.setup_bottom())
91
60
  layout.setContentsMargins(0, 5, 0, 0)
92
61
 
@@ -177,18 +146,29 @@ class Output:
177
146
  self.window.ui.nodes['prompt.context'].setToolTip(trans('tip.tokens.ctx'))
178
147
  self.window.ui.nodes['prompt.context'].setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
179
148
 
149
+ self.window.ui.nodes['input.counter'] = ChatStatusLabel("")
150
+ self.window.ui.nodes['input.counter'].setToolTip(trans('tip.tokens.input'))
151
+ self.window.ui.nodes['input.counter'].setWordWrap(False)
152
+
180
153
  # plugin audio output addon
181
154
  self.window.ui.plugin_addon['audio.output'] = AudioOutput(self.window)
182
155
 
183
156
  # schedule
184
157
  self.window.ui.plugin_addon['schedule'] = ChatStatusLabel("")
185
158
 
159
+ # inline vision
160
+ self.window.ui.nodes['inline.vision'] = HelpLabel(trans('inline.vision'))
161
+ self.window.ui.nodes['inline.vision'].setVisible(False)
162
+ self.window.ui.nodes['inline.vision'].setContentsMargins(0, 0, 0, 0)
163
+ self.window.ui.nodes['inline.vision'].setToolTip(trans('vision.checkbox.tooltip'))
164
+
186
165
  opts_layout = QHBoxLayout()
187
166
  # opts_layout.setSpacing(2) #
188
167
  opts_layout.setContentsMargins(0, 0, 0, 0)
189
168
  opts_layout.addWidget(self.window.ui.nodes['output.timestamp'])
190
169
  # opts_layout.addWidget(self.window.ui.nodes['output.edit'])
191
170
  opts_layout.addWidget(self.window.ui.nodes['output.raw'])
171
+ opts_layout.addWidget(self.window.ui.nodes['inline.vision'])
192
172
  opts_layout.setAlignment(Qt.AlignLeft)
193
173
 
194
174
  left_layout = QHBoxLayout()
@@ -210,6 +190,8 @@ class Output:
210
190
  right_layout.addWidget(self.window.ui.nodes['chat.model'])
211
191
  right_layout.addWidget(QLabel(" "))
212
192
  right_layout.addWidget(self.window.ui.nodes['prompt.context'])
193
+ right_layout.addWidget(QLabel(" "))
194
+ right_layout.addWidget(self.window.ui.nodes['input.counter'])
213
195
  right_layout.setContentsMargins(0, 0, 0, 0)
214
196
 
215
197
  left_widget = QWidget()
@@ -224,14 +206,14 @@ class Output:
224
206
 
225
207
  left_layout = QHBoxLayout()
226
208
  left_layout.addWidget(left_widget)
227
- left_layout.addStretch(1)
209
+ #left_layout.addStretch(1)
228
210
  left_layout.setContentsMargins(0, 0, 0, 0)
229
211
 
230
212
  center_layout = QHBoxLayout()
231
- center_layout.addStretch()
213
+ #center_layout.addStretch()
232
214
  center_layout.addWidget(self.window.ui.nodes['anim.loading'])
233
215
  center_layout.addStretch()
234
- center_layout.setContentsMargins(0, 0, 0, 0)
216
+ center_layout.setContentsMargins(20, 0, 0, 0)
235
217
 
236
218
  right_layout = QHBoxLayout()
237
219
  right_layout.addStretch(1)
@@ -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.05 23:00:00 #
9
+ # Updated Date: 2024.12.12 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6 import QtCore
@@ -211,10 +211,19 @@ class CtxList:
211
211
  item.dt = dt
212
212
  item.isPinned = data.important
213
213
  item.setData(tooltip_text, QtCore.Qt.ToolTipRole)
214
+ is_important = False
215
+ is_attachment = False
216
+ label = data.label
214
217
  if data.important:
215
- item.setData(data.label + 10, QtCore.Qt.ItemDataRole.UserRole)
216
- else:
217
- item.setData(data.label, QtCore.Qt.ItemDataRole.UserRole)
218
+ is_important = True
219
+ if data.additional_ctx and len(data.additional_ctx) > 0:
220
+ is_attachment = True
221
+ custom_data = {
222
+ "label": label,
223
+ "is_important": is_important,
224
+ "is_attachment": is_attachment,
225
+ }
226
+ item.setData(custom_data, QtCore.Qt.ItemDataRole.UserRole)
218
227
  item.setData(name)
219
228
  return item
220
229
 
@@ -6,14 +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.17 03:00:00 #
9
+ # Updated Date: 2024.12.09 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
 
14
14
  from PySide6.QtCore import QSize
15
15
  from PySide6.QtGui import QIcon
16
- from PySide6.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget, QSizePolicy
16
+ from PySide6.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget, QSizePolicy, QHBoxLayout
17
17
 
18
18
  from pygpt_net.ui.widget.textarea.name import NameInput
19
19
  from pygpt_net.ui.widget.option.slider import OptionSlider
@@ -25,6 +25,7 @@ from .agent_llama import AgentLlama
25
25
  from .image import Image
26
26
  from .indexes import Indexes
27
27
  from .vision import Vision
28
+ from ...widget.option.toggle_label import ToggleLabel
28
29
 
29
30
 
30
31
  class Footer:
@@ -75,6 +76,21 @@ class Footer:
75
76
  rows.addWidget(self.window.ui.nodes['voice.control.btn'])
76
77
  rows.setContentsMargins(2, 0, 0, 0)
77
78
 
79
+ self.window.ui.nodes['layout.split'] = ToggleLabel(trans('layout.split'), label_position="left",
80
+ icon=":/icons/split_screen.svg")
81
+ self.window.ui.nodes['layout.split'].box.stateChanged.connect(
82
+ lambda: self.window.controller.ui.tabs.toggle_split_screen(self.window.ui.nodes['layout.split'].box.isChecked())
83
+ )
84
+ split_layout = QHBoxLayout()
85
+
86
+ split_layout.addWidget(QLabel(""))
87
+ split_layout.addStretch(1)
88
+ split_layout.addWidget(self.window.ui.nodes['layout.split'])
89
+ split_layout.setContentsMargins(5, 0, 15, 0)
90
+ split_widget = QWidget()
91
+ split_widget.setLayout(split_layout)
92
+ rows.addWidget(split_widget)
93
+
78
94
  # logo
79
95
  logo_button = self.setup_logo()
80
96
 
pygpt_net/ui/main.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: 2024.11.21 17:00:00 #
9
+ # Updated Date: 2024.12.09 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -192,8 +192,8 @@ class MainWindow(QMainWindow, QtStyleTools):
192
192
 
193
193
  def setup(self):
194
194
  """Setup app"""
195
- self.controller.setup()
196
195
  self.tools.setup()
196
+ self.controller.setup()
197
197
  self.controller.plugins.setup()
198
198
  self.controller.post_setup()
199
199
 
@@ -6,9 +6,11 @@
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.05.02 19:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ import os
13
+
12
14
  from PySide6.QtGui import QAction, QIcon
13
15
  from PySide6.QtWidgets import QMenu
14
16
 
@@ -42,16 +44,10 @@ class Config:
42
44
  self.window.ui.menu['config.access'] = QAction(QIcon(":/icons/accessibility.svg"),
43
45
  trans("menu.config.access"), self.window)
44
46
 
45
- css_files = []
46
- css_files.append("style.css")
47
- css_files.append("style.dark.css")
48
- css_files.append("style.light.css")
49
- css_files.append("markdown.css")
50
- css_files.append("markdown.dark.css")
51
- css_files.append("markdown.light.css")
52
- css_files.append("web.css")
53
- css_files.append("web.dark.css")
54
- css_files.append("web.light.css")
47
+ css_dir = os.path.join(self.window.core.config.path, 'css')
48
+ css_files = os.listdir(css_dir)
49
+ css_files = [f for f in css_files if not f.endswith('.backup')] # remove .backup files
50
+ css_files = sorted(css_files) # sort by name
55
51
 
56
52
  json_files = []
57
53
  json_files.append("attachments.json")