pygpt-net 2.4.41__py3-none-any.whl → 2.4.44__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 (183) hide show
  1. CHANGELOG.md +19 -0
  2. README.md +151 -71
  3. pygpt_net/CHANGELOG.txt +19 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/app.py +3 -1
  6. pygpt_net/controller/attachment.py +31 -3
  7. pygpt_net/controller/audio/__init__.py +2 -2
  8. pygpt_net/controller/camera.py +1 -10
  9. pygpt_net/controller/chat/attachment.py +37 -36
  10. pygpt_net/controller/chat/audio.py +2 -2
  11. pygpt_net/controller/config/placeholder.py +20 -4
  12. pygpt_net/controller/idx/common.py +7 -3
  13. pygpt_net/controller/ui/mode.py +16 -21
  14. pygpt_net/core/attachments/__init__.py +7 -2
  15. pygpt_net/core/attachments/context.py +52 -34
  16. pygpt_net/core/audio/__init__.py +4 -1
  17. pygpt_net/core/audio/whisper.py +37 -0
  18. pygpt_net/core/bridge/worker.py +2 -2
  19. pygpt_net/core/db/__init__.py +2 -1
  20. pygpt_net/core/debug/attachments.py +1 -0
  21. pygpt_net/core/debug/events.py +22 -10
  22. pygpt_net/core/debug/tabs.py +6 -3
  23. pygpt_net/core/history.py +3 -2
  24. pygpt_net/core/idx/__init__.py +23 -6
  25. pygpt_net/core/idx/chat.py +15 -5
  26. pygpt_net/core/idx/indexing.py +47 -14
  27. pygpt_net/core/idx/ui/__init__.py +22 -0
  28. pygpt_net/core/idx/ui/loaders.py +217 -0
  29. pygpt_net/core/installer.py +2 -4
  30. pygpt_net/core/models.py +62 -17
  31. pygpt_net/core/modes.py +11 -13
  32. pygpt_net/core/notepad.py +4 -4
  33. pygpt_net/core/plugins.py +27 -16
  34. pygpt_net/core/presets.py +20 -9
  35. pygpt_net/core/profile.py +11 -3
  36. pygpt_net/core/render/web/parser.py +3 -1
  37. pygpt_net/core/settings.py +5 -5
  38. pygpt_net/core/tabs/tab.py +10 -2
  39. pygpt_net/core/tokens.py +8 -6
  40. pygpt_net/core/web/__init__.py +105 -0
  41. pygpt_net/core/{web.py → web/helpers.py} +93 -67
  42. pygpt_net/data/config/config.json +4 -4
  43. pygpt_net/data/config/models.json +3 -3
  44. pygpt_net/data/config/modes.json +3 -3
  45. pygpt_net/data/config/settings.json +5 -5
  46. pygpt_net/data/locale/locale.de.ini +3 -3
  47. pygpt_net/data/locale/locale.en.ini +12 -9
  48. pygpt_net/data/locale/locale.es.ini +3 -3
  49. pygpt_net/data/locale/locale.fr.ini +3 -3
  50. pygpt_net/data/locale/locale.it.ini +3 -3
  51. pygpt_net/data/locale/locale.pl.ini +3 -3
  52. pygpt_net/data/locale/locale.uk.ini +3 -3
  53. pygpt_net/data/locale/locale.zh.ini +3 -3
  54. pygpt_net/data/locale/plugin.cmd_web.en.ini +2 -0
  55. pygpt_net/data/locale/plugin.mailer.en.ini +21 -0
  56. pygpt_net/item/attachment.py +5 -1
  57. pygpt_net/item/ctx.py +111 -3
  58. pygpt_net/migrations/Version20241215110000.py +25 -0
  59. pygpt_net/migrations/__init__.py +3 -1
  60. pygpt_net/plugin/agent/__init__.py +7 -2
  61. pygpt_net/plugin/audio_output/__init__.py +6 -1
  62. pygpt_net/plugin/base/plugin.py +58 -26
  63. pygpt_net/plugin/base/worker.py +20 -17
  64. pygpt_net/plugin/cmd_files/__init__.py +3 -2
  65. pygpt_net/plugin/cmd_history/config.py +2 -2
  66. pygpt_net/plugin/cmd_web/__init__.py +3 -4
  67. pygpt_net/plugin/cmd_web/config.py +71 -3
  68. pygpt_net/plugin/cmd_web/websearch.py +20 -12
  69. pygpt_net/plugin/cmd_web/worker.py +67 -4
  70. pygpt_net/plugin/idx_llama_index/config.py +3 -3
  71. pygpt_net/plugin/mailer/__init__.py +123 -0
  72. pygpt_net/plugin/mailer/config.py +149 -0
  73. pygpt_net/plugin/mailer/runner.py +285 -0
  74. pygpt_net/plugin/mailer/worker.py +123 -0
  75. pygpt_net/provider/agents/base.py +5 -2
  76. pygpt_net/provider/agents/openai.py +4 -2
  77. pygpt_net/provider/agents/openai_assistant.py +4 -2
  78. pygpt_net/provider/agents/planner.py +4 -2
  79. pygpt_net/provider/agents/react.py +4 -2
  80. pygpt_net/provider/audio_output/openai_tts.py +5 -11
  81. pygpt_net/provider/core/assistant/base.py +5 -3
  82. pygpt_net/provider/core/assistant/json_file.py +8 -5
  83. pygpt_net/provider/core/assistant_file/base.py +4 -3
  84. pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +4 -3
  85. pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +3 -2
  86. pygpt_net/provider/core/assistant_store/base.py +6 -4
  87. pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +5 -4
  88. pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +5 -3
  89. pygpt_net/provider/core/attachment/base.py +5 -3
  90. pygpt_net/provider/core/attachment/json_file.py +7 -3
  91. pygpt_net/provider/core/calendar/base.py +5 -3
  92. pygpt_net/provider/core/calendar/db_sqlite/__init__.py +6 -5
  93. pygpt_net/provider/core/calendar/db_sqlite/storage.py +5 -4
  94. pygpt_net/provider/core/config/base.py +8 -6
  95. pygpt_net/provider/core/config/json_file.py +9 -7
  96. pygpt_net/provider/core/config/patch.py +6 -0
  97. pygpt_net/provider/core/ctx/base.py +27 -25
  98. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +51 -35
  99. pygpt_net/provider/core/ctx/db_sqlite/storage.py +92 -38
  100. pygpt_net/provider/core/ctx/db_sqlite/utils.py +37 -11
  101. pygpt_net/provider/core/index/base.py +129 -23
  102. pygpt_net/provider/core/index/db_sqlite/__init__.py +130 -23
  103. pygpt_net/provider/core/index/db_sqlite/storage.py +130 -23
  104. pygpt_net/provider/core/index/db_sqlite/utils.py +4 -2
  105. pygpt_net/provider/core/mode/base.py +5 -3
  106. pygpt_net/provider/core/mode/json_file.py +7 -6
  107. pygpt_net/provider/core/model/base.py +6 -4
  108. pygpt_net/provider/core/model/json_file.py +9 -7
  109. pygpt_net/provider/core/notepad/base.py +5 -3
  110. pygpt_net/provider/core/notepad/db_sqlite/__init__.py +5 -4
  111. pygpt_net/provider/core/notepad/db_sqlite/storage.py +4 -3
  112. pygpt_net/provider/core/plugin_preset/base.py +4 -2
  113. pygpt_net/provider/core/plugin_preset/json_file.py +5 -3
  114. pygpt_net/provider/core/preset/base.py +6 -4
  115. pygpt_net/provider/core/preset/json_file.py +9 -9
  116. pygpt_net/provider/core/prompt/base.py +6 -3
  117. pygpt_net/provider/core/prompt/json_file.py +11 -6
  118. pygpt_net/provider/gpt/assistants.py +15 -6
  119. pygpt_net/provider/gpt/audio.py +5 -5
  120. pygpt_net/provider/gpt/chat.py +7 -5
  121. pygpt_net/provider/gpt/completion.py +8 -4
  122. pygpt_net/provider/gpt/image.py +3 -3
  123. pygpt_net/provider/gpt/store.py +46 -12
  124. pygpt_net/provider/gpt/vision.py +16 -11
  125. pygpt_net/provider/llms/anthropic.py +7 -2
  126. pygpt_net/provider/llms/azure_openai.py +26 -5
  127. pygpt_net/provider/llms/base.py +47 -9
  128. pygpt_net/provider/llms/google.py +7 -2
  129. pygpt_net/provider/llms/hugging_face.py +13 -3
  130. pygpt_net/provider/llms/hugging_face_api.py +18 -4
  131. pygpt_net/provider/llms/local.py +7 -2
  132. pygpt_net/provider/llms/ollama.py +30 -6
  133. pygpt_net/provider/llms/openai.py +32 -6
  134. pygpt_net/provider/loaders/base.py +14 -0
  135. pygpt_net/provider/loaders/hub/yt/base.py +5 -0
  136. pygpt_net/provider/loaders/web_database.py +13 -5
  137. pygpt_net/provider/loaders/web_github_issues.py +5 -1
  138. pygpt_net/provider/loaders/web_google_calendar.py +9 -1
  139. pygpt_net/provider/loaders/web_google_docs.py +6 -1
  140. pygpt_net/provider/loaders/web_google_drive.py +10 -1
  141. pygpt_net/provider/loaders/web_google_gmail.py +2 -1
  142. pygpt_net/provider/loaders/web_google_keep.py +5 -1
  143. pygpt_net/provider/loaders/web_google_sheets.py +5 -1
  144. pygpt_net/provider/loaders/web_microsoft_onedrive.py +15 -1
  145. pygpt_net/provider/loaders/web_page.py +4 -2
  146. pygpt_net/provider/loaders/web_rss.py +2 -1
  147. pygpt_net/provider/loaders/web_sitemap.py +2 -1
  148. pygpt_net/provider/loaders/web_twitter.py +4 -2
  149. pygpt_net/provider/loaders/web_yt.py +17 -2
  150. pygpt_net/provider/vector_stores/__init__.py +45 -14
  151. pygpt_net/provider/vector_stores/base.py +35 -8
  152. pygpt_net/provider/vector_stores/chroma.py +13 -3
  153. pygpt_net/provider/vector_stores/ctx_attachment.py +32 -13
  154. pygpt_net/provider/vector_stores/elasticsearch.py +12 -3
  155. pygpt_net/provider/vector_stores/pinecode.py +12 -3
  156. pygpt_net/provider/vector_stores/redis.py +12 -3
  157. pygpt_net/provider/vector_stores/simple.py +12 -3
  158. pygpt_net/provider/vector_stores/temp.py +16 -4
  159. pygpt_net/provider/web/base.py +10 -3
  160. pygpt_net/provider/web/google_custom_search.py +9 -3
  161. pygpt_net/provider/web/microsoft_bing.py +9 -3
  162. pygpt_net/tools/__init__.py +13 -5
  163. pygpt_net/tools/audio_transcriber/__init__.py +4 -3
  164. pygpt_net/tools/base.py +15 -8
  165. pygpt_net/tools/code_interpreter/__init__.py +4 -3
  166. pygpt_net/tools/html_canvas/__init__.py +4 -3
  167. pygpt_net/tools/image_viewer/__init__.py +10 -4
  168. pygpt_net/tools/indexer/__init__.py +15 -46
  169. pygpt_net/tools/indexer/ui/web.py +20 -78
  170. pygpt_net/tools/media_player/__init__.py +4 -3
  171. pygpt_net/tools/text_editor/__init__.py +36 -10
  172. pygpt_net/ui/layout/chat/output.py +2 -2
  173. pygpt_net/ui/layout/ctx/ctx_list.py +86 -18
  174. pygpt_net/ui/menu/audio.py +12 -1
  175. pygpt_net/ui/widget/dialog/url.py +151 -14
  176. pygpt_net/ui/widget/element/group.py +15 -2
  177. pygpt_net/ui/widget/lists/context.py +23 -9
  178. pygpt_net/utils.py +1 -1
  179. {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/METADATA +152 -72
  180. {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/RECORD +183 -173
  181. {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/LICENSE +0 -0
  182. {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/WHEEL +0 -0
  183. {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/entry_points.txt +0 -0
@@ -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.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import time
13
+ from typing import List, Dict, Optional
13
14
  from uuid import uuid4
14
15
  from packaging.version import Version
15
16
 
@@ -29,6 +30,11 @@ class DbSqliteProvider(BaseProvider):
29
30
  self.type = "ctx"
30
31
 
31
32
  def attach(self, window):
33
+ """
34
+ Attach window
35
+
36
+ :param window: Window instance
37
+ """
32
38
  self.window = window
33
39
  self.storage.attach(window)
34
40
 
@@ -68,14 +74,14 @@ class DbSqliteProvider(BaseProvider):
68
74
 
69
75
  def get_meta(
70
76
  self,
71
- search_string: str = None,
72
- order_by: str = None,
73
- order_direction: str = None,
74
- limit: int = None,
75
- offset: int = None,
76
- filters: dict = None,
77
+ search_string: Optional[str] = None,
78
+ order_by: Optional[str] = None,
79
+ order_direction: Optional[str] = None,
80
+ limit: Optional[int] = None,
81
+ offset: Optional[int] = None,
82
+ filters: Optional[dict] = None,
77
83
  search_content: bool = False,
78
- ) -> dict:
84
+ ) -> Dict[int, CtxMeta]:
79
85
  """
80
86
  Return dict of ctx meta, TODO: add order, limit, offset, etc.
81
87
 
@@ -102,7 +108,7 @@ class DbSqliteProvider(BaseProvider):
102
108
  search_content=search_content,
103
109
  )
104
110
 
105
- def get_meta_indexed(self) -> dict:
111
+ def get_meta_indexed(self) -> Dict[int, CtxMeta]:
106
112
  """
107
113
  Return dict of ctx meta indexed by ID
108
114
 
@@ -118,7 +124,7 @@ class DbSqliteProvider(BaseProvider):
118
124
  """
119
125
  return self.storage.get_last_meta_id()
120
126
 
121
- def get_item_by_id(self, id: int) -> CtxItem:
127
+ def get_item_by_id(self, id: int) -> Optional[CtxItem]:
122
128
  """
123
129
  Get ctx item by ID
124
130
 
@@ -127,7 +133,7 @@ class DbSqliteProvider(BaseProvider):
127
133
  """
128
134
  return self.storage.get_item_by_id(id)
129
135
 
130
- def load(self, id: int) -> list:
136
+ def load(self, id: int) -> List[CtxItem]:
131
137
  """
132
138
  Load items for ctx ID
133
139
 
@@ -137,13 +143,14 @@ class DbSqliteProvider(BaseProvider):
137
143
  return self.storage.get_items(id)
138
144
 
139
145
  def get_ctx_count_by_day(
140
- self, year: int,
141
- month: int = None,
142
- day: int = None,
143
- search_string: str = None,
144
- filters: dict = None,
146
+ self,
147
+ year: int,
148
+ month: Optional[int] = None,
149
+ day: Optional[int] = None,
150
+ search_string: Optional[str] = None,
151
+ filters: Optional[dict] = None,
145
152
  search_content: bool = False,
146
- ) -> dict:
153
+ ) -> Dict[str, int]:
147
154
  """
148
155
  Get ctx count by day or by month if only year is provided
149
156
 
@@ -165,13 +172,14 @@ class DbSqliteProvider(BaseProvider):
165
172
  )
166
173
 
167
174
  def get_ctx_labels_count_by_day(
168
- self, year: int,
169
- month: int = None,
170
- day: int = None,
171
- search_string: str = None,
172
- filters: dict = None,
175
+ self,
176
+ year: int,
177
+ month: Optional[int] = None,
178
+ day: Optional[int] = None,
179
+ search_string: Optional[str] = None,
180
+ filters: Optional[dict] = None,
173
181
  search_content: bool = False,
174
- ) -> dict:
182
+ ) -> Dict[str, Dict[int, int]]:
175
183
  """
176
184
  Get ctx labels count by day or by month if only year is provided
177
185
 
@@ -213,7 +221,7 @@ class DbSqliteProvider(BaseProvider):
213
221
  self.storage.update_meta_ts(item.meta_id)
214
222
  return self.storage.update_item(item) is not None
215
223
 
216
- def save(self, id: int, meta: CtxMeta, items: list) -> bool:
224
+ def save(self, id: int, meta: CtxMeta, items: List[CtxItem]) -> bool:
217
225
  """
218
226
  Save ctx
219
227
 
@@ -225,7 +233,7 @@ class DbSqliteProvider(BaseProvider):
225
233
  if self.storage.update_meta(meta):
226
234
  return True # update only meta, items are appended separately
227
235
 
228
- def save_all(self, id: int, meta: CtxMeta, items: list) -> bool:
236
+ def save_all(self, id: int, meta: CtxMeta, items: List[CtxItem]) -> bool:
229
237
  """
230
238
  Save ctx
231
239
 
@@ -255,7 +263,7 @@ class DbSqliteProvider(BaseProvider):
255
263
  """
256
264
  return self.storage.delete_item_by_id(id)
257
265
 
258
- def remove_items_from(self, meta_id: int, item_id: int):
266
+ def remove_items_from(self, meta_id: int, item_id: int) -> bool:
259
267
  """
260
268
  Remove ctx items from meta_id
261
269
 
@@ -328,7 +336,7 @@ class DbSqliteProvider(BaseProvider):
328
336
  """
329
337
  return self.storage.clear_meta_indexed_all()
330
338
 
331
- def get_groups(self) -> dict:
339
+ def get_groups(self) -> Dict[int, CtxGroup]:
332
340
  """
333
341
  Return dict of groups
334
342
 
@@ -336,7 +344,7 @@ class DbSqliteProvider(BaseProvider):
336
344
  """
337
345
  return self.storage.get_groups()
338
346
 
339
- def get_meta_by_id(self, id: int) -> CtxMeta or None:
347
+ def get_meta_by_id(self, id: int) -> Optional[CtxMeta]:
340
348
  """
341
349
  Get meta by ID
342
350
 
@@ -353,15 +361,16 @@ class DbSqliteProvider(BaseProvider):
353
361
  """
354
362
  return self.storage.get_meta_by_root_id_and_preset_id(root_id, preset_id)
355
363
 
356
- def insert_group(self, group: CtxGroup):
364
+ def insert_group(self, group: CtxGroup) -> int:
357
365
  """
358
366
  Insert group
359
367
 
360
368
  :param group: CtxGroup
369
+ :return: group ID
361
370
  """
362
371
  return self.storage.insert_group(group)
363
372
 
364
- def update_group(self, group: CtxGroup):
373
+ def update_group(self, group: CtxGroup) -> bool:
365
374
  """
366
375
  Update group
367
376
 
@@ -369,32 +378,39 @@ class DbSqliteProvider(BaseProvider):
369
378
  """
370
379
  return self.storage.update_group(group)
371
380
 
372
- def remove_group(self, id: int, all: bool = False):
381
+ def remove_group(self, id: int, all: bool = False) -> bool:
373
382
  """
374
383
  Remove group by ID
375
384
 
376
385
  :param id: group ID
377
386
  :param all: remove items
387
+ :return: True if removed
378
388
  """
379
389
  return self.storage.delete_group(id, all=all)
380
390
 
381
- def truncate_groups(self):
382
- """Remove groups"""
391
+ def truncate_groups(self) -> bool:
392
+ """
393
+ Remove groups
394
+
395
+ :return: True if removed
396
+ """
383
397
  return self.storage.truncate_groups()
384
398
 
385
- def update_meta_group_id(self, id: int, group_id: int):
399
+ def update_meta_group_id(self, id: int, group_id: int) -> bool:
386
400
  """
387
401
  Update meta group ID
388
402
 
389
403
  :param id: ctx ID
390
404
  :param group_id: group ID
405
+ :return: True if updated
391
406
  """
392
407
  return self.storage.update_meta_group_id(id, group_id)
393
408
 
394
- def clear_meta(self, id: int):
409
+ def clear_meta(self, id: int) -> bool:
395
410
  """
396
411
  Clear meta by ID
397
412
 
398
413
  :param id: ctx ID
414
+ :return: True if cleared
399
415
  """
400
416
  return self.storage.clear_meta(id)
@@ -6,12 +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.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from datetime import datetime
13
13
  import re
14
14
  import time
15
+ from typing import Dict, Optional, Tuple, List
15
16
 
16
17
  from sqlalchemy import text
17
18
 
@@ -46,11 +47,11 @@ class Storage:
46
47
 
47
48
  def prepare_query(
48
49
  self,
49
- search_string: str = None,
50
- filters: dict = None,
50
+ search_string: Optional[str] = None,
51
+ filters: Optional[dict] = None,
51
52
  search_content: bool = False,
52
53
  append_date_ranges: bool = True,
53
- ):
54
+ ) -> Tuple[str, str, dict]:
54
55
  """
55
56
  Prepare query for search_string and filters
56
57
 
@@ -67,6 +68,9 @@ class Storage:
67
68
  # only base by default
68
69
  where_clauses.append("(m.root_id IS NULL OR m.root_id = 0)")
69
70
 
71
+ # join group
72
+ join_clauses.append("LEFT JOIN ctx_group g ON m.group_id = g.id")
73
+
70
74
  # search_string
71
75
  if search_string:
72
76
  date_ranges = search_by_date_string(search_string)
@@ -105,15 +109,16 @@ class Storage:
105
109
  continue
106
110
  mode = filter.get('mode', '=')
107
111
  value = filter.get('value', '')
112
+ key_name = 'm.' + key
108
113
  if isinstance(value, int):
109
- where_clauses.append(f"{key} {mode} :{key}")
114
+ where_clauses.append(f"{key_name} {mode} :{key}")
110
115
  bind_params[key] = value
111
116
  elif isinstance(value, str):
112
- where_clauses.append(f"{key} {mode} :{key}")
117
+ where_clauses.append(f"{key_name} {mode} :{key}")
113
118
  bind_params[key] = f"%{value}%"
114
119
  elif isinstance(value, list):
115
120
  values = "(" + ",".join([str(x) for x in value]) + ")"
116
- where_clauses.append(f"{key} {mode} {values}")
121
+ where_clauses.append(f"{key_name} {mode} {values}")
117
122
 
118
123
  where_statement = " AND ".join(where_clauses) if where_clauses else "1"
119
124
  join_statement = " ".join(join_clauses) if join_clauses else ""
@@ -122,14 +127,14 @@ class Storage:
122
127
 
123
128
  def get_meta(
124
129
  self,
125
- search_string: str = None,
126
- order_by: str = None,
127
- order_direction: str = None,
128
- limit: int = None,
129
- offset: int = None,
130
- filters: dict = None,
130
+ search_string: Optional[str] = None,
131
+ order_by: Optional[str] = None,
132
+ order_direction: Optional[str] = None,
133
+ limit: Optional[int] = None,
134
+ offset: Optional[int] = None,
135
+ filters: Optional[dict] = None,
131
136
  search_content: bool = False,
132
- ) -> dict:
137
+ ) -> Dict[int, CtxMeta]:
133
138
  """
134
139
  Return dict with CtxMeta objects, indexed by ID
135
140
 
@@ -153,8 +158,18 @@ class Storage:
153
158
  append_date_ranges=True,
154
159
  )
155
160
  stmt_text = f"""
156
- SELECT m.* FROM ctx_meta m {join_statement} WHERE {where_statement}
157
- ORDER BY m.updated_ts DESC {limit_suffix}
161
+ SELECT
162
+ m.*,
163
+ g.name as group_name,
164
+ g.uuid as group_uuid,
165
+ g.additional_ctx_json as group_additional_ctx_json
166
+ FROM
167
+ ctx_meta m
168
+ {join_statement}
169
+ WHERE
170
+ {where_statement}
171
+ ORDER BY
172
+ m.updated_ts DESC {limit_suffix}
158
173
  """
159
174
  stmt = text(stmt_text).bindparams(**bind_params)
160
175
 
@@ -169,14 +184,24 @@ class Storage:
169
184
 
170
185
  return items
171
186
 
172
- def get_meta_indexed(self) -> dict:
187
+ def get_meta_indexed(self) -> Dict[int, CtxMeta]:
173
188
  """
174
189
  Return dict with indexed CtxMeta objects, indexed by ID
175
190
 
176
191
  :return: dict of CtxMeta
177
192
  """
178
193
  stmt_text = f"""
179
- SELECT * FROM ctx_meta WHERE indexed_ts > 0
194
+ SELECT
195
+ m.*,
196
+ g.name as group_name,
197
+ g.uuid as group_uuid,
198
+ g.additional_ctx_json as group_additional_ctx_json
199
+ FROM
200
+ ctx_meta m
201
+ LEFT JOIN
202
+ ctx_group g ON m.group_id = g.id
203
+ WHERE
204
+ indexed_ts > 0
180
205
  """
181
206
  stmt = text(stmt_text)
182
207
  items = {}
@@ -189,7 +214,7 @@ class Storage:
189
214
  items[meta.id] = meta
190
215
  return items
191
216
 
192
- def get_item_by_id(self, id: int) -> CtxItem:
217
+ def get_item_by_id(self, id: int) -> Optional[CtxItem]:
193
218
  """
194
219
  Return ctx item by ID
195
220
 
@@ -210,7 +235,11 @@ class Storage:
210
235
  return item
211
236
  return None
212
237
 
213
- def get_meta_by_root_id_and_preset_id(self, root_id: int, preset_id: str) -> dict:
238
+ def get_meta_by_root_id_and_preset_id(
239
+ self,
240
+ root_id: int,
241
+ preset_id: str
242
+ ) -> Dict[int, CtxMeta]:
214
243
  """
215
244
  Return dict with indexed CtxMeta objects, indexed by ID
216
245
 
@@ -233,7 +262,7 @@ class Storage:
233
262
  items[meta.id] = meta
234
263
  return items
235
264
 
236
- def get_meta_by_id(self, id: int) -> CtxMeta or None:
265
+ def get_meta_by_id(self, id: int) -> Optional[CtxMeta]:
237
266
  """
238
267
  Return ctx meta by ID
239
268
 
@@ -269,7 +298,7 @@ class Storage:
269
298
  return int(row.id)
270
299
  return 0
271
300
 
272
- def get_items(self, id: int) -> list:
301
+ def get_items(self, id: int) -> List[CtxItem]:
273
302
  """
274
303
  Return ctx items list by ctx meta ID
275
304
 
@@ -426,9 +455,32 @@ class Storage:
426
455
  )
427
456
  with db.begin() as conn:
428
457
  conn.execute(stmt)
429
- return True
430
458
 
431
- def update_meta_all(self, meta: CtxMeta, items: list) -> bool:
459
+ # update group
460
+ if meta.group:
461
+ stmt = text("""
462
+ UPDATE ctx_group
463
+ SET
464
+ name = :name,
465
+ additional_ctx_json = :additional_ctx_json,
466
+ updated_ts = :updated_ts
467
+ WHERE id = :id
468
+ """).bindparams(
469
+ id=meta.group.id,
470
+ name=meta.group.name,
471
+ additional_ctx_json=pack_item_value(meta.group.additional_ctx),
472
+ updated_ts=int(time.time()),
473
+ )
474
+ with db.begin() as conn:
475
+ conn.execute(stmt)
476
+
477
+ return True
478
+
479
+ def update_meta_all(
480
+ self,
481
+ meta: CtxMeta,
482
+ items: List[CtxItem]
483
+ ) -> bool:
432
484
  """
433
485
  Update all, meta and items
434
486
 
@@ -891,12 +943,12 @@ class Storage:
891
943
  def get_ctx_count_by_day(
892
944
  self,
893
945
  year: int,
894
- month: int = None,
895
- day: int = None,
896
- search_string: str = None,
897
- filters: dict = None,
946
+ month: Optional[int] = None,
947
+ day: Optional[int] = None,
948
+ search_string: Optional[str] = None,
949
+ filters: Optional[dict] = None,
898
950
  search_content: bool = False,
899
- ) -> dict:
951
+ ) -> Dict[str, int]:
900
952
  """
901
953
  Return ctx counters by day for given year and month
902
954
 
@@ -987,12 +1039,12 @@ class Storage:
987
1039
  def get_ctx_labels_count_by_day(
988
1040
  self,
989
1041
  year: int,
990
- month: int = None,
991
- day: int = None,
992
- search_string: str = None,
993
- filters: dict = None,
1042
+ month: Optional[int] = None,
1043
+ day: Optional[int] = None,
1044
+ search_string: Optional[str] = None,
1045
+ filters: Optional[dict] = None,
994
1046
  search_content: bool = False,
995
- ) -> dict:
1047
+ ) -> Dict[str, Dict[int, int]]:
996
1048
  """
997
1049
  Return ctx counters by day for given year and month
998
1050
 
@@ -1116,7 +1168,7 @@ class Storage:
1116
1168
 
1117
1169
  return result_dict
1118
1170
 
1119
- def get_groups(self) -> dict:
1171
+ def get_groups(self) -> Dict[int, CtxGroup]:
1120
1172
  """
1121
1173
  Return dict with CtxGroup objects, indexed by ID
1122
1174
 
@@ -1189,16 +1241,17 @@ class Storage:
1189
1241
  conn.execute(text("DELETE FROM sqlite_sequence WHERE name='ctx_group'"))
1190
1242
  return True
1191
1243
 
1192
- def clear_meta(self, meta_id: int):
1244
+ def clear_meta(self, meta_id: int) -> bool:
1193
1245
  """
1194
1246
  Delete all items with meta ID
1195
1247
 
1196
1248
  :param meta_id: meta ID
1197
- :return:
1249
+ :return: True if cleared
1198
1250
  """
1199
1251
  db = self.window.core.db.get_db()
1200
1252
  with db.begin() as conn:
1201
1253
  conn.execute(text(f"DELETE FROM ctx_item WHERE meta_id = {meta_id}"))
1254
+ return True
1202
1255
 
1203
1256
  def update_group(self, group: CtxGroup) -> bool:
1204
1257
  """
@@ -1258,12 +1311,13 @@ class Storage:
1258
1311
  group.id = result.lastrowid
1259
1312
  return group.id
1260
1313
 
1261
- def update_meta_group_id(self, meta_id: int, group_id: int = None):
1314
+ def update_meta_group_id(self, meta_id: int, group_id: int = None) -> bool:
1262
1315
  """
1263
1316
  Update meta group ID
1264
1317
 
1265
1318
  :param meta_id: ctx meta ID
1266
1319
  :param group_id: ctx group ID
1320
+ :return: True if updated
1267
1321
  """
1268
1322
  db = self.window.core.db.get_db()
1269
1323
  stmt = text("""
@@ -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.26 19:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
13
13
  import re
14
+
14
15
  from datetime import datetime, timedelta
16
+ from typing import List, Tuple, Any, Dict
15
17
 
16
18
  from pygpt_net.item.ctx import CtxMeta, CtxItem, CtxGroup
17
19
  from pygpt_net.utils import unpack_var
18
20
 
19
21
 
20
- def search_by_date_string(search_string: str) -> list:
22
+ def search_by_date_string(search_string: str) -> List[Tuple[Any, Any]]:
21
23
  """
22
24
  Prepare date ranges from search string if @date() syntax is used
23
25
 
@@ -64,7 +66,7 @@ def search_by_date_string(search_string: str) -> list:
64
66
  return date_ranges
65
67
 
66
68
 
67
- def get_month_start_end_timestamps(year: int, month: int) -> (int, int):
69
+ def get_month_start_end_timestamps(year: int, month: int) -> Tuple[int, int]:
68
70
  """
69
71
  Get start and end timestamps for given month
70
72
 
@@ -82,7 +84,7 @@ def get_month_start_end_timestamps(year: int, month: int) -> (int, int):
82
84
  return start_timestamp, end_timestamp
83
85
 
84
86
 
85
- def get_year_start_end_timestamps(year: int) -> (int, int):
87
+ def get_year_start_end_timestamps(year: int) -> Tuple[int, int]:
86
88
  """
87
89
  Get start and end timestamps for given year
88
90
 
@@ -96,7 +98,7 @@ def get_year_start_end_timestamps(year: int) -> (int, int):
96
98
  return start_timestamp, end_timestamp
97
99
 
98
100
 
99
- def pack_item_value(value: any) -> str:
101
+ def pack_item_value(value: Any) -> str:
100
102
  """
101
103
  Pack item value to JSON
102
104
 
@@ -108,7 +110,7 @@ def pack_item_value(value: any) -> str:
108
110
  return value
109
111
 
110
112
 
111
- def unpack_item_value(value: any) -> any:
113
+ def unpack_item_value(value: Any) -> Any:
112
114
  """
113
115
  Unpack item value from JSON
114
116
 
@@ -123,7 +125,10 @@ def unpack_item_value(value: any) -> any:
123
125
  return value
124
126
 
125
127
 
126
- def unpack_item(item: CtxItem, row: dict) -> CtxItem:
128
+ def unpack_item(
129
+ item: CtxItem,
130
+ row: Dict[str, Any]
131
+ ) -> CtxItem:
127
132
  """
128
133
  Unpack context item from DB row
129
134
 
@@ -183,9 +188,12 @@ def unpack_item(item: CtxItem, row: dict) -> CtxItem:
183
188
  return item
184
189
 
185
190
 
186
- def unpack_meta(meta: CtxMeta, row: dict) -> CtxMeta:
191
+ def unpack_meta(
192
+ meta: CtxMeta,
193
+ row: Dict[str, Any]
194
+ ) -> CtxMeta:
187
195
  """
188
- Unpack context meta data from DB row
196
+ Unpack context meta-data from DB row
189
197
 
190
198
  :param meta: Context meta (CtxMeta)
191
199
  :param row: DB row
@@ -219,20 +227,38 @@ def unpack_meta(meta: CtxMeta, row: dict) -> CtxMeta:
219
227
 
220
228
  if meta.additional_ctx is None:
221
229
  meta.additional_ctx = []
230
+
231
+ # add group if exists
232
+ if meta.group_id:
233
+ group = CtxGroup()
234
+ group.id = meta.group_id
235
+ group.uuid = row['group_uuid']
236
+ group.name = row['group_name']
237
+ group.additional_ctx = unpack_item_value(row['group_additional_ctx_json'])
238
+ if group.additional_ctx is None:
239
+ group.additional_ctx = []
240
+ meta.group = group
241
+
222
242
  return meta
223
243
 
224
244
 
225
- def unpack_group(group: CtxGroup, row: dict) -> CtxGroup:
245
+ def unpack_group(
246
+ group: CtxGroup,
247
+ row: Dict[str, Any]
248
+ ) -> CtxGroup:
226
249
  """
227
250
  Unpack context group data from DB row
228
251
 
229
252
  :param group: Context group (CtxGroup)
230
253
  :param row: DB row
231
- :return: context meta
254
+ :return: context group
232
255
  """
233
256
  group.id = unpack_var(row['id'], 'int')
234
257
  group.uuid = row['uuid']
235
258
  group.created = unpack_var(row['created_ts'], 'int')
236
259
  group.updated = unpack_var(row['updated_ts'], 'int')
237
260
  group.name = row['name']
261
+ group.additional_ctx = unpack_item_value(row['additional_ctx_json'])
262
+ if group.additional_ctx is None:
263
+ group.additional_ctx = []
238
264
  return group