pygpt-net 2.4.37__py3-none-any.whl → 2.4.38__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 (49) hide show
  1. CHANGELOG.md +5 -0
  2. README.md +18 -5
  3. pygpt_net/CHANGELOG.txt +5 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/config/placeholder.py +29 -0
  6. pygpt_net/controller/lang/mapping.py +2 -2
  7. pygpt_net/controller/settings/editor.py +6 -0
  8. pygpt_net/controller/theme/__init__.py +33 -8
  9. pygpt_net/controller/theme/common.py +22 -1
  10. pygpt_net/controller/theme/markdown.py +26 -14
  11. pygpt_net/controller/theme/menu.py +26 -5
  12. pygpt_net/core/attachments/context.py +14 -12
  13. pygpt_net/core/audio/__init__.py +59 -1
  14. pygpt_net/core/filesystem/__init__.py +5 -19
  15. pygpt_net/core/render/web/body.py +31 -15
  16. pygpt_net/data/config/config.json +7 -3
  17. pygpt_net/data/config/models.json +3 -3
  18. pygpt_net/data/config/modes.json +3 -3
  19. pygpt_net/data/config/settings.json +55 -10
  20. pygpt_net/data/config/settings_section.json +3 -0
  21. pygpt_net/data/css/style.light.css +1 -0
  22. pygpt_net/data/css/{web.css → web-blocks.css} +144 -133
  23. pygpt_net/data/css/web-chatgpt.css +342 -0
  24. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  25. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  26. pygpt_net/data/css/web-chatgpt_wide.css +342 -0
  27. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  28. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  29. pygpt_net/data/locale/locale.de.ini +9 -0
  30. pygpt_net/data/locale/locale.en.ini +11 -1
  31. pygpt_net/data/locale/locale.es.ini +9 -0
  32. pygpt_net/data/locale/locale.fr.ini +9 -0
  33. pygpt_net/data/locale/locale.it.ini +9 -0
  34. pygpt_net/data/locale/locale.pl.ini +9 -0
  35. pygpt_net/data/locale/locale.uk.ini +9 -0
  36. pygpt_net/data/locale/locale.zh.ini +9 -0
  37. pygpt_net/plugin/audio_input/simple.py +17 -3
  38. pygpt_net/provider/core/config/patch.py +15 -1
  39. pygpt_net/ui/menu/config.py +7 -11
  40. pygpt_net/ui/menu/theme.py +9 -2
  41. pygpt_net/ui/widget/lists/context.py +1 -0
  42. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  43. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.38.dist-info}/METADATA +19 -6
  44. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.38.dist-info}/RECORD +49 -43
  45. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  46. /pygpt_net/data/css/{web.light.css → web-blocks.light.css} +0 -0
  47. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.38.dist-info}/LICENSE +0 -0
  48. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.38.dist-info}/WHEEL +0 -0
  49. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.38.dist-info}/entry_points.txt +0 -0
CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.4.38 (2024-12-08)
4
+
5
+ - Added the ability to select a style for chat display between: Blocks, ChatGPT-like, and ChatGPT-like Wide. New option in the menu: Config -> Theme -> Style...
6
+ - Added configuration options for audio input in Settings -> Audio -> Audio Input Device, Channels, and Sampling rate.
7
+
3
8
  ## 2.4.37 (2024-11-30)
4
9
 
5
10
  - The `Query only` mode in `Uploaded` tab has been renamed to `RAG`.
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.37** | build: **2024.11.30** | Python: **>=3.10, <3.12**
5
+ Release: **2.4.38** | build: **2024.12.08** | Python: **>=3.10, <3.12**
6
6
 
7
7
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
8
8
  >
@@ -2680,6 +2680,8 @@ Config -> Settings...
2680
2680
 
2681
2681
  - `Zoom`: Adjusts the zoom in chat window (web render view). `WebEngine / Chromium` render mode only.
2682
2682
 
2683
+ - `Style (chat)`: Chat style (Blocks, or ChatGPT-like, or ChatGPT-like Wide. `WebEngine / Chromium` render mode only.
2684
+
2683
2685
  - `Code syntax highlight`: Syntax highlight theme in code blocks. `WebEngine / Chromium` render mode only.
2684
2686
 
2685
2687
  - `Font Size (chat window)`: Adjusts the font size in the chat window (plain-text) and notepads.
@@ -2702,8 +2704,6 @@ Config -> Settings...
2702
2704
 
2703
2705
  - `Use theme colors in chat window`: Use color theme in chat window, Default: True.
2704
2706
 
2705
- - `Disable markdown formatting in output`: Enables plain-text display in output window, Default: False.
2706
-
2707
2707
  **Files and attachments**
2708
2708
 
2709
2709
  - `Store attachments in the workdir upload directory`: Enable to store a local copy of uploaded attachments for future use. Default: True
@@ -2814,14 +2814,22 @@ Config -> Settings...
2814
2814
 
2815
2815
  **Vision**
2816
2816
 
2817
+ - `Vision: Camera Input Device`: Video capture camera index (index of the camera, default: 0).
2818
+
2817
2819
  - `Vision: Camera capture width (px)`: Video capture resolution (width).
2818
2820
 
2819
2821
  - `Vision: Camera capture height (px)`: Video capture resolution (height).
2820
2822
 
2821
- - `Vision: Camera IDX (number)`: Video capture camera index (number of camera).
2822
-
2823
2823
  - `Vision: Image capture quality`: Video capture image JPEG quality (%).
2824
2824
 
2825
+ **Audio**
2826
+
2827
+ - `Audio Input Device`: Selects the audio device for Microphone input.
2828
+
2829
+ - `Channels`: Input channels, default: 1
2830
+
2831
+ - `Sampling Rate`: Sampling rate, default: 44100
2832
+
2825
2833
  **Indexes (LlamaIndex)**
2826
2834
 
2827
2835
  - `Indexes`: List of created indexes.
@@ -3865,6 +3873,11 @@ may consume additional tokens that are not displayed in the main window.
3865
3873
 
3866
3874
  ## Recent changes:
3867
3875
 
3876
+ **2.4.38 (2024-12-08)**
3877
+
3878
+ - Added the ability to select a style for chat display between: Blocks, ChatGPT-like, and ChatGPT-like Wide. New option in the menu: Config -> Theme -> Style...
3879
+ - Added configuration options for audio input in Settings -> Audio -> Audio Input Device, Channels, and Sampling rate.
3880
+
3868
3881
  **2.4.37 (2024-11-30)**
3869
3882
 
3870
3883
  - The `Query only` mode in `Uploaded` tab has been renamed to `RAG`.
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,8 @@
1
+ 2.4.38 (2024-12-08)
2
+
3
+ - Added the ability to select a style for chat display between: Blocks, ChatGPT-like, and ChatGPT-like Wide. New option in the menu: Config -> Theme -> Style...
4
+ - Added configuration options for audio input in Settings -> Audio -> Audio Input Device, Channels, and Sampling rate.
5
+
1
6
  2.4.37 (2024-11-30)
2
7
 
3
8
  - The `Query only` mode in `Uploaded` tab has been renamed to `RAG`.
pygpt_net/__init__.py CHANGED
@@ -6,15 +6,15 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.30 01:00:00 #
9
+ # Updated Date: 2024.12.08 01: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.37"
17
- __build__ = "2024.11.30"
16
+ __version__ = "2.4.38"
17
+ __build__ = "2024.12.08"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __website__ = "https://pygpt.net"
@@ -86,6 +86,8 @@ class Placeholder:
86
86
  return self.get_agent_providers()
87
87
  elif id == "syntax_styles":
88
88
  return self.get_syntax_styles()
89
+ elif id == "styles":
90
+ return self.get_styles()
89
91
  elif id == "idx":
90
92
  return self.get_idx()
91
93
  elif id == "keys":
@@ -98,9 +100,23 @@ class Placeholder:
98
100
  return self.get_speech_synthesis_actions()
99
101
  elif id == "voice_control_actions":
100
102
  return self.get_voice_control_actions()
103
+ elif id == "audio_input_devices":
104
+ return self.get_audio_input_devices()
101
105
  else:
102
106
  return []
103
107
 
108
+ def get_audio_input_devices(self) -> list:
109
+ """
110
+ Get audio input devices list
111
+
112
+ :return: placeholders list
113
+ """
114
+ devices = self.window.core.audio.get_input_devices()
115
+ data = []
116
+ for device in devices:
117
+ data.append({str(device[0]): device[1]})
118
+ return data
119
+
104
120
  def get_langchain_providers(self) -> list:
105
121
  """
106
122
  Get Langchain LLM provider placeholders list
@@ -276,6 +292,19 @@ class Placeholder:
276
292
  data.append({id: id})
277
293
  return data
278
294
 
295
+ def get_styles(self) -> list:
296
+ """
297
+ Get styles list
298
+
299
+ :return: placeholders list
300
+ """
301
+ styles = self.window.controller.theme.common.get_styles_list()
302
+ styles.sort()
303
+ data = []
304
+ for id in styles:
305
+ data.append({id: id})
306
+ return data
307
+
279
308
  def get_keys(self) -> list:
280
309
  """
281
310
  Get keys
@@ -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.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.utils import trans
@@ -357,7 +357,7 @@ class Mapping:
357
357
  menu_text['config.profile.new'] = 'menu.config.profile.new'
358
358
  menu_text['config.save'] = 'menu.config.save'
359
359
  menu_text['theme.tooltips'] = 'menu.theme.tooltips'
360
- menu_text['theme.blocks'] = 'menu.theme.blocks'
360
+ menu_text['theme.style'] = 'menu.theme.style'
361
361
  menu_text['theme.settings'] = 'menu.theme.settings'
362
362
  menu_text['plugins.presets.new'] = 'menu.plugins.presets.new'
363
363
  menu_text['plugins.presets.edit'] = 'menu.plugins.presets.edit'
@@ -63,6 +63,7 @@ class Editor:
63
63
  self.window.ui.add_hook("update.config.debug", self.hook_update)
64
64
  self.window.ui.add_hook("update.config.notepad.num", self.hook_update)
65
65
  self.window.ui.add_hook("update.config.render.code_syntax", self.hook_update)
66
+ self.window.ui.add_hook("update.config.theme.style", self.hook_update)
66
67
  # self.window.ui.add_hook("llama.idx.storage", self.hook_update) # vector store update
67
68
  # self.window.ui.add_hook("update.config.llama.idx.list", self.hook_update)
68
69
 
@@ -163,6 +164,11 @@ class Editor:
163
164
  value = self.window.core.config.get('render.code_syntax')
164
165
  self.window.controller.theme.toggle_syntax(value, update_menu=True)
165
166
 
167
+ # style
168
+ if self.config_changed('theme.style'):
169
+ value = self.window.core.config.get('theme.style')
170
+ self.window.controller.theme.toggle_style(value)
171
+
166
172
  # convert lists
167
173
  if self.config_changed('ctx.convert_lists'):
168
174
  self.window.controller.ctx.refresh()
@@ -6,17 +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.20 21:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
 
14
+ from pygpt_net.core.events import RenderEvent
15
+
14
16
  from .common import Common
15
17
  from .markdown import Markdown
16
18
  from .menu import Menu
17
19
  from .nodes import Nodes
18
- from ...core.events import RenderEvent
19
-
20
20
 
21
21
  class Theme:
22
22
  def __init__(self, window=None):
@@ -68,11 +68,22 @@ class Theme:
68
68
  # update themes menu
69
69
  self.menu.update_list()
70
70
  self.menu.update_syntax()
71
- self.window.ui.menu['theme.blocks'].setChecked(self.window.core.config.get("render.blocks"))
72
71
 
73
72
  if force:
74
73
  self.window.controller.ui.restore_state() # restore state after theme change
75
74
 
75
+ def toggle_style(self, name: str):
76
+ """
77
+ Toggle theme style (web)
78
+
79
+ :param name: web style name
80
+ """
81
+ self.window.core.config.set('theme.style', name)
82
+ self.window.core.config.save()
83
+ event = RenderEvent(RenderEvent.ON_THEME_CHANGE)
84
+ self.window.dispatch(event)
85
+ self.reload()
86
+
76
87
  def toggle_option(self, name: str, value: any = None):
77
88
  """
78
89
  Toggle theme menu option
@@ -120,10 +131,24 @@ class Theme:
120
131
  if update_menu:
121
132
  self.menu.update_syntax()
122
133
 
134
+ def update_style(self):
135
+ """Update style"""
136
+ current = self.window.core.config.get('theme.style')
137
+ self.toggle_style(current)
138
+
139
+ def update_theme(self, force: bool = True):
140
+ """
141
+ Update theme
142
+
143
+ :param force: force theme change (manual trigger)
144
+ """
145
+ current = self.window.core.config.get('theme')
146
+ self.toggle(current, force=force)
147
+
123
148
  def update_syntax(self):
124
149
  """Update syntax menu"""
125
- curr = self.window.core.config.get('render.code_syntax')
126
- self.toggle_syntax(curr, update_menu=True)
150
+ current = self.window.core.config.get('render.code_syntax')
151
+ self.toggle_syntax(current, update_menu=True)
127
152
 
128
153
  def reload(self, force: bool = True):
129
154
  """
@@ -131,8 +156,7 @@ class Theme:
131
156
 
132
157
  :param force: force theme change (manual trigger)
133
158
  """
134
- current = self.window.core.config.get('theme')
135
- self.toggle(current, force=force)
159
+ self.update_theme(force=force)
136
160
 
137
161
  def apply(self, theme: str = 'dark_teal.xml', custom: str = None):
138
162
  """
@@ -183,4 +207,5 @@ class Theme:
183
207
  def reload_all(self):
184
208
  """Reload all"""
185
209
  self.setup()
210
+ self.update_style()
186
211
  self.update_syntax()
@@ -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.04.30 15:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -156,3 +156,24 @@ class Common:
156
156
  with open(path) as file:
157
157
  content += file.read()
158
158
  return content
159
+
160
+ def get_styles_list(self) -> list:
161
+ """
162
+ Return a list of available styles
163
+
164
+ :return: list of styles names
165
+ """
166
+ styles = []
167
+ app_dir = os.path.join(self.window.core.config.get_app_path(), 'data', 'css')
168
+ user_dir = os.path.join(self.window.core.config.path, 'css')
169
+ for path in [app_dir, user_dir]:
170
+ if not os.path.exists(path):
171
+ continue
172
+ for file in os.listdir(path):
173
+ if file.startswith("web-") and file.endswith('.css'):
174
+ to_replace = ['web-', '.css', '.light', '.dark']
175
+ for item in to_replace:
176
+ file = file.replace(item, '')
177
+ if file not in styles:
178
+ styles.append(file)
179
+ return sorted(styles)
@@ -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.20 21:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -23,6 +23,7 @@ class Markdown:
23
23
  """
24
24
  self.window = window
25
25
  self.css = {} # external styles
26
+ self.web_style = ""
26
27
 
27
28
  def update(self, force: bool = False):
28
29
  """
@@ -60,7 +61,8 @@ class Markdown:
60
61
 
61
62
  :return: stylesheet
62
63
  """
63
- if "web" not in self.css:
64
+ web_style = self.window.core.config.get("theme.style", "blocks")
65
+ if "web" not in self.css or self.web_style != web_style:
64
66
  self.load()
65
67
  if "web" in self.css:
66
68
  return self.css["web"]
@@ -73,31 +75,41 @@ class Markdown:
73
75
  self.window.dispatch(event) # per current engine
74
76
  self.window.controller.ctx.refresh()
75
77
  self.window.controller.ctx.refresh_output()
76
- data = {
78
+ event = RenderEvent(RenderEvent.END, {
77
79
  "meta": meta,
78
- }
79
- event = RenderEvent(RenderEvent.END, data)
80
+ })
80
81
  self.window.dispatch(event)
81
82
 
82
83
  def load(self):
83
84
  """Load markdown styles"""
84
- parents = ["markdown", "web"]
85
+ parents = [
86
+ "markdown",
87
+ "web",
88
+ ]
89
+ web_style = self.window.core.config.get("theme.style", "blocks")
85
90
  for base_name in parents:
91
+ suffix = ""
92
+ if base_name == 'web':
93
+ suffix = "-" + web_style
94
+ self.web_style = web_style
86
95
  theme = self.window.core.config.get('theme')
87
96
  name = str(base_name)
88
- color_name = str(base_name)
89
97
  if theme.startswith('light'):
90
- color_name += '.light'
98
+ color = '.light'
91
99
  else:
92
- color_name += '.dark'
100
+ color = '.dark'
101
+
102
+ # load CSS, app + user
103
+ file_base = name + suffix + '.css'
104
+ file_color = name + suffix + color + '.css'
93
105
  paths = []
94
- paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', name + '.css'))
95
- paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', color_name + '.css'))
96
- paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', name + '.css'))
97
- paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', color_name + '.css'))
106
+ paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', file_base))
107
+ paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', file_color))
108
+ paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', file_base))
109
+ paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', file_color))
98
110
  content = ''
99
111
  for path in paths:
100
- if os.path.exists(path):
112
+ if os.path.exists(path) and os.path.isfile(path):
101
113
  with open(path, 'r') as file:
102
114
  content += file.read()
103
115
 
@@ -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.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction
@@ -30,6 +30,18 @@ class Menu:
30
30
  # setup themes list menu
31
31
  if self.loaded:
32
32
  return
33
+
34
+ # styles
35
+ styles = self.window.controller.theme.common.get_styles_list()
36
+ for style in styles:
37
+ style_id = style.lower()
38
+ title = style.replace('_', ' ').title()
39
+ self.window.ui.menu['theme_style'][style_id] = QAction(title, self.window, checkable=True)
40
+ self.window.ui.menu['theme_style'][style_id].triggered.connect(
41
+ lambda checked=None, style=style_id: self.window.controller.theme.toggle_style(style))
42
+ self.window.ui.menu['theme.style'].addAction(self.window.ui.menu['theme_style'][style_id])
43
+
44
+ # color themes
33
45
  themes = self.window.controller.theme.common.get_themes_list()
34
46
  for theme in themes:
35
47
  name = self.window.controller.theme.common.translate(theme)
@@ -42,6 +54,7 @@ class Menu:
42
54
  self.window.ui.menu['theme.dark'].addAction(self.window.ui.menu['theme'][theme])
43
55
  elif theme.startswith('light'):
44
56
  self.window.ui.menu['theme.light'].addAction(self.window.ui.menu['theme'][theme])
57
+
45
58
  self.loaded = True
46
59
 
47
60
  def setup_syntax(self):
@@ -86,14 +99,22 @@ class Menu:
86
99
 
87
100
  def update_list(self):
88
101
  """Update theme list menu"""
89
- current = self.window.core.config.get('theme')
102
+ # styles
103
+ current_style = self.window.core.config.get('theme.style')
104
+ for style in self.window.ui.menu['theme_style']:
105
+ self.window.ui.menu['theme_style'][style].setChecked(False)
106
+ if current_style in self.window.ui.menu['theme_style']:
107
+ self.window.ui.menu['theme_style'][current_style].setChecked(True)
108
+
109
+ # color themes
110
+ current_theme = self.window.core.config.get('theme')
90
111
  for theme in self.window.ui.menu['theme']:
91
112
  self.window.ui.menu['theme'][theme].setChecked(False)
92
- if current in self.window.ui.menu['theme']:
93
- self.window.ui.menu['theme'][current].setChecked(True)
113
+ if current_theme in self.window.ui.menu['theme']:
114
+ self.window.ui.menu['theme'][current_theme].setChecked(True)
94
115
 
95
116
  def update_syntax(self):
96
- """Update syntax menu"""
117
+ """Update code syntax highlight menu"""
97
118
  current = self.window.core.config.get('render.code_syntax')
98
119
  for style in self.window.ui.menu['theme_syntax']:
99
120
  self.window.ui.menu['theme_syntax'][style].setChecked(False)
@@ -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.29 23:00:00 #
9
+ # Updated Date: 2024.11.30 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -119,6 +119,8 @@ class Context:
119
119
  if ("type" not in file
120
120
  or file["type"] not in ["local_file", "url"]):
121
121
  continue
122
+ if not "uuid" in file:
123
+ continue
122
124
  file_id = file["uuid"]
123
125
  file_idx_path = os.path.join(meta_path, file_id)
124
126
  text_path = os.path.join(file_idx_path, file_id + ".txt")
@@ -555,17 +557,6 @@ class Context:
555
557
  if meta is not None:
556
558
  self.delete_index(meta)
557
559
 
558
- def reset_by_meta_id(self, meta_id: int, delete_files: bool = False):
559
- """
560
- Delete all attachments for meta by id
561
-
562
- :param meta_id: Meta id
563
- :param delete_files: delete files
564
- """
565
- meta = self.window.core.ctx.get_meta_by_id(meta_id)
566
- if meta is not None:
567
- self.reset_by_meta(meta, delete_files)
568
-
569
560
  def reset_by_meta(self, meta: CtxMeta, delete_files: bool = False):
570
561
  """
571
562
  Delete all attachments for meta
@@ -578,6 +569,17 @@ class Context:
578
569
  if delete_files:
579
570
  self.delete_index(meta)
580
571
 
572
+ def reset_by_meta_id(self, meta_id: int, delete_files: bool = False):
573
+ """
574
+ Delete all attachments for meta by id
575
+
576
+ :param meta_id: Meta id
577
+ :param delete_files: delete files
578
+ """
579
+ meta = self.window.core.ctx.get_meta_by_id(meta_id)
580
+ if meta is not None:
581
+ self.reset_by_meta(meta, delete_files)
582
+
581
583
  def clear(self, meta: CtxMeta, delete_files: bool = False):
582
584
  """
583
585
  Clear all attachments by ctx meta
@@ -6,10 +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.11.26 19:00:00 #
9
+ # Updated Date: 2024.12.08 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
13
+ from bs4 import UnicodeDammit
13
14
 
14
15
  from pygpt_net.provider.audio_input.base import BaseProvider as InputBaseProvider
15
16
  from pygpt_net.provider.audio_output.base import BaseProvider as OutputBaseProvider
@@ -27,6 +28,55 @@ class Audio:
27
28
  "input": {},
28
29
  "output": {},
29
30
  }
31
+ self.last_error = None
32
+
33
+ def get_input_devices(self) -> list:
34
+ """
35
+ Get input devices
36
+
37
+ :return devices list: [(id, name)]
38
+ """
39
+ import pyaudio
40
+ devices = []
41
+ try:
42
+ p = pyaudio.PyAudio()
43
+ num_devices = p.get_device_count()
44
+ for i in range(num_devices):
45
+ info = p.get_device_info_by_index(i)
46
+ if info["maxInputChannels"] > 0:
47
+ dammit = UnicodeDammit(info["name"])
48
+ devices.append((i, dammit.unicode_markup))
49
+ # print(f"Device ID {i}: {info['name']}")
50
+ p.terminate()
51
+ except Exception as e:
52
+ print(f"Audio input devices receive error: {e}")
53
+ return devices
54
+
55
+ def is_device_compatible(self, device_index) -> bool:
56
+ """
57
+ Check if device is compatible
58
+
59
+ :param device_index: device index
60
+ :return: True if compatible
61
+ """
62
+ import pyaudio
63
+ rate = int(self.window.core.config.get('audio.input.rate', 44100))
64
+ channels = int(self.window.core.config.get('audio.input.channels', 1))
65
+ p = pyaudio.PyAudio()
66
+ info = p.get_device_info_by_index(device_index)
67
+ supported = False
68
+ try:
69
+ p.is_format_supported(
70
+ rate=rate,
71
+ input_device=info['index'],
72
+ input_channels=channels,
73
+ input_format=pyaudio.paInt16)
74
+ supported = True
75
+ except ValueError as e:
76
+ self.last_error = str(e)
77
+ supported = False
78
+ p.terminate()
79
+ return supported
30
80
 
31
81
  def is_registered(self, id: str, type: str = "output") -> bool:
32
82
  """
@@ -92,3 +142,11 @@ class Audio:
92
142
  :return: cleaned text
93
143
  """
94
144
  return re.sub(r'~###~.*?~###~', '', str(text))
145
+
146
+ def get_last_error(self) -> str:
147
+ """
148
+ Return last error
149
+
150
+ :return: Error
151
+ """
152
+ return self.last_error
@@ -6,13 +6,12 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.23 21:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  import shutil
14
14
 
15
- from datetime import datetime
16
15
  from pathlib import PurePath
17
16
  from uuid import uuid4
18
17
 
@@ -38,18 +37,6 @@ class Filesystem:
38
37
  self.types = Types(window)
39
38
  self.url = Url(window)
40
39
  self.workdir_placeholder = "%workdir%"
41
- self.styles = [
42
- "style.css",
43
- "style.dark.css",
44
- "style.light.css",
45
- "markdown.css",
46
- "markdown.dark.css",
47
- "markdown.light.css",
48
- "web.css",
49
- "web.dark.css",
50
- "web.light.css",
51
- "fix_windows.css",
52
- ]
53
40
 
54
41
  def install(self):
55
42
  """Install provider data"""
@@ -77,9 +64,9 @@ class Filesystem:
77
64
 
78
65
  src_dir = os.path.join(self.window.core.config.get_app_path(), 'data', 'css')
79
66
  dst_dir = os.path.join(self.window.core.config.path, 'css')
80
-
67
+ app_styles = os.listdir(src_dir)
81
68
  try:
82
- for style in self.styles:
69
+ for style in app_styles:
83
70
  src = os.path.join(src_dir, style)
84
71
  dst = os.path.join(dst_dir, style)
85
72
  if (not os.path.exists(dst) or force) and os.path.exists(src):
@@ -91,7 +78,8 @@ class Filesystem:
91
78
  """Backup user custom css styles"""
92
79
  css_dir = os.path.join(self.window.core.config.path, 'css')
93
80
  backup_file_extension = '.backup'
94
- for style in self.styles:
81
+ user_styles = os.listdir(css_dir)
82
+ for style in user_styles:
95
83
  src = os.path.join(css_dir, style)
96
84
  dst = os.path.join(css_dir, style + backup_file_extension)
97
85
  if os.path.exists(src):
@@ -457,5 +445,3 @@ class Filesystem:
457
445
  else:
458
446
  files = [os.path.join(path, f) for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
459
447
  return files
460
-
461
-