symbolicai 1.0.0__py3-none-any.whl → 1.1.0__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 (127) hide show
  1. symai/__init__.py +198 -134
  2. symai/backend/base.py +51 -51
  3. symai/backend/engines/drawing/engine_bfl.py +33 -33
  4. symai/backend/engines/drawing/engine_gpt_image.py +4 -10
  5. symai/backend/engines/embedding/engine_llama_cpp.py +50 -35
  6. symai/backend/engines/embedding/engine_openai.py +22 -16
  7. symai/backend/engines/execute/engine_python.py +16 -16
  8. symai/backend/engines/files/engine_io.py +51 -49
  9. symai/backend/engines/imagecaptioning/engine_blip2.py +27 -23
  10. symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +53 -46
  11. symai/backend/engines/index/engine_pinecone.py +116 -88
  12. symai/backend/engines/index/engine_qdrant.py +1011 -0
  13. symai/backend/engines/index/engine_vectordb.py +78 -52
  14. symai/backend/engines/lean/engine_lean4.py +65 -25
  15. symai/backend/engines/neurosymbolic/__init__.py +28 -28
  16. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +137 -135
  17. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +145 -152
  18. symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
  19. symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +75 -49
  20. symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +199 -155
  21. symai/backend/engines/neurosymbolic/engine_groq.py +106 -72
  22. symai/backend/engines/neurosymbolic/engine_huggingface.py +100 -67
  23. symai/backend/engines/neurosymbolic/engine_llama_cpp.py +121 -93
  24. symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +213 -132
  25. symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +180 -137
  26. symai/backend/engines/ocr/engine_apilayer.py +18 -20
  27. symai/backend/engines/output/engine_stdout.py +9 -9
  28. symai/backend/engines/{webscraping → scrape}/engine_requests.py +25 -11
  29. symai/backend/engines/search/engine_openai.py +95 -83
  30. symai/backend/engines/search/engine_parallel.py +665 -0
  31. symai/backend/engines/search/engine_perplexity.py +40 -41
  32. symai/backend/engines/search/engine_serpapi.py +33 -28
  33. symai/backend/engines/speech_to_text/engine_local_whisper.py +37 -27
  34. symai/backend/engines/symbolic/engine_wolframalpha.py +14 -8
  35. symai/backend/engines/text_to_speech/engine_openai.py +15 -19
  36. symai/backend/engines/text_vision/engine_clip.py +34 -28
  37. symai/backend/engines/userinput/engine_console.py +3 -4
  38. symai/backend/mixin/anthropic.py +48 -40
  39. symai/backend/mixin/deepseek.py +4 -5
  40. symai/backend/mixin/google.py +5 -4
  41. symai/backend/mixin/groq.py +2 -4
  42. symai/backend/mixin/openai.py +132 -110
  43. symai/backend/settings.py +14 -14
  44. symai/chat.py +164 -94
  45. symai/collect/dynamic.py +13 -11
  46. symai/collect/pipeline.py +39 -31
  47. symai/collect/stats.py +109 -69
  48. symai/components.py +556 -238
  49. symai/constraints.py +14 -5
  50. symai/core.py +1495 -1210
  51. symai/core_ext.py +55 -50
  52. symai/endpoints/api.py +113 -58
  53. symai/extended/api_builder.py +22 -17
  54. symai/extended/arxiv_pdf_parser.py +13 -5
  55. symai/extended/bibtex_parser.py +8 -4
  56. symai/extended/conversation.py +88 -69
  57. symai/extended/document.py +40 -27
  58. symai/extended/file_merger.py +45 -7
  59. symai/extended/graph.py +38 -24
  60. symai/extended/html_style_template.py +17 -11
  61. symai/extended/interfaces/blip_2.py +1 -1
  62. symai/extended/interfaces/clip.py +4 -2
  63. symai/extended/interfaces/console.py +5 -3
  64. symai/extended/interfaces/dall_e.py +3 -1
  65. symai/extended/interfaces/file.py +2 -0
  66. symai/extended/interfaces/flux.py +3 -1
  67. symai/extended/interfaces/gpt_image.py +15 -6
  68. symai/extended/interfaces/input.py +2 -1
  69. symai/extended/interfaces/llava.py +1 -1
  70. symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +3 -2
  71. symai/extended/interfaces/naive_vectordb.py +2 -2
  72. symai/extended/interfaces/ocr.py +4 -2
  73. symai/extended/interfaces/openai_search.py +2 -0
  74. symai/extended/interfaces/parallel.py +30 -0
  75. symai/extended/interfaces/perplexity.py +2 -0
  76. symai/extended/interfaces/pinecone.py +6 -4
  77. symai/extended/interfaces/python.py +2 -0
  78. symai/extended/interfaces/serpapi.py +2 -0
  79. symai/extended/interfaces/terminal.py +0 -1
  80. symai/extended/interfaces/tts.py +2 -1
  81. symai/extended/interfaces/whisper.py +2 -1
  82. symai/extended/interfaces/wolframalpha.py +1 -0
  83. symai/extended/metrics/__init__.py +1 -1
  84. symai/extended/metrics/similarity.py +5 -2
  85. symai/extended/os_command.py +31 -22
  86. symai/extended/packages/symdev.py +39 -34
  87. symai/extended/packages/sympkg.py +30 -27
  88. symai/extended/packages/symrun.py +46 -35
  89. symai/extended/repo_cloner.py +10 -9
  90. symai/extended/seo_query_optimizer.py +15 -12
  91. symai/extended/solver.py +104 -76
  92. symai/extended/summarizer.py +8 -7
  93. symai/extended/taypan_interpreter.py +10 -9
  94. symai/extended/vectordb.py +28 -15
  95. symai/formatter/formatter.py +39 -31
  96. symai/formatter/regex.py +46 -44
  97. symai/functional.py +184 -86
  98. symai/imports.py +85 -51
  99. symai/interfaces.py +1 -1
  100. symai/memory.py +33 -24
  101. symai/menu/screen.py +28 -19
  102. symai/misc/console.py +27 -27
  103. symai/misc/loader.py +4 -3
  104. symai/models/base.py +147 -76
  105. symai/models/errors.py +1 -1
  106. symai/ops/__init__.py +1 -1
  107. symai/ops/measures.py +17 -14
  108. symai/ops/primitives.py +933 -635
  109. symai/post_processors.py +28 -24
  110. symai/pre_processors.py +58 -52
  111. symai/processor.py +15 -9
  112. symai/prompts.py +714 -649
  113. symai/server/huggingface_server.py +115 -32
  114. symai/server/llama_cpp_server.py +14 -6
  115. symai/server/qdrant_server.py +206 -0
  116. symai/shell.py +98 -39
  117. symai/shellsv.py +307 -223
  118. symai/strategy.py +135 -81
  119. symai/symbol.py +276 -225
  120. symai/utils.py +62 -46
  121. {symbolicai-1.0.0.dist-info → symbolicai-1.1.0.dist-info}/METADATA +19 -9
  122. symbolicai-1.1.0.dist-info/RECORD +168 -0
  123. symbolicai-1.0.0.dist-info/RECORD +0 -163
  124. {symbolicai-1.0.0.dist-info → symbolicai-1.1.0.dist-info}/WHEEL +0 -0
  125. {symbolicai-1.0.0.dist-info → symbolicai-1.1.0.dist-info}/entry_points.txt +0 -0
  126. {symbolicai-1.0.0.dist-info → symbolicai-1.1.0.dist-info}/licenses/LICENSE +0 -0
  127. {symbolicai-1.0.0.dist-info → symbolicai-1.1.0.dist-info}/top_level.txt +0 -0
symai/backend/base.py CHANGED
@@ -7,48 +7,47 @@ from ..collect import CollectionRepository, rec_serialize
7
7
  from ..utils import UserMessage
8
8
  from .settings import HOME_PATH
9
9
 
10
- ENGINE_UNREGISTERED = '<UNREGISTERED/>'
10
+ ENGINE_UNREGISTERED = "<UNREGISTERED/>"
11
11
 
12
12
  COLLECTION_LOGGING_ENGINES = {
13
- 'GPTXChatEngine',
14
- 'GPTXCompletionEngine',
15
- 'SerpApiEngine',
16
- 'WolframAlphaEngine',
17
- 'SeleniumEngine',
18
- 'OCREngine',
13
+ "GPTXChatEngine",
14
+ "GPTXCompletionEngine",
15
+ "SerpApiEngine",
16
+ "WolframAlphaEngine",
17
+ "SeleniumEngine",
18
+ "OCREngine",
19
19
  }
20
20
 
21
+
21
22
  class Engine(ABC):
22
23
  def __init__(self) -> None:
23
24
  super().__init__()
24
- self.verbose = False
25
- self.logging = False
26
- self.log_level = logging.DEBUG
25
+ self.verbose = False
26
+ self.logging = False
27
+ self.log_level = logging.DEBUG
27
28
  self.time_clock = False
28
29
  self.collection = CollectionRepository()
29
30
  self.collection.connect()
30
31
  # create formatter
31
- __root_dir__ = HOME_PATH
32
+ __root_dir__ = HOME_PATH
32
33
  __root_dir__.mkdir(parents=True, exist_ok=True)
33
34
  __file_path__ = __root_dir__ / "engine.log"
34
- logging.basicConfig(filename=__file_path__, filemode="a", format='%(asctime)s %(name)s %(levelname)s %(message)s')
35
- self.logger = logging.getLogger()
35
+ logging.basicConfig(
36
+ filename=__file_path__,
37
+ filemode="a",
38
+ format="%(asctime)s %(name)s %(levelname)s %(message)s",
39
+ )
40
+ self.logger = logging.getLogger()
36
41
  self.logger.setLevel(logging.DEBUG)
37
42
  # logging to console
38
- stream = logging.StreamHandler()
39
- streamformat = logging.Formatter("%(asctime)s %(message)s")
43
+ stream = logging.StreamHandler()
44
+ streamformat = logging.Formatter("%(asctime)s %(message)s")
40
45
  stream.setLevel(logging.INFO)
41
46
  stream.setFormatter(streamformat)
42
47
  self.logger.addHandler(stream)
43
48
 
44
49
  def __call__(self, argument: Any) -> tuple[list[str], dict]:
45
- log = {
46
- 'Input': {
47
- 'self': self,
48
- 'args': argument.args,
49
- **argument.kwargs
50
- }
51
- }
50
+ log = {"Input": {"self": self, "args": argument.args, **argument.kwargs}}
52
51
  start_time = time.time()
53
52
 
54
53
  self._trigger_input_handlers(argument)
@@ -56,12 +55,12 @@ class Engine(ABC):
56
55
  res, metadata = self.forward(argument)
57
56
 
58
57
  req_time = time.time() - start_time
59
- metadata['time'] = req_time
58
+ metadata["time"] = req_time
60
59
  if self.time_clock:
61
60
  UserMessage(f"{argument.prop.func}: {req_time} sec")
62
- log['Output'] = res
61
+ log["Output"] = res
63
62
  if self.verbose:
64
- view = {k: v for k, v in list(log['Input'].items()) if k != 'self'}
63
+ view = {k: v for k, v in list(log["Input"].items()) if k != "self"}
65
64
  input_ = f"{str(log['Input']['self'])[:50]}, {argument.prop.func!s}, {view!s}"
66
65
  UserMessage(f"{input_[:150]} {str(log['Output'])[:100]}")
67
66
  if self.logging:
@@ -74,9 +73,9 @@ class Engine(ABC):
74
73
  return res, metadata
75
74
 
76
75
  def _trigger_input_handlers(self, argument: Any) -> None:
77
- instance_metadata = getattr(argument.prop.instance, '_metadata', None)
76
+ instance_metadata = getattr(argument.prop.instance, "_metadata", None)
78
77
  if instance_metadata is not None:
79
- input_handler = getattr(instance_metadata, 'input_handler', None)
78
+ input_handler = getattr(instance_metadata, "input_handler", None)
80
79
  if input_handler is not None:
81
80
  input_handler((argument.prop.processed_input, argument))
82
81
  argument_handler = argument.prop.input_handler
@@ -84,9 +83,9 @@ class Engine(ABC):
84
83
  argument_handler((argument.prop.processed_input, argument))
85
84
 
86
85
  def _trigger_output_handlers(self, argument: Any, result: Any, metadata: dict | None) -> None:
87
- instance_metadata = getattr(argument.prop.instance, '_metadata', None)
86
+ instance_metadata = getattr(argument.prop.instance, "_metadata", None)
88
87
  if instance_metadata is not None:
89
- output_handler = getattr(instance_metadata, 'output_handler', None)
88
+ output_handler = getattr(instance_metadata, "output_handler", None)
90
89
  if output_handler:
91
90
  output_handler(result)
92
91
  argument_handler = argument.prop.output_handler
@@ -95,13 +94,13 @@ class Engine(ABC):
95
94
 
96
95
  def _record_collection_entry(self, argument: Any, metadata: dict, req_time: float) -> None:
97
96
  self.collection.add(
98
- forward={'args': rec_serialize(argument.args), 'kwds': rec_serialize(argument.kwargs)},
97
+ forward={"args": rec_serialize(argument.args), "kwds": rec_serialize(argument.kwargs)},
99
98
  engine=str(self),
100
99
  metadata={
101
- 'time': req_time,
102
- 'data': rec_serialize(metadata),
103
- 'argument': rec_serialize(argument)
104
- }
100
+ "time": req_time,
101
+ "data": rec_serialize(metadata),
102
+ "argument": rec_serialize(argument),
103
+ },
105
104
  )
106
105
 
107
106
  def id(self) -> str:
@@ -109,17 +108,18 @@ class Engine(ABC):
109
108
 
110
109
  def preview(self, argument):
111
110
  # Used here to avoid backend.base <-> symbol circular import.
112
- from ..symbol import ( # noqa
111
+ from ..symbol import ( # noqa
113
112
  Symbol,
114
113
  )
114
+
115
115
  class Preview(Symbol):
116
116
  def __repr__(self) -> str:
117
- '''
117
+ """
118
118
  Get the representation of the Symbol object as a string.
119
119
 
120
120
  Returns:
121
121
  str: The representation of the Symbol object.
122
- '''
122
+ """
123
123
  return str(self.value.prop.prepared_input)
124
124
 
125
125
  def prepared_input(self):
@@ -136,29 +136,29 @@ class Engine(ABC):
136
136
  raise NotImplementedError
137
137
 
138
138
  def command(self, *_args, **kwargs):
139
- if kwargs.get('verbose'):
140
- self.verbose = kwargs['verbose']
141
- if kwargs.get('logging'):
142
- self.logging = kwargs['logging']
143
- if kwargs.get('log_level'):
144
- self.log_level = kwargs['log_level']
145
- if kwargs.get('time_clock'):
146
- self.time_clock = kwargs['time_clock']
139
+ if kwargs.get("verbose"):
140
+ self.verbose = kwargs["verbose"]
141
+ if kwargs.get("logging"):
142
+ self.logging = kwargs["logging"]
143
+ if kwargs.get("log_level"):
144
+ self.log_level = kwargs["log_level"]
145
+ if kwargs.get("time_clock"):
146
+ self.time_clock = kwargs["time_clock"]
147
147
 
148
148
  def __str__(self) -> str:
149
149
  return self.__class__.__name__
150
150
 
151
151
  def __repr__(self) -> str:
152
- '''
152
+ """
153
153
  Get the representation of the Symbol object as a string.
154
154
 
155
155
  Returns:
156
156
  str: The representation of the Symbol object.
157
- '''
157
+ """
158
158
  # class with full path
159
- class_ = self.__class__.__module__ + '.' + self.__class__.__name__
160
- hex_ = hex(id(self))
161
- return f'<class {class_} at {hex_}>'
159
+ class_ = self.__class__.__module__ + "." + self.__class__.__name__
160
+ hex_ = hex(id(self))
161
+ return f"<class {class_} at {hex_}>"
162
162
 
163
163
 
164
164
  class BatchEngine(Engine):
@@ -196,7 +196,7 @@ class BatchEngine(Engine):
196
196
  return_list = []
197
197
  for arg, result, metadata in zip(arguments, results, metadata_list, strict=False):
198
198
  if metadata is not None:
199
- metadata['time'] = total_time / len(arguments)
199
+ metadata["time"] = total_time / len(arguments)
200
200
 
201
201
  self._trigger_output_handlers(arg, result, metadata)
202
202
  return_list.append((result, metadata))
@@ -22,7 +22,7 @@ class FluxResult(Result):
22
22
  # unpack the result
23
23
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
24
24
  path = tmp_file.name
25
- url = value.get('result').get('sample')
25
+ url = value.get("result").get("sample")
26
26
  request = requests.get(url, allow_redirects=True)
27
27
  request.raise_for_status()
28
28
  with Path(path).open("wb") as f:
@@ -34,57 +34,57 @@ class DrawingEngine(Engine):
34
34
  def __init__(self, api_key: str | None = None, model: str | None = None):
35
35
  super().__init__()
36
36
  self.config = SYMAI_CONFIG
37
- self.api_key = self.config['DRAWING_ENGINE_API_KEY'] if api_key is None else api_key
38
- self.model = self.config['DRAWING_ENGINE_MODEL'] if model is None else model
37
+ self.api_key = self.config["DRAWING_ENGINE_API_KEY"] if api_key is None else api_key
38
+ self.model = self.config["DRAWING_ENGINE_MODEL"] if model is None else model
39
39
  self.name = self.__class__.__name__
40
40
 
41
41
  def id(self) -> str:
42
- if self.config['DRAWING_ENGINE_API_KEY'] and self.config['DRAWING_ENGINE_MODEL'].startswith("flux"):
43
- return 'drawing'
44
- return super().id() # default to unregistered
42
+ if self.config["DRAWING_ENGINE_API_KEY"] and self.config["DRAWING_ENGINE_MODEL"].startswith(
43
+ "flux"
44
+ ):
45
+ return "drawing"
46
+ return super().id() # default to unregistered
45
47
 
46
48
  def command(self, *args, **kwargs):
47
49
  super().command(*args, **kwargs)
48
- if 'DRAWING_ENGINE_API_KEY' in kwargs:
49
- self.api_key = kwargs['DRAWING_ENGINE_API_KEY']
50
- if 'DRAWING_ENGINE_MODEL' in kwargs:
51
- self.model = kwargs['DRAWING_ENGINE_MODEL']
50
+ if "DRAWING_ENGINE_API_KEY" in kwargs:
51
+ self.api_key = kwargs["DRAWING_ENGINE_API_KEY"]
52
+ if "DRAWING_ENGINE_MODEL" in kwargs:
53
+ self.model = kwargs["DRAWING_ENGINE_MODEL"]
52
54
 
53
55
  def forward(self, argument):
54
56
  prompt = argument.prop.prepared_input
55
57
  kwargs = argument.kwargs
56
- width = kwargs.get('width', 1024)
57
- height = kwargs.get('height', 768)
58
- steps = kwargs.get('steps', 40)
59
- seed = kwargs.get('seed', None)
60
- guidance = kwargs.get('guidance', None)
61
- safety_tolerance = kwargs.get('safety_tolerance', 2)
62
- except_remedy = kwargs.get('except_remedy', None)
58
+ width = kwargs.get("width", 1024)
59
+ height = kwargs.get("height", 768)
60
+ steps = kwargs.get("steps", 40)
61
+ seed = kwargs.get("seed", None)
62
+ guidance = kwargs.get("guidance", None)
63
+ safety_tolerance = kwargs.get("safety_tolerance", 2)
64
+ except_remedy = kwargs.get("except_remedy", None)
63
65
 
64
66
  headers = {
65
- 'accept': 'application/json',
66
- 'x-key': self.api_key,
67
- 'Content-Type': 'application/json',
67
+ "accept": "application/json",
68
+ "x-key": self.api_key,
69
+ "Content-Type": "application/json",
68
70
  }
69
71
 
70
72
  payload = {
71
- 'prompt': prompt,
72
- 'width': width,
73
- 'height': height,
74
- 'num_inference_steps': steps,
75
- 'guidance_scale': guidance,
76
- 'seed': seed,
77
- 'safety_tolerance': safety_tolerance,
73
+ "prompt": prompt,
74
+ "width": width,
75
+ "height": height,
76
+ "num_inference_steps": steps,
77
+ "guidance_scale": guidance,
78
+ "seed": seed,
79
+ "safety_tolerance": safety_tolerance,
78
80
  }
79
81
  # drop any None values so Flux API won't return 500
80
82
  payload = {k: v for k, v in payload.items() if v is not None}
81
83
 
82
- if kwargs.get('operation') == 'create':
84
+ if kwargs.get("operation") == "create":
83
85
  try:
84
86
  response = requests.post(
85
- f'https://api.us1.bfl.ai/v1/{self.model}',
86
- headers=headers,
87
- json=payload
87
+ f"https://api.us1.bfl.ai/v1/{self.model}", headers=headers, json=payload
88
88
  )
89
89
  # fail early on HTTP errors
90
90
  response.raise_for_status()
@@ -100,9 +100,9 @@ class DrawingEngine(Engine):
100
100
  time.sleep(5)
101
101
 
102
102
  result = requests.get(
103
- 'https://api.us1.bfl.ai/v1/get_result',
103
+ "https://api.us1.bfl.ai/v1/get_result",
104
104
  headers=headers,
105
- params={'id': request_id}
105
+ params={"id": request_id},
106
106
  )
107
107
 
108
108
  result.raise_for_status()
@@ -26,6 +26,7 @@ class GPTImageResult(Result):
26
26
  Exposes .value as the raw response and ._value as the
27
27
  first URL or decoded b64 image string.
28
28
  """
29
+
29
30
  def __init__(self, value, **kwargs):
30
31
  super().__init__(value, **kwargs)
31
32
  imgs = []
@@ -53,6 +54,7 @@ class GPTImageEngine(Engine):
53
54
  supporting gpt-image-1, dall-e-2, dall-e-3,
54
55
  with all the extra parameters (background, moderation, etc).
55
56
  """
57
+
56
58
  def __init__(
57
59
  self,
58
60
  api_key: str | None = None,
@@ -61,16 +63,8 @@ class GPTImageEngine(Engine):
61
63
  super().__init__()
62
64
  self.config = SYMAI_CONFIG
63
65
  # pick up a separate config slot if you like, or fall back
64
- openai.api_key = (
65
- self.config.get("DRAWING_ENGINE_API_KEY")
66
- if api_key is None
67
- else api_key
68
- )
69
- self.model = (
70
- self.config.get("DRAWING_ENGINE_MODEL")
71
- if model is None
72
- else model
73
- )
66
+ openai.api_key = self.config.get("DRAWING_ENGINE_API_KEY") if api_key is None else api_key
67
+ self.model = self.config.get("DRAWING_ENGINE_MODEL") if model is None else model
74
68
  self.name = self.__class__.__name__
75
69
  # quiet OpenAI's internal logger
76
70
  log = logging.getLogger("openai")
@@ -15,58 +15,66 @@ logging.getLogger("urllib").setLevel(logging.ERROR)
15
15
  logging.getLogger("httpx").setLevel(logging.ERROR)
16
16
  logging.getLogger("httpcore").setLevel(logging.ERROR)
17
17
 
18
+
18
19
  class LlamaCppEmbeddingEngine(Engine):
19
20
  _retry_params: ClassVar[dict[str, Any]] = {
20
- 'tries': 5,
21
- 'delay': 2,
22
- 'max_delay': 60,
23
- 'backoff': 2,
24
- 'jitter': (1, 5),
25
- 'graceful': True
21
+ "tries": 5,
22
+ "delay": 2,
23
+ "max_delay": 60,
24
+ "backoff": 2,
25
+ "jitter": (1, 5),
26
+ "graceful": True,
26
27
  }
27
28
  _timeout_params: ClassVar[dict[str, Any]] = {
28
- 'read': None,
29
- 'connect': None,
29
+ "read": None,
30
+ "connect": None,
30
31
  }
31
32
 
32
- def __init__(
33
- self,
34
- retry_params: dict = _retry_params,
35
- timeout_params: dict = _timeout_params
36
- ):
33
+ def __init__(self, retry_params: dict = _retry_params, timeout_params: dict = _timeout_params):
37
34
  super().__init__()
38
35
  self.config = SYMAI_CONFIG
39
- if self.id() != 'embedding':
36
+ if self.id() != "embedding":
40
37
  return
41
- if not SYMSERVER_CONFIG.get('online'):
42
- UserMessage('You are using the llama.cpp embedding engine, but the server endpoint is not started. Please start the server with `symserver [--args]`.', raise_with=ValueError)
38
+ if not SYMSERVER_CONFIG.get("online"):
39
+ UserMessage(
40
+ "You are using the llama.cpp embedding engine, but the server endpoint is not started. Please start the server with `symserver [--args]`.",
41
+ raise_with=ValueError,
42
+ )
43
43
 
44
- self.server_endpoint = f"http://{SYMSERVER_CONFIG.get('--host')}:{SYMSERVER_CONFIG.get('--port')}"
44
+ self.server_endpoint = (
45
+ f"http://{SYMSERVER_CONFIG.get('--host')}:{SYMSERVER_CONFIG.get('--port')}"
46
+ )
45
47
  self.timeout_params = self._validate_timeout_params(timeout_params)
46
48
  self.retry_params = self._validate_retry_params(retry_params)
47
49
  self.name = self.__class__.__name__
48
50
 
49
51
  def id(self) -> str:
50
- if self.config.get('EMBEDDING_ENGINE_MODEL') and self.config.get('EMBEDDING_ENGINE_MODEL').startswith('llama'):
51
- return 'embedding'
52
+ if self.config.get("EMBEDDING_ENGINE_MODEL") and self.config.get(
53
+ "EMBEDDING_ENGINE_MODEL"
54
+ ).startswith("llama"):
55
+ return "embedding"
52
56
  return super().id() # default to unregistered
53
57
 
54
58
  def command(self, *args, **kwargs):
55
59
  super().command(*args, **kwargs)
56
- if 'EMBEDDING_ENGINE_MODEL' in kwargs:
57
- self.model = kwargs['EMBEDDING_ENGINE_MODEL']
60
+ if "EMBEDDING_ENGINE_MODEL" in kwargs:
61
+ self.model = kwargs["EMBEDDING_ENGINE_MODEL"]
58
62
 
59
63
  def _validate_timeout_params(self, timeout_params):
60
64
  if not isinstance(timeout_params, dict):
61
65
  UserMessage("timeout_params must be a dictionary", raise_with=ValueError)
62
- assert all(key in timeout_params for key in ['read', 'connect']), "Available keys: ['read', 'connect']"
66
+ assert all(key in timeout_params for key in ["read", "connect"]), (
67
+ "Available keys: ['read', 'connect']"
68
+ )
63
69
  return timeout_params
64
70
 
65
71
  def _validate_retry_params(self, retry_params):
66
72
  if not isinstance(retry_params, dict):
67
73
  UserMessage("retry_params must be a dictionary", raise_with=ValueError)
68
- assert all(key in retry_params for key in ['tries', 'delay', 'max_delay', 'backoff', 'jitter', 'graceful']), \
69
- "Available keys: ['tries', 'delay', 'max_delay', 'backoff', 'jitter', 'graceful']"
74
+ assert all(
75
+ key in retry_params
76
+ for key in ["tries", "delay", "max_delay", "backoff", "jitter", "graceful"]
77
+ ), "Available keys: ['tries', 'delay', 'max_delay', 'backoff', 'jitter', 'graceful']"
70
78
  return retry_params
71
79
 
72
80
  @staticmethod
@@ -86,18 +94,23 @@ class LlamaCppEmbeddingEngine(Engine):
86
94
 
87
95
  async def _arequest(self, text: str, embd_normalize: str) -> dict:
88
96
  """Makes an async HTTP request to the llama.cpp server."""
97
+
89
98
  @retry(**self.retry_params)
90
99
  async def _make_request():
91
100
  timeout = aiohttp.ClientTimeout(
92
- sock_connect=self.timeout_params['connect'],
93
- sock_read=self.timeout_params['read']
101
+ sock_connect=self.timeout_params["connect"], sock_read=self.timeout_params["read"]
94
102
  )
95
- async with aiohttp.ClientSession(timeout=timeout) as session, session.post(
96
- f"{self.server_endpoint}/v1/embeddings",
97
- json={"content": text, "embd_normalize": embd_normalize}
98
- ) as res:
103
+ async with (
104
+ aiohttp.ClientSession(timeout=timeout) as session,
105
+ session.post(
106
+ f"{self.server_endpoint}/v1/embeddings",
107
+ json={"content": text, "embd_normalize": embd_normalize},
108
+ ) as res,
109
+ ):
99
110
  if res.status != 200:
100
- UserMessage(f"Request failed with status code: {res.status}", raise_with=ValueError)
111
+ UserMessage(
112
+ f"Request failed with status code: {res.status}", raise_with=ValueError
113
+ )
101
114
  return await res.json()
102
115
 
103
116
  return await _make_request()
@@ -107,9 +120,9 @@ class LlamaCppEmbeddingEngine(Engine):
107
120
  kwargs = argument.kwargs
108
121
 
109
122
  inp = prepared_input if isinstance(prepared_input, list) else [prepared_input]
110
- embd_normalize = kwargs.get('embd_normalize', -1) # -1 = no normalization
123
+ embd_normalize = kwargs.get("embd_normalize", -1) # -1 = no normalization
111
124
 
112
- new_dim = kwargs.get('new_dim')
125
+ new_dim = kwargs.get("new_dim")
113
126
  if new_dim:
114
127
  UserMessage("new_dim is not yet supported", raise_with=NotImplementedError)
115
128
 
@@ -122,10 +135,12 @@ class LlamaCppEmbeddingEngine(Engine):
122
135
  UserMessage(f"Request failed with error: {e!s}", raise_with=ValueError)
123
136
 
124
137
  output = [r["embedding"] for r in res] if res is not None else None # B x 1 x D
125
- metadata = {'raw_output': res}
138
+ metadata = {"raw_output": res}
126
139
 
127
140
  return [output], metadata
128
141
 
129
142
  def prepare(self, argument):
130
- assert not argument.prop.processed_input, "LlamaCppEmbeddingEngine does not support processed_input."
143
+ assert not argument.prop.processed_input, (
144
+ "LlamaCppEmbeddingEngine does not support processed_input."
145
+ )
131
146
  argument.prop.prepared_input = argument.prop.entries
@@ -17,28 +17,30 @@ logging.getLogger("httpcore").setLevel(logging.ERROR)
17
17
  class EmbeddingEngine(Engine, OpenAIMixin):
18
18
  def __init__(self, api_key: str | None = None, model: str | None = None):
19
19
  super().__init__()
20
- logger = logging.getLogger('openai')
20
+ logger = logging.getLogger("openai")
21
21
  logger.setLevel(logging.WARNING)
22
22
  self.config = SYMAI_CONFIG
23
- if self.id() != 'embedding':
24
- return # do not initialize if not embedding; avoids conflict with llama.cpp check in EngineRepository.register_from_package
25
- openai.api_key = self.config['EMBEDDING_ENGINE_API_KEY'] if api_key is None else api_key
26
- self.model = self.config['EMBEDDING_ENGINE_MODEL'] if model is None else model
23
+ if self.id() != "embedding":
24
+ return # do not initialize if not embedding; avoids conflict with llama.cpp check in EngineRepository.register_from_package
25
+ openai.api_key = self.config["EMBEDDING_ENGINE_API_KEY"] if api_key is None else api_key
26
+ self.model = self.config["EMBEDDING_ENGINE_MODEL"] if model is None else model
27
27
  self.max_tokens = self.api_max_context_tokens()
28
28
  self.embedding_dim = self.api_embedding_dims()
29
29
  self.name = self.__class__.__name__
30
30
 
31
31
  def id(self) -> str:
32
- if self.config.get('EMBEDDING_ENGINE_API_KEY') and self.config['EMBEDDING_ENGINE_MODEL'].startswith('text-embedding'):
33
- return 'embedding'
34
- return super().id() # default to unregistered
32
+ if self.config.get("EMBEDDING_ENGINE_API_KEY") and self.config[
33
+ "EMBEDDING_ENGINE_MODEL"
34
+ ].startswith("text-embedding"):
35
+ return "embedding"
36
+ return super().id() # default to unregistered
35
37
 
36
38
  def command(self, *args, **kwargs):
37
39
  super().command(*args, **kwargs)
38
- if 'EMBEDDING_ENGINE_API_KEY' in kwargs:
39
- openai.api_key = kwargs['EMBEDDING_ENGINE_API_KEY']
40
- if 'EMBEDDING_ENGINE_MODEL' in kwargs:
41
- self.model = kwargs['EMBEDDING_ENGINE_MODEL']
40
+ if "EMBEDDING_ENGINE_API_KEY" in kwargs:
41
+ openai.api_key = kwargs["EMBEDDING_ENGINE_API_KEY"]
42
+ if "EMBEDDING_ENGINE_MODEL" in kwargs:
43
+ self.model = kwargs["EMBEDDING_ENGINE_MODEL"]
42
44
 
43
45
  def forward(self, argument):
44
46
  prepared_input = argument.prop.prepared_input
@@ -46,8 +48,8 @@ class EmbeddingEngine(Engine, OpenAIMixin):
46
48
  kwargs = argument.kwargs
47
49
 
48
50
  inp = prepared_input if isinstance(prepared_input, list) else [prepared_input]
49
- except_remedy = kwargs.get('except_remedy')
50
- new_dim = kwargs.get('new_dim')
51
+ except_remedy = kwargs.get("except_remedy")
52
+ new_dim = kwargs.get("new_dim")
51
53
 
52
54
  try:
53
55
  res = openai.embeddings.create(model=self.model, input=inp)
@@ -58,7 +60,9 @@ class EmbeddingEngine(Engine, OpenAIMixin):
58
60
  res = except_remedy(e, inp, callback, self, *args, **kwargs)
59
61
 
60
62
  if new_dim:
61
- mn = min(new_dim, self.embedding_dim) #@NOTE: new_dim should be less than or equal to the original embedding dim
63
+ mn = min(
64
+ new_dim, self.embedding_dim
65
+ ) # @NOTE: new_dim should be less than or equal to the original embedding dim
62
66
  output = [self._normalize_l2(r.embedding[:mn]) for r in res.data]
63
67
  else:
64
68
  output = [r.embedding for r in res.data]
@@ -68,7 +72,9 @@ class EmbeddingEngine(Engine, OpenAIMixin):
68
72
  return [output], metadata
69
73
 
70
74
  def prepare(self, argument):
71
- assert not argument.prop.processed_input, "EmbeddingEngine does not support processed_input."
75
+ assert not argument.prop.processed_input, (
76
+ "EmbeddingEngine does not support processed_input."
77
+ )
72
78
  argument.prop.prepared_input = argument.prop.entries
73
79
 
74
80
  def _normalize_l2(self, x):
@@ -8,13 +8,13 @@ from ...base import Engine
8
8
  def full_stack():
9
9
  exc = sys.exc_info()[0]
10
10
  stack = traceback.extract_stack()[-10:-1] # last one would be full_stack()
11
- if exc is not None: # i.e. an exception is present
12
- del stack[-1] # remove call of full_stack, the printed exception
13
- # will contain the caught exception caller instead
14
- trc = 'Traceback (most recent call last):\n'
15
- stackstr = trc + ''.join(traceback.format_list(stack))
11
+ if exc is not None: # i.e. an exception is present
12
+ del stack[-1] # remove call of full_stack, the printed exception
13
+ # will contain the caught exception caller instead
14
+ trc = "Traceback (most recent call last):\n"
15
+ stackstr = trc + "".join(traceback.format_list(stack))
16
16
  if exc is not None:
17
- stackstr += ' ' + traceback.format_exc().lstrip(trc)
17
+ stackstr += " " + traceback.format_exc().lstrip(trc)
18
18
  return stackstr
19
19
 
20
20
 
@@ -64,14 +64,14 @@ class PythonEngine(Engine):
64
64
  self.name = self.__class__.__name__
65
65
 
66
66
  def id(self) -> str:
67
- return 'execute'
67
+ return "execute"
68
68
 
69
69
  def forward(self, argument):
70
70
  code = argument.prop.prepared_input
71
71
  kwargs = argument.kwargs
72
- globals_ = kwargs.get('globals', {})
73
- locals_ = kwargs.get('locals', {})
74
- input_handler = kwargs.get('input_handler')
72
+ globals_ = kwargs.get("globals", {})
73
+ locals_ = kwargs.get("locals", {})
74
+ input_handler = kwargs.get("input_handler")
75
75
  if input_handler:
76
76
  input_handler((code,))
77
77
 
@@ -79,18 +79,18 @@ class PythonEngine(Engine):
79
79
  err = None
80
80
  try:
81
81
  exec(str(code), globals_, locals_)
82
- rsp = {'globals': globals_, 'locals': locals_}
83
- if 'res' in locals_:
84
- rsp['locals_res'] = locals_['res']
85
- if 'res' in globals_:
86
- rsp['globals_res'] = globals_['res']
82
+ rsp = {"globals": globals_, "locals": locals_}
83
+ if "res" in locals_:
84
+ rsp["locals_res"] = locals_["res"]
85
+ if "res" in globals_:
86
+ rsp["globals_res"] = globals_["res"]
87
87
  rsp = Result(rsp)
88
88
  except Exception as e:
89
89
  err = e
90
90
  raise e
91
91
 
92
92
  metadata = {}
93
- metadata['error'] = None if not err else full_stack()
93
+ metadata["error"] = None if not err else full_stack()
94
94
 
95
95
  return [rsp], metadata
96
96