ApiLogicServer 14.5.0__py3-none-any.whl → 14.5.3__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.
- api_logic_server_cli/add_cust/add_cust.py +7 -21
- api_logic_server_cli/api_logic_server.py +4 -2
- api_logic_server_cli/api_logic_server_info.yaml +2 -2
- api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/{mcp_server_executor.py → mcp_discovery.py} +1 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/config/server_setup.py +388 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/system/SAFRSBaseX.py +136 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +3 -1
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_client_executor.py +82 -27
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +22 -2
- api_logic_server_cli/prototypes/basic_demo/iteration/logic/declare_logic.py +1 -1
- api_logic_server_cli/prototypes/nw/logic/declare_logic.py +2 -2
- api_logic_server_cli/prototypes/nw_no_cust/.obsidian/app.json +1 -0
- api_logic_server_cli/prototypes/nw_no_cust/.obsidian/appearance.json +1 -0
- api_logic_server_cli/prototypes/nw_no_cust/.obsidian/core-plugins.json +31 -0
- api_logic_server_cli/prototypes/nw_no_cust/.obsidian/workspace.json +166 -0
- apilogicserver-14.5.3.dist-info/METADATA +168 -0
- {apilogicserver-14.5.0.dist-info → apilogicserver-14.5.3.dist-info}/RECORD +24 -42
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/proper_update_def.json +0 -71
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/1_langchain_loader.py +0 -71
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/2_gpt_mcp_prompt.txt +0 -19
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_flow.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_orchestration.yaml +0 -49
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/wny mcp flows.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/natlang_to_api.py +0 -73
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/curl.txt +0 -5
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP Overview.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Arch.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Overview_Executor.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/1 - prompt_messages_array.json +0 -10
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/2 - completion_tool_context.json +0 -12
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/llm_schema.txt +0 -38
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_2.yaml +0 -17393
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3.yaml +0 -16660
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3_relaxed.yaml +0 -109
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_server.py +0 -51
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_serverZ.py +0 -72
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/validate_jsonapi.py +0 -64
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/run_executor.py +0 -23
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/swagger_converter.py +0 -65
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/z_old/3_executor_test_agent.py +0 -52
- api_logic_server_cli/prototypes/manager/README_X.md +0 -663
- apilogicserver-14.5.0.dist-info/METADATA +0 -76
- {apilogicserver-14.5.0.dist-info → apilogicserver-14.5.3.dist-info}/WHEEL +0 -0
- {apilogicserver-14.5.0.dist-info → apilogicserver-14.5.3.dist-info}/entry_points.txt +0 -0
- {apilogicserver-14.5.0.dist-info → apilogicserver-14.5.3.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-14.5.0.dist-info → apilogicserver-14.5.3.dist-info}/top_level.txt +0 -0
api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_client_executor.py
CHANGED
|
@@ -20,6 +20,7 @@ ToDo - email example is incomplete:
|
|
|
20
20
|
|
|
21
21
|
import json
|
|
22
22
|
import os
|
|
23
|
+
import re
|
|
23
24
|
import openai
|
|
24
25
|
import requests
|
|
25
26
|
|
|
@@ -83,16 +84,22 @@ def discover_mcp_servers():
|
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
def get_user_nl_query():
|
|
86
|
-
""" Get the natural language query from the user.
|
|
87
|
+
""" Get the natural language query from the user.
|
|
88
|
+
|
|
89
|
+
"""
|
|
87
90
|
|
|
88
91
|
global test_type
|
|
89
|
-
# this doesn't work -- missing commands for mcp_server_executor....
|
|
90
|
-
default_request = "List the orders created more than 30 days ago, and post an email message to the order's customer offering a discount"
|
|
91
92
|
|
|
92
93
|
default_request = "List the orders created more than 30 days ago, and send a discount email to the customer for each one."
|
|
93
|
-
#
|
|
94
|
+
# eg, curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"gt","val":"2023-07-14"}]'
|
|
95
|
+
# eg, curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"eq","val":null}]'
|
|
96
|
+
# eg, curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"eq","val":null},{"name":"CreatedOn","op":"lt","val":"2023-07-14"}]'
|
|
97
|
+
# eg, curl -qg 'http://localhost:5656/api/Customer?filter=[{"name":"credit_limit","op":"gt","val":"1000"}]'
|
|
98
|
+
|
|
99
|
+
# curl -qg 'http://localhost:5656/api/Order?filter=[{"name":%20"date_shipped",%20"op":%20"eq",%20"val":%20null},%20{"name":%20"CreatedOn",%20"op":%20"lt",%20"val":%20"2023-07-14"}]'
|
|
94
100
|
|
|
95
101
|
default_request = "List the orders for customer 5, and send a discount email to the customer for each one."
|
|
102
|
+
default_request = "List the unshipped orders created before 2023-07-14, and send a discount email to the customer for each one."
|
|
96
103
|
|
|
97
104
|
if test_type != 'orchestration':
|
|
98
105
|
default_request = "List customers with credit over 1000"
|
|
@@ -102,7 +109,7 @@ def get_user_nl_query():
|
|
|
102
109
|
query += """
|
|
103
110
|
Respond with a JSON array of tool context blocks using:
|
|
104
111
|
- tool: 'json-api'
|
|
105
|
-
- JSON:API
|
|
112
|
+
- JSON:API custom filtering (e.g., filter=[{"name":"date_shipped","op":"gt","val":"2023-07-14"}])
|
|
106
113
|
- Use {{ order.customer_id }} as a placeholder in the second step.
|
|
107
114
|
- Include method, url, query_params or body, headers, expected_output.
|
|
108
115
|
"""
|
|
@@ -138,26 +145,37 @@ def query_llm_with_nl(nl_query):
|
|
|
138
145
|
"method": "GET",
|
|
139
146
|
"url": "http://localhost:5656/api/Order",
|
|
140
147
|
"query_params": {
|
|
141
|
-
"filter
|
|
148
|
+
"filter": [
|
|
149
|
+
{
|
|
150
|
+
"name": "date_shipped",
|
|
151
|
+
"op": "eq",
|
|
152
|
+
"val": None
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"name": "date_created",
|
|
156
|
+
"op": "lt",
|
|
157
|
+
"val": "2023-07-14"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
142
160
|
},
|
|
143
161
|
"headers": {
|
|
144
|
-
"Content-Type": "application/
|
|
162
|
+
"Content-Type": "application/json"
|
|
145
163
|
},
|
|
146
|
-
"expected_output": "JSON array of orders
|
|
164
|
+
"expected_output": "JSON array of unshipped orders created before 2023-07-14"
|
|
147
165
|
},
|
|
148
166
|
{
|
|
149
167
|
"tool": "email",
|
|
150
168
|
"method": "POST",
|
|
151
|
-
"url": "http://localhost:5656/api/
|
|
169
|
+
"url": "http://localhost:5656/api/sendEmail",
|
|
152
170
|
"body": {
|
|
153
|
-
"
|
|
171
|
+
"customer_id": "{{ order.customer_id }}",
|
|
154
172
|
"subject": "Discount Offer",
|
|
155
|
-
"message": "
|
|
173
|
+
"message": "You have a new discount offer for your unshipped order."
|
|
156
174
|
},
|
|
157
175
|
"headers": {
|
|
158
176
|
"Content-Type": "application/json"
|
|
159
177
|
},
|
|
160
|
-
"expected_output": "
|
|
178
|
+
"expected_output": "Confirmation of email sent"
|
|
161
179
|
}
|
|
162
180
|
]
|
|
163
181
|
else: # simple get request - list customers with credit over 4000
|
|
@@ -213,26 +231,61 @@ def process_tool_context(tool_context):
|
|
|
213
231
|
|
|
214
232
|
def get_query_param_filter(query_params):
|
|
215
233
|
""" return json:api filter
|
|
234
|
+
|
|
235
|
+
see api_logic_server_cli/prototypes/base/api/system/expression_parser.py (doc?)
|
|
236
|
+
|
|
237
|
+
eg
|
|
238
|
+
curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"eq","val":null},{"name":"CreatedOn","op":"gt","val":"2023-07-14"}]'
|
|
216
239
|
|
|
217
|
-
query_params might be:
|
|
240
|
+
query_params might be simple:
|
|
218
241
|
"query_params": {
|
|
219
242
|
"filter[credit_limit][gt]": 1000 }
|
|
220
|
-
|
|
243
|
+
==> ?filter=[{"name":"credit_limit","op":"gt","val":"1000"}]
|
|
244
|
+
or a list:
|
|
221
245
|
"query_params": {
|
|
222
|
-
|
|
223
|
-
|
|
246
|
+
"filter": [
|
|
247
|
+
{
|
|
248
|
+
"name": "date_shipped",
|
|
249
|
+
"op": "eq",
|
|
250
|
+
"val": null
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"name": "date_created",
|
|
254
|
+
"op": "lt",
|
|
255
|
+
"val": "2023-07-14"
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
},
|
|
224
259
|
"""
|
|
260
|
+
|
|
261
|
+
added_rows = 0
|
|
262
|
+
|
|
225
263
|
query_param_filter = ''
|
|
226
264
|
if isinstance(query_params, dict):
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
265
|
+
if "filter" not in query_params: # simple - "query_params": {"filter[credit_limit][gt]": 1000 }
|
|
266
|
+
for each_key, each_value in query_params.items():
|
|
267
|
+
assert not isinstance(each_value, dict), "Unexpected dict in simple query_params"
|
|
268
|
+
# convert {"filter[credit_limit][gt]": 1000 } to ?filter=[{"name":"credit_limit","op":"gt","val":"1000"}]
|
|
269
|
+
match = re.match(r"filter\[(\w+)\]\[(\w+)\]", each_key)
|
|
270
|
+
if match:
|
|
271
|
+
name, op = match.groups()
|
|
272
|
+
filter_json = json.dumps([{"name": name, "op": op, "val": str(each_value)}])
|
|
273
|
+
query_param_filter += f"&filter={filter_json}"
|
|
274
|
+
else:
|
|
275
|
+
query_param_filter += f"&{each_key}={each_value}"
|
|
276
|
+
|
|
277
|
+
else: # complex - "query_params": {"filter": ...
|
|
278
|
+
assert isinstance(query_params["filter"], list), "Query Params filter expected to be a list"
|
|
279
|
+
query_param_filter = 'filter=' + str(query_params["filter"])
|
|
280
|
+
# use urlencode to convert to JSON:API format...
|
|
281
|
+
# val urllib.parse.quote() or urllib.parse.urlencode()
|
|
282
|
+
# tool instructions... filtering, email etc
|
|
283
|
+
query_param_filter = query_param_filter.replace("'", '"') # convert single quotes to double quotes
|
|
284
|
+
query_param_filter = query_param_filter.replace("None", 'null')
|
|
285
|
+
query_param_filter = query_param_filter.replace("date_created", 'CreatedOn') # TODO - why this name?
|
|
233
286
|
# query_params = ''
|
|
234
|
-
|
|
235
|
-
assert False, "Query Params dict
|
|
287
|
+
else:
|
|
288
|
+
assert False, "Query Params not a dict"
|
|
236
289
|
return query_param_filter
|
|
237
290
|
|
|
238
291
|
|
|
@@ -259,12 +312,12 @@ def process_tool_context(tool_context):
|
|
|
259
312
|
)
|
|
260
313
|
context_data = mcp_response.json()['data'] # result rows...
|
|
261
314
|
elif each_block["method"] in ["POST"]:
|
|
262
|
-
add_rows = 0
|
|
263
315
|
for each_order in context_data:
|
|
264
316
|
url = each_block["url"]
|
|
317
|
+
url = url.replace("sendEmail", "Email") # TODO name fix
|
|
265
318
|
json_update_data = { 'data': {"type": "Email", 'attributes': {} } }
|
|
266
319
|
json_update_data_attributes = json_update_data["data"]["attributes"]
|
|
267
|
-
json_update_data_attributes["customer_id"] = context_data[0]['attributes']["customer_id"]
|
|
320
|
+
json_update_data_attributes["customer_id"] = context_data[0]['attributes']["customer_id"] # TODO - fix
|
|
268
321
|
json_update_data_attributes["message"] = each_block["body"]["message"]
|
|
269
322
|
# eg: POST http://localhost:5656/api/Email {'data': {'type': 'Email', 'attributes': {'customer_id': 5, 'message': {'to': '{{ order.customer_id }}', 'subject': 'Discount for your order', 'body': 'Dear customer, you have a discount for your recent order. Thank you for shopping with us.'}}}}
|
|
270
323
|
mcp_response = requests.post(
|
|
@@ -272,12 +325,14 @@ def process_tool_context(tool_context):
|
|
|
272
325
|
headers=each_block["headers"],
|
|
273
326
|
json=json_update_data
|
|
274
327
|
)
|
|
275
|
-
|
|
328
|
+
added_rows += 1
|
|
276
329
|
pass
|
|
277
330
|
else:
|
|
278
331
|
print("Invalid tool context format. Expected a dictionary or a list.")
|
|
279
332
|
return None
|
|
280
333
|
print("\n3. MCP Server (als) Response:\n", mcp_response.text)
|
|
334
|
+
if added_rows > 0:
|
|
335
|
+
print(f"...Added {added_rows} rows to the database; last row (only) shown above.")
|
|
281
336
|
return mcp_response
|
|
282
337
|
|
|
283
338
|
|
|
@@ -9,6 +9,7 @@ import api.system.opt_locking.opt_locking as opt_locking
|
|
|
9
9
|
from security.system.authorization import Grant, Security
|
|
10
10
|
from logic.load_verify_rules import load_verify_rules
|
|
11
11
|
import integration.kafka.kafka_producer as kafka_producer
|
|
12
|
+
from integration.n8n.n8n_producer import send_n8n_message
|
|
12
13
|
import logging
|
|
13
14
|
|
|
14
15
|
app_logger = logging.getLogger(__name__)
|
|
@@ -32,7 +33,7 @@ def declare_logic():
|
|
|
32
33
|
discover_logic()
|
|
33
34
|
|
|
34
35
|
# Logic from GenAI: (or, use your IDE w/ code completion)
|
|
35
|
-
from database.models import Product, Order, Item, Customer
|
|
36
|
+
from database.models import Product, Order, Item, Customer, Email
|
|
36
37
|
|
|
37
38
|
# Ensure the customer's balance is less than their credit limit
|
|
38
39
|
Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit, error_msg="Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})")
|
|
@@ -54,6 +55,25 @@ def declare_logic():
|
|
|
54
55
|
|
|
55
56
|
# End Logic from GenAI
|
|
56
57
|
|
|
58
|
+
def send_mail(row: Email, old_row: Email, logic_row: LogicRow):
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
#als: Send N8N email message (also see discovery/integration.py)
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
row (Email): inserted Email
|
|
65
|
+
old_row (Email): n/a
|
|
66
|
+
logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt logic
|
|
67
|
+
"""
|
|
68
|
+
if logic_row.is_inserted():
|
|
69
|
+
customer = row.customer # parent accessor
|
|
70
|
+
if customer.email_opt_out:
|
|
71
|
+
logic_row.log("customer opted out of email")
|
|
72
|
+
return
|
|
73
|
+
logic_row.log(f"send email {row.message} to {customer.email} (stub, eg use N8N") # see in log
|
|
74
|
+
|
|
75
|
+
Rule.after_flush_row_event(on_class=Email, calling=send_mail) # see above
|
|
76
|
+
|
|
57
77
|
|
|
58
78
|
def handle_all(logic_row: LogicRow): # #als: TIME / DATE STAMPING, OPTIMISTIC LOCKING
|
|
59
79
|
"""
|
|
@@ -77,7 +97,7 @@ def declare_logic():
|
|
|
77
97
|
Grant.process_updates(logic_row=logic_row)
|
|
78
98
|
|
|
79
99
|
did_stamping = False
|
|
80
|
-
if enable_stamping :=
|
|
100
|
+
if enable_stamping := True: # #als: DATE / USER STAMPING
|
|
81
101
|
row = logic_row.row
|
|
82
102
|
if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedOn"):
|
|
83
103
|
row.CreatedOn = datetime.datetime.now()
|
|
@@ -119,7 +119,7 @@ def declare_logic():
|
|
|
119
119
|
Grant.process_updates(logic_row=logic_row)
|
|
120
120
|
|
|
121
121
|
did_stamping = False
|
|
122
|
-
if enable_stamping :=
|
|
122
|
+
if enable_stamping := True: # #als: DATE / USER STAMPING
|
|
123
123
|
row = logic_row.row
|
|
124
124
|
if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedOn"):
|
|
125
125
|
row.CreatedOn = datetime.datetime.now()
|
|
@@ -148,8 +148,8 @@ def declare_logic():
|
|
|
148
148
|
"Order Date": row.OrderDate,
|
|
149
149
|
#"items": [row.OrderDetailList]
|
|
150
150
|
},
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
ins_upd_dlt="upd", wh_entity="Order",
|
|
152
|
+
msg="1. /Webhook integration.py: n8n, sending ready Order payload")
|
|
153
153
|
|
|
154
154
|
logic_row.log("send_order_to_shipping - sent order to shipping and N8N/sendgrid") # see in log
|
|
155
155
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"file-explorer": true,
|
|
3
|
+
"global-search": true,
|
|
4
|
+
"switcher": true,
|
|
5
|
+
"graph": true,
|
|
6
|
+
"backlink": true,
|
|
7
|
+
"canvas": true,
|
|
8
|
+
"outgoing-link": true,
|
|
9
|
+
"tag-pane": true,
|
|
10
|
+
"properties": false,
|
|
11
|
+
"page-preview": true,
|
|
12
|
+
"daily-notes": true,
|
|
13
|
+
"templates": true,
|
|
14
|
+
"note-composer": true,
|
|
15
|
+
"command-palette": true,
|
|
16
|
+
"slash-command": false,
|
|
17
|
+
"editor-status": true,
|
|
18
|
+
"bookmarks": true,
|
|
19
|
+
"markdown-importer": false,
|
|
20
|
+
"zk-prefixer": false,
|
|
21
|
+
"random-note": false,
|
|
22
|
+
"outline": true,
|
|
23
|
+
"word-count": true,
|
|
24
|
+
"slides": false,
|
|
25
|
+
"audio-recorder": false,
|
|
26
|
+
"workspaces": false,
|
|
27
|
+
"file-recovery": true,
|
|
28
|
+
"publish": false,
|
|
29
|
+
"sync": true,
|
|
30
|
+
"webviewer": false
|
|
31
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"main": {
|
|
3
|
+
"id": "286a834d839adefc",
|
|
4
|
+
"type": "split",
|
|
5
|
+
"children": [
|
|
6
|
+
{
|
|
7
|
+
"id": "dd6d74d8e8e2033a",
|
|
8
|
+
"type": "tabs",
|
|
9
|
+
"children": [
|
|
10
|
+
{
|
|
11
|
+
"id": "27459de4487926a5",
|
|
12
|
+
"type": "leaf",
|
|
13
|
+
"state": {
|
|
14
|
+
"type": "empty",
|
|
15
|
+
"state": {},
|
|
16
|
+
"icon": "lucide-file",
|
|
17
|
+
"title": "New tab"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"direction": "vertical"
|
|
24
|
+
},
|
|
25
|
+
"left": {
|
|
26
|
+
"id": "46df2b3e60483310",
|
|
27
|
+
"type": "split",
|
|
28
|
+
"children": [
|
|
29
|
+
{
|
|
30
|
+
"id": "b1e255effaa8b3c7",
|
|
31
|
+
"type": "tabs",
|
|
32
|
+
"children": [
|
|
33
|
+
{
|
|
34
|
+
"id": "5d955bc80fce9623",
|
|
35
|
+
"type": "leaf",
|
|
36
|
+
"state": {
|
|
37
|
+
"type": "file-explorer",
|
|
38
|
+
"state": {
|
|
39
|
+
"sortOrder": "alphabetical",
|
|
40
|
+
"autoReveal": false
|
|
41
|
+
},
|
|
42
|
+
"icon": "lucide-folder-closed",
|
|
43
|
+
"title": "Files"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "28074419fd6a8eda",
|
|
48
|
+
"type": "leaf",
|
|
49
|
+
"state": {
|
|
50
|
+
"type": "search",
|
|
51
|
+
"state": {
|
|
52
|
+
"query": "",
|
|
53
|
+
"matchingCase": false,
|
|
54
|
+
"explainSearch": false,
|
|
55
|
+
"collapseAll": false,
|
|
56
|
+
"extraContext": false,
|
|
57
|
+
"sortOrder": "alphabetical"
|
|
58
|
+
},
|
|
59
|
+
"icon": "lucide-search",
|
|
60
|
+
"title": "Search"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "17e52ebf5918c581",
|
|
65
|
+
"type": "leaf",
|
|
66
|
+
"state": {
|
|
67
|
+
"type": "bookmarks",
|
|
68
|
+
"state": {},
|
|
69
|
+
"icon": "lucide-bookmark",
|
|
70
|
+
"title": "Bookmarks"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"direction": "horizontal",
|
|
77
|
+
"width": 300
|
|
78
|
+
},
|
|
79
|
+
"right": {
|
|
80
|
+
"id": "4089a9f1f65dc943",
|
|
81
|
+
"type": "split",
|
|
82
|
+
"children": [
|
|
83
|
+
{
|
|
84
|
+
"id": "55c5ab028d9835b4",
|
|
85
|
+
"type": "tabs",
|
|
86
|
+
"children": [
|
|
87
|
+
{
|
|
88
|
+
"id": "4b91ab7bf798a851",
|
|
89
|
+
"type": "leaf",
|
|
90
|
+
"state": {
|
|
91
|
+
"type": "backlink",
|
|
92
|
+
"state": {
|
|
93
|
+
"collapseAll": false,
|
|
94
|
+
"extraContext": false,
|
|
95
|
+
"sortOrder": "alphabetical",
|
|
96
|
+
"showSearch": false,
|
|
97
|
+
"searchQuery": "",
|
|
98
|
+
"backlinkCollapsed": false,
|
|
99
|
+
"unlinkedCollapsed": true
|
|
100
|
+
},
|
|
101
|
+
"icon": "links-coming-in",
|
|
102
|
+
"title": "Backlinks"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "990860d64994582e",
|
|
107
|
+
"type": "leaf",
|
|
108
|
+
"state": {
|
|
109
|
+
"type": "outgoing-link",
|
|
110
|
+
"state": {
|
|
111
|
+
"linksCollapsed": false,
|
|
112
|
+
"unlinkedCollapsed": true
|
|
113
|
+
},
|
|
114
|
+
"icon": "links-going-out",
|
|
115
|
+
"title": "Outgoing links"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"id": "320704f56a6b4c3e",
|
|
120
|
+
"type": "leaf",
|
|
121
|
+
"state": {
|
|
122
|
+
"type": "tag",
|
|
123
|
+
"state": {
|
|
124
|
+
"sortOrder": "frequency",
|
|
125
|
+
"useHierarchy": true,
|
|
126
|
+
"showSearch": false,
|
|
127
|
+
"searchQuery": ""
|
|
128
|
+
},
|
|
129
|
+
"icon": "lucide-tags",
|
|
130
|
+
"title": "Tags"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "2abbfb3e874500e0",
|
|
135
|
+
"type": "leaf",
|
|
136
|
+
"state": {
|
|
137
|
+
"type": "outline",
|
|
138
|
+
"state": {
|
|
139
|
+
"followCursor": false,
|
|
140
|
+
"showSearch": false,
|
|
141
|
+
"searchQuery": ""
|
|
142
|
+
},
|
|
143
|
+
"icon": "lucide-list",
|
|
144
|
+
"title": "Outline"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
"direction": "horizontal",
|
|
151
|
+
"width": 300,
|
|
152
|
+
"collapsed": true
|
|
153
|
+
},
|
|
154
|
+
"left-ribbon": {
|
|
155
|
+
"hiddenItems": {
|
|
156
|
+
"switcher:Open quick switcher": false,
|
|
157
|
+
"graph:Open graph view": false,
|
|
158
|
+
"canvas:Create new canvas": false,
|
|
159
|
+
"daily-notes:Open today's daily note": false,
|
|
160
|
+
"templates:Insert template": false,
|
|
161
|
+
"command-palette:Open command palette": false
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"active": "27459de4487926a5",
|
|
165
|
+
"lastOpenFiles": []
|
|
166
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ApiLogicServer
|
|
3
|
+
Version: 14.5.3
|
|
4
|
+
Author-email: Val Huber <apilogicserver@gmail.com>
|
|
5
|
+
License: BSD-3-Clause
|
|
6
|
+
Project-URL: Homepage, https://www.genai-logic.com
|
|
7
|
+
Project-URL: Docs, https://apilogicserver.github.io/Docs/Doc-Home/
|
|
8
|
+
Project-URL: Source, https://github.com/ApiLogicServer/ApiLogicServer-src
|
|
9
|
+
Project-URL: Issues, https://github.com/ApiLogicServer/ApiLogicServer-src/issues
|
|
10
|
+
Keywords: Flask,SQLAlchemy,Rules,WebApp,Microservice,ReactAdmin,Angular
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: PyJWT==2.6.0
|
|
26
|
+
Requires-Dist: python-dateutil==2.8.2
|
|
27
|
+
Requires-Dist: SQLAlchemy-Utils==0.38.2
|
|
28
|
+
Requires-Dist: logicbankutils==0.6.0
|
|
29
|
+
Requires-Dist: inflect==5.0.2
|
|
30
|
+
Requires-Dist: inflection==0.5.1
|
|
31
|
+
Requires-Dist: Flask==2.3.2
|
|
32
|
+
Requires-Dist: Flask-Cors==3.0.10
|
|
33
|
+
Requires-Dist: Flask-RESTful>=0.3.9
|
|
34
|
+
Requires-Dist: flask-restful-swagger-2>=0.35
|
|
35
|
+
Requires-Dist: Flask-SQLAlchemy==3.0.3
|
|
36
|
+
Requires-Dist: flask-swagger-ui>=4.11.1
|
|
37
|
+
Requires-Dist: flask_bcrypt==1.0.1
|
|
38
|
+
Requires-Dist: itsdangerous==2.1.2
|
|
39
|
+
Requires-Dist: Jinja2==3.1.5
|
|
40
|
+
Requires-Dist: MarkupSafe==2.1.3
|
|
41
|
+
Requires-Dist: six==1.16.0
|
|
42
|
+
Requires-Dist: SQLAlchemy==2.0.15
|
|
43
|
+
Requires-Dist: Werkzeug==2.3.3
|
|
44
|
+
Requires-Dist: safrs>=3.1.7
|
|
45
|
+
Requires-Dist: Flask-Admin==1.5.7
|
|
46
|
+
Requires-Dist: Flask-JWT-Extended==4.4.4
|
|
47
|
+
Requires-Dist: Flask-Login==0.6.2
|
|
48
|
+
Requires-Dist: Flask-OpenID==1.3.0
|
|
49
|
+
Requires-Dist: python-dotenv==0.15.0
|
|
50
|
+
Requires-Dist: email-validator==1.1.1
|
|
51
|
+
Requires-Dist: LogicBank>=1.20.26
|
|
52
|
+
Requires-Dist: cryptography==36.0.1
|
|
53
|
+
Requires-Dist: rsa
|
|
54
|
+
Requires-Dist: PyMySQL==1.0.3
|
|
55
|
+
Requires-Dist: oracledb==2.1.2
|
|
56
|
+
Requires-Dist: requests==2.31.0
|
|
57
|
+
Requires-Dist: gunicorn==20.1.0
|
|
58
|
+
Requires-Dist: psycopg2-binary==2.9.9
|
|
59
|
+
Requires-Dist: dotmap==1.3.25
|
|
60
|
+
Requires-Dist: WTForms==2.3.3
|
|
61
|
+
Requires-Dist: behave==1.2.6
|
|
62
|
+
Requires-Dist: alembic==1.7.7
|
|
63
|
+
Requires-Dist: python-ulid==2.7.0
|
|
64
|
+
Requires-Dist: psutil==6.0.0
|
|
65
|
+
Requires-Dist: pandas==2.2.2
|
|
66
|
+
Requires-Dist: openpyxl==3.1.5
|
|
67
|
+
Requires-Dist: GeoAlchemy2==0.12.5
|
|
68
|
+
Requires-Dist: confluent-kafka==2.3.0
|
|
69
|
+
Requires-Dist: translate==3.6.1
|
|
70
|
+
Requires-Dist: libretranslatepy==2.1.1
|
|
71
|
+
Requires-Dist: reportlab==4.2.0
|
|
72
|
+
Requires-Dist: xlsxwriter==3.2.0
|
|
73
|
+
Requires-Dist: natsort==8.4.0
|
|
74
|
+
Requires-Dist: astor==0.8.1
|
|
75
|
+
Requires-Dist: colorama==0.4.6
|
|
76
|
+
Requires-Dist: openai==1.55.3
|
|
77
|
+
Dynamic: license-file
|
|
78
|
+
|
|
79
|
+
[](https://pepy.tech/project/apilogicserver)
|
|
80
|
+
[](https://pypi.python.org/pypi/apilogicserver/)
|
|
81
|
+
[](https://pypi.python.org/pypi/apilogicserver/)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# TL;DR
|
|
86
|
+
|
|
87
|
+
Create an executable project (API and Admin App) from a database or natural language prompt with 1 command, customize with declarative rules and Python in your IDE, containerize and deploy.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
<details markdown>
|
|
92
|
+
|
|
93
|
+
<summary>Video Overview (4 min)</summary>
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
See how **Microservice Automation** creates and runs a microservice - a multi-page app, and an API.
|
|
98
|
+
|
|
99
|
+
* Here is a microservice -- api and admin app -- **created / running in 5 seconds**
|
|
100
|
+
|
|
101
|
+
* It would be similar for your databases
|
|
102
|
+
|
|
103
|
+
* Then, customize in your IDE with Python and **Logic Automation:** spreadsheet-like rules
|
|
104
|
+
|
|
105
|
+
[](https://www.youtube.com/watch?v=7I33Fa9Ulos "Microservice Automation")
|
|
106
|
+
|
|
107
|
+
</details>
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# Quickstart
|
|
112
|
+
|
|
113
|
+
If you have a supported Python (version 3.10 - 3.12), install is standard, typically:
|
|
114
|
+
|
|
115
|
+
```bash title="Install API Logic Server in a Virtual Environment"
|
|
116
|
+
python3 -m venv venv # windows: python -m venv venv
|
|
117
|
+
source venv/bin/activate # windows: venv\Scripts\activate
|
|
118
|
+
python -m pip install ApiLogicServer
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
<br>Now, verify it's working - open the Project Manager for instructions (readme), and run the demo:
|
|
122
|
+
|
|
123
|
+
```bash title="Start Manager"
|
|
124
|
+
ApiLogicServer start
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Find the [user documentation here](https://apilogicserver.github.io/Docs/). Use this for normal installation, to create and customize API Logic Projects.
|
|
128
|
+
|
|
129
|
+
To install the ***dev*** version, [see here](https://apilogicserver.github.io/Docs/Architecture-Internals). This installs the source of API Logic Server, so you can explore or extend it.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Welcome to API Logic Server
|
|
134
|
+
|
|
135
|
+
For Developers and their organizations seeking to **increase business agility,**
|
|
136
|
+
|
|
137
|
+
API Logic Server provides ***Microservice Automation:*** create executable projects with 1 command:
|
|
138
|
+
|
|
139
|
+
1. ***API Automation:*** crud for each table, with pagination, optimistic locking, filtering and sorting, and
|
|
140
|
+
|
|
141
|
+
2. ***App Automation:*** a multi-page, multi-table Admin App. <br>
|
|
142
|
+
|
|
143
|
+
**Customize in your IDE:** use standard tools (Python, Flask, SQLAlchemy, GitHub and Docker), plus<br>
|
|
144
|
+
|
|
145
|
+
3. ***Logic Automation:*** unique **rules - 40X** more concise multi-table derivations and constraints.
|
|
146
|
+
|
|
147
|
+
Unlike frameworks, weeks-to-months of complex development is no longer necessary. <br>
|
|
148
|
+
API Logic Server provides unique automation **for instant integrations and app backends**.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
For more information, including install procedures, [please see the docs](https://apilogicserver.github.io/Docs/).
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
### Making Contributions
|
|
158
|
+
|
|
159
|
+
This is an open source project. We are open to suggestions. Some of our ideas include:
|
|
160
|
+
|
|
161
|
+
| Component | Provides | Consider Adding |
|
|
162
|
+
|:---------------------------|:-----------------|:-------------------------------------------------------------------------------|
|
|
163
|
+
| 1. JSON:**API** and Swagger | API Execution | Serverless, Kubernetes |
|
|
164
|
+
| 2. Transactional **Logic** | Rule Enforcement | Recompute Derivations |
|
|
165
|
+
| 3. This project | API Logic Project Creation | General support - see issues |
|
|
166
|
+
| 3. GenAI | Web version | Create projects with logic |
|
|
167
|
+
|
|
168
|
+
|