symbolicai 0.21.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.
- symai/__init__.py +269 -173
- symai/backend/base.py +123 -110
- symai/backend/engines/drawing/engine_bfl.py +45 -44
- symai/backend/engines/drawing/engine_gpt_image.py +112 -97
- symai/backend/engines/embedding/engine_llama_cpp.py +63 -52
- symai/backend/engines/embedding/engine_openai.py +25 -21
- symai/backend/engines/execute/engine_python.py +19 -18
- symai/backend/engines/files/engine_io.py +104 -95
- symai/backend/engines/imagecaptioning/engine_blip2.py +28 -24
- symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +102 -79
- symai/backend/engines/index/engine_pinecone.py +124 -97
- symai/backend/engines/index/engine_qdrant.py +1011 -0
- symai/backend/engines/index/engine_vectordb.py +84 -56
- symai/backend/engines/lean/engine_lean4.py +96 -52
- symai/backend/engines/neurosymbolic/__init__.py +41 -13
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +330 -248
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +329 -264
- symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
- symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +118 -88
- symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +344 -299
- symai/backend/engines/neurosymbolic/engine_groq.py +173 -115
- symai/backend/engines/neurosymbolic/engine_huggingface.py +114 -84
- symai/backend/engines/neurosymbolic/engine_llama_cpp.py +144 -118
- symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +415 -307
- symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +394 -231
- symai/backend/engines/ocr/engine_apilayer.py +23 -27
- symai/backend/engines/output/engine_stdout.py +10 -13
- symai/backend/engines/{webscraping → scrape}/engine_requests.py +101 -54
- symai/backend/engines/search/engine_openai.py +100 -88
- symai/backend/engines/search/engine_parallel.py +665 -0
- symai/backend/engines/search/engine_perplexity.py +44 -45
- symai/backend/engines/search/engine_serpapi.py +37 -34
- symai/backend/engines/speech_to_text/engine_local_whisper.py +54 -51
- symai/backend/engines/symbolic/engine_wolframalpha.py +15 -9
- symai/backend/engines/text_to_speech/engine_openai.py +20 -26
- symai/backend/engines/text_vision/engine_clip.py +39 -37
- symai/backend/engines/userinput/engine_console.py +5 -6
- symai/backend/mixin/__init__.py +13 -0
- symai/backend/mixin/anthropic.py +48 -38
- symai/backend/mixin/deepseek.py +6 -5
- symai/backend/mixin/google.py +7 -4
- symai/backend/mixin/groq.py +2 -4
- symai/backend/mixin/openai.py +140 -110
- symai/backend/settings.py +87 -20
- symai/chat.py +216 -123
- symai/collect/__init__.py +7 -1
- symai/collect/dynamic.py +80 -70
- symai/collect/pipeline.py +67 -51
- symai/collect/stats.py +161 -109
- symai/components.py +707 -360
- symai/constraints.py +24 -12
- symai/core.py +1857 -1233
- symai/core_ext.py +83 -80
- symai/endpoints/api.py +166 -104
- symai/extended/.DS_Store +0 -0
- symai/extended/__init__.py +46 -12
- symai/extended/api_builder.py +29 -21
- symai/extended/arxiv_pdf_parser.py +23 -14
- symai/extended/bibtex_parser.py +9 -6
- symai/extended/conversation.py +156 -126
- symai/extended/document.py +50 -30
- symai/extended/file_merger.py +57 -14
- symai/extended/graph.py +51 -32
- symai/extended/html_style_template.py +18 -14
- symai/extended/interfaces/blip_2.py +2 -3
- symai/extended/interfaces/clip.py +4 -3
- symai/extended/interfaces/console.py +9 -1
- symai/extended/interfaces/dall_e.py +4 -2
- symai/extended/interfaces/file.py +2 -0
- symai/extended/interfaces/flux.py +4 -2
- symai/extended/interfaces/gpt_image.py +16 -7
- symai/extended/interfaces/input.py +2 -1
- symai/extended/interfaces/llava.py +1 -2
- symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +4 -3
- symai/extended/interfaces/naive_vectordb.py +9 -10
- symai/extended/interfaces/ocr.py +5 -3
- 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 +12 -9
- symai/extended/interfaces/python.py +2 -0
- symai/extended/interfaces/serpapi.py +3 -1
- symai/extended/interfaces/terminal.py +2 -4
- symai/extended/interfaces/tts.py +3 -2
- symai/extended/interfaces/whisper.py +3 -2
- symai/extended/interfaces/wolframalpha.py +2 -1
- symai/extended/metrics/__init__.py +11 -1
- symai/extended/metrics/similarity.py +14 -13
- symai/extended/os_command.py +39 -29
- symai/extended/packages/__init__.py +29 -3
- symai/extended/packages/symdev.py +51 -43
- symai/extended/packages/sympkg.py +41 -35
- symai/extended/packages/symrun.py +63 -50
- symai/extended/repo_cloner.py +14 -12
- symai/extended/seo_query_optimizer.py +15 -13
- symai/extended/solver.py +116 -91
- symai/extended/summarizer.py +12 -10
- symai/extended/taypan_interpreter.py +17 -18
- symai/extended/vectordb.py +122 -92
- symai/formatter/__init__.py +9 -1
- symai/formatter/formatter.py +51 -47
- symai/formatter/regex.py +70 -69
- symai/functional.py +325 -176
- symai/imports.py +190 -147
- symai/interfaces.py +57 -28
- symai/memory.py +45 -35
- symai/menu/screen.py +28 -19
- symai/misc/console.py +66 -56
- symai/misc/loader.py +8 -5
- symai/models/__init__.py +17 -1
- symai/models/base.py +395 -236
- symai/models/errors.py +1 -2
- symai/ops/__init__.py +32 -22
- symai/ops/measures.py +24 -25
- symai/ops/primitives.py +1149 -731
- symai/post_processors.py +58 -50
- symai/pre_processors.py +86 -82
- symai/processor.py +21 -13
- symai/prompts.py +764 -685
- symai/server/huggingface_server.py +135 -49
- symai/server/llama_cpp_server.py +21 -11
- symai/server/qdrant_server.py +206 -0
- symai/shell.py +100 -42
- symai/shellsv.py +700 -492
- symai/strategy.py +630 -346
- symai/symbol.py +368 -322
- symai/utils.py +100 -78
- {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/METADATA +22 -10
- symbolicai-1.1.0.dist-info/RECORD +168 -0
- symbolicai-0.21.0.dist-info/RECORD +0 -162
- {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/WHEEL +0 -0
- {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/entry_points.txt +0 -0
- {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/top_level.txt +0 -0
symai/endpoints/api.py
CHANGED
|
@@ -1,65 +1,67 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
import inspect
|
|
3
3
|
import pickle
|
|
4
|
-
import
|
|
4
|
+
from typing import Any, Generic, TypeVar
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
from fastapi import
|
|
8
|
-
from fastapi.security import APIKeyHeader
|
|
6
|
+
import redis
|
|
7
|
+
from fastapi import APIRouter, FastAPI, HTTPException, Security, status
|
|
9
8
|
from fastapi.middleware.cors import CORSMiddleware
|
|
9
|
+
from fastapi.security import APIKeyHeader
|
|
10
10
|
from pydantic import BaseModel
|
|
11
|
-
from
|
|
11
|
+
from redis.exceptions import ConnectionError as RedisConnectionError
|
|
12
12
|
|
|
13
13
|
from symai.backend import settings
|
|
14
14
|
|
|
15
15
|
from .. import core_ext
|
|
16
|
-
from ..symbol import
|
|
17
|
-
|
|
16
|
+
from ..symbol import Expression, Symbol
|
|
17
|
+
from ..utils import UserMessage
|
|
18
18
|
|
|
19
19
|
# Configure Redis server connection parameters and executable path
|
|
20
|
-
HOST
|
|
21
|
-
PORT
|
|
20
|
+
HOST = "localhost"
|
|
21
|
+
PORT = 6379
|
|
22
22
|
DEBUG = True
|
|
23
|
-
API_KEY = settings.SYMAI_CONFIG.get(
|
|
23
|
+
API_KEY = settings.SYMAI_CONFIG.get("FASTAPI_API_KEY", None)
|
|
24
|
+
|
|
24
25
|
|
|
25
26
|
def is_redis_running(host: str, port: int) -> bool:
|
|
26
27
|
"""Check if a Redis server is running at the given host and port."""
|
|
27
28
|
try:
|
|
28
29
|
r = redis.Redis(host=host, port=port)
|
|
29
30
|
r.ping()
|
|
30
|
-
|
|
31
|
+
UserMessage(f"Redis server is running at {host}:{port}")
|
|
31
32
|
return True
|
|
32
|
-
except
|
|
33
|
-
|
|
33
|
+
except RedisConnectionError:
|
|
34
|
+
UserMessage(
|
|
35
|
+
f"Redis server is not running at {host}:{port} or is not reachable - falling back to in-memory storage"
|
|
36
|
+
)
|
|
34
37
|
return False
|
|
35
38
|
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
T = TypeVar('T')
|
|
40
|
+
T = TypeVar("T")
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
class GenericRepository(Generic[T]):
|
|
42
44
|
def __init__(self, redis_client: redis.Redis, id_key: str, use_redis: bool = True):
|
|
43
|
-
self.storage:
|
|
44
|
-
self.use_redis
|
|
45
|
-
self.id_key
|
|
46
|
-
self.redis_client
|
|
45
|
+
self.storage: dict[str, T] = {} # In-memory dictionary to mock Redis
|
|
46
|
+
self.use_redis = use_redis
|
|
47
|
+
self.id_key = id_key # Key used for storing the incremental ID counter
|
|
48
|
+
self.redis_client = redis_client
|
|
47
49
|
if self.use_redis:
|
|
48
|
-
self.set
|
|
49
|
-
self.get
|
|
50
|
-
self.delete
|
|
51
|
-
self.uid
|
|
50
|
+
self.set = self._store_redis
|
|
51
|
+
self.get = self._retrieve_redis
|
|
52
|
+
self.delete = self._delete_redis
|
|
53
|
+
self.uid = self._generate_id_redis
|
|
52
54
|
else:
|
|
53
|
-
self.set
|
|
54
|
-
self.get
|
|
55
|
-
self.delete
|
|
56
|
-
self.uid
|
|
55
|
+
self.set = self._store_memory
|
|
56
|
+
self.get = self._retrieve_memory
|
|
57
|
+
self.delete = self._delete_memory
|
|
58
|
+
self.uid = self._generate_id_memory
|
|
57
59
|
|
|
58
60
|
def _deserialize_object(self, serialized_item: bytes) -> T:
|
|
59
61
|
"""Deserialize the byte object back into a Python object of type T."""
|
|
60
62
|
return pickle.loads(serialized_item)
|
|
61
63
|
|
|
62
|
-
def _serialize_object(self,
|
|
64
|
+
def _serialize_object(self, _item_id: str, item: T) -> None:
|
|
63
65
|
return pickle.dumps(item)
|
|
64
66
|
|
|
65
67
|
def _store_memory(self, item_id: str, item: T) -> None:
|
|
@@ -76,7 +78,7 @@ class GenericRepository(Generic[T]):
|
|
|
76
78
|
|
|
77
79
|
def _generate_id_memory(self) -> str:
|
|
78
80
|
id_ = len(self.storage) + 1
|
|
79
|
-
return f
|
|
81
|
+
return f"{self.id_key}:{id_}"
|
|
80
82
|
|
|
81
83
|
def _store_redis(self, item_id: str, item: T) -> None:
|
|
82
84
|
item = self._serialize_object(item_id, item)
|
|
@@ -85,8 +87,7 @@ class GenericRepository(Generic[T]):
|
|
|
85
87
|
def _retrieve_redis(self, item_id: str) -> T:
|
|
86
88
|
item = self.redis_client.get(item_id)
|
|
87
89
|
if item:
|
|
88
|
-
|
|
89
|
-
return item
|
|
90
|
+
return self._deserialize_object(item)
|
|
90
91
|
return None
|
|
91
92
|
|
|
92
93
|
def _delete_redis(self, item_id: str) -> bool:
|
|
@@ -94,39 +95,67 @@ class GenericRepository(Generic[T]):
|
|
|
94
95
|
|
|
95
96
|
def _generate_id_redis(self) -> str:
|
|
96
97
|
id_ = self.redis_client.incr(self.id_key)
|
|
97
|
-
return f
|
|
98
|
+
return f"{self.id_key}:{id_}"
|
|
98
99
|
|
|
99
100
|
|
|
100
101
|
# Initialize the Redis client
|
|
101
102
|
redis_client = redis.Redis(
|
|
102
|
-
host=HOST,
|
|
103
|
-
port=PORT,
|
|
104
|
-
db=0
|
|
103
|
+
host=HOST, # Or use the host where your Redis server is running
|
|
104
|
+
port=PORT, # The default Redis port number
|
|
105
|
+
db=0, # The default database index
|
|
105
106
|
)
|
|
106
107
|
|
|
107
108
|
# Initialize the FastAPI app and API router
|
|
108
|
-
app
|
|
109
|
-
api_key_header
|
|
110
|
-
router
|
|
111
|
-
use_redis
|
|
109
|
+
app = FastAPI(title="SymbolicAI API", version="1.0")
|
|
110
|
+
api_key_header = APIKeyHeader(name="X-API-Key")
|
|
111
|
+
router = APIRouter()
|
|
112
|
+
use_redis = is_redis_running(HOST, PORT)
|
|
112
113
|
|
|
113
114
|
# Instantiate the generic repositories with the counter keys
|
|
114
|
-
symbol_repository
|
|
115
|
-
expression_repository
|
|
115
|
+
symbol_repository = GenericRepository[Symbol](redis_client, "sym_id", use_redis=use_redis)
|
|
116
|
+
expression_repository = GenericRepository[Expression](redis_client, "expr_id", use_redis=use_redis)
|
|
116
117
|
# Register all types which subclass Expression and offer a get() method with default=None
|
|
117
118
|
component_class_types = {
|
|
118
|
-
name: cls
|
|
119
|
+
name: cls
|
|
120
|
+
for name, cls in inspect.getmembers(
|
|
121
|
+
importlib.import_module("symai.components"), inspect.isclass
|
|
122
|
+
)
|
|
123
|
+
if issubclass(cls, Expression)
|
|
119
124
|
}
|
|
120
|
-
component_instance_repository = GenericRepository[
|
|
125
|
+
component_instance_repository = GenericRepository[Symbol | Expression](
|
|
126
|
+
redis_client, "comp_id", use_redis=use_redis
|
|
127
|
+
)
|
|
121
128
|
|
|
122
|
-
|
|
129
|
+
|
|
130
|
+
def _load_extended_types():
|
|
131
|
+
"""Load extended classes lazily to avoid premature engine initialization."""
|
|
132
|
+
extended_module = importlib.import_module("symai.extended")
|
|
133
|
+
personas_module = importlib.import_module("symai.extended.personas")
|
|
134
|
+
sales_module = importlib.import_module("symai.extended.personas.sales")
|
|
135
|
+
student_module = importlib.import_module("symai.extended.personas.student")
|
|
136
|
+
return [
|
|
137
|
+
extended_module.Conversation,
|
|
138
|
+
personas_module.Persona,
|
|
139
|
+
personas_module.Dialogue,
|
|
140
|
+
student_module.MaxTenner,
|
|
141
|
+
sales_module.ErikJames,
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
app.add_middleware(
|
|
146
|
+
CORSMiddleware,
|
|
147
|
+
allow_origins=["*"],
|
|
148
|
+
allow_credentials=True,
|
|
149
|
+
allow_methods=["*"],
|
|
150
|
+
allow_headers=["*"],
|
|
151
|
+
)
|
|
123
152
|
|
|
124
153
|
### Symbols Endpoints ###
|
|
125
154
|
|
|
126
155
|
|
|
127
156
|
class CreateSymbolRequest(BaseModel):
|
|
128
|
-
value:
|
|
129
|
-
static_context:
|
|
157
|
+
value: Any | None = None
|
|
158
|
+
static_context: str | None = ""
|
|
130
159
|
|
|
131
160
|
|
|
132
161
|
class UpdateSymbolRequest(BaseModel):
|
|
@@ -135,11 +164,12 @@ class UpdateSymbolRequest(BaseModel):
|
|
|
135
164
|
|
|
136
165
|
|
|
137
166
|
class SymbolMethodRequest(BaseModel):
|
|
138
|
-
args:
|
|
139
|
-
kwargs:
|
|
167
|
+
args: list[Any] = []
|
|
168
|
+
kwargs: dict[str, Any] = {}
|
|
169
|
+
|
|
140
170
|
|
|
141
171
|
def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else None) -> str:
|
|
142
|
-
if API_KEY
|
|
172
|
+
if API_KEY is None:
|
|
143
173
|
return True
|
|
144
174
|
if api_key_header == API_KEY:
|
|
145
175
|
return api_key_header
|
|
@@ -148,8 +178,9 @@ def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else N
|
|
|
148
178
|
detail="Invalid or missing API Key",
|
|
149
179
|
)
|
|
150
180
|
|
|
181
|
+
|
|
151
182
|
@app.post("/symbol/")
|
|
152
|
-
def create_symbol(symbol_request: CreateSymbolRequest,
|
|
183
|
+
def create_symbol(symbol_request: CreateSymbolRequest, _api_key: str = Security(get_api_key)):
|
|
153
184
|
symbol = Symbol(symbol_request.value, static_context=symbol_request.static_context)
|
|
154
185
|
symbol_id = symbol_repository.uid()
|
|
155
186
|
symbol_repository.set(symbol_id, symbol)
|
|
@@ -157,7 +188,7 @@ def create_symbol(symbol_request: CreateSymbolRequest, api_key: str = Security(g
|
|
|
157
188
|
|
|
158
189
|
|
|
159
190
|
@app.get("/symbol/{symbol_id}/")
|
|
160
|
-
def get_symbol(symbol_id: str,
|
|
191
|
+
def get_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
|
|
161
192
|
symbol = symbol_repository.get(symbol_id)
|
|
162
193
|
if symbol is None:
|
|
163
194
|
raise HTTPException(status_code=404, detail="Symbol not found")
|
|
@@ -165,7 +196,9 @@ def get_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
|
|
|
165
196
|
|
|
166
197
|
|
|
167
198
|
@app.patch("/symbol/{symbol_id}/")
|
|
168
|
-
def update_symbol(
|
|
199
|
+
def update_symbol(
|
|
200
|
+
symbol_id: str, update_request: UpdateSymbolRequest, _api_key: str = Security(get_api_key)
|
|
201
|
+
):
|
|
169
202
|
symbol = symbol_repository.get(symbol_id)
|
|
170
203
|
if symbol is None:
|
|
171
204
|
raise HTTPException(status_code=404, detail="Symbol not found")
|
|
@@ -176,7 +209,7 @@ def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, api_key:
|
|
|
176
209
|
|
|
177
210
|
|
|
178
211
|
@app.delete("/symbol/{symbol_id}/")
|
|
179
|
-
def delete_symbol(symbol_id: str,
|
|
212
|
+
def delete_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
|
|
180
213
|
symbol = symbol_repository.delete(symbol_id)
|
|
181
214
|
if symbol is None:
|
|
182
215
|
raise HTTPException(status_code=404, detail="Symbol not found")
|
|
@@ -185,13 +218,20 @@ def delete_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
|
|
|
185
218
|
|
|
186
219
|
@app.post("/symbol/{symbol_id}/{method_name}/")
|
|
187
220
|
@core_ext.error_logging(debug=DEBUG)
|
|
188
|
-
def operate_on_symbol(
|
|
221
|
+
def operate_on_symbol(
|
|
222
|
+
symbol_id: str,
|
|
223
|
+
method_name: str,
|
|
224
|
+
method_request: SymbolMethodRequest,
|
|
225
|
+
_api_key: str = Security(get_api_key),
|
|
226
|
+
):
|
|
189
227
|
symbol = symbol_repository.get(symbol_id)
|
|
190
228
|
if symbol is None:
|
|
191
229
|
raise HTTPException(status_code=404, detail="Symbol not found")
|
|
192
230
|
method = getattr(symbol, method_name, None)
|
|
193
231
|
if method is None or not callable(method):
|
|
194
|
-
raise HTTPException(
|
|
232
|
+
raise HTTPException(
|
|
233
|
+
status_code=404, detail=f"Method {method_name} not found or is not callable"
|
|
234
|
+
)
|
|
195
235
|
result = method(*method_request.args, **method_request.kwargs)
|
|
196
236
|
return {"result": result.json() if isinstance(result, Symbol) else result}
|
|
197
237
|
|
|
@@ -200,7 +240,7 @@ def operate_on_symbol(symbol_id: str, method_name: str, method_request: SymbolMe
|
|
|
200
240
|
|
|
201
241
|
|
|
202
242
|
class CreateExpressionRequest(BaseModel):
|
|
203
|
-
value:
|
|
243
|
+
value: Any | None = None
|
|
204
244
|
|
|
205
245
|
|
|
206
246
|
class UpdateExpressionRequest(BaseModel):
|
|
@@ -208,7 +248,9 @@ class UpdateExpressionRequest(BaseModel):
|
|
|
208
248
|
|
|
209
249
|
|
|
210
250
|
@app.post("/expression/")
|
|
211
|
-
def create_expression(
|
|
251
|
+
def create_expression(
|
|
252
|
+
expression_request: CreateExpressionRequest, _api_key: str = Security(get_api_key)
|
|
253
|
+
):
|
|
212
254
|
expression = Expression(expression_request.value)
|
|
213
255
|
expression_id = expression_repository.uid()
|
|
214
256
|
expression_repository.set(expression_id, expression)
|
|
@@ -216,7 +258,7 @@ def create_expression(expression_request: CreateExpressionRequest, api_key: str
|
|
|
216
258
|
|
|
217
259
|
|
|
218
260
|
@app.get("/expression/{expression_id}/")
|
|
219
|
-
def get_expression(expression_id: str,
|
|
261
|
+
def get_expression(expression_id: str, _api_key: str = Security(get_api_key)):
|
|
220
262
|
expression = expression_repository.get(expression_id)
|
|
221
263
|
if expression is None:
|
|
222
264
|
raise HTTPException(status_code=404, detail="Expression not found")
|
|
@@ -225,7 +267,9 @@ def get_expression(expression_id: str, api_key: str = Security(get_api_key)):
|
|
|
225
267
|
|
|
226
268
|
@app.post("/expression/{expression_id}/call/")
|
|
227
269
|
@core_ext.error_logging(debug=DEBUG)
|
|
228
|
-
def call_expression(
|
|
270
|
+
def call_expression(
|
|
271
|
+
expression_id: str, method_request: SymbolMethodRequest, _api_key: str = Security(get_api_key)
|
|
272
|
+
):
|
|
229
273
|
# Retrieve the expression instance by ID
|
|
230
274
|
expression = expression_repository.get(expression_id)
|
|
231
275
|
if expression is None:
|
|
@@ -236,19 +280,30 @@ def call_expression(expression_id: str, method_request: SymbolMethodRequest, api
|
|
|
236
280
|
|
|
237
281
|
@app.post("/expression/{expression_id}/{method_name}/")
|
|
238
282
|
@core_ext.error_logging(debug=DEBUG)
|
|
239
|
-
def operate_on_expression(
|
|
283
|
+
def operate_on_expression(
|
|
284
|
+
expression_id: str,
|
|
285
|
+
method_name: str,
|
|
286
|
+
method_request: SymbolMethodRequest,
|
|
287
|
+
_api_key: str = Security(get_api_key),
|
|
288
|
+
):
|
|
240
289
|
expression = expression_repository.get(expression_id)
|
|
241
290
|
if expression is None:
|
|
242
291
|
raise HTTPException(status_code=404, detail="Expression not found")
|
|
243
292
|
method = getattr(expression, method_name, None)
|
|
244
293
|
if method is None or not callable(method):
|
|
245
|
-
raise HTTPException(
|
|
294
|
+
raise HTTPException(
|
|
295
|
+
status_code=404, detail=f"Method {method_name} not found or is not callable"
|
|
296
|
+
)
|
|
246
297
|
result = method(*method_request.args, **method_request.kwargs)
|
|
247
298
|
return {"result": result.json() if isinstance(result, Symbol) else result}
|
|
248
299
|
|
|
249
300
|
|
|
250
301
|
@app.patch("/expression/{expression_id}/")
|
|
251
|
-
def update_expression(
|
|
302
|
+
def update_expression(
|
|
303
|
+
expression_id: str,
|
|
304
|
+
update_request: UpdateExpressionRequest,
|
|
305
|
+
_api_key: str = Security(get_api_key),
|
|
306
|
+
):
|
|
252
307
|
expression = expression_repository.get(expression_id)
|
|
253
308
|
if expression is None:
|
|
254
309
|
raise HTTPException(status_code=404, detail="Expression not found")
|
|
@@ -259,7 +314,7 @@ def update_expression(expression_id: str, update_request: UpdateExpressionReques
|
|
|
259
314
|
|
|
260
315
|
|
|
261
316
|
@app.delete("/expression/{expression_id}/")
|
|
262
|
-
def delete_expression(expression_id: str,
|
|
317
|
+
def delete_expression(expression_id: str, _api_key: str = Security(get_api_key)):
|
|
263
318
|
expression = expression_repository.delete(expression_id)
|
|
264
319
|
if expression is None:
|
|
265
320
|
raise HTTPException(status_code=404, detail="Expression not found")
|
|
@@ -278,25 +333,25 @@ class AddComponentRequest(BaseModel):
|
|
|
278
333
|
# Endpoint to instantiate a generic component class and get the ID
|
|
279
334
|
class CreateComponentGenericRequest(BaseModel):
|
|
280
335
|
class_name: str
|
|
281
|
-
init_args:
|
|
282
|
-
init_kwargs:
|
|
336
|
+
init_args: list[Any] = []
|
|
337
|
+
init_kwargs: dict[str, Any] = {}
|
|
283
338
|
|
|
284
339
|
|
|
285
340
|
# Modify the existing GenericRequest
|
|
286
341
|
class GenericRequest(BaseModel):
|
|
287
342
|
class_name: str
|
|
288
|
-
init_args:
|
|
289
|
-
init_kwargs:
|
|
290
|
-
forward_args:
|
|
291
|
-
forward_kwargs:
|
|
343
|
+
init_args: list[Any] = {}
|
|
344
|
+
init_kwargs: dict[str, Any] = {}
|
|
345
|
+
forward_args: list[Any] = {}
|
|
346
|
+
forward_kwargs: dict[str, Any] = {}
|
|
292
347
|
|
|
293
348
|
|
|
294
349
|
class UpdateComponentRequest(BaseModel):
|
|
295
|
-
update_kwargs:
|
|
350
|
+
update_kwargs: dict[str, Any] = {}
|
|
296
351
|
|
|
297
352
|
|
|
298
353
|
@app.post("/components/")
|
|
299
|
-
def create_component(request: CreateComponentGenericRequest,
|
|
354
|
+
def create_component(request: CreateComponentGenericRequest, _api_key: str = Security(get_api_key)):
|
|
300
355
|
# Retrieve the class from the repository
|
|
301
356
|
cls = component_class_types.get(request.class_name)
|
|
302
357
|
if cls is None:
|
|
@@ -305,12 +360,14 @@ def create_component(request: CreateComponentGenericRequest, api_key: str = Secu
|
|
|
305
360
|
instance = cls(*request.init_args, **request.init_kwargs)
|
|
306
361
|
# Store the instance with a generated ID and return the ID
|
|
307
362
|
instance_id = component_instance_repository.uid()
|
|
308
|
-
component_instance_repository.set(
|
|
363
|
+
component_instance_repository.set(
|
|
364
|
+
instance_id, instance
|
|
365
|
+
) # Assuming component_instance_repository exists
|
|
309
366
|
return {"id": instance_id}
|
|
310
367
|
|
|
311
368
|
|
|
312
369
|
@app.get("/components/{instance_id}/")
|
|
313
|
-
def get_component(instance_id: str,
|
|
370
|
+
def get_component(instance_id: str, _api_key: str = Security(get_api_key)):
|
|
314
371
|
# Retrieve an instance by its ID from the repository
|
|
315
372
|
instance = component_instance_repository.get(instance_id)
|
|
316
373
|
if instance is None:
|
|
@@ -321,13 +378,15 @@ def get_component(instance_id: str, api_key: str = Security(get_api_key)):
|
|
|
321
378
|
# Endpoint to execute a command on a component instance
|
|
322
379
|
@app.post("/components/call/")
|
|
323
380
|
@core_ext.error_logging(debug=DEBUG)
|
|
324
|
-
def generic_forward(request: GenericRequest,
|
|
381
|
+
def generic_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
|
|
325
382
|
# Dynamically import the class from components module based on request.class_name
|
|
326
|
-
components_module = importlib.import_module(
|
|
383
|
+
components_module = importlib.import_module(".components", package="symai")
|
|
327
384
|
cls = getattr(components_module, request.class_name)
|
|
328
385
|
# Check if cls is subclass of Expression and instantiate
|
|
329
386
|
if not issubclass(cls, components_module.Expression):
|
|
330
|
-
|
|
387
|
+
msg = "The provided class name must be a subclass of Expression"
|
|
388
|
+
UserMessage(msg)
|
|
389
|
+
raise ValueError(msg)
|
|
331
390
|
# Initialize the class with provided init_args, requiring unpacking **kwargs
|
|
332
391
|
instance = cls(*request.init_args, **request.init_kwargs)
|
|
333
392
|
# Call the forward method with provided forward_args, requiring unpacking **kwargs
|
|
@@ -339,7 +398,9 @@ def generic_forward(request: GenericRequest, api_key: str = Security(get_api_key
|
|
|
339
398
|
|
|
340
399
|
|
|
341
400
|
@app.patch("/components/{instance_id}/")
|
|
342
|
-
def update_component(
|
|
401
|
+
def update_component(
|
|
402
|
+
instance_id: str, update_request: UpdateComponentRequest, _api_key: str = Security(get_api_key)
|
|
403
|
+
):
|
|
343
404
|
instance = component_instance_repository.get(instance_id)
|
|
344
405
|
if instance is None:
|
|
345
406
|
raise HTTPException(status_code=404, detail="Component instance not found")
|
|
@@ -350,7 +411,7 @@ def update_component(instance_id: str, update_request: UpdateComponentRequest, a
|
|
|
350
411
|
|
|
351
412
|
|
|
352
413
|
@app.delete("/components/{instance_id}/")
|
|
353
|
-
def delete_component(instance_id: str,
|
|
414
|
+
def delete_component(instance_id: str, _api_key: str = Security(get_api_key)):
|
|
354
415
|
instance = component_instance_repository.delete(instance_id)
|
|
355
416
|
if instance is None:
|
|
356
417
|
raise HTTPException(status_code=404, detail="Component instance not found")
|
|
@@ -359,33 +420,29 @@ def delete_component(instance_id: str, api_key: str = Security(get_api_key)):
|
|
|
359
420
|
|
|
360
421
|
### Selectively register the endpoints with the API router ###
|
|
361
422
|
|
|
362
|
-
# extended
|
|
363
|
-
|
|
364
|
-
from ..extended.personas import Persona, Dialogue
|
|
365
|
-
from ..extended.personas.student import MaxTenner
|
|
366
|
-
from ..extended.personas.sales import ErikJames
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
extended_types = [Conversation, Persona, Dialogue, MaxTenner, ErikJames]
|
|
423
|
+
# extended types loaded lazily to avoid early engine configuration
|
|
424
|
+
extended_types = _load_extended_types()
|
|
370
425
|
# Register only the extended types from the extended_types Union
|
|
371
|
-
extended_class_types
|
|
372
|
-
extended_instance_repository = GenericRepository[extended_types](
|
|
426
|
+
extended_class_types = {c.__name__: c for c in extended_types}
|
|
427
|
+
extended_instance_repository = GenericRepository[extended_types](
|
|
428
|
+
redis_client, "ext_id", use_redis=use_redis
|
|
429
|
+
)
|
|
373
430
|
|
|
374
431
|
|
|
375
432
|
# Model definitions for extended classes
|
|
376
433
|
class CreateExtendedRequest(BaseModel):
|
|
377
434
|
class_name: str
|
|
378
|
-
init_args:
|
|
379
|
-
init_kwargs:
|
|
435
|
+
init_args: list[Any] = []
|
|
436
|
+
init_kwargs: dict[str, Any] = {}
|
|
380
437
|
|
|
381
438
|
|
|
382
439
|
class UpdateExtendedRequest(BaseModel):
|
|
383
|
-
update_kwargs:
|
|
440
|
+
update_kwargs: dict[str, Any] = {}
|
|
384
441
|
|
|
385
442
|
|
|
386
443
|
# Create endpoints for each of the extended classes
|
|
387
444
|
@app.post("/extended/")
|
|
388
|
-
def create_extended(request: CreateExtendedRequest,
|
|
445
|
+
def create_extended(request: CreateExtendedRequest, _api_key: str = Security(get_api_key)):
|
|
389
446
|
# Dynamically retrieve the extended class
|
|
390
447
|
extended_class = extended_class_types.get(request.class_name)
|
|
391
448
|
if extended_class is None:
|
|
@@ -401,7 +458,7 @@ def create_extended(request: CreateExtendedRequest, api_key: str = Security(get_
|
|
|
401
458
|
# Endpoint to execute a command on a component instance
|
|
402
459
|
@app.post("/extended/call/")
|
|
403
460
|
@core_ext.error_logging(debug=DEBUG)
|
|
404
|
-
def extended_forward(request: GenericRequest,
|
|
461
|
+
def extended_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
|
|
405
462
|
# Dynamically import the class from components module based on request.class_name
|
|
406
463
|
try:
|
|
407
464
|
# get request.class_name from extended_types if it's a type of extended_types
|
|
@@ -409,7 +466,9 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
|
|
|
409
466
|
# look for the class in the extended module if not found in extended_types
|
|
410
467
|
# iterate over the extended_type Union and check if the class name is in the __dict__
|
|
411
468
|
if cls is None:
|
|
412
|
-
|
|
469
|
+
msg = f"Class {request.class_name} not found in extended types"
|
|
470
|
+
UserMessage(msg)
|
|
471
|
+
raise ImportError(msg)
|
|
413
472
|
# Initialize the class with provided init_args and init_kwargs
|
|
414
473
|
instance = cls(*request.init_args, **request.init_kwargs)
|
|
415
474
|
# Call the 'forward' or similar method with provided forward_args and forward_kwargs
|
|
@@ -418,20 +477,19 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
|
|
|
418
477
|
# Check if the type of the result is within extended types or a primitive that can be serialized directly
|
|
419
478
|
if isinstance(result, Symbol):
|
|
420
479
|
return result.json() # Convert to dictionary if it's a complex type
|
|
421
|
-
|
|
422
|
-
return {"result": result} # Return as is if it's a primitive type
|
|
480
|
+
return {"result": result} # Return as is if it's a primitive type
|
|
423
481
|
except ImportError as e:
|
|
424
|
-
raise HTTPException(status_code=404, detail=f"Module not found: {
|
|
482
|
+
raise HTTPException(status_code=404, detail=f"Module not found: {e!s}") from e
|
|
425
483
|
except AttributeError as e:
|
|
426
|
-
raise HTTPException(status_code=404, detail=str(e))
|
|
484
|
+
raise HTTPException(status_code=404, detail=str(e)) from e
|
|
427
485
|
except TypeError as e:
|
|
428
|
-
raise HTTPException(status_code=422, detail=str(e))
|
|
486
|
+
raise HTTPException(status_code=422, detail=str(e)) from e
|
|
429
487
|
except Exception as e:
|
|
430
|
-
raise HTTPException(status_code=500, detail=f"An error occurred: {
|
|
488
|
+
raise HTTPException(status_code=500, detail=f"An error occurred: {e!s}") from e
|
|
431
489
|
|
|
432
490
|
|
|
433
491
|
@app.get("/extended/{instance_id}/")
|
|
434
|
-
def get_extended(instance_id: str,
|
|
492
|
+
def get_extended(instance_id: str, _api_key: str = Security(get_api_key)):
|
|
435
493
|
# Retrieve an instance by its ID
|
|
436
494
|
extended_instance = extended_instance_repository.get(instance_id)
|
|
437
495
|
if extended_instance is None:
|
|
@@ -440,7 +498,9 @@ def get_extended(instance_id: str, api_key: str = Security(get_api_key)):
|
|
|
440
498
|
|
|
441
499
|
|
|
442
500
|
@app.patch("/extended/{instance_id}/")
|
|
443
|
-
def update_extended(
|
|
501
|
+
def update_extended(
|
|
502
|
+
instance_id: str, update_request: UpdateExtendedRequest, _api_key: str = Security(get_api_key)
|
|
503
|
+
):
|
|
444
504
|
# Retrieve the instance by its ID
|
|
445
505
|
extended_instance = extended_instance_repository.get(instance_id)
|
|
446
506
|
if extended_instance is None:
|
|
@@ -453,11 +513,13 @@ def update_extended(instance_id: str, update_request: UpdateExtendedRequest, api
|
|
|
453
513
|
|
|
454
514
|
|
|
455
515
|
@app.delete("/extended/{instance_id}/")
|
|
456
|
-
def delete_extended(instance_id: str,
|
|
516
|
+
def delete_extended(instance_id: str, _api_key: str = Security(get_api_key)):
|
|
457
517
|
# Attempt to delete the instance by its ID
|
|
458
518
|
success = extended_instance_repository.delete(instance_id)
|
|
459
519
|
if not success:
|
|
460
|
-
raise HTTPException(
|
|
520
|
+
raise HTTPException(
|
|
521
|
+
status_code=404, detail="Extended instance not found or already deleted"
|
|
522
|
+
)
|
|
461
523
|
return {"message": "Extended instance deleted successfully"}
|
|
462
524
|
|
|
463
525
|
|
symai/extended/.DS_Store
ADDED
|
Binary file
|
symai/extended/__init__.py
CHANGED
|
@@ -1,16 +1,50 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from .document import *
|
|
4
|
-
from .file_merger import *
|
|
5
|
-
from .graph import *
|
|
6
|
-
from .html_style_template import *
|
|
7
|
-
from .packages import *
|
|
8
|
-
from .repo_cloner import *
|
|
9
|
-
from .solver import *
|
|
10
|
-
from .summarizer import *
|
|
11
|
-
from .personas import *
|
|
1
|
+
from importlib import import_module as _import_module
|
|
2
|
+
|
|
12
3
|
from .api_builder import APIBuilder, APIExecutor
|
|
4
|
+
from .bibtex_parser import BibTexParser
|
|
13
5
|
from .os_command import OSCommand
|
|
14
6
|
from .taypan_interpreter import TaypanInterpreter
|
|
15
|
-
from .bibtex_parser import BibTexParser
|
|
16
7
|
from .vectordb import VectorDB
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"APIBuilder",
|
|
11
|
+
"APIExecutor",
|
|
12
|
+
"BibTexParser",
|
|
13
|
+
"OSCommand",
|
|
14
|
+
"TaypanInterpreter",
|
|
15
|
+
"VectorDB",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
_seen_names = set(__all__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _export_module(module_name: str, seen_names: set[str] = _seen_names) -> None:
|
|
22
|
+
module = _import_module(f"{__name__}.{module_name}")
|
|
23
|
+
public_names = getattr(module, "__all__", None)
|
|
24
|
+
if public_names is None:
|
|
25
|
+
public_names = [name for name in dir(module) if not name.startswith("_")]
|
|
26
|
+
for name in public_names:
|
|
27
|
+
globals()[name] = getattr(module, name)
|
|
28
|
+
if name not in seen_names:
|
|
29
|
+
__all__.append(name)
|
|
30
|
+
seen_names.add(name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
for _module_name in [
|
|
34
|
+
"arxiv_pdf_parser",
|
|
35
|
+
"conversation",
|
|
36
|
+
"document",
|
|
37
|
+
"file_merger",
|
|
38
|
+
"graph",
|
|
39
|
+
"html_style_template",
|
|
40
|
+
"packages",
|
|
41
|
+
"repo_cloner",
|
|
42
|
+
"solver",
|
|
43
|
+
"summarizer",
|
|
44
|
+
]:
|
|
45
|
+
_export_module(_module_name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
del _export_module
|
|
49
|
+
del _module_name
|
|
50
|
+
del _seen_names
|