pygpt-net 2.6.3__py3-none-any.whl → 2.6.4__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 (66) hide show
  1. pygpt_net/CHANGELOG.txt +5 -0
  2. pygpt_net/__init__.py +1 -1
  3. pygpt_net/config.py +55 -65
  4. pygpt_net/controller/chat/chat.py +38 -35
  5. pygpt_net/controller/chat/render.py +144 -217
  6. pygpt_net/controller/chat/stream.py +51 -25
  7. pygpt_net/controller/config/config.py +39 -42
  8. pygpt_net/controller/config/field/checkbox.py +16 -12
  9. pygpt_net/controller/config/field/checkbox_list.py +36 -31
  10. pygpt_net/controller/config/field/cmd.py +51 -57
  11. pygpt_net/controller/config/field/combo.py +33 -16
  12. pygpt_net/controller/config/field/dictionary.py +48 -55
  13. pygpt_net/controller/config/field/input.py +50 -32
  14. pygpt_net/controller/config/field/slider.py +40 -45
  15. pygpt_net/controller/config/field/textarea.py +20 -6
  16. pygpt_net/controller/config/placeholder.py +110 -231
  17. pygpt_net/controller/lang/mapping.py +57 -95
  18. pygpt_net/controller/lang/plugins.py +64 -55
  19. pygpt_net/controller/lang/settings.py +39 -38
  20. pygpt_net/controller/layout/layout.py +11 -2
  21. pygpt_net/controller/plugins/plugins.py +19 -1
  22. pygpt_net/controller/ui/mode.py +107 -125
  23. pygpt_net/core/bridge/bridge.py +5 -5
  24. pygpt_net/core/command/command.py +149 -219
  25. pygpt_net/core/ctx/ctx.py +94 -146
  26. pygpt_net/core/debug/debug.py +48 -58
  27. pygpt_net/core/models/models.py +74 -112
  28. pygpt_net/core/modes/modes.py +13 -21
  29. pygpt_net/core/plugins/plugins.py +154 -177
  30. pygpt_net/core/presets/presets.py +103 -176
  31. pygpt_net/core/render/web/body.py +2 -3
  32. pygpt_net/core/render/web/renderer.py +109 -180
  33. pygpt_net/core/text/utils.py +28 -44
  34. pygpt_net/core/tokens/tokens.py +104 -203
  35. pygpt_net/data/config/config.json +2 -2
  36. pygpt_net/data/config/models.json +2 -2
  37. pygpt_net/item/ctx.py +141 -139
  38. pygpt_net/plugin/agent/plugin.py +2 -1
  39. pygpt_net/plugin/audio_output/plugin.py +5 -2
  40. pygpt_net/plugin/base/plugin.py +77 -93
  41. pygpt_net/plugin/bitbucket/plugin.py +3 -2
  42. pygpt_net/plugin/cmd_code_interpreter/plugin.py +3 -2
  43. pygpt_net/plugin/cmd_custom/plugin.py +3 -2
  44. pygpt_net/plugin/cmd_files/plugin.py +3 -2
  45. pygpt_net/plugin/cmd_history/plugin.py +3 -2
  46. pygpt_net/plugin/cmd_mouse_control/plugin.py +5 -2
  47. pygpt_net/plugin/cmd_serial/plugin.py +3 -2
  48. pygpt_net/plugin/cmd_system/plugin.py +3 -6
  49. pygpt_net/plugin/cmd_web/plugin.py +3 -2
  50. pygpt_net/plugin/experts/plugin.py +2 -2
  51. pygpt_net/plugin/facebook/plugin.py +3 -4
  52. pygpt_net/plugin/github/plugin.py +4 -2
  53. pygpt_net/plugin/google/plugin.py +3 -3
  54. pygpt_net/plugin/idx_llama_index/plugin.py +3 -2
  55. pygpt_net/plugin/mailer/plugin.py +3 -5
  56. pygpt_net/plugin/openai_vision/plugin.py +3 -2
  57. pygpt_net/plugin/real_time/plugin.py +52 -60
  58. pygpt_net/plugin/slack/plugin.py +3 -4
  59. pygpt_net/plugin/telegram/plugin.py +3 -4
  60. pygpt_net/plugin/twitter/plugin.py +3 -4
  61. pygpt_net/ui/widget/textarea/web.py +18 -14
  62. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/METADATA +7 -2
  63. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/RECORD +66 -66
  64. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/LICENSE +0 -0
  65. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/WHEEL +0 -0
  66. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/entry_points.txt +0 -0
pygpt_net/core/ctx/ctx.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: 2025.08.09 20:00:00 #
9
+ # Updated Date: 2025.08.15 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -264,7 +264,7 @@ class Ctx:
264
264
 
265
265
  :param run: run ID
266
266
  """
267
- self.preset = run
267
+ self.run = run
268
268
 
269
269
  def get_thread(self) -> str:
270
270
  """
@@ -393,18 +393,15 @@ class Ctx:
393
393
  ctx = self.meta[id]
394
394
  self.current = id
395
395
 
396
- # reset
397
396
  self.thread = None
398
397
  self.mode = None
399
398
  self.assistant = None
400
399
 
401
- # restore
402
400
  self.thread = ctx.thread
403
401
  self.mode = ctx.mode
404
402
  self.assistant = ctx.assistant
405
403
  self.preset = ctx.preset
406
404
 
407
- # restore model if exists in current mode
408
405
  if restore_model:
409
406
  if ctx.last_model is not None \
410
407
  and self.window.core.models.has_model(self.mode, ctx.last_model):
@@ -425,7 +422,7 @@ class Ctx:
425
422
  :param group_id: group id
426
423
  :return: CtxMeta instance (new ctx meta)
427
424
  """
428
- meta = self.create(group_id) # create new ctx meta
425
+ meta = self.create(group_id)
429
426
  if meta is None:
430
427
  self.window.core.debug.log("Error creating new ctx")
431
428
  return
@@ -451,7 +448,7 @@ class Ctx:
451
448
 
452
449
  :return: created CtxMeta instance
453
450
  """
454
- meta = CtxMeta() # create ctx meta
451
+ meta = CtxMeta()
455
452
  meta.name = "{}".format(trans('ctx.new.prefix'))
456
453
  meta.date = datetime.datetime.now().strftime("%Y-%m-%d")
457
454
  meta.mode = self.window.core.config.get('mode')
@@ -489,15 +486,13 @@ class Ctx:
489
486
  :param item: CtxItem to append
490
487
  :param parent_id: parent id
491
488
  """
492
- # custom parent
493
489
  if parent_id is not None:
494
490
  self.add_to_meta(item, parent_id)
495
491
  return
496
492
 
497
- # to current
498
- self.get_items().append(item) # add CtxItem to context items
493
+ items = self.get_items()
494
+ items.append(item)
499
495
 
500
- # append in provider
501
496
  if self.current is not None:
502
497
  if self.current not in self.meta:
503
498
  self.load_tmp_meta(self.current)
@@ -505,7 +500,7 @@ class Ctx:
505
500
  meta = self.meta[self.current]
506
501
  result = self.provider.append_item(meta, item)
507
502
  if not result:
508
- self.store() # if not stored, e.g. in JSON file provider, then store whole ctx (save all)
503
+ self.store()
509
504
 
510
505
  def add_to_meta(
511
506
  self,
@@ -551,10 +546,7 @@ class Ctx:
551
546
  """
552
547
  if self.current is None:
553
548
  return True
554
- else:
555
- if self.count_items() == 0:
556
- return True
557
- return False
549
+ return self.count_items() == 0
558
550
 
559
551
  def update(self):
560
552
  """
@@ -597,21 +589,17 @@ class Ctx:
597
589
  if self.current not in self.meta:
598
590
  return
599
591
 
600
- # update current
601
- self.assistant = self.window.core.config.get('assistant') # update assistant
602
- self.preset = self.window.core.config.get('preset') # update preset
603
- self.model = self.window.core.config.get('model') # get current model
592
+ self.assistant = self.window.core.config.get('assistant')
593
+ self.preset = self.window.core.config.get('preset')
594
+ self.model = self.window.core.config.get('model')
604
595
 
605
- # update current meta
606
596
  self.meta[self.current].last_mode = mode
607
597
  self.meta[self.current].last_model = self.model
608
598
  self.meta[self.current].preset = self.preset
609
599
 
610
- # if assistant then update assistant
611
- if mode == 'assistant':
600
+ if mode == MODE_ASSISTANT:
612
601
  self.meta[self.current].assistant = self.assistant
613
602
 
614
- # save ctx
615
603
  self.save(self.current)
616
604
 
617
605
  def is_initialized(self) -> bool:
@@ -626,6 +614,7 @@ class Ctx:
626
614
  self.load_tmp_meta(self.current)
627
615
  if self.current in self.meta:
628
616
  return self.meta[self.current].initialized
617
+ return False
629
618
 
630
619
  def set_initialized(self):
631
620
  """Set ctx as initialized (name assigned)"""
@@ -644,9 +633,7 @@ class Ctx:
644
633
  :param id: ctx ID
645
634
  :return: True if exists, false otherwise
646
635
  """
647
- if id in self.meta:
648
- return True
649
- return False
636
+ return id in self.meta
650
637
 
651
638
  def get(self, idx: int) -> CtxItem:
652
639
  """
@@ -665,10 +652,11 @@ class Ctx:
665
652
  :param id: item id
666
653
  :return: context item
667
654
  """
668
- for item in self.get_items():
655
+ items = self.get_items()
656
+ for item in items:
669
657
  if item.id == id:
670
658
  return item
671
- return self.fetch_item_by_id(id) # if no item found, try to fetch from DB
659
+ return self.fetch_item_by_id(id)
672
660
 
673
661
  def fetch_item_by_id(self, id: int) -> CtxItem:
674
662
  """
@@ -719,9 +707,9 @@ class Ctx:
719
707
  :param id: id
720
708
  :return: idx
721
709
  """
722
- items = self.get_meta()
723
- if id in items:
724
- return list(items.keys()).index(id)
710
+ for i, key in enumerate(self.get_meta()):
711
+ if key == id:
712
+ return i
725
713
 
726
714
  def get_first(self) -> str:
727
715
  """
@@ -749,8 +737,9 @@ class Ctx:
749
737
 
750
738
  :return: last ctx item
751
739
  """
752
- if self.count_items() > 0:
753
- return self.get_items()[-1]
740
+ items = self.get_items()
741
+ if items:
742
+ return items[-1]
754
743
  return None
755
744
 
756
745
  def is_first_item(self, item_id: int) -> bool:
@@ -760,8 +749,9 @@ class Ctx:
760
749
  :param item_id: item id
761
750
  :return: True if first
762
751
  """
763
- if self.count_items() > 0:
764
- return self.get_items()[0].id == item_id
752
+ items = self.get_items()
753
+ if items:
754
+ return items[0].id == item_id
765
755
  return False
766
756
 
767
757
  def is_last_item(self, item_id: int) -> bool:
@@ -771,8 +761,9 @@ class Ctx:
771
761
  :param item_id: item id
772
762
  :return: True if last
773
763
  """
774
- if self.count_items() > 0:
775
- return self.get_items()[-1].id == item_id
764
+ items = self.get_items()
765
+ if items:
766
+ return items[-1].id == item_id
776
767
  return False
777
768
 
778
769
  def get_previous_item(self, item_id: int) -> Optional[CtxItem]:
@@ -782,15 +773,16 @@ class Ctx:
782
773
  :param item_id: item id
783
774
  :return: ctx item
784
775
  """
785
- for i in range(self.count_items()):
786
- if self.get_items()[i].id == item_id:
787
- if i > 0:
788
- return self.get_items()[i - 1]
776
+ items = self.get_items()
777
+ prev = None
778
+ for it in items:
779
+ if it.id == item_id:
780
+ return prev
781
+ prev = it
789
782
  return None
790
783
 
791
784
  def prepare(self):
792
785
  """Prepare context for prompt"""
793
- # if no contexts, create new one
794
786
  if self.count_meta() == 0:
795
787
  self.new()
796
788
 
@@ -808,10 +800,7 @@ class Ctx:
808
800
 
809
801
  :return: ctx meta count
810
802
  """
811
- extra = 0
812
- if self.tmp_meta is not None:
813
- extra = 1 # prevent create new if tmp meta exists
814
- return len(self.meta) + extra
803
+ return len(self.meta) + (1 if self.tmp_meta is not None else 0)
815
804
 
816
805
  def count_found_meta(self) -> int:
817
806
  """
@@ -852,9 +841,10 @@ class Ctx:
852
841
 
853
842
  :param id: ctx id
854
843
  """
855
- for item in self.get_items():
844
+ items = self.get_items()
845
+ for i, item in enumerate(items):
856
846
  if item.id == id:
857
- self.get_items().remove(item)
847
+ items.pop(i)
858
848
  self.provider.remove_item(id)
859
849
  break
860
850
 
@@ -869,17 +859,13 @@ class Ctx:
869
859
  :param meta_id: meta_id
870
860
  :param item_id: item_id
871
861
  """
872
- items = self.get_items()
873
- items = [item for item in items if item.id < item_id]
874
- self.set_items(items) # update items in container
862
+ items = [item for item in self.get_items() if item.id < item_id]
863
+ self.set_items(items)
875
864
  return self.provider.remove_items_from(meta_id, item_id)
876
865
 
877
866
  def truncate(self):
878
867
  """Delete all ctx"""
879
- # empty ctx index
880
868
  self.meta = {}
881
-
882
- # remove all ctx data in provider
883
869
  self.provider.truncate()
884
870
 
885
871
  def clear(self):
@@ -948,7 +934,7 @@ class Ctx:
948
934
  preset_id,
949
935
  )
950
936
  if len(slaves) > 0:
951
- return list(slaves.values())[0]
937
+ return next(iter(slaves.values()))
952
938
  slave = self.build()
953
939
 
954
940
  if master_ctx.meta is not None:
@@ -969,9 +955,8 @@ class Ctx:
969
955
  if self.current is None:
970
956
  return None
971
957
  idx = self.get_idx_by_id(self.current)
972
- if idx is not None:
973
- if idx > 0:
974
- return self.get_id_by_idx(idx - 1)
958
+ if idx is not None and idx > 0:
959
+ return self.get_id_by_idx(idx - 1)
975
960
 
976
961
  def get_next(self) -> Optional[int]:
977
962
  """
@@ -982,9 +967,8 @@ class Ctx:
982
967
  if self.current is None:
983
968
  return None
984
969
  idx = self.get_idx_by_id(self.current)
985
- if idx is not None:
986
- if idx < self.count_meta() - 1:
987
- return self.get_id_by_idx(idx + 1)
970
+ if idx is not None and idx < self.count_meta() - 1:
971
+ return self.get_id_by_idx(idx + 1)
988
972
 
989
973
  def get_last_meta(self) -> Optional[int]:
990
974
  """
@@ -1013,14 +997,15 @@ class Ctx:
1013
997
  :return: ctx items count, ctx tokens count
1014
998
  """
1015
999
  i = 0
1016
- # loop on items from end to start
1017
1000
  tokens = used_tokens
1018
1001
  context_tokens = 0
1002
+ from_ctx = self.window.core.tokens.from_ctx
1019
1003
  for item in reversed(history_items):
1020
- num = self.window.core.tokens.from_ctx(item, mode, model) # get num tokens for input and output
1021
- tokens += num
1022
- if tokens > max_tokens > 0:
1004
+ num = from_ctx(item, mode, model)
1005
+ new_total = tokens + num
1006
+ if max_tokens > 0 and new_total > max_tokens:
1023
1007
  break
1008
+ tokens = new_total
1024
1009
  context_tokens += num
1025
1010
  i += 1
1026
1011
 
@@ -1047,19 +1032,20 @@ class Ctx:
1047
1032
  :return: ctx items list
1048
1033
  """
1049
1034
  items = []
1050
- # loop on items from end to start
1051
1035
  tokens = used_tokens
1052
1036
  is_first = True
1037
+ from_ctx = self.window.core.tokens.from_ctx
1053
1038
  for item in reversed(history_items):
1054
1039
  if is_first and ignore_first:
1055
1040
  is_first = False
1056
1041
  continue
1057
- tokens += self.window.core.tokens.from_ctx(item, mode, model)
1058
- if 0 < max_tokens < tokens:
1042
+ cost = from_ctx(item, mode, model)
1043
+ new_total = tokens + cost
1044
+ if 0 < max_tokens < new_total:
1059
1045
  break
1046
+ tokens = new_total
1060
1047
  items.append(item)
1061
1048
 
1062
- # reverse items
1063
1049
  items.reverse()
1064
1050
  return items
1065
1051
 
@@ -1121,17 +1107,10 @@ class Ctx:
1121
1107
  :param ignore_first: ignore current item (provided by user)
1122
1108
  :return: ctx items list
1123
1109
  """
1124
- items = []
1125
- is_first = True
1126
- for item in reversed(self.get_items()):
1127
- if is_first and ignore_first:
1128
- is_first = False
1129
- continue
1130
- items.append(item)
1131
-
1132
- # reverse items
1133
- items.reverse()
1134
- return items
1110
+ items = self.get_items()
1111
+ if ignore_first:
1112
+ return items[:-1]
1113
+ return items[:]
1135
1114
 
1136
1115
  def check(self, threshold: int, max_total: int):
1137
1116
  """
@@ -1169,15 +1148,13 @@ class Ctx:
1169
1148
 
1170
1149
  :return: last tokens
1171
1150
  """
1172
- last = self.get_last()
1173
- if last is not None:
1174
- return last.total_tokens
1175
- return 0
1151
+ return self.get_total_tokens()
1176
1152
 
1177
1153
  def remove_last(self):
1178
1154
  """Remove last item"""
1179
- if self.count_items() > 0:
1180
- self.get_items().pop()
1155
+ items = self.get_items()
1156
+ if items:
1157
+ items.pop()
1181
1158
 
1182
1159
  def duplicate(self, id: int) -> int:
1183
1160
  """
@@ -1198,8 +1175,9 @@ class Ctx:
1198
1175
 
1199
1176
  def remove_first(self):
1200
1177
  """Remove first item"""
1201
- if self.count_items() > 0:
1202
- self.get_items().pop(0)
1178
+ items = self.get_items()
1179
+ if items:
1180
+ items.pop(0)
1203
1181
 
1204
1182
  def set_display_filters(self, filters: dict):
1205
1183
  """
@@ -1221,43 +1199,33 @@ class Ctx:
1221
1199
  :param check_assistant: True if check also current assistant
1222
1200
  :return: True if allowed for mode
1223
1201
  """
1224
- # always allow if lock_modes is disabled
1225
1202
  if not self.window.core.config.get('lock_modes'):
1226
1203
  return True
1227
1204
 
1228
1205
  if self.is_empty():
1229
1206
  return True
1230
1207
 
1231
- # always allow if no ctx
1232
1208
  if self.current is None or self.current == '' or not self.has(self.current):
1233
1209
  return True
1234
1210
 
1235
1211
  meta = self.get_meta_by_id(self.current)
1236
1212
 
1237
- # always allow if no last mode
1238
1213
  if meta.last_mode is None:
1239
1214
  return True
1240
1215
 
1241
- # get last used mode from ctx meta
1242
1216
  prev_mode = meta.last_mode
1243
1217
  if prev_mode not in self.allowed_modes[mode]:
1244
- # exception for assistant (if assistant exists in ctx then allow)
1245
- if mode == 'assistant':
1218
+ if mode == MODE_ASSISTANT:
1246
1219
  if meta.assistant is not None:
1247
- # if the same assistant then allow
1248
1220
  if meta.assistant == self.window.core.config.get('assistant'):
1249
1221
  return True
1250
1222
  else:
1251
- return True # if no assistant in ctx then allow
1252
- # if other mode, then always disallow
1223
+ return True
1253
1224
  return False
1254
1225
 
1255
- # check if the same assistant
1256
- if mode == 'assistant' and check_assistant:
1257
- # allow if no assistant yet in ctx
1226
+ if mode == MODE_ASSISTANT and check_assistant:
1258
1227
  if meta.assistant is None:
1259
1228
  return True
1260
- # disallow if different assistant
1261
1229
  if meta.assistant != self.window.core.config.get('assistant'):
1262
1230
  return False
1263
1231
  return True
@@ -1269,9 +1237,7 @@ class Ctx:
1269
1237
  :return: True if labels not default
1270
1238
  """
1271
1239
  num_all = len(self.window.controller.ui.get_colors())
1272
- if len(self.filters_labels) < num_all:
1273
- return True
1274
- return False
1240
+ return len(self.filters_labels) < num_all
1275
1241
 
1276
1242
  def load_meta(self):
1277
1243
  """Load ctx list from provider"""
@@ -1279,9 +1245,7 @@ class Ctx:
1279
1245
  if self.window.core.config.has('ctx.records.limit'):
1280
1246
  limit = int(self.window.core.config.get('ctx.records.limit') or 0)
1281
1247
 
1282
- # display: all
1283
1248
  if "is_important" not in self.filters and "indexed_ts" not in self.filters:
1284
- # pinned
1285
1249
  filters_pinned = self.get_parsed_filters()
1286
1250
  filters_pinned['is_important'] = {
1287
1251
  "mode": "=",
@@ -1291,12 +1255,11 @@ class Ctx:
1291
1255
  search_string=self.search_string,
1292
1256
  order_by='updated_ts',
1293
1257
  order_direction='DESC',
1294
- limit=0, # no limit for pinned
1258
+ limit=0,
1295
1259
  filters=filters_pinned,
1296
1260
  search_content=self.is_search_content(),
1297
1261
  )
1298
1262
 
1299
- # not-pinned
1300
1263
  filters = self.get_parsed_filters()
1301
1264
  meta_unpinned = self.provider.get_meta(
1302
1265
  search_string=self.search_string,
@@ -1307,11 +1270,9 @@ class Ctx:
1307
1270
  search_content=self.is_search_content(),
1308
1271
  )
1309
1272
 
1310
- # join both, pinned first
1311
1273
  self.meta = {**meta_pinned, **meta_unpinned}
1312
1274
 
1313
1275
  else:
1314
- # display: important or indexed
1315
1276
  filters = self.get_parsed_filters()
1316
1277
  self.meta = self.provider.get_meta(
1317
1278
  search_string=self.search_string,
@@ -1340,9 +1301,8 @@ class Ctx:
1340
1301
  }
1341
1302
  )
1342
1303
  if len(meta) > 0:
1343
- self.tmp_meta = list(meta.values())[0]
1304
+ self.tmp_meta = next(iter(meta.values()))
1344
1305
  if self.tmp_meta.id not in self.meta:
1345
- # append at first position
1346
1306
  self.meta = {self.tmp_meta.id: self.tmp_meta, **self.meta}
1347
1307
 
1348
1308
  def clear_tmp_meta(self):
@@ -1350,7 +1310,6 @@ class Ctx:
1350
1310
  if self.tmp_meta is not None and self.current != self.tmp_meta.id:
1351
1311
  self.tmp_meta = None
1352
1312
 
1353
-
1354
1313
  def get_parsed_filters(self) -> dict:
1355
1314
  """
1356
1315
  Get parsed filters
@@ -1361,7 +1320,7 @@ class Ctx:
1361
1320
  if self.has_labels():
1362
1321
  filters['label'] = {
1363
1322
  "mode": "IN",
1364
- "value": self.filters_labels, # append label colors
1323
+ "value": self.filters_labels,
1365
1324
  }
1366
1325
  return filters
1367
1326
 
@@ -1375,7 +1334,7 @@ class Ctx:
1375
1334
  items = self.provider.load(id)
1376
1335
  meta = self.get_meta_by_id(id)
1377
1336
  for item in items:
1378
- item.meta = meta # append meta to each item
1337
+ item.meta = meta
1379
1338
  return items
1380
1339
 
1381
1340
  def load_groups(self):
@@ -1389,9 +1348,7 @@ class Ctx:
1389
1348
  :param id: group id
1390
1349
  :return: True if exists
1391
1350
  """
1392
- if id in self.groups:
1393
- return True
1394
- return False
1351
+ return id in self.groups
1395
1352
 
1396
1353
  def get_groups(self) -> Dict[int, CtxGroup]:
1397
1354
  """
@@ -1426,8 +1383,9 @@ class Ctx:
1426
1383
  """
1427
1384
  if self.current is None:
1428
1385
  return
1429
- if self.current in self.meta:
1430
- self.meta[self.current].last_model = model
1386
+ meta = self.meta.get(self.current)
1387
+ if meta is not None:
1388
+ meta.last_model = model
1431
1389
  self.save(self.current)
1432
1390
 
1433
1391
  def remove_group(
@@ -1505,7 +1463,6 @@ class Ctx:
1505
1463
  items = self.provider.load(id)
1506
1464
  data = []
1507
1465
  for item in items:
1508
- # data.append("Me: " + str(item.input) + "\n" + "You: " + str(item.output) + "\n")
1509
1466
  data.append("Human: " + str(item.input) + "\n" + "Assistant: " + str(item.output) + "\n")
1510
1467
  return data
1511
1468
 
@@ -1544,9 +1501,7 @@ class Ctx:
1544
1501
 
1545
1502
  :return: True if enabled
1546
1503
  """
1547
- if self.window.core.config.get('ctx.search_content'):
1548
- return True
1549
- return False
1504
+ return bool(self.window.core.config.get('ctx.search_content'))
1550
1505
 
1551
1506
  def save(self, id: int):
1552
1507
  """
@@ -1558,11 +1513,12 @@ class Ctx:
1558
1513
 
1559
1514
  def store(self):
1560
1515
  """Store current ctx"""
1561
- if self.current is not None:
1562
- if self.current not in self.meta:
1563
- self.load_tmp_meta(self.current)
1564
- if self.current in self.meta:
1565
- self.save(self.current)
1516
+ cur = self.current
1517
+ if cur is not None:
1518
+ if cur not in self.meta:
1519
+ self.load_tmp_meta(cur)
1520
+ if cur in self.meta:
1521
+ self.save(cur)
1566
1522
 
1567
1523
  def reset_meta(self, id: int):
1568
1524
  """
@@ -1583,23 +1539,15 @@ class Ctx:
1583
1539
  :return: CtxItem instance (previous)
1584
1540
  """
1585
1541
  prev_ctx = CtxItem()
1586
- prev_ctx.urls = copy.deepcopy(ctx.urls)
1587
- prev_ctx.urls_before = copy.deepcopy(ctx.urls_before)
1588
- prev_ctx.images = copy.deepcopy(ctx.images)
1589
- prev_ctx.images_before = copy.deepcopy(ctx.images_before)
1590
- prev_ctx.files = copy.deepcopy(ctx.files)
1591
- prev_ctx.files_before = copy.deepcopy(ctx.files_before)
1592
- prev_ctx.attachments = copy.deepcopy(ctx.attachments)
1593
- prev_ctx.attachments_before = copy.deepcopy(ctx.attachments_before)
1594
- prev_ctx.results = copy.deepcopy(ctx.results)
1595
- prev_ctx.index_meta = copy.deepcopy(ctx.index_meta)
1596
- prev_ctx.doc_ids = copy.deepcopy(ctx.doc_ids)
1597
- prev_ctx.input_name = copy.deepcopy(ctx.input_name)
1598
- prev_ctx.output_name = copy.deepcopy(ctx.output_name)
1599
-
1600
- ctx.clear_reply() # clear current reply result
1542
+ for name in (
1543
+ "urls", "urls_before", "images", "images_before", "files", "files_before",
1544
+ "attachments", "attachments_before", "results", "index_meta", "doc_ids",
1545
+ "input_name", "output_name"
1546
+ ):
1547
+ setattr(prev_ctx, name, copy.deepcopy(getattr(ctx, name)))
1548
+ ctx.clear_reply()
1601
1549
  if len(ctx.cmds) == 0:
1602
- ctx.from_previous() # get result from previous if exists
1550
+ ctx.from_previous()
1603
1551
  return prev_ctx
1604
1552
 
1605
1553
  def dump(self, ctx: CtxItem) -> str: