ApiLogicServer 14.3.0__py3-none-any.whl → 14.3.7__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.
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/METADATA +2 -2
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/RECORD +46 -43
- api_logic_server_cli/api_logic_server.py +2 -1
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +5 -2
- api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/ont_build.py +1 -1
- api_logic_server_cli/genai/genai.py +4 -0
- api_logic_server_cli/genai/genai_svcs.py +2 -0
- api_logic_server_cli/manager.py +20 -16
- api_logic_server_cli/prototypes/base/api/system/expression_parser.py +10 -4
- api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +32 -8
- api_logic_server_cli/prototypes/base/integration/system/RowDictMapper.py +33 -16
- api_logic_server_cli/prototypes/base/logic/declare_logic.py +1 -0
- api_logic_server_cli/prototypes/base/logic/load_verify_rules.py +2 -1
- api_logic_server_cli/prototypes/genai_demo/api/customize_api.py +9 -11
- api_logic_server_cli/prototypes/genai_demo/database/.DS_Store +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/models.py +52 -42
- api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/OrderB2B.py +4 -6
- api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/__pycache__/OrderB2B.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/row_dict_maps_readme.md +3 -0
- api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/declare_logic.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/load_verify_rules.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/declare_logic.py +57 -69
- api_logic_server_cli/prototypes/genai_demo/logic/load_verify_rules.py +216 -0
- api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/error_testing.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/auto_discovery.py +52 -0
- api_logic_server_cli/prototypes/genai_demo/logic/readme_declare_logic.md +172 -0
- api_logic_server_cli/prototypes/genai_demo/security/__pycache__/declare_security.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +86 -53
- api_logic_server_cli/prototypes/manager/.vscode/launch.json +1 -1
- api_logic_server_cli/prototypes/manager/README.md +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +4 -1
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +15 -8
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +3 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/readme.md +58 -5
- api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt +15 -1
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/codegen.py +2 -1
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/copilot_models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/sample_ai_models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.chatgpt +0 -16
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.sql +0 -66
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.sqlite +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_items.sqlite +0 -0
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.py +0 -156
- api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.sqlite +0 -0
- api_logic_server_cli/prototypes/genai_demo/logic/cocktail-napkin.jpg +0 -0
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/LICENSE +0 -0
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/WHEEL +0 -0
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/entry_points.txt +0 -0
- {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
This describes how to use Logic; for more information, [see here](https://apilogicserver.github.io/Docs/Logic-Why).
|
|
2
|
+
|
|
3
|
+
> Key Takeway - Logic: Multi-table Derivation and Constraint Rules, Extensible with Python
|
|
4
|
+
<br>Rules are:
|
|
5
|
+
<br>1. **Declared** in your IDE - 40X more concise
|
|
6
|
+
<br>2. **Activated** on server start
|
|
7
|
+
<br>3. **Executed** - *automatically* - on updates (using SQLAlchemy events)
|
|
8
|
+
<br>4. **Debugged** in your IDE, and with the console log
|
|
9
|
+
<br>For more on rules, [click here](https://apilogicserver.github.io/Docs/Logic-Why/).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
Examples from tutorial project:
|
|
15
|
+
* Examples drawn from [tutorial project](https://github.com/ApiLogicServer/demo/blob/main/logic/declare_logic.py)
|
|
16
|
+
* Use Shift + "." to view in project mode
|
|
17
|
+
|
|
18
|
+
You can [find the rules here](https://apilogicserver.github.io/Docs/Logic). Below, we explore the syntax of 3 typical rules.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### 1. Multi-Table Derivations
|
|
23
|
+
|
|
24
|
+
This declares the Customer.Balance as the sum of the unshipped Order.AmountTotal:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
Rule.sum(derive=models.Customer.Balance,
|
|
28
|
+
as_sum_of=models.Order.AmountTotal,
|
|
29
|
+
where=lambda row: row.ShippedDate is None)
|
|
30
|
+
```
|
|
31
|
+
It means the rule engine **watches** for these changes:
|
|
32
|
+
* Order inserted/deleted, or
|
|
33
|
+
* AmountTotal or ShippedDate or CustomerID changes
|
|
34
|
+
|
|
35
|
+
Iff changes are detected, the engine **reacts** by *adjusting* the Customer.Balance. SQLs are [optimized](#declarative-logic-important-notes).
|
|
36
|
+
|
|
37
|
+
This would **chain** to check the Customers' Constraint rule, described below.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### 2. Constraints: lambda or function
|
|
42
|
+
|
|
43
|
+
Constraints are multi-field conditions which must be true for transactions to succeed (else an exception is raised). You can express the condition as a lambda or a function:
|
|
44
|
+
|
|
45
|
+
**As a lambda:**
|
|
46
|
+
```python
|
|
47
|
+
Rule.constraint(validate=models.Customer,
|
|
48
|
+
as_condition=lambda row: row.Balance <= row.CreditLimit, # parent references are supported
|
|
49
|
+
error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Or, as a function:**
|
|
53
|
+
```python
|
|
54
|
+
def check_balance(row: models.Customer, old_row: models.Customer, logic_row: LogicRow):
|
|
55
|
+
if logic_row.ins_upd_dlt != "dlt": # see also: logic_row.old_row
|
|
56
|
+
return row.Balance <= row.CreditLimit
|
|
57
|
+
else:
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
Rule.constraint(validate=models.Customer,
|
|
61
|
+
calling=check_balance,
|
|
62
|
+
error_msg=f"balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### 3. Row Events: Extensible with Python
|
|
68
|
+
|
|
69
|
+
Events are procedural Python code, providing extensibility for declarative rules:
|
|
70
|
+
```python
|
|
71
|
+
def congratulate_sales_rep(row: models.Order, old_row: models.Order, logic_row: LogicRow):
|
|
72
|
+
pass # event code here - sending email, messages, etc.
|
|
73
|
+
|
|
74
|
+
Rule.commit_row_event(on_class=models.Order, calling=congratulate_sales_rep)
|
|
75
|
+
```
|
|
76
|
+
Note there are multiple kinds of events, so you can control whether they run before or after rule execution. For more information, [see here](https://apilogicserver.github.io/Docs/Logic-Type-Constraint).
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## LogicRow: old_row, verb, etc
|
|
81
|
+
|
|
82
|
+
A key argument to functions is `logic_row`:
|
|
83
|
+
|
|
84
|
+
* **Wraps row and old_row,** plus methods for insert, update and delete - rule enforcement
|
|
85
|
+
|
|
86
|
+
* **Additional instance variables:** ins_upd_dlt, nest_level, session, etc.
|
|
87
|
+
|
|
88
|
+
* **Helper Methods:** are_attributes_changed, set_same_named_attributes, get_parent_logic_row(role_name), get_derived_attributes, log, is_inserted, etc
|
|
89
|
+
|
|
90
|
+
Here is an example:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
"""
|
|
94
|
+
STATE TRANSITION LOGIC, using old_row
|
|
95
|
+
"""
|
|
96
|
+
def raise_over_20_percent(row: models.Employee, old_row: models.Employee, logic_row: LogicRow):
|
|
97
|
+
if logic_row.ins_upd_dlt == "upd" and row.Salary > old_row.Salary:
|
|
98
|
+
return row.Salary >= Decimal('1.20') * old_row.Salary
|
|
99
|
+
else:
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
Rule.constraint(validate=models.Employee,
|
|
103
|
+
calling=raise_over_20_percent,
|
|
104
|
+
error_msg="{row.LastName} needs a more meaningful raise")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Note the `log` method, which enables you to write row/old_row into the log with a short message:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
logic_row.log("no manager for this order's salesrep")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
## Declarative Logic: Important Notes
|
|
116
|
+
|
|
117
|
+
Logic *declarative*, which differs from conventional *procedural* logic:
|
|
118
|
+
|
|
119
|
+
1. **Automatic Invocation:** you don't call the rules; they execute in response to updates (via SQLAlchemy events).
|
|
120
|
+
|
|
121
|
+
2. **Automatic Ordering:** you don't order the rules; execution order is based on system-discovered depencencies.
|
|
122
|
+
|
|
123
|
+
3. **Automatic Optimizations:** logic is optimized to reduce SQLs.
|
|
124
|
+
|
|
125
|
+
* Rule execution is *pruned* if dependent attributes are not altered
|
|
126
|
+
* SQL is optimized, e.g., `sum` rules operate by *adjustment*, not expensive SQL `select sum`
|
|
127
|
+
|
|
128
|
+
These simplify maintenance / iteration: you can be sure new logic is always called, in the correct order.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
## Debugging
|
|
133
|
+
|
|
134
|
+
Debug rules using **system-generated logic log** and your **IDE debugger**; for more information, [see here](https://apilogicserver.github.io/Docs/Logic-Use).
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
### Using the debugger
|
|
139
|
+
|
|
140
|
+
Use the debugger as shown below. Note you can stop in lambda functions.
|
|
141
|
+
|
|
142
|
+

|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
### Logic Log
|
|
147
|
+
|
|
148
|
+
Logging is performed using standard Python logging, with a logger named `logic_logger`. Use `info` for tracing, and `debug` for additional information (e.g., all declared rules are logged).
|
|
149
|
+
|
|
150
|
+
In addition, the system logs all rules that fire, to aid in debugging. Referring the the screen shot above:
|
|
151
|
+
|
|
152
|
+
* Each line represents a rule execution, showing row state (old/new values), and the _{reason}_ that caused the update (e.g., client, sum adjustment)
|
|
153
|
+
* Log indention shows multi-table chaining
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
## How Logic works
|
|
158
|
+
|
|
159
|
+
*Activation* occurs in `api_logic_server_run.py`:
|
|
160
|
+
```python
|
|
161
|
+
LogicBank.activate(session=session, activator=declare_logic, constraint_event=constraint_handler)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This installs the rule engine as a SQLAlchemy event listener (`before_flush`). So, Logic *runs* automatically, in response to transaction commits (typically via the API).
|
|
165
|
+
|
|
166
|
+
Rules plug into SQLAlchemy events, and execute as follows:
|
|
167
|
+
|
|
168
|
+
| Logic Phase | Why It Matters |
|
|
169
|
+
|:-----------------------------|:---------------------|
|
|
170
|
+
| **Watch** for changes at the attribute level | Performance - Automatic Attribute-level Pruning |
|
|
171
|
+
| **React** by recomputing value | Ensures Reuse - Invocation is automatic<br>Derivations are optimized (e.g. *adjustment updates* - not aggregate queries) |
|
|
172
|
+
| **Chain** to other referencing data | Simplifies Maintenance - ordering is automatic<br>Multi-table logic automation |
|
api_logic_server_cli/prototypes/genai_demo/security/__pycache__/declare_security.cpython-312.pyc
ADDED
|
Binary file
|
|
@@ -1,109 +1,142 @@
|
|
|
1
1
|
about:
|
|
2
|
-
date:
|
|
3
|
-
merged:
|
|
4
|
-
at: January 28, 2024 13:17:27
|
|
5
|
-
new_attributes: 'Product.CarbonNeutral '
|
|
6
|
-
new_resources: ''
|
|
7
|
-
new_tab_groups: ''
|
|
2
|
+
date: February 02, 2025 11:44:16
|
|
8
3
|
recent_changes: works with modified safrs-react-admin
|
|
9
4
|
version: 0.0.0
|
|
10
5
|
api_root: '{http_type}://{swagger_host}:{port}/{api}'
|
|
11
|
-
authentication:
|
|
12
|
-
endpoint: '{http_type}://{swagger_host}:{port}/api/auth/login'
|
|
6
|
+
authentication: '{system-default}'
|
|
13
7
|
info:
|
|
14
8
|
number_relationships: 3
|
|
15
9
|
number_tables: 4
|
|
10
|
+
info_toggle_checked: true
|
|
16
11
|
resources:
|
|
17
12
|
Customer:
|
|
18
13
|
attributes:
|
|
19
|
-
- label: '
|
|
20
|
-
name:
|
|
21
|
-
required: true
|
|
14
|
+
- label: ' name*'
|
|
15
|
+
name: name
|
|
22
16
|
search: true
|
|
23
17
|
sort: true
|
|
24
|
-
- name:
|
|
25
|
-
|
|
26
|
-
- name:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
- name: balance
|
|
19
|
+
type: DECIMAL
|
|
20
|
+
- name: credit_limit
|
|
21
|
+
type: DECIMAL
|
|
22
|
+
- name: id
|
|
23
|
+
description: Represents a customer in the system with unique name, balance, and
|
|
24
|
+
credit limit attributes.
|
|
25
|
+
info_list: Represents a customer in the system with unique name, balance, and
|
|
26
|
+
credit limit attributes.
|
|
30
27
|
tab_groups:
|
|
31
28
|
- direction: tomany
|
|
32
29
|
fks:
|
|
33
|
-
-
|
|
30
|
+
- customer_id
|
|
34
31
|
name: OrderList
|
|
35
32
|
resource: Order
|
|
36
33
|
type: Customer
|
|
37
|
-
user_key:
|
|
34
|
+
user_key: name
|
|
38
35
|
Item:
|
|
39
36
|
attributes:
|
|
40
|
-
- label: '
|
|
41
|
-
name:
|
|
37
|
+
- label: ' id*'
|
|
38
|
+
name: id
|
|
42
39
|
search: true
|
|
43
40
|
sort: true
|
|
44
|
-
- name:
|
|
45
|
-
- name:
|
|
46
|
-
- name:
|
|
41
|
+
- name: order_id
|
|
42
|
+
- name: product_id
|
|
43
|
+
- name: quantity
|
|
47
44
|
required: true
|
|
48
|
-
- name:
|
|
49
|
-
|
|
45
|
+
- name: unit_price
|
|
46
|
+
type: DECIMAL
|
|
47
|
+
- name: amount
|
|
48
|
+
type: DECIMAL
|
|
49
|
+
description: Represents an item in an order, including quantity and pricing details.
|
|
50
|
+
info_list: Represents an item in an order, including quantity and pricing details.
|
|
50
51
|
tab_groups:
|
|
51
52
|
- direction: toone
|
|
52
53
|
fks:
|
|
53
|
-
-
|
|
54
|
-
name:
|
|
54
|
+
- order_id
|
|
55
|
+
name: order
|
|
55
56
|
resource: Order
|
|
56
57
|
- direction: toone
|
|
57
58
|
fks:
|
|
58
|
-
-
|
|
59
|
-
name:
|
|
59
|
+
- product_id
|
|
60
|
+
name: product
|
|
60
61
|
resource: Product
|
|
61
62
|
type: Item
|
|
62
|
-
user_key:
|
|
63
|
+
user_key: id
|
|
63
64
|
Order:
|
|
64
65
|
attributes:
|
|
65
|
-
- label: '
|
|
66
|
-
name:
|
|
66
|
+
- label: ' id*'
|
|
67
|
+
name: id
|
|
67
68
|
search: true
|
|
68
69
|
sort: true
|
|
69
|
-
- name:
|
|
70
|
-
- name:
|
|
71
|
-
|
|
72
|
-
- name:
|
|
73
|
-
- name:
|
|
70
|
+
- name: customer_id
|
|
71
|
+
- name: amount_total
|
|
72
|
+
type: DECIMAL
|
|
73
|
+
- name: notes
|
|
74
|
+
- name: date_shipped
|
|
75
|
+
type: DATE
|
|
76
|
+
description: Represents an order made by a customer, including a notes field.
|
|
77
|
+
info_list: Represents an order made by a customer, including a notes field.
|
|
74
78
|
tab_groups:
|
|
75
79
|
- direction: tomany
|
|
76
80
|
fks:
|
|
77
|
-
-
|
|
81
|
+
- order_id
|
|
78
82
|
name: ItemList
|
|
79
83
|
resource: Item
|
|
80
84
|
- direction: toone
|
|
81
85
|
fks:
|
|
82
|
-
-
|
|
83
|
-
name:
|
|
86
|
+
- customer_id
|
|
87
|
+
name: customer
|
|
84
88
|
resource: Customer
|
|
85
89
|
type: Order
|
|
86
|
-
user_key:
|
|
90
|
+
user_key: id
|
|
87
91
|
Product:
|
|
88
92
|
attributes:
|
|
89
|
-
- label: '
|
|
90
|
-
name:
|
|
91
|
-
required: true
|
|
93
|
+
- label: ' name*'
|
|
94
|
+
name: name
|
|
92
95
|
search: true
|
|
93
96
|
sort: true
|
|
94
|
-
- name:
|
|
95
|
-
|
|
96
|
-
- name:
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
- name: unit_price
|
|
98
|
+
type: DECIMAL
|
|
99
|
+
- name: carbon_neutral
|
|
100
|
+
type: BOOLEAN
|
|
101
|
+
- name: id
|
|
102
|
+
description: Represents a product available in the system with a unit price.
|
|
103
|
+
info_list: Represents a product available in the system with a unit price.
|
|
99
104
|
tab_groups:
|
|
100
105
|
- direction: tomany
|
|
101
106
|
fks:
|
|
102
|
-
-
|
|
107
|
+
- product_id
|
|
103
108
|
name: ItemList
|
|
104
109
|
resource: Item
|
|
105
110
|
type: Product
|
|
106
|
-
user_key:
|
|
111
|
+
user_key: name
|
|
107
112
|
settings:
|
|
108
|
-
HomeJS:
|
|
113
|
+
HomeJS: /admin-app/home.js
|
|
109
114
|
max_list_columns: 8
|
|
115
|
+
style_guide:
|
|
116
|
+
applicationLocales:
|
|
117
|
+
- en
|
|
118
|
+
- es
|
|
119
|
+
currency_symbol: $
|
|
120
|
+
currency_symbol_position: left
|
|
121
|
+
date_format: LL
|
|
122
|
+
decimal_max: '1000000000'
|
|
123
|
+
decimal_min: '0'
|
|
124
|
+
decimal_separator: .
|
|
125
|
+
detail_mode: tab
|
|
126
|
+
edit_on_mode: dblclick
|
|
127
|
+
exclude_listpicker: false
|
|
128
|
+
include_translation: 'false'
|
|
129
|
+
keycloak_client_id: alsclient
|
|
130
|
+
keycloak_realm: kcals
|
|
131
|
+
keycloak_url: http://localhost:8080
|
|
132
|
+
locale: en
|
|
133
|
+
max_decimal_digits: '4'
|
|
134
|
+
min_decimal_digits: '2'
|
|
135
|
+
new_mode: dialog
|
|
136
|
+
pick_style: list
|
|
137
|
+
row_height: small,
|
|
138
|
+
serviceType: OntimizeEE
|
|
139
|
+
startSessionPath: /auth/login
|
|
140
|
+
style: light
|
|
141
|
+
thousand_separator: ','
|
|
142
|
+
use_keycloak: 'false'
|
|
@@ -109,7 +109,7 @@ als genai --using=system/genai/examples/genai_demo/genai_demo.prompt --project-n
|
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
|
-
als genai --repaired-response=system/genai/examples/genai_demo/
|
|
112
|
+
als genai --repaired-response=system/genai/examples/genai_demo/genai_demo.response_example --project-name=genai_demo
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Verify it's operating properly:
|
|
@@ -4,13 +4,16 @@ Include a notes field for orders.
|
|
|
4
4
|
|
|
5
5
|
Use LogicBank to enforce business logic.
|
|
6
6
|
|
|
7
|
-
Use case: Check Credit
|
|
7
|
+
Use case: Check Credit
|
|
8
8
|
1. The Customer's balance is less than the credit limit
|
|
9
9
|
2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
|
|
10
10
|
3. The Order's amount_total is the sum of the Item amount
|
|
11
11
|
4. The Item amount is the quantity * unit_price
|
|
12
12
|
5. The Item unit_price is copied from the Product unit_price
|
|
13
13
|
|
|
14
|
+
Use case: App Integration
|
|
15
|
+
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
|
|
16
|
+
|
|
14
17
|
Ensure each customer has a unique name.
|
|
15
18
|
|
|
16
19
|
Ensure each Item quantity is not null.
|
api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example
CHANGED
|
@@ -60,25 +60,32 @@
|
|
|
60
60
|
"use_case": "Store the Item.unit_price as a copy from Product.unit_price",
|
|
61
61
|
"entity": "Item",
|
|
62
62
|
"code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "Order Kafka Integration",
|
|
66
|
+
"description": "Sends the order to Kafka topic 'order_shipping' if the date shipped is not None.",
|
|
67
|
+
"use_case": "App Integration",
|
|
68
|
+
"entity": "Order",
|
|
69
|
+
"code": "Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka, if_condition=lambda row: row.date_shipped is not None, with_args={\"topic\": \"order_shipping\"})"
|
|
63
70
|
}
|
|
64
71
|
],
|
|
65
72
|
"test_data": "Insert test data into the tables with values compatible with the derived logic.",
|
|
66
73
|
"test_data_rows": [
|
|
67
74
|
{
|
|
68
75
|
"test_data_row_variable": "test_customer_1",
|
|
69
|
-
"code": "test_customer_1 = Customer(name='Customer 1', balance=
|
|
76
|
+
"code": "test_customer_1 = Customer(name='Customer 1', balance=150, credit_limit=1000)"
|
|
70
77
|
},
|
|
71
78
|
{
|
|
72
79
|
"test_data_row_variable": "test_customer_2",
|
|
73
|
-
"code": "test_customer_2 = Customer(name='Customer 2', balance=
|
|
80
|
+
"code": "test_customer_2 = Customer(name='Customer 2', balance=275, credit_limit=750)"
|
|
74
81
|
},
|
|
75
82
|
{
|
|
76
83
|
"test_data_row_variable": "test_customer_3",
|
|
77
|
-
"code": "test_customer_3 = Customer(name='Customer 3', balance=
|
|
84
|
+
"code": "test_customer_3 = Customer(name='Customer 3', balance=150, credit_limit=1500)"
|
|
78
85
|
},
|
|
79
86
|
{
|
|
80
87
|
"test_data_row_variable": "test_customer_4",
|
|
81
|
-
"code": "test_customer_4 = Customer(name='Customer 4', balance=
|
|
88
|
+
"code": "test_customer_4 = Customer(name='Customer 4', balance=0, credit_limit=1200)"
|
|
82
89
|
},
|
|
83
90
|
{
|
|
84
91
|
"test_data_row_variable": "test_order_1",
|
|
@@ -86,11 +93,11 @@
|
|
|
86
93
|
},
|
|
87
94
|
{
|
|
88
95
|
"test_data_row_variable": "test_order_2",
|
|
89
|
-
"code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=
|
|
96
|
+
"code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=225)"
|
|
90
97
|
},
|
|
91
98
|
{
|
|
92
99
|
"test_data_row_variable": "test_order_3",
|
|
93
|
-
"code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=
|
|
100
|
+
"code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=50)"
|
|
94
101
|
},
|
|
95
102
|
{
|
|
96
103
|
"test_data_row_variable": "test_order_4",
|
|
@@ -102,11 +109,11 @@
|
|
|
102
109
|
},
|
|
103
110
|
{
|
|
104
111
|
"test_data_row_variable": "test_item_2",
|
|
105
|
-
"code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=
|
|
112
|
+
"code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=25, amount=50)"
|
|
106
113
|
},
|
|
107
114
|
{
|
|
108
115
|
"test_data_row_variable": "test_item_3",
|
|
109
|
-
"code": "test_item_3 = Item(order_id=3, product_id=3, quantity=
|
|
116
|
+
"code": "test_item_3 = Item(order_id=3, product_id=3, quantity=3, unit_price=75, amount=225)"
|
|
110
117
|
},
|
|
111
118
|
{
|
|
112
119
|
"test_data_row_variable": "test_item_4",
|
api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt
CHANGED
|
@@ -11,6 +11,9 @@ Use case: Check Credit
|
|
|
11
11
|
4. The Item amount is the quantity * unit_price
|
|
12
12
|
5. The Item unit_price is copied from the Product unit_price
|
|
13
13
|
|
|
14
|
+
Use case: App Integration
|
|
15
|
+
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
|
|
16
|
+
|
|
14
17
|
Ensure each customer has a unique name.
|
|
15
18
|
|
|
16
19
|
Ensure each Item quantity is not null.
|
api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/readme.md
CHANGED
|
@@ -1,8 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# Time Tracking and Billing
|
|
2
|
+
Here, we create a time-tracking system, being specific about tables and columns in the [002_create_db_models.prompt](./). Each table has additional attributes that are used to hold sums, counts, and formula. Each table has a Use Case definition that describes the business logic using natural language.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
## Command Line - create this system:
|
|
5
5
|
```bash
|
|
6
|
-
# create the
|
|
7
|
-
als genai --project-name=
|
|
6
|
+
# create the time_track system
|
|
7
|
+
$als genai --project-name=time_track --using=system/genai/examples/time_tracking_billing/002_create_db_models.prompt
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Review the created system
|
|
11
|
+
Open the time_track in VSCode or CodeSpaces and start the ApiLogicServer (F5). This will start the server and the react-admin site (http://localhost:5656). You should see Client, Project, Task, Timesheet, Person, and Invoice with sample data generated by WebGenAI.
|
|
12
|
+
|
|
13
|
+
## Review the Logic
|
|
14
|
+
The /logic directory contains the generated logic (/logic/wg_rules). This will show how natural language is translated into LogicBank rules (/logic/wg_rules/active_rules_export.py). The other rules[n].py in the wg_rules folder are used and tested by WebGenAI and can be ignored.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
# Exported Rules:
|
|
18
|
+
# Rule 1
|
|
19
|
+
# Total Hours entered is sum of timesheet hours worked
|
|
20
|
+
Rule.sum(derive=Person.total_hours_entered, as_sum_of=Timesheet.hours_worked)
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Add Security and Enable Defaults
|
|
25
|
+
The authentication service can be added using the command line
|
|
26
|
+
```
|
|
27
|
+
$als add-auth --provider-type=sql # Local SQLIte
|
|
28
|
+
$als add-auth --provider-type=keycloak # Local KeyCloak (see docs)
|
|
29
|
+
$als add-auth --provider-type=sql --db-url={database config} # Use SQL database User/Role
|
|
30
|
+
```
|
|
31
|
+
To ensure defaults are applied (impacts rules) we need to add a global environment variable in the environment and restart the application.
|
|
32
|
+
ALL_DEFAULTS=True
|
|
33
|
+
|
|
34
|
+
## Add Ontimize Application
|
|
35
|
+
To create an angular Ontimize application, you need to follow these steps. Note the name 'app' is your project name which you can change or create another project.
|
|
36
|
+
```
|
|
37
|
+
$cd timetrack
|
|
38
|
+
$als app-create --app=app #if the ui/app folder does not exist
|
|
39
|
+
$als app-build --app=app # generates pages from the API entities
|
|
40
|
+
$cd ui/app
|
|
41
|
+
|
|
42
|
+
$npm install && npm start # install and start the NodeJS/Angular app
|
|
43
|
+
|
|
44
|
+
# Launch your new Ontimize application (http://localhost:4299)
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Testing Time Tracker and Billing
|
|
49
|
+
You can delete the existing sample data or you can start by entering new data. To test the logic - follow these steps:
|
|
50
|
+
```
|
|
51
|
+
1. Enter new Client
|
|
52
|
+
2. Enter new Person (works for Client)
|
|
53
|
+
3. Enter new Project for client (enter billing rate)
|
|
54
|
+
4. Enter new Task for Project
|
|
55
|
+
5. Enter new Timesheet - enter task and person for client (enter hours worked)
|
|
56
|
+
|
|
57
|
+
Watch Rules fired in log and then review the sums, counts, formula and constraints.
|
|
58
|
+
Note: The Client total amount should be the same value as Project, Task, and Timesheet.
|
|
59
|
+
|
|
60
|
+
Bonus: Enter an Invoice for a Client/Project then add Invoice Item for a specific Client Task. Once the invoice is ready - we can add a new Event (logic) to send to Kafka.
|
|
8
61
|
```
|
api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Here is the simplified API for LogicBank:
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Translate the user prompt into a series of calls to Rule methods, described here.
|
|
4
4
|
|
|
5
5
|
Do not generate import statements.
|
|
6
6
|
|
|
@@ -126,6 +126,20 @@ class Rule:
|
|
|
126
126
|
return Copy(derive=derive, from_parent=from_parent)
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
@staticmethod
|
|
130
|
+
def after_flush_row_event(on_class: object, calling: Callable = None,
|
|
131
|
+
if_condition: any = None,
|
|
132
|
+
when_condition: any = None,
|
|
133
|
+
with_args: dict = None):
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
Prompt:
|
|
137
|
+
Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None
|
|
138
|
+
Response:
|
|
139
|
+
Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka,
|
|
140
|
+
if_condition=lambda row: row.date_shipped is not None,
|
|
141
|
+
with_args={"topic": "order_shipping"})
|
|
142
|
+
|
|
129
143
|
Expanded example:
|
|
130
144
|
|
|
131
145
|
Prompt:
|
api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc
CHANGED
|
Binary file
|
|
@@ -480,6 +480,7 @@ class ManyToOneRelationship(Relationship):
|
|
|
480
480
|
parent_accessor_from_fk = True
|
|
481
481
|
else:
|
|
482
482
|
self.preferred_name = inflect_engine.singular_noun(tablename) or tablename
|
|
483
|
+
# TODO - consider using the target class name as the preferred name (lower case fk -> a_child.parent)
|
|
483
484
|
|
|
484
485
|
|
|
485
486
|
# Add uselist=False to One-to-One relationships
|
|
@@ -1512,7 +1513,7 @@ else:
|
|
|
1512
1513
|
child_accessor = f' {child_accessor_name} : Mapped[List["{reln.source_cls}"]] = '\
|
|
1513
1514
|
f'relationship({multi_reln_fix}back_populates="{reln.parent_accessor_name}")\n'
|
|
1514
1515
|
|
|
1515
|
-
if model.name in ["Employee", "CharacterClass"]: # Emp has Department and Department1
|
|
1516
|
+
if model.name in ["Item", "Employee", "CharacterClass"]: # Emp has Department and Department1
|
|
1516
1517
|
debug_str = "nice breakpoint" # DND CharacterClass - check parent acceossor (class_ not class)
|
|
1517
1518
|
model.rendered_parent_relationships += parent_accessor
|
|
1518
1519
|
parent_model.rendered_child_relationships += child_accessor
|
|
Binary file
|
|
Binary file
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
Create a sqlite database for customers, orders, items and product
|
|
3
|
-
|
|
4
|
-
Hints: use autonum keys, allow nulls, Decimal types, foreign keys, no check constraints.
|
|
5
|
-
|
|
6
|
-
Include a notes field for orders.
|
|
7
|
-
|
|
8
|
-
Create a few rows of only customer and product data.
|
|
9
|
-
|
|
10
|
-
Enforce the Check Credit requirement (do not generate check constraints):
|
|
11
|
-
|
|
12
|
-
1. Customer.Balance <= CreditLimit
|
|
13
|
-
2. Customer.Balance = Sum(Order.AmountTotal where date shipped is null)
|
|
14
|
-
3. Order.AmountTotal = Sum(Items.Amount)
|
|
15
|
-
4. Items.Amount = Quantity * UnitPrice
|
|
16
|
-
5. Store the Items.UnitPrice as a copy from Product.UnitPrice
|