symbolicai 1.0.0__py3-none-any.whl → 1.1.1__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.
- symai/__init__.py +198 -134
- symai/backend/base.py +51 -51
- symai/backend/engines/drawing/engine_bfl.py +33 -33
- symai/backend/engines/drawing/engine_gpt_image.py +4 -10
- symai/backend/engines/embedding/engine_llama_cpp.py +50 -35
- symai/backend/engines/embedding/engine_openai.py +22 -16
- symai/backend/engines/execute/engine_python.py +16 -16
- symai/backend/engines/files/engine_io.py +51 -49
- symai/backend/engines/imagecaptioning/engine_blip2.py +27 -23
- symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +53 -46
- symai/backend/engines/index/engine_pinecone.py +116 -88
- symai/backend/engines/index/engine_qdrant.py +1011 -0
- symai/backend/engines/index/engine_vectordb.py +78 -52
- symai/backend/engines/lean/engine_lean4.py +65 -25
- symai/backend/engines/neurosymbolic/__init__.py +35 -28
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +137 -135
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +145 -152
- symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
- symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +75 -49
- symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +199 -155
- symai/backend/engines/neurosymbolic/engine_groq.py +106 -72
- symai/backend/engines/neurosymbolic/engine_huggingface.py +100 -67
- symai/backend/engines/neurosymbolic/engine_llama_cpp.py +121 -93
- symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +213 -132
- symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +180 -137
- symai/backend/engines/ocr/engine_apilayer.py +18 -20
- symai/backend/engines/output/engine_stdout.py +9 -9
- symai/backend/engines/{webscraping → scrape}/engine_requests.py +25 -11
- symai/backend/engines/search/engine_openai.py +95 -83
- symai/backend/engines/search/engine_parallel.py +665 -0
- symai/backend/engines/search/engine_perplexity.py +40 -41
- symai/backend/engines/search/engine_serpapi.py +33 -28
- symai/backend/engines/speech_to_text/engine_local_whisper.py +37 -27
- symai/backend/engines/symbolic/engine_wolframalpha.py +14 -8
- symai/backend/engines/text_to_speech/engine_openai.py +15 -19
- symai/backend/engines/text_vision/engine_clip.py +34 -28
- symai/backend/engines/userinput/engine_console.py +3 -4
- symai/backend/mixin/__init__.py +4 -0
- symai/backend/mixin/anthropic.py +48 -40
- symai/backend/mixin/cerebras.py +9 -0
- symai/backend/mixin/deepseek.py +4 -5
- symai/backend/mixin/google.py +5 -4
- symai/backend/mixin/groq.py +2 -4
- symai/backend/mixin/openai.py +132 -110
- symai/backend/settings.py +14 -14
- symai/chat.py +164 -94
- symai/collect/dynamic.py +13 -11
- symai/collect/pipeline.py +39 -31
- symai/collect/stats.py +109 -69
- symai/components.py +578 -238
- symai/constraints.py +14 -5
- symai/core.py +1495 -1210
- symai/core_ext.py +55 -50
- symai/endpoints/api.py +113 -58
- symai/extended/api_builder.py +22 -17
- symai/extended/arxiv_pdf_parser.py +13 -5
- symai/extended/bibtex_parser.py +8 -4
- symai/extended/conversation.py +88 -69
- symai/extended/document.py +40 -27
- symai/extended/file_merger.py +45 -7
- symai/extended/graph.py +38 -24
- symai/extended/html_style_template.py +17 -11
- symai/extended/interfaces/blip_2.py +1 -1
- symai/extended/interfaces/clip.py +4 -2
- symai/extended/interfaces/console.py +5 -3
- symai/extended/interfaces/dall_e.py +3 -1
- symai/extended/interfaces/file.py +2 -0
- symai/extended/interfaces/flux.py +3 -1
- symai/extended/interfaces/gpt_image.py +15 -6
- symai/extended/interfaces/input.py +2 -1
- symai/extended/interfaces/llava.py +1 -1
- symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +3 -2
- symai/extended/interfaces/naive_vectordb.py +2 -2
- symai/extended/interfaces/ocr.py +4 -2
- symai/extended/interfaces/openai_search.py +2 -0
- symai/extended/interfaces/parallel.py +30 -0
- symai/extended/interfaces/perplexity.py +2 -0
- symai/extended/interfaces/pinecone.py +6 -4
- symai/extended/interfaces/python.py +2 -0
- symai/extended/interfaces/serpapi.py +2 -0
- symai/extended/interfaces/terminal.py +0 -1
- symai/extended/interfaces/tts.py +2 -1
- symai/extended/interfaces/whisper.py +2 -1
- symai/extended/interfaces/wolframalpha.py +1 -0
- symai/extended/metrics/__init__.py +1 -1
- symai/extended/metrics/similarity.py +5 -2
- symai/extended/os_command.py +31 -22
- symai/extended/packages/symdev.py +39 -34
- symai/extended/packages/sympkg.py +30 -27
- symai/extended/packages/symrun.py +46 -35
- symai/extended/repo_cloner.py +10 -9
- symai/extended/seo_query_optimizer.py +15 -12
- symai/extended/solver.py +104 -76
- symai/extended/summarizer.py +8 -7
- symai/extended/taypan_interpreter.py +10 -9
- symai/extended/vectordb.py +28 -15
- symai/formatter/formatter.py +39 -31
- symai/formatter/regex.py +46 -44
- symai/functional.py +184 -86
- symai/imports.py +85 -51
- symai/interfaces.py +1 -1
- symai/memory.py +33 -24
- symai/menu/screen.py +28 -19
- symai/misc/console.py +27 -27
- symai/misc/loader.py +4 -3
- symai/models/base.py +147 -76
- symai/models/errors.py +1 -1
- symai/ops/__init__.py +1 -1
- symai/ops/measures.py +17 -14
- symai/ops/primitives.py +933 -635
- symai/post_processors.py +28 -24
- symai/pre_processors.py +58 -52
- symai/processor.py +15 -9
- symai/prompts.py +714 -649
- symai/server/huggingface_server.py +115 -32
- symai/server/llama_cpp_server.py +14 -6
- symai/server/qdrant_server.py +206 -0
- symai/shell.py +98 -39
- symai/shellsv.py +307 -223
- symai/strategy.py +135 -81
- symai/symbol.py +276 -225
- symai/utils.py +62 -46
- {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/METADATA +19 -9
- symbolicai-1.1.1.dist-info/RECORD +169 -0
- symbolicai-1.0.0.dist-info/RECORD +0 -163
- {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/WHEEL +0 -0
- {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/entry_points.txt +0 -0
- {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/licenses/LICENSE +0 -0
- {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/top_level.txt +0 -0
symai/imports.py
CHANGED
|
@@ -16,14 +16,16 @@ from .utils import UserMessage
|
|
|
16
16
|
logging.getLogger("subprocess").setLevel(logging.ERROR)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
__root_dir__
|
|
20
|
-
BASE_PACKAGE_MODULE =
|
|
19
|
+
__root_dir__ = HOME_PATH / "packages"
|
|
20
|
+
BASE_PACKAGE_MODULE = "" # use relative path
|
|
21
21
|
BASE_PACKAGE_PATH = __root_dir__
|
|
22
22
|
sys.path.append(str(__root_dir__))
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Import(Expression):
|
|
26
|
-
def __init__(
|
|
26
|
+
def __init__(
|
|
27
|
+
self, module: str, local_path: str | None = None, submodules: bool = False, *args, **kwargs
|
|
28
|
+
):
|
|
27
29
|
super(self).__init__(*args, **kwargs)
|
|
28
30
|
self.module = module
|
|
29
31
|
self.local_path = local_path
|
|
@@ -34,8 +36,8 @@ class Import(Expression):
|
|
|
34
36
|
# Check if module is a local path or a GitHub repo reference
|
|
35
37
|
module_path = Path(module)
|
|
36
38
|
if module_path.exists() and module_path.is_dir():
|
|
37
|
-
return (module_path /
|
|
38
|
-
return (BASE_PACKAGE_PATH / module /
|
|
39
|
+
return (module_path / "package.json").exists()
|
|
40
|
+
return (BASE_PACKAGE_PATH / module / "package.json").exists()
|
|
39
41
|
|
|
40
42
|
@staticmethod
|
|
41
43
|
def get_from_local(module, local_path):
|
|
@@ -60,25 +62,29 @@ class Import(Expression):
|
|
|
60
62
|
logger.info(f"Copied local package from {local_path} to {module_path}")
|
|
61
63
|
|
|
62
64
|
# Install dependencies
|
|
63
|
-
package_json = module_path /
|
|
65
|
+
package_json = module_path / "package.json"
|
|
64
66
|
if package_json.exists():
|
|
65
67
|
with package_json.open() as f:
|
|
66
68
|
pkg = json.load(f)
|
|
67
|
-
for dependency in pkg.get(
|
|
69
|
+
for dependency in pkg.get("dependencies", []):
|
|
68
70
|
# Update git_url for the dependency
|
|
69
|
-
git_url_dependency = f
|
|
71
|
+
git_url_dependency = f"git@github.com:{dependency}.git"
|
|
70
72
|
dependency_path = BASE_PACKAGE_PATH / dependency
|
|
71
73
|
if not dependency_path.exists():
|
|
72
|
-
subprocess.check_call(
|
|
74
|
+
subprocess.check_call(
|
|
75
|
+
["git", "clone", git_url_dependency, str(dependency_path)]
|
|
76
|
+
)
|
|
73
77
|
|
|
74
78
|
# Install requirements
|
|
75
|
-
requirements_file = module_path /
|
|
79
|
+
requirements_file = module_path / "requirements.txt"
|
|
76
80
|
if requirements_file.exists():
|
|
77
81
|
with requirements_file.open() as f:
|
|
78
82
|
for dependency in f.readlines():
|
|
79
83
|
dependency_name = dependency.strip()
|
|
80
84
|
if dependency_name:
|
|
81
|
-
subprocess.check_call(
|
|
85
|
+
subprocess.check_call(
|
|
86
|
+
[sys.executable, "-m", "pip", "install", dependency_name]
|
|
87
|
+
)
|
|
82
88
|
except Exception as e:
|
|
83
89
|
logger.error(f"Error installing from local path: {e}")
|
|
84
90
|
raise
|
|
@@ -89,30 +95,32 @@ class Import(Expression):
|
|
|
89
95
|
BASE_PACKAGE_PATH.mkdir(parents=True, exist_ok=True)
|
|
90
96
|
|
|
91
97
|
# Clone repository
|
|
92
|
-
git_url = f
|
|
93
|
-
clone_cmd = [
|
|
98
|
+
git_url = f"git@github.com:{module}.git"
|
|
99
|
+
clone_cmd = ["git", "clone"]
|
|
94
100
|
if submodules:
|
|
95
|
-
clone_cmd.extend([
|
|
101
|
+
clone_cmd.extend(["--recurse-submodules"])
|
|
96
102
|
clone_cmd.extend([git_url, str(BASE_PACKAGE_PATH / module)])
|
|
97
103
|
subprocess.check_call(clone_cmd)
|
|
98
104
|
|
|
99
105
|
# Install dependencies
|
|
100
|
-
package_json = BASE_PACKAGE_PATH / module /
|
|
106
|
+
package_json = BASE_PACKAGE_PATH / module / "package.json"
|
|
101
107
|
with package_json.open() as f:
|
|
102
108
|
pkg = json.load(f)
|
|
103
|
-
for dependency in pkg[
|
|
109
|
+
for dependency in pkg["dependencies"]:
|
|
104
110
|
# Update git_url for the dependency
|
|
105
|
-
git_url_dependency = f
|
|
111
|
+
git_url_dependency = f"git@github.com:{dependency}.git"
|
|
106
112
|
dependency_path = BASE_PACKAGE_PATH / dependency
|
|
107
113
|
if not dependency_path.exists():
|
|
108
|
-
subprocess.check_call(
|
|
114
|
+
subprocess.check_call(
|
|
115
|
+
["git", "clone", git_url_dependency, str(dependency_path)]
|
|
116
|
+
)
|
|
109
117
|
|
|
110
118
|
# Install requirements
|
|
111
|
-
requirements_file = BASE_PACKAGE_PATH / module /
|
|
119
|
+
requirements_file = BASE_PACKAGE_PATH / module / "requirements.txt"
|
|
112
120
|
if requirements_file.exists():
|
|
113
121
|
with requirements_file.open() as f:
|
|
114
122
|
for dependency in f.readlines():
|
|
115
|
-
subprocess.check_call([
|
|
123
|
+
subprocess.check_call(["pip", "install", dependency])
|
|
116
124
|
|
|
117
125
|
@staticmethod
|
|
118
126
|
def load_module_class(module):
|
|
@@ -123,9 +131,9 @@ class Import(Expression):
|
|
|
123
131
|
|
|
124
132
|
package_path = module_path_obj if is_local_path else BASE_PACKAGE_PATH / module
|
|
125
133
|
|
|
126
|
-
with (package_path /
|
|
134
|
+
with (package_path / "package.json").open() as f:
|
|
127
135
|
pkg = json.load(f)
|
|
128
|
-
for expr in pkg[
|
|
136
|
+
for expr in pkg["expressions"]:
|
|
129
137
|
if is_local_path:
|
|
130
138
|
# For local modules, we need to add the path to sys.path
|
|
131
139
|
parent_dir = package_path.parent
|
|
@@ -135,11 +143,15 @@ class Import(Expression):
|
|
|
135
143
|
module_name = package_path.name
|
|
136
144
|
relative_module_path = f"{module_name}.{expr['module'].replace('/', '.')}"
|
|
137
145
|
else:
|
|
138
|
-
module_parts = module.split(
|
|
139
|
-
relative_module_path =
|
|
146
|
+
module_parts = module.split("/")
|
|
147
|
+
relative_module_path = ".".join(
|
|
148
|
+
[*module_parts, expr["module"].replace("/", ".")]
|
|
149
|
+
)
|
|
140
150
|
|
|
141
151
|
try:
|
|
142
|
-
module_class = getattr(
|
|
152
|
+
module_class = getattr(
|
|
153
|
+
importlib.import_module(relative_module_path), expr["type"]
|
|
154
|
+
)
|
|
143
155
|
module_classes.append(module_class)
|
|
144
156
|
except (ImportError, ModuleNotFoundError) as e:
|
|
145
157
|
logger.error(f"Error importing module {relative_module_path}: {e}")
|
|
@@ -158,7 +170,9 @@ class Import(Expression):
|
|
|
158
170
|
raise Exception(msg)
|
|
159
171
|
|
|
160
172
|
@staticmethod
|
|
161
|
-
def load_expression(
|
|
173
|
+
def load_expression(
|
|
174
|
+
module, expressions: list[str] | tuple[str] | str
|
|
175
|
+
) -> list[Expression] | Expression:
|
|
162
176
|
expression_list, return_single = Import._normalize_expressions(expressions)
|
|
163
177
|
expected_count = len(expression_list)
|
|
164
178
|
expression_targets = set(expression_list)
|
|
@@ -175,23 +189,23 @@ class Import(Expression):
|
|
|
175
189
|
sys.path.append(str(parent_dir))
|
|
176
190
|
module_name = package_path.name
|
|
177
191
|
else:
|
|
178
|
-
module_parts = module.split(
|
|
192
|
+
module_parts = module.split("/")
|
|
179
193
|
|
|
180
|
-
with (package_path /
|
|
194
|
+
with (package_path / "package.json").open() as f:
|
|
181
195
|
pkg = json.load(f)
|
|
182
|
-
for expr in pkg[
|
|
196
|
+
for expr in pkg["expressions"]:
|
|
183
197
|
relative_module_path = (
|
|
184
198
|
f"{module_name}.{expr['module'].replace('/', '.')}"
|
|
185
199
|
if is_local_path
|
|
186
|
-
else
|
|
200
|
+
else ".".join([*module_parts, expr["module"].replace("/", ".")])
|
|
187
201
|
)
|
|
188
202
|
|
|
189
|
-
if expr[
|
|
203
|
+
if expr["type"] not in expression_targets:
|
|
190
204
|
continue
|
|
191
205
|
|
|
192
206
|
try:
|
|
193
207
|
module_obj = importlib.import_module(relative_module_path)
|
|
194
|
-
module_class = getattr(module_obj, expr[
|
|
208
|
+
module_class = getattr(module_obj, expr["type"])
|
|
195
209
|
except (ImportError, ModuleNotFoundError) as e:
|
|
196
210
|
logger.error(f"Error importing module {relative_module_path}: {e}")
|
|
197
211
|
raise
|
|
@@ -203,11 +217,21 @@ class Import(Expression):
|
|
|
203
217
|
assert len(module_classes) > 0, f"Expression '{expressions}' not found in module '{module}'"
|
|
204
218
|
module_classes_names = [str(class_.__name__) for class_ in module_classes]
|
|
205
219
|
missing_expressions = [expr for expr in expression_list if expr not in module_classes_names]
|
|
206
|
-
assert len(module_classes) == expected_count,
|
|
220
|
+
assert len(module_classes) == expected_count, (
|
|
221
|
+
f"Not all expressions found in module '{module}'. Could not load {missing_expressions}"
|
|
222
|
+
)
|
|
207
223
|
return module_classes
|
|
208
224
|
|
|
209
|
-
def __new__(
|
|
210
|
-
|
|
225
|
+
def __new__(
|
|
226
|
+
cls,
|
|
227
|
+
module,
|
|
228
|
+
auto_clone: bool = True,
|
|
229
|
+
verbose: bool = False,
|
|
230
|
+
local_path: str | None = None,
|
|
231
|
+
submodules: bool = False,
|
|
232
|
+
*args,
|
|
233
|
+
**kwargs,
|
|
234
|
+
):
|
|
211
235
|
"""
|
|
212
236
|
Import a module from GitHub or local path.
|
|
213
237
|
|
|
@@ -226,12 +250,12 @@ class Import(Expression):
|
|
|
226
250
|
if is_local_path:
|
|
227
251
|
# If module is a local path
|
|
228
252
|
package_path = module_path_obj
|
|
229
|
-
if not (package_path /
|
|
253
|
+
if not (package_path / "package.json").exists():
|
|
230
254
|
msg = f"No package.json found in {module}"
|
|
231
255
|
UserMessage(msg)
|
|
232
256
|
raise ValueError(msg)
|
|
233
257
|
|
|
234
|
-
with (package_path /
|
|
258
|
+
with (package_path / "package.json").open() as f:
|
|
235
259
|
pkg = json.load(f)
|
|
236
260
|
else:
|
|
237
261
|
# Module is a GitHub reference
|
|
@@ -241,17 +265,17 @@ class Import(Expression):
|
|
|
241
265
|
else:
|
|
242
266
|
Import.get_from_github(module, submodules)
|
|
243
267
|
|
|
244
|
-
with (BASE_PACKAGE_PATH / module /
|
|
268
|
+
with (BASE_PACKAGE_PATH / module / "package.json").open() as f:
|
|
245
269
|
pkg = json.load(f)
|
|
246
|
-
if
|
|
270
|
+
if "run" not in pkg:
|
|
247
271
|
msg = f"Module '{module}' has no 'run' expression defined."
|
|
248
272
|
UserMessage(msg)
|
|
249
273
|
raise Exception(msg)
|
|
250
|
-
expr = pkg[
|
|
251
|
-
module_rel = expr[
|
|
252
|
-
module_parts = module.split(
|
|
253
|
-
relative_module_path =
|
|
254
|
-
class_ = expr[
|
|
274
|
+
expr = pkg["run"]
|
|
275
|
+
module_rel = expr["module"].replace("/", ".")
|
|
276
|
+
module_parts = module.split("/")
|
|
277
|
+
relative_module_path = ".".join([*module_parts, module_rel])
|
|
278
|
+
class_ = expr["type"]
|
|
255
279
|
if verbose:
|
|
256
280
|
logger.info(f"Loading module '{relative_module_path}.{expr['type']}'")
|
|
257
281
|
module_class = getattr(importlib.import_module(relative_module_path), class_)
|
|
@@ -273,7 +297,9 @@ class Import(Expression):
|
|
|
273
297
|
"""
|
|
274
298
|
# Determine if module is a local path
|
|
275
299
|
local_path_obj = Path(local_path) if local_path is not None else None
|
|
276
|
-
is_local_path =
|
|
300
|
+
is_local_path = (
|
|
301
|
+
local_path_obj is not None and local_path_obj.exists() and local_path_obj.is_dir()
|
|
302
|
+
)
|
|
277
303
|
|
|
278
304
|
if not Import.exists(module):
|
|
279
305
|
if is_local_path:
|
|
@@ -294,10 +320,12 @@ class Import(Expression):
|
|
|
294
320
|
if is_local_path:
|
|
295
321
|
# For local path, remove directly
|
|
296
322
|
if module_path_obj.exists():
|
|
323
|
+
|
|
297
324
|
def del_rw(_action, name, _exc):
|
|
298
325
|
path_obj = Path(name)
|
|
299
326
|
path_obj.chmod(stat.S_IWRITE)
|
|
300
327
|
path_obj.unlink()
|
|
328
|
+
|
|
301
329
|
shutil.rmtree(module_path_obj, onerror=del_rw)
|
|
302
330
|
logger.success(f"Removed local module at '{module}'")
|
|
303
331
|
else:
|
|
@@ -306,15 +334,17 @@ class Import(Expression):
|
|
|
306
334
|
# For GitHub modules, remove from packages directory
|
|
307
335
|
module_path = BASE_PACKAGE_PATH / module
|
|
308
336
|
if module_path.exists():
|
|
337
|
+
|
|
309
338
|
def del_rw(_action, name, _exc):
|
|
310
339
|
path_obj = Path(name)
|
|
311
340
|
path_obj.chmod(stat.S_IWRITE)
|
|
312
341
|
path_obj.unlink()
|
|
342
|
+
|
|
313
343
|
shutil.rmtree(module_path, onerror=del_rw)
|
|
314
344
|
logger.success(f"Removed module '{module}'")
|
|
315
345
|
|
|
316
346
|
# Check if folder is empty and remove it
|
|
317
|
-
parent_path = BASE_PACKAGE_PATH / module.split(
|
|
347
|
+
parent_path = BASE_PACKAGE_PATH / module.split("/")[0]
|
|
318
348
|
if parent_path.exists() and not any(parent_path.iterdir()):
|
|
319
349
|
parent_path.rmdir()
|
|
320
350
|
logger.info(f"Removed empty parent folder '{parent_path}'")
|
|
@@ -329,7 +359,9 @@ class Import(Expression):
|
|
|
329
359
|
|
|
330
360
|
sub_dirs = []
|
|
331
361
|
for base_dir in base_dirs:
|
|
332
|
-
sub_dirs.extend(
|
|
362
|
+
sub_dirs.extend(
|
|
363
|
+
[f"{base_dir.name}/{entry.name}" for entry in base_dir.iterdir() if entry.is_dir()]
|
|
364
|
+
)
|
|
333
365
|
|
|
334
366
|
return sub_dirs
|
|
335
367
|
|
|
@@ -347,16 +379,18 @@ class Import(Expression):
|
|
|
347
379
|
is_local_path = module_path_obj.exists() and module_path_obj.is_dir()
|
|
348
380
|
|
|
349
381
|
# Use the appropriate path based on whether it's local or not
|
|
350
|
-
module_path =
|
|
382
|
+
module_path = (
|
|
383
|
+
module_path_obj if is_local_path else BASE_PACKAGE_PATH / module.replace(".", "/")
|
|
384
|
+
)
|
|
351
385
|
|
|
352
386
|
# Construct the git pull command based on whether submodules should be included
|
|
353
|
-
pull_cmd = [
|
|
387
|
+
pull_cmd = ["git", "-C", str(module_path)]
|
|
354
388
|
if submodules:
|
|
355
|
-
pull_cmd.extend([
|
|
389
|
+
pull_cmd.extend(["pull", "--recurse-submodules"])
|
|
356
390
|
subprocess.check_call(pull_cmd)
|
|
357
391
|
logger.success(f"Module '{module}' and its submodules updated.")
|
|
358
392
|
else:
|
|
359
|
-
pull_cmd.extend([
|
|
393
|
+
pull_cmd.extend(["pull"])
|
|
360
394
|
subprocess.check_call(pull_cmd)
|
|
361
395
|
logger.success(f"Module '{module}' updated.")
|
|
362
396
|
else:
|
symai/interfaces.py
CHANGED
|
@@ -94,7 +94,7 @@ def cfg_to_interface():
|
|
|
94
94
|
_add_tts_interface(mapping)
|
|
95
95
|
|
|
96
96
|
mapping["indexing"] = Interface("naive_vectordb")
|
|
97
|
-
mapping["scraper"] = Interface("
|
|
97
|
+
mapping["scraper"] = Interface("naive_scrape")
|
|
98
98
|
mapping["stt"] = Interface("whisper")
|
|
99
99
|
mapping["file"] = Interface("file")
|
|
100
100
|
|
symai/memory.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from . import core_ext
|
|
3
2
|
from .components import Function
|
|
4
3
|
from .symbol import Expression, Symbol
|
|
@@ -25,52 +24,56 @@ class SlidingWindowListMemory(Memory):
|
|
|
25
24
|
def __init__(self, window_size: int = 10, max_size: int = 1000, **kwargs):
|
|
26
25
|
super().__init__(**kwargs)
|
|
27
26
|
self._memory: list[str] = []
|
|
28
|
-
self._window_size: int
|
|
29
|
-
self._max_size: int
|
|
27
|
+
self._window_size: int = window_size
|
|
28
|
+
self._max_size: int = max_size
|
|
30
29
|
|
|
31
30
|
def store(self, query: str, *_args, **_kwargs):
|
|
32
31
|
self._memory.append(query)
|
|
33
32
|
if len(self._memory) > self._max_size:
|
|
34
|
-
self._memory = self._memory[-self._max_size:]
|
|
33
|
+
self._memory = self._memory[-self._max_size :]
|
|
35
34
|
|
|
36
35
|
def forget(self, query: Symbol, *_args, **_kwargs):
|
|
37
36
|
self._memory.remove(query)
|
|
38
37
|
|
|
39
38
|
def recall(self, *_args, **_kwargs):
|
|
40
|
-
return self._memory[-self._window_size:]
|
|
39
|
+
return self._memory[-self._window_size :]
|
|
41
40
|
|
|
42
41
|
|
|
43
42
|
class SlidingWindowStringConcatMemory(Memory):
|
|
44
43
|
def __init__(self, *_args, **kwargs):
|
|
45
44
|
super().__init__(**kwargs)
|
|
46
|
-
self._memory: str
|
|
47
|
-
self.marker: str
|
|
45
|
+
self._memory: str = ""
|
|
46
|
+
self.marker: str = "[--++=|=++--]"
|
|
48
47
|
|
|
49
|
-
@core_ext.bind(engine=
|
|
50
|
-
def max_tokens(self):
|
|
48
|
+
@core_ext.bind(engine="neurosymbolic", property="max_context_tokens")
|
|
49
|
+
def max_tokens(self):
|
|
50
|
+
pass
|
|
51
51
|
|
|
52
52
|
def __getstate__(self):
|
|
53
53
|
state = super().__getstate__().copy()
|
|
54
54
|
# Exclude the max_tokens property from being serialized
|
|
55
|
-
state.pop(
|
|
55
|
+
state.pop("_max_tokens", None)
|
|
56
56
|
return state
|
|
57
57
|
|
|
58
58
|
def __setstate__(self, state):
|
|
59
59
|
self.__dict__.update(state)
|
|
60
|
+
|
|
60
61
|
# Initialize _max_tokens as None, it should be set again after deserialization
|
|
61
|
-
@core_ext.bind(engine=
|
|
62
|
-
def _max_tokens(self):
|
|
62
|
+
@core_ext.bind(engine="neurosymbolic", property="max_context_tokens")
|
|
63
|
+
def _max_tokens(self):
|
|
64
|
+
pass
|
|
65
|
+
|
|
63
66
|
self.max_tokens = _max_tokens
|
|
64
67
|
|
|
65
68
|
def history(self):
|
|
66
69
|
return [hist for hist in self._memory.split(self.marker) if hist]
|
|
67
70
|
|
|
68
71
|
def drop(self):
|
|
69
|
-
self._memory =
|
|
72
|
+
self._memory = ""
|
|
70
73
|
|
|
71
74
|
def store(self, query: str):
|
|
72
75
|
# append to string to memory
|
|
73
|
-
self._memory += f
|
|
76
|
+
self._memory += f"{query!s}{self.marker}"
|
|
74
77
|
|
|
75
78
|
def forget(self, query: Symbol, *_args, **_kwargs):
|
|
76
79
|
# remove substring from memory
|
|
@@ -78,29 +81,33 @@ class SlidingWindowStringConcatMemory(Memory):
|
|
|
78
81
|
self._memory = str(sym - query)
|
|
79
82
|
|
|
80
83
|
def recall(self, query: str, *args, **kwargs) -> Symbol:
|
|
81
|
-
hist
|
|
82
|
-
memory
|
|
84
|
+
hist = self.history()
|
|
85
|
+
memory = ""
|
|
83
86
|
if len(hist) > 0:
|
|
84
|
-
memory
|
|
85
|
-
val
|
|
87
|
+
memory = "[MEMORY]\n"
|
|
88
|
+
val = "\n".join(hist)
|
|
86
89
|
memory += val
|
|
87
90
|
that = self
|
|
91
|
+
|
|
88
92
|
class Recall(Function):
|
|
89
93
|
@property
|
|
90
94
|
def static_context(self):
|
|
91
95
|
return that.static_context
|
|
96
|
+
|
|
92
97
|
func = Recall(memory)
|
|
93
98
|
return func(query, *args, **kwargs)
|
|
94
99
|
|
|
95
100
|
|
|
96
101
|
class VectorDatabaseMemory(Memory):
|
|
97
|
-
def __init__(
|
|
102
|
+
def __init__(
|
|
103
|
+
self, enabled: bool = True, top_k: int = 3, index_name: str = "defaultindex", **kwargs
|
|
104
|
+
):
|
|
98
105
|
super().__init__(**kwargs)
|
|
99
106
|
self.enabled: bool = enabled
|
|
100
|
-
self.top_k: int
|
|
101
|
-
self.index_name
|
|
107
|
+
self.top_k: int = top_k
|
|
108
|
+
self.index_name = index_name
|
|
102
109
|
|
|
103
|
-
def store(self, query: str
|
|
110
|
+
def store(self, query: str, *_args, **_kwargs):
|
|
104
111
|
if not self.enabled:
|
|
105
112
|
return
|
|
106
113
|
|
|
@@ -110,6 +117,8 @@ class VectorDatabaseMemory(Memory):
|
|
|
110
117
|
if not self.enabled:
|
|
111
118
|
return None
|
|
112
119
|
|
|
113
|
-
res = self.get(
|
|
120
|
+
res = self.get(
|
|
121
|
+
Symbol(query).embed().value, index_top_k=self.top_k, index_name=self.index_name
|
|
122
|
+
).ast()
|
|
114
123
|
|
|
115
|
-
return [v[
|
|
124
|
+
return [v["metadata"]["text"] for v in res["matches"]]
|
symai/menu/screen.py
CHANGED
|
@@ -6,42 +6,51 @@ from ..misc.console import ConsoleStyle
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def show_splash_screen(print: callable = print_formatted_text):
|
|
9
|
-
print(
|
|
10
|
-
print(
|
|
11
|
-
print(
|
|
12
|
-
print(
|
|
9
|
+
print("\n\n")
|
|
10
|
+
print("- " * 42)
|
|
11
|
+
print("==" * 41 + "=")
|
|
12
|
+
print(
|
|
13
|
+
r"""
|
|
13
14
|
____| | _) | \ _ _|
|
|
14
15
|
__| \ \ / __| _ \ __ \ __| | __| | | _ \ |
|
|
15
16
|
| ` < | __/ | | \__ \ | | | | ___ \ |
|
|
16
17
|
_____| _/\_\ \__| \___| _| _| ____/ _| \__| \__, | _/ _\ ___|
|
|
17
18
|
____/
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
""",
|
|
20
|
+
escape=True,
|
|
21
|
+
)
|
|
22
|
+
print("- " * 42)
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
def show_info_message(print: callable = print_formatted_text):
|
|
23
|
-
print(
|
|
24
|
-
print(
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
print("Welcome to SymbolicAI!" + "\n")
|
|
27
|
+
print(
|
|
28
|
+
"SymbolicAI is an open-source Python project for building AI-powered applications\nand assistants."
|
|
29
|
+
)
|
|
30
|
+
print("We utilize the power of large language models and the latest research in AI." + "\n")
|
|
31
|
+
print(
|
|
32
|
+
"SymbolicAI is backed by ExtensityAI. We are committed to open research,\nthe democratization of AI tools and much more ..."
|
|
33
|
+
"\n"
|
|
34
|
+
)
|
|
27
35
|
|
|
28
|
-
print(
|
|
29
|
-
print(
|
|
30
|
-
print(
|
|
36
|
+
print("... and we also like peanut butter and jelly sandwiches, and cookies." + "\n\n")
|
|
37
|
+
print("If you like what we are doing please help us achieve our mission!")
|
|
38
|
+
print("More information is available at https://www.extensity.ai" + "\n")
|
|
31
39
|
|
|
32
40
|
|
|
33
41
|
def show_separator(print: callable = print_formatted_text):
|
|
34
|
-
print(
|
|
42
|
+
print("- " * 42 + "\n")
|
|
35
43
|
|
|
36
44
|
|
|
37
45
|
def show_intro_menu():
|
|
38
|
-
if os.environ.get(
|
|
39
|
-
with ConsoleStyle(
|
|
46
|
+
if os.environ.get("SYMAI_WARNINGS", "1") == "1":
|
|
47
|
+
with ConsoleStyle("extensity") as console:
|
|
40
48
|
show_splash_screen(print=console.print)
|
|
41
|
-
with ConsoleStyle(
|
|
49
|
+
with ConsoleStyle("text") as console:
|
|
42
50
|
show_info_message(print=console.print)
|
|
43
|
-
with ConsoleStyle(
|
|
51
|
+
with ConsoleStyle("extensity") as console:
|
|
44
52
|
show_separator(print=console.print)
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
47
56
|
show_intro_menu()
|
symai/misc/console.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# @TODO: refactor to use rich instead of prompt_toolkit
|
|
5
5
|
from html import escape as escape_html
|
|
6
6
|
from typing import ClassVar
|
|
7
7
|
|
|
@@ -14,28 +14,28 @@ from pygments.lexers.python import PythonLexer
|
|
|
14
14
|
from pygments.lexers.shell import BashLexer
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
|
-
print = print_formatted_text
|
|
17
|
+
print = print_formatted_text # noqa
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class ConsoleStyle:
|
|
21
21
|
style_types: ClassVar[dict[str, str]] = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
"alert": "orange",
|
|
23
|
+
"error": "ansired",
|
|
24
|
+
"warn": "ansiyellow",
|
|
25
|
+
"info": "ansiblue",
|
|
26
|
+
"success": "ansigreen",
|
|
27
|
+
"extensity": "#009499",
|
|
28
|
+
"text": "ansigray",
|
|
29
|
+
"debug": "gray",
|
|
30
|
+
"custom": "custom",
|
|
31
|
+
"code": "code",
|
|
32
|
+
"default": "",
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
def __init__(self, style_type
|
|
35
|
+
def __init__(self, style_type="", color="", logging: bool = False):
|
|
36
36
|
self.style_type = style_type
|
|
37
|
-
self.color
|
|
38
|
-
self.logging
|
|
37
|
+
self.color = color
|
|
38
|
+
self.logging = logging
|
|
39
39
|
|
|
40
40
|
def __call__(self, message):
|
|
41
41
|
self.print(message)
|
|
@@ -52,43 +52,43 @@ class ConsoleStyle:
|
|
|
52
52
|
logger.debug(message)
|
|
53
53
|
# Prepare safe content for HTML printing without mutating the original
|
|
54
54
|
content_for_html = escape_html(message) if escape else message
|
|
55
|
-
style = self.style_types.get(self.style_type, self.style_types[
|
|
55
|
+
style = self.style_types.get(self.style_type, self.style_types["default"])
|
|
56
56
|
|
|
57
|
-
if style == self.style_types[
|
|
57
|
+
if style == self.style_types["code"]:
|
|
58
58
|
self._print_code_message(message)
|
|
59
59
|
return
|
|
60
|
-
if style == self.style_types[
|
|
60
|
+
if style == self.style_types["default"]:
|
|
61
61
|
print(message)
|
|
62
62
|
return
|
|
63
|
-
if style == self.style_types[
|
|
63
|
+
if style == self.style_types["custom"]:
|
|
64
64
|
self._print_html(self.color, content_for_html)
|
|
65
65
|
return
|
|
66
66
|
self._print_html(style, content_for_html)
|
|
67
67
|
|
|
68
68
|
def _print_code_message(self, message: str) -> None:
|
|
69
|
-
segments = re.split(r
|
|
69
|
+
segments = re.split(r"(```)", message)
|
|
70
70
|
is_code_segment = False
|
|
71
71
|
for segment in segments:
|
|
72
|
-
if segment ==
|
|
72
|
+
if segment == "```":
|
|
73
73
|
is_code_segment = not is_code_segment
|
|
74
74
|
continue
|
|
75
75
|
if is_code_segment:
|
|
76
76
|
self._print_code_segment(segment)
|
|
77
77
|
continue
|
|
78
|
-
print(segment, end=
|
|
78
|
+
print(segment, end="\n")
|
|
79
79
|
|
|
80
80
|
def _print_code_segment(self, segment: str) -> None:
|
|
81
81
|
lexer = self._select_lexer(segment)
|
|
82
82
|
tokens = list(pygments.lex("```" + segment + "```", lexer))
|
|
83
|
-
print(PygmentsTokens(tokens), end=
|
|
83
|
+
print(PygmentsTokens(tokens), end="")
|
|
84
84
|
|
|
85
85
|
def _select_lexer(self, segment: str):
|
|
86
86
|
lowered_segment = segment.lower()
|
|
87
|
-
if
|
|
87
|
+
if "python" in lowered_segment:
|
|
88
88
|
return PythonLexer()
|
|
89
|
-
if
|
|
89
|
+
if "javascript" in lowered_segment or "typescript" in lowered_segment:
|
|
90
90
|
return JavascriptLexer()
|
|
91
|
-
if
|
|
91
|
+
if "c++" in lowered_segment:
|
|
92
92
|
return CppLexer()
|
|
93
93
|
return BashLexer()
|
|
94
94
|
|