pygpt-net 2.4.37__py3-none-any.whl → 2.4.39__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 (81) hide show
  1. CHANGELOG.md +11 -0
  2. README.md +24 -5
  3. pygpt_net/CHANGELOG.txt +11 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/__init__.py +3 -1
  6. pygpt_net/controller/calendar/__init__.py +3 -1
  7. pygpt_net/controller/chat/render.py +8 -5
  8. pygpt_net/controller/config/placeholder.py +29 -0
  9. pygpt_net/controller/ctx/__init__.py +32 -24
  10. pygpt_net/controller/ctx/common.py +3 -2
  11. pygpt_net/controller/dialogs/confirm.py +2 -2
  12. pygpt_net/controller/lang/custom.py +2 -7
  13. pygpt_net/controller/lang/mapping.py +2 -2
  14. pygpt_net/controller/layout.py +2 -2
  15. pygpt_net/controller/notepad.py +8 -5
  16. pygpt_net/controller/settings/editor.py +6 -0
  17. pygpt_net/controller/theme/__init__.py +33 -8
  18. pygpt_net/controller/theme/common.py +22 -1
  19. pygpt_net/controller/theme/markdown.py +26 -14
  20. pygpt_net/controller/theme/menu.py +26 -5
  21. pygpt_net/controller/ui/tabs.py +201 -58
  22. pygpt_net/core/attachments/context.py +14 -12
  23. pygpt_net/core/audio/__init__.py +59 -1
  24. pygpt_net/core/ctx/__init__.py +11 -1
  25. pygpt_net/core/ctx/container.py +16 -9
  26. pygpt_net/core/ctx/output.py +86 -67
  27. pygpt_net/core/debug/tabs.py +3 -2
  28. pygpt_net/core/filesystem/__init__.py +5 -19
  29. pygpt_net/core/filesystem/url.py +7 -3
  30. pygpt_net/core/render/base.py +14 -3
  31. pygpt_net/core/render/markdown/renderer.py +3 -1
  32. pygpt_net/core/render/plain/renderer.py +3 -3
  33. pygpt_net/core/render/web/body.py +39 -17
  34. pygpt_net/core/render/web/renderer.py +7 -5
  35. pygpt_net/core/tabs/__init__.py +180 -71
  36. pygpt_net/core/tabs/tab.py +13 -4
  37. pygpt_net/data/config/config.json +14 -4
  38. pygpt_net/data/config/models.json +3 -3
  39. pygpt_net/data/config/modes.json +3 -3
  40. pygpt_net/data/config/settings.json +55 -10
  41. pygpt_net/data/config/settings_section.json +3 -0
  42. pygpt_net/data/css/style.light.css +1 -0
  43. pygpt_net/data/css/{web.css → web-blocks.css} +144 -133
  44. pygpt_net/data/css/web-chatgpt.css +342 -0
  45. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  46. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  47. pygpt_net/data/css/web-chatgpt_wide.css +342 -0
  48. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  49. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  50. pygpt_net/data/locale/locale.de.ini +12 -0
  51. pygpt_net/data/locale/locale.en.ini +14 -1
  52. pygpt_net/data/locale/locale.es.ini +12 -0
  53. pygpt_net/data/locale/locale.fr.ini +12 -0
  54. pygpt_net/data/locale/locale.it.ini +12 -0
  55. pygpt_net/data/locale/locale.pl.ini +12 -0
  56. pygpt_net/data/locale/locale.uk.ini +12 -0
  57. pygpt_net/data/locale/locale.zh.ini +12 -0
  58. pygpt_net/plugin/audio_input/simple.py +21 -5
  59. pygpt_net/provider/core/config/patch.py +22 -1
  60. pygpt_net/provider/core/ctx/base.py +4 -1
  61. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +10 -1
  62. pygpt_net/provider/core/ctx/db_sqlite/storage.py +22 -1
  63. pygpt_net/ui/layout/chat/input.py +10 -18
  64. pygpt_net/ui/layout/chat/output.py +26 -44
  65. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  66. pygpt_net/ui/menu/config.py +7 -11
  67. pygpt_net/ui/menu/theme.py +9 -2
  68. pygpt_net/ui/widget/lists/context.py +1 -0
  69. pygpt_net/ui/widget/tabs/layout.py +195 -0
  70. pygpt_net/ui/widget/tabs/output.py +124 -35
  71. pygpt_net/ui/widget/textarea/html.py +11 -1
  72. pygpt_net/ui/widget/textarea/output.py +10 -1
  73. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  74. pygpt_net/ui/widget/textarea/web.py +49 -9
  75. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/METADATA +25 -6
  76. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/RECORD +81 -74
  77. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  78. /pygpt_net/data/css/{web.light.css → web-blocks.light.css} +0 -0
  79. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/LICENSE +0 -0
  80. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/WHEEL +0 -0
  81. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/entry_points.txt +0 -0
@@ -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.11 04:00:00 #
9
+ # Updated Date: 2024.12.09 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import uuid
@@ -22,6 +22,9 @@ from pygpt_net.utils import trans
22
22
 
23
23
  class Tabs:
24
24
 
25
+ # number of columns
26
+ NUM_COLS = 2
27
+
25
28
  # types
26
29
  TAB_ADD = -1
27
30
  TAB_CHAT = 0
@@ -54,14 +57,15 @@ class Tabs:
54
57
  self.TAB_TOOL_CALENDAR: "output.tab.calendar",
55
58
  }
56
59
 
57
- def get_tab_by_index(self, idx: int) -> Tab or None:
60
+ def get_tab_by_index(self, idx: int, column_idx: int = 0) -> Tab or None:
58
61
  """
59
62
  Get tab by index
60
63
 
61
64
  :param idx: Tab index
65
+ :param column_idx: Column index
62
66
  :return: Tab
63
67
  """
64
- tab = self.window.ui.tabs['output'].widget(idx)
68
+ tab = self.window.ui.layout.get_tabs_by_idx(column_idx).widget(idx)
65
69
  if tab is None:
66
70
  return None
67
71
  return tab.getOwner()
@@ -96,19 +100,28 @@ class Tabs:
96
100
 
97
101
  :return: PID
98
102
  """
99
- tab = self.get_tab_by_index(self.window.ui.tabs['output'].currentIndex())
103
+ current_column_idx = self.window.controller.ui.tabs.get_current_column_idx()
104
+ tabs = self.window.ui.layout.get_tabs_by_idx(current_column_idx)
105
+ tab = self.get_tab_by_index(tabs.currentIndex(), current_column_idx)
100
106
  if tab is None:
101
107
  return 0
102
108
  return tab.pid
103
109
 
104
- def add(self, type: int, title: str, icon=None, reference=None, data_id=None) -> Tab:
110
+ def add(
111
+ self,
112
+ type: int,
113
+ title: str,
114
+ icon=None,
115
+ child=None,
116
+ data_id=None
117
+ ) -> Tab:
105
118
  """
106
119
  Add tab
107
120
 
108
121
  :param type: Tab type
109
122
  :param title: Tab title
110
123
  :param icon: Tab icon
111
- :param reference: Tab reference
124
+ :param child: Tab child
112
125
  :param data_id: Tab data ID
113
126
  :return: Tab
114
127
  """
@@ -120,7 +133,7 @@ class Tabs:
120
133
  tab.type = type
121
134
  tab.title = title
122
135
  tab.icon = icon
123
- tab.reference = reference
136
+ tab.child = child
124
137
  tab.data_id = data_id
125
138
 
126
139
  if type == Tab.TAB_CHAT:
@@ -137,12 +150,18 @@ class Tabs:
137
150
  self.pids[tab.pid] = tab
138
151
  return tab
139
152
 
140
- def append(self, type: int, idx: int) -> Tab:
153
+ def append(
154
+ self,
155
+ type: int,
156
+ idx: int,
157
+ column_idx: int = 0
158
+ ) -> Tab:
141
159
  """
142
160
  Append tab to the right side of the tab with the specified index
143
161
 
144
162
  :param type: tab type
145
163
  :param idx: index of the tab to the right of which the new tab will be added
164
+ :param column_idx: index of the column in which the tab will be added
146
165
  :return: Tab
147
166
  """
148
167
  self.last_pid += 1 # PID++, start from 0
@@ -160,6 +179,7 @@ class Tabs:
160
179
  tab.title = title
161
180
  tab.icon = icon
162
181
  tab.new_idx = idx + 1 # place on right side
182
+ tab.column_idx = column_idx
163
183
 
164
184
  if type == Tab.TAB_CHAT:
165
185
  self.add_chat(tab)
@@ -186,11 +206,17 @@ class Tabs:
186
206
  tab.type = data["type"]
187
207
  tab.title = data["title"]
188
208
  tab.data_id = data["data_id"]
189
- tab.reference = None
209
+ tab.child = None
190
210
 
191
211
  if 'tooltip' in data and data['tooltip'] is not None:
192
212
  tab.tooltip = data['tooltip']
193
213
 
214
+ if 'custom_name' in data and data['custom_name'] is not None:
215
+ tab.custom_name = data['custom_name']
216
+
217
+ if 'column_idx' in data and data['column_idx'] is not None:
218
+ tab.column_idx = data['column_idx']
219
+
194
220
  if tab.type in self.icons:
195
221
  tab.icon = self.icons[tab.type]
196
222
 
@@ -211,13 +237,14 @@ class Tabs:
211
237
  self.pids[tab.pid] = tab
212
238
  self.last_pid = self.get_max_pid()
213
239
 
214
- def remove_tab_by_idx(self, idx: int):
240
+ def remove_tab_by_idx(self, idx: int, column_idx: int = 0):
215
241
  """
216
242
  Remove tab by index
217
243
 
218
244
  :param idx: Tab index
245
+ :param column_idx: Column index
219
246
  """
220
- tab = self.get_tab_by_index(idx)
247
+ tab = self.get_tab_by_index(idx, column_idx)
221
248
  if tab is None:
222
249
  return
223
250
  self.remove(tab.pid)
@@ -231,7 +258,8 @@ class Tabs:
231
258
  tab = self.get_tab_by_pid(pid)
232
259
  if tab is None:
233
260
  return
234
- self.window.ui.tabs['output'].removeTab(tab.idx)
261
+ column_idx = tab.column_idx
262
+ self.window.ui.layout.get_tabs_by_idx(column_idx).removeTab(tab.idx)
235
263
  del self.pids[pid]
236
264
  self.update()
237
265
 
@@ -241,15 +269,16 @@ class Tabs:
241
269
  self.remove(pid) # delete from PIDs and UI
242
270
  self.window.core.ctx.output.clear() # clear mapping
243
271
 
244
- def remove_all_by_type(self, type: int):
272
+ def remove_all_by_type(self, type: int, column_idx: int = 0):
245
273
  """
246
274
  Remove all tabs by type
247
275
 
248
276
  :param type: Tab type
277
+ :param column_idx: Column index
249
278
  """
250
279
  for pid in list(self.pids):
251
280
  tab = self.pids[pid]
252
- if tab.type == type:
281
+ if tab.type == type and tab.column_idx == column_idx:
253
282
  if type == self.TAB_CHAT:
254
283
  if self.count_by_type(type) == 1:
255
284
  continue # do not remove last chat tab
@@ -312,7 +341,11 @@ class Tabs:
312
341
  count += 1
313
342
  return count
314
343
 
315
- def get_order_by_idx_and_type(self, idx: int, type: int) -> int:
344
+ def get_order_by_idx_and_type(
345
+ self,
346
+ idx: int,
347
+ type: int
348
+ ) -> int:
316
349
  """
317
350
  Get the order of the tab by index and type
318
351
 
@@ -328,28 +361,42 @@ class Tabs:
328
361
  return order
329
362
  return -1 # Return -1 if the tab with the specified index and type is not found
330
363
 
331
- def get_min_idx_by_type(self, type: int) -> int:
364
+ def get_min_idx_by_type(self, type: int, column_idx: int = 0) -> int:
332
365
  """
333
366
  Get min index by type
334
367
 
335
368
  :param type: Tab type
369
+ :param column_idx: Column index
336
370
  :return: Min index
337
371
  """
338
372
  min = 999999
339
373
  for pid in self.pids:
340
374
  tab = self.pids[pid]
341
- if tab.type == type and tab.idx < min:
375
+ if (tab.type == type
376
+ and tab.column_idx == column_idx
377
+ and tab.idx < min):
342
378
  min = tab.idx
343
379
  return min
344
380
 
345
381
  def update(self):
346
- """Update tabs data (pids) from UI"""
382
+ """Update tabs data (pids) from UI (all columns)"""
383
+ for n in range(0, self.NUM_COLS):
384
+ self.update_column(n)
385
+
386
+ def update_column(self, column_idx: int):
387
+ """
388
+ Update column data by index
389
+
390
+ :param column_idx: Column index
391
+ """
392
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
347
393
  for pid in self.pids:
348
394
  tab = self.pids[pid]
349
- tab.idx = self.window.ui.tabs['output'].indexOf(tab.reference)
350
- tab.title = self.window.ui.tabs['output'].tabText(tab.idx)
351
- tab.tooltip = self.window.ui.tabs['output'].tabToolTip(tab.idx)
352
- tab.updated_at = datetime.now()
395
+ if tab.column_idx == column_idx:
396
+ tab.idx = tabs.indexOf(tab.child)
397
+ tab.title = tabs.tabText(tab.idx)
398
+ tab.tooltip = tabs.tabToolTip(tab.idx)
399
+ tab.updated_at = datetime.now()
353
400
 
354
401
  def add_chat(self, tab: Tab):
355
402
  """
@@ -357,15 +404,18 @@ class Tabs:
357
404
 
358
405
  :param tab: Tab instance
359
406
  """
360
- tab.reference = self.window.core.ctx.container.register_output(tab.pid)
407
+ column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
408
+ tabs = column.get_tabs()
409
+ tab.parent = column
410
+ tab.child = self.window.core.ctx.container.get(tab)
361
411
  if tab.new_idx is not None:
362
- tab.idx = self.window.ui.tabs['output'].insertTab(tab.new_idx, tab.reference, tab.title)
412
+ tab.idx = tabs.insertTab(tab.new_idx, tab.child, tab.title)
363
413
  else:
364
- tab.idx = self.window.ui.tabs['output'].addTab(tab.reference, tab.title)
365
- tab.reference.setOwner(tab)
366
- self.window.ui.tabs['output'].setTabIcon(tab.idx, QIcon(tab.icon))
414
+ tab.idx = tabs.addTab(tab.child, tab.title)
415
+ tab.child.setOwner(tab)
416
+ tabs.setTabIcon(tab.idx, QIcon(tab.icon))
367
417
  if tab.tooltip is not None:
368
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.tooltip)
418
+ tabs.setTabToolTip(tab.idx, tab.tooltip)
369
419
 
370
420
  def add_notepad(self, tab: Tab):
371
421
  """
@@ -374,18 +424,22 @@ class Tabs:
374
424
  :param tab: Tab instance
375
425
  """
376
426
  idx = None
427
+ column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
428
+ tabs = column.get_tabs()
429
+ tab.parent = column
430
+ tab.parent = tabs.get_column()
377
431
  if tab.data_id is not None:
378
432
  idx = tab.data_id # restore prev idx
379
- tab.reference, idx = self.window.controller.notepad.create(idx)
433
+ tab.child, idx = self.window.controller.notepad.create(idx)
380
434
  tab.data_id = idx # notepad idx in db, enumerated from 1
381
435
  if tab.new_idx is not None:
382
- tab.idx = self.window.ui.tabs['output'].insertTab(tab.new_idx, tab.reference, tab.title)
436
+ tab.idx = tabs.insertTab(tab.new_idx, tab.child, tab.title)
383
437
  else:
384
- tab.idx = self.window.ui.tabs['output'].addTab(tab.reference, tab.title)
385
- tab.reference.setOwner(tab)
386
- self.window.ui.tabs['output'].setTabIcon(tab.idx, QIcon(tab.icon))
438
+ tab.idx = tabs.addTab(tab.child, tab.title)
439
+ tab.child.setOwner(tab)
440
+ tabs.setTabIcon(tab.idx, QIcon(tab.icon))
387
441
  if tab.tooltip is not None:
388
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.tooltip)
442
+ tabs.setTabToolTip(tab.idx, tab.tooltip)
389
443
 
390
444
  def add_tool_explorer(self, tab: Tab):
391
445
  """
@@ -393,12 +447,15 @@ class Tabs:
393
447
 
394
448
  :param tab: Tab instance
395
449
  """
396
- tab.reference = self.window.ui.chat.output.explorer.setup()
397
- tab.idx = self.window.ui.tabs['output'].addTab(tab.reference, tab.title)
398
- tab.reference.setOwner(tab)
399
- self.window.ui.tabs['output'].setTabIcon(tab.idx, QIcon(tab.icon))
450
+ column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
451
+ tabs = column.get_tabs()
452
+ tab.parent = column
453
+ tab.child = self.window.ui.chat.output.explorer.setup()
454
+ tab.idx = tabs.addTab(tab.child, tab.title)
455
+ tab.child.setOwner(tab)
456
+ tabs.setTabIcon(tab.idx, QIcon(tab.icon))
400
457
  if tab.tooltip is not None:
401
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.tooltip)
458
+ tabs.setTabToolTip(tab.idx, tab.tooltip)
402
459
 
403
460
  def add_tool_painter(self, tab: Tab):
404
461
  """
@@ -406,12 +463,15 @@ class Tabs:
406
463
 
407
464
  :param tab: Tab instance
408
465
  """
409
- tab.reference = self.window.ui.chat.output.painter.setup()
410
- tab.idx = self.window.ui.tabs['output'].addTab(tab.reference, tab.title)
411
- tab.reference.setOwner(tab)
412
- self.window.ui.tabs['output'].setTabIcon(tab.idx, QIcon(tab.icon))
466
+ column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
467
+ tabs = column.get_tabs()
468
+ tab.parent = column
469
+ tab.child = self.window.ui.chat.output.painter.setup()
470
+ tab.idx = tabs.addTab(tab.child, tab.title)
471
+ tab.child.setOwner(tab)
472
+ tabs.setTabIcon(tab.idx, QIcon(tab.icon))
413
473
  if tab.tooltip is not None:
414
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.tooltip)
474
+ tabs.setTabToolTip(tab.idx, tab.tooltip)
415
475
 
416
476
  def add_tool_calendar(self, tab: Tab):
417
477
  """
@@ -419,12 +479,37 @@ class Tabs:
419
479
 
420
480
  :param tab: Tab instance
421
481
  """
422
- tab.reference = self.window.ui.chat.output.calendar.setup()
423
- tab.idx = self.window.ui.tabs['output'].addTab(tab.reference, tab.title)
424
- tab.reference.setOwner(tab)
425
- self.window.ui.tabs['output'].setTabIcon(tab.idx, QIcon(tab.icon))
482
+ column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
483
+ tabs = column.get_tabs()
484
+ tab.parent = column
485
+ tab.child = self.window.ui.chat.output.calendar.setup()
486
+ tab.idx = tabs.addTab(tab.child, tab.title)
487
+ tab.child.setOwner(tab)
488
+ tabs.setTabIcon(tab.idx, QIcon(tab.icon))
426
489
  if tab.tooltip is not None:
427
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.tooltip)
490
+ tabs.setTabToolTip(tab.idx, tab.tooltip)
491
+
492
+ def move_tab(self, tab: Tab, column_idx: int):
493
+ """
494
+ Move tab to column
495
+
496
+ :param tab: Tab instance
497
+ :param column_idx: Column index
498
+ """
499
+ if tab is None:
500
+ return
501
+ if tab.column_idx == column_idx:
502
+ return
503
+ tab.column_idx = column_idx
504
+ old_column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
505
+ old_tabs = old_column.get_tabs()
506
+ old_tabs.removeTab(tab.idx)
507
+ new_column = self.window.ui.layout.get_column_by_idx(column_idx)
508
+ new_tabs = new_column.get_tabs()
509
+ tab.idx = new_tabs.addTab(tab.child, tab.title)
510
+ tab.parent = new_column
511
+ self.update()
512
+ self.window.core.tabs.reload_titles()
428
513
 
429
514
  def get_first_by_type(self, type: int) -> Tab or None:
430
515
  """
@@ -454,6 +539,7 @@ class Tabs:
454
539
  "data_id": None,
455
540
  "title": "Chat",
456
541
  "tooltip": "Chat",
542
+ "column_idx": 0,
457
543
  }
458
544
  data[1] = {
459
545
  "uuid": uuid.uuid4(),
@@ -463,6 +549,7 @@ class Tabs:
463
549
  "data_id": None,
464
550
  "title": "Files",
465
551
  "tooltip": "Files",
552
+ "column_idx": 0,
466
553
  }
467
554
  data[2] = {
468
555
  "uuid": uuid.uuid4(),
@@ -472,6 +559,7 @@ class Tabs:
472
559
  "data_id": None,
473
560
  "title": "Calendar",
474
561
  "tooltip": "Calendar",
562
+ "column_idx": 0,
475
563
  }
476
564
  data[3] = {
477
565
  "uuid": uuid.uuid4(),
@@ -481,6 +569,7 @@ class Tabs:
481
569
  "data_id": None,
482
570
  "title": "Painter",
483
571
  "tooltip": "Painter",
572
+ "column_idx": 0,
484
573
  }
485
574
  """
486
575
  data[4] = {
@@ -491,6 +580,7 @@ class Tabs:
491
580
  "data_id": 1,
492
581
  "title": "Notepad",
493
582
  "tooltip": "Notepad",
583
+ "column_idx": 0,
494
584
  }
495
585
  """
496
586
  # load notepads from db
@@ -507,6 +597,7 @@ class Tabs:
507
597
  "data_id": item['data_id'],
508
598
  "title": item['title'],
509
599
  "tooltip": item['title'],
600
+ "column_idx": 0,
510
601
  }
511
602
  next_idx += 1
512
603
  return data
@@ -536,6 +627,7 @@ class Tabs:
536
627
  "title": trans(self.titles[type]),
537
628
  "tooltip": trans(self.titles[type]),
538
629
  "custom_name": False,
630
+ "column_idx": 0,
539
631
  }
540
632
  tmp_pid += 1
541
633
 
@@ -564,11 +656,22 @@ class Tabs:
564
656
  "title": tab.title,
565
657
  "tooltip": tab.tooltip,
566
658
  "custom_name": tab.custom_name,
659
+ "column_idx": tab.column_idx,
567
660
  }
661
+ opened_tabs = {}
662
+ for column_idx in range(0, self.NUM_COLS):
663
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
664
+ opened_tabs[column_idx] = tabs.currentIndex()
665
+ self.window.core.config.set("tabs.opened", opened_tabs)
568
666
  self.window.core.config.set("tabs.data", data)
569
667
  self.window.core.config.save()
570
668
 
571
- def update_title(self, idx: int, title: str, tooltip: str = None):
669
+ def update_title(
670
+ self,
671
+ idx: int,
672
+ title: str,
673
+ tooltip: str = None
674
+ ):
572
675
  """
573
676
  Update tab title
574
677
 
@@ -576,37 +679,43 @@ class Tabs:
576
679
  :param title: Tab title
577
680
  :param tooltip: Tab tooltip
578
681
  """
579
- tab = self.get_tab_by_index(idx)
682
+ column_idx = self.window.controller.ui.tabs.get_current_column_idx()
683
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
684
+ tab = self.get_tab_by_index(idx, column_idx)
580
685
  if tab is None:
581
686
  return
582
687
  tab.title = title
583
688
  tab.tooltip = tooltip
584
689
  tab.custom_name = True
585
690
  if title is not None:
586
- self.window.ui.tabs['output'].setTabText(idx, title)
691
+ tabs.setTabText(idx, title)
587
692
  if tooltip is not None:
588
- self.window.ui.tabs['output'].setTabToolTip(idx, tooltip)
693
+ tabs.setTabToolTip(idx, tooltip)
589
694
 
590
695
  def reload_titles(self):
591
696
  """Reload default tab titles"""
592
- counters = {
593
- self.TAB_CHAT: 1,
594
- self.TAB_NOTEPAD: 1,
595
- self.TAB_FILES: 1,
596
- self.TAB_TOOL_PAINTER: 1,
597
- self.TAB_TOOL_CALENDAR: 1,
598
- }
599
- for pid in self.pids:
600
- tab = self.pids[pid]
601
- if tab.custom_name:
602
- continue # leave custom names
603
- tab.title = trans(self.titles[tab.type])
604
- num_tabs = self.count_by_type(tab.type)
605
- if num_tabs > 1:
606
- tab.title += " {}".format(counters[tab.type])
607
- counters[tab.type] += 1
608
- self.window.ui.tabs['output'].setTabText(tab.idx, tab.title)
609
- self.window.ui.tabs['output'].setTabToolTip(tab.idx, tab.title)
697
+ for column_idx in range(0, self.NUM_COLS):
698
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
699
+ counters = {
700
+ self.TAB_CHAT: 1,
701
+ self.TAB_NOTEPAD: 1,
702
+ self.TAB_FILES: 1,
703
+ self.TAB_TOOL_PAINTER: 1,
704
+ self.TAB_TOOL_CALENDAR: 1,
705
+ }
706
+ for pid in self.pids:
707
+ tab = self.pids[pid]
708
+ if tab.column_idx != column_idx:
709
+ continue
710
+ if tab.custom_name:
711
+ continue # leave custom names
712
+ tab.title = trans(self.titles[tab.type])
713
+ num_tabs = self.count_by_type(tab.type)
714
+ if num_tabs > 1:
715
+ tab.title += " {}".format(counters[tab.type])
716
+ counters[tab.type] += 1
717
+ tabs.setTabText(tab.idx, tab.title)
718
+ tabs.setTabToolTip(tab.idx, tab.title)
610
719
 
611
720
  def from_widget(self, widget: QWidget) -> TabBody:
612
721
  """
@@ -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.08 17:00:00 #
9
+ # Updated Date: 2024.12.09 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from datetime import datetime
@@ -34,15 +34,22 @@ class Tab:
34
34
  self.icon = None
35
35
  self.tooltip = None
36
36
  self.data_id = None
37
- self.reference = None
38
37
  self.new_idx = None
39
38
  self.custom_name = False
39
+ self.child = None
40
+ self.parent = None
41
+ self.column_idx = 0
40
42
 
41
43
  dt = datetime.now()
42
44
  self.created_at = dt
43
45
  self.updated_at = dt
44
46
 
45
- def to_dict(self):
47
+ def to_dict(self) -> dict:
48
+ """
49
+ Convert to dict
50
+
51
+ :return: dict
52
+ """
46
53
  return {
47
54
  "uuid": str(self.uuid),
48
55
  "pid": self.pid,
@@ -52,9 +59,11 @@ class Tab:
52
59
  "icon": self.icon,
53
60
  "tooltip": self.tooltip,
54
61
  "data_id": self.data_id,
55
- "reference": str(self.reference),
62
+ "child": str(self.child), # child widget
63
+ "parent": str(self.parent), # parent column
56
64
  "custom_name": self.custom_name,
57
65
  "custom_idx": self.new_idx,
58
66
  "created_at": str(self.created_at),
59
67
  "updated_at": str(self.updated_at),
68
+ "column_idx": self.column_idx,
60
69
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.39",
4
+ "app.version": "2.4.39",
5
+ "updated_at": "2024-12-09T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -68,6 +68,9 @@
68
68
  "attachments_auto_index": true,
69
69
  "attachments_send_clear": true,
70
70
  "attachments_capture_clear": true,
71
+ "audio.input.channels": 1,
72
+ "audio.input.device": "0",
73
+ "audio.input.rate": 44100,
71
74
  "audio.transcribe.convert_video": true,
72
75
  "context_threshold": 200,
73
76
  "cmd": false,
@@ -158,7 +161,13 @@
158
161
  "layout.dpi.scaling": true,
159
162
  "layout.dpi.factor": 1.0,
160
163
  "layout.groups": {},
161
- "layout.splitters": {},
164
+ "layout.splitters": {
165
+ "columns": [
166
+ 1,
167
+ 0
168
+ ]
169
+ },
170
+ "layout.split": false,
162
171
  "layout.tabs": {},
163
172
  "layout.tooltips": true,
164
173
  "layout.tray": true,
@@ -335,6 +344,7 @@
335
344
  "temperature": 1.0,
336
345
  "theme": "dark_cyan",
337
346
  "theme.markdown": true,
347
+ "theme.style": "blocks",
338
348
  "top_p": 1.0,
339
349
  "upload.store": true,
340
350
  "upload.data_dir": false,
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.39",
4
+ "app.version": "2.4.39",
5
+ "updated_at": "2024-12-09T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "claude-3-5-sonnet-20240620": {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.39",
4
+ "app.version": "2.4.39",
5
+ "updated_at": "2024-12-09T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "chat": {