ApiLogicServer 14.2.2__py3-none-any.whl → 14.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/METADATA +2 -2
  2. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/RECORD +73 -54
  3. api_logic_server_cli/api_logic_server.py +47 -10
  4. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  5. api_logic_server_cli/cli.py +9 -3
  6. api_logic_server_cli/create_from_model/__pycache__/api_logic_server_utils.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  8. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  9. api_logic_server_cli/create_from_model/api_logic_server_utils.py +4 -0
  10. api_logic_server_cli/create_from_model/ont_build.py +53 -19
  11. api_logic_server_cli/create_from_model/ont_create.py +14 -5
  12. api_logic_server_cli/fragments/declare_logic.py +72 -0
  13. api_logic_server_cli/{prototypes/manager/system/genai/create_db_models_inserts/logic_discovery_prefix.py → fragments/declare_logic_begin.py} +2 -1
  14. api_logic_server_cli/fragments/declare_logic_end.py +52 -0
  15. api_logic_server_cli/genai/client.py +24 -0
  16. api_logic_server_cli/genai/genai.py +37 -17
  17. api_logic_server_cli/genai/genai_logic_builder.py +21 -35
  18. api_logic_server_cli/genai/genai_svcs.py +109 -13
  19. api_logic_server_cli/genai/genai_utils.py +0 -1
  20. api_logic_server_cli/model_migrator/model_migrator_start.py +1 -1
  21. api_logic_server_cli/model_migrator/reposreader.py +9 -1
  22. api_logic_server_cli/model_migrator/rule_obj.py +24 -6
  23. api_logic_server_cli/prototypes/base/api/api_discovery/ontimize_api.py +4 -1
  24. api_logic_server_cli/prototypes/base/config/activate_logicbank.py +8 -4
  25. api_logic_server_cli/prototypes/base/config/config.py +10 -6
  26. api_logic_server_cli/prototypes/base/database/bind_dbs.py +2 -1
  27. api_logic_server_cli/prototypes/base/database/test_data/readme.md +5 -5
  28. api_logic_server_cli/prototypes/base/logic/declare_logic.py +8 -3
  29. api_logic_server_cli/prototypes/base/logic/load_verify_rules.py +216 -0
  30. api_logic_server_cli/prototypes/base/logic/logic_discovery/auto_discovery.py +23 -11
  31. api_logic_server_cli/prototypes/genai_demo/database/models.py +11 -55
  32. api_logic_server_cli/prototypes/genai_demo/logic/declare_logic.py +29 -21
  33. api_logic_server_cli/prototypes/manager/.vscode/launch.json +3 -3
  34. api_logic_server_cli/prototypes/manager/README.md +25 -10
  35. api_logic_server_cli/prototypes/manager/system/genai/create_db_models_inserts/create_db_models_imports.py +1 -0
  36. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +19 -18
  37. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/.DS_Store +0 -0
  38. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/000_you_are.prompt +1 -0
  39. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/001_logic_training.prompt +314 -0
  40. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/002_create_db_models.prompt +150 -0
  41. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/003_create_db_models.response +134 -0
  42. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/004_iteratio_logic.prompt +131 -0
  43. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/005_create_db_models.response-example +141 -0
  44. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/create_db_models.py +105 -0
  45. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/db.dbml +70 -0
  46. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/readme.md +6 -0
  47. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/response.json +178 -0
  48. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  49. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  50. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  51. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  52. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/wg_genai_demo_no_logic_fixed_from_CLI/logic/declare_logic.py +0 -1
  53. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  54. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  55. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  56. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/wg_genai_demo_no_logic_fixed_from_CLI/logic/declare_logic.py +0 -1
  57. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/002_create_db_models.prompt +194 -0
  58. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/003_create_db_models.response +298 -0
  59. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/db.sqlite +0 -0
  60. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/readme.md +8 -0
  61. api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt +14 -10
  62. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/iteration.prompt +2 -1
  63. api_logic_server_cli/prototypes/nw_no_cust/venv_setup/system_note.txt +1 -1
  64. api_logic_server_cli/prototypes/ont_app/templates/home_tree_template.html +9 -0
  65. api_logic_server_cli/prototypes/ont_app/templates/tree_routing.jinja +32 -0
  66. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc +0 -0
  67. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/codegen.py +2 -1
  68. api_logic_server_cli/tools/mini_skel/logic/load_verify_rules.py +1 -1
  69. api_logic_server_cli/tools/mini_skel/run.py +1 -0
  70. api_logic_server_cli/model_migrator/system/custom_endpoint.py +0 -545
  71. api_logic_server_cli/prototypes/base/database/test_data/z_test_data_rows.py +0 -98
  72. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/LICENSE +0 -0
  73. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/WHEEL +0 -0
  74. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/entry_points.txt +0 -0
  75. {ApiLogicServer-14.2.2.dist-info → ApiLogicServer-14.3.0.dist-info}/top_level.txt +0 -0
@@ -23,18 +23,30 @@ def discover_logic():
23
23
  spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
24
24
  each_logic_file.declare_logic() # invoke create function
25
25
 
26
+ # if False and Path(__file__).parent.parent.parent.joinpath("docs/project_is_genai_demo.txt").exists():
27
+ # return # for genai_demo, logic is in logic/declare_logic.py (so ignore logic_discovery)
28
+
26
29
  wg_logic_path = Path(__file__).parent.parent.joinpath("wg_rules")
27
- for root, dirs, files in os.walk(wg_logic_path):
28
- for file in files:
29
- if file.endswith(".py"):
30
- spec = importlib.util.spec_from_file_location("module.name", wg_logic_path.joinpath(file))
31
- if file.endswith("auto_discovery.py"):
32
- pass
33
- else:
34
- logic.append(file)
35
- each_logic_file = importlib.util.module_from_spec(spec)
36
- spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
37
- each_logic_file.init_rule() # invoke create function
30
+ if wg_logic_path.exists():
31
+ run_local = os.environ.get("WG_PROJECT") is None # eg, running export locally
32
+ # run_local = False # for debug
33
+ if run_local:
34
+ wg_export_logic_path = Path(__file__).parent.parent.parent.joinpath("logic/wg_rules/active_rules_export.py")
35
+ if wg_export_logic_path.is_file():
36
+ spec = importlib.util.spec_from_file_location("module.name", wg_export_logic_path)
37
+ logic.append(str(wg_export_logic_path))
38
+ wg_export_logic_file = importlib.util.module_from_spec(spec)
39
+ spec.loader.exec_module(wg_export_logic_file) # runs "bare" module code (e.g., initialization)
40
+ wg_export_logic_file.declare_logic() # invoke create function
41
+ else:
42
+ for root, dirs, files in os.walk(wg_logic_path):
43
+ for file in files:
44
+ if file.endswith(".py") and 'active_rules_export.py' != file:
45
+ spec = importlib.util.spec_from_file_location("module.name", wg_logic_path.joinpath(file))
46
+ logic.append(file)
47
+ each_logic_file = importlib.util.module_from_spec(spec)
48
+ spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
49
+ each_logic_file.init_rule() # invoke create function
38
50
 
39
51
  app_logger.info(f"..discovered logic: {logic}")
40
52
  return
@@ -16,9 +16,9 @@ from sqlalchemy.ext.declarative import declarative_base
16
16
  # mypy: ignore-errors
17
17
  ########################################################################################################################
18
18
 
19
- from safrs import SAFRSBase
19
+ from database.system.SAFRSBaseX import SAFRSBaseX, TestBase
20
20
  from flask_login import UserMixin
21
- import safrs, flask_sqlalchemy
21
+ import safrs, flask_sqlalchemy, os
22
22
  from safrs import jsonapi_attr
23
23
  from flask_sqlalchemy import SQLAlchemy
24
24
  from sqlalchemy.orm import relationship
@@ -35,12 +35,16 @@ metadata = Base.metadata
35
35
 
36
36
  from sqlalchemy.dialects.sqlite import *
37
37
 
38
+ if os.getenv('APILOGICPROJECT_NO_FLASK') is None or os.getenv('APILOGICPROJECT_NO_FLASK') == 'None':
39
+ Base = SAFRSBaseX # enables rules to be used outside of Flask, e.g., test data loading
40
+ else:
41
+ Base = TestBase # ensure proper types, so rules work for data loading
42
+ print('*** Models.py Using TestBase ***')
38
43
 
39
44
 
40
- class Customer(SAFRSBase, Base):
45
+ class Customer(Base):
41
46
  __tablename__ = 'Customers'
42
47
  _s_collection_name = 'Customer' # type: ignore
43
- __bind_key__ = 'None'
44
48
 
45
49
  CustomerID = Column(Integer, primary_key=True)
46
50
  CustomerName = Column(Text, nullable=False)
@@ -54,23 +58,10 @@ class Customer(SAFRSBase, Base):
54
58
  # child relationships (access children)
55
59
  OrderList : Mapped[List["Order"]] = relationship(back_populates="Customer")
56
60
 
57
- @jsonapi_attr
58
- def _check_sum_(self): # type: ignore [no-redef]
59
- return None if isinstance(self, flask_sqlalchemy.model.DefaultMeta) \
60
- else self._check_sum_property if hasattr(self,"_check_sum_property") \
61
- else None # property does not exist during initialization
62
61
 
63
- @_check_sum_.setter
64
- def _check_sum_(self, value): # type: ignore [no-redef]
65
- self._check_sum_property = value
66
-
67
- S_CheckSum = _check_sum_
68
-
69
-
70
- class Product(SAFRSBase, Base):
62
+ class Product(Base):
71
63
  __tablename__ = 'Products'
72
64
  _s_collection_name = 'Product' # type: ignore
73
- __bind_key__ = 'None'
74
65
 
75
66
  ProductID = Column(Integer, primary_key=True)
76
67
  ProductName = Column(Text, nullable=False)
@@ -82,23 +73,11 @@ class Product(SAFRSBase, Base):
82
73
  # child relationships (access children)
83
74
  ItemList : Mapped[List["Item"]] = relationship(back_populates="Product")
84
75
 
85
- @jsonapi_attr
86
- def _check_sum_(self): # type: ignore [no-redef]
87
- return None if isinstance(self, flask_sqlalchemy.model.DefaultMeta) \
88
- else self._check_sum_property if hasattr(self,"_check_sum_property") \
89
- else None # property does not exist during initialization
90
-
91
- @_check_sum_.setter
92
- def _check_sum_(self, value): # type: ignore [no-redef]
93
- self._check_sum_property = value
94
-
95
- S_CheckSum = _check_sum_
96
76
 
97
77
 
98
- class Order(SAFRSBase, Base):
78
+ class Order(Base):
99
79
  __tablename__ = 'Orders'
100
80
  _s_collection_name = 'Order' # type: ignore
101
- __bind_key__ = 'None'
102
81
 
103
82
  OrderID = Column(Integer, primary_key=True)
104
83
  CustomerID = Column(ForeignKey('Customers.CustomerID'))
@@ -113,23 +92,11 @@ class Order(SAFRSBase, Base):
113
92
  # child relationships (access children)
114
93
  ItemList : Mapped[List["Item"]] = relationship(back_populates="Order")
115
94
 
116
- @jsonapi_attr
117
- def _check_sum_(self): # type: ignore [no-redef]
118
- return None if isinstance(self, flask_sqlalchemy.model.DefaultMeta) \
119
- else self._check_sum_property if hasattr(self,"_check_sum_property") \
120
- else None # property does not exist during initialization
121
95
 
122
- @_check_sum_.setter
123
- def _check_sum_(self, value): # type: ignore [no-redef]
124
- self._check_sum_property = value
125
96
 
126
- S_CheckSum = _check_sum_
127
-
128
-
129
- class Item(SAFRSBase, Base):
97
+ class Item(Base):
130
98
  __tablename__ = 'Items'
131
99
  _s_collection_name = 'Item' # type: ignore
132
- __bind_key__ = 'None'
133
100
 
134
101
  ItemID = Column(Integer, primary_key=True)
135
102
  OrderID = Column(ForeignKey('Orders.OrderID'))
@@ -144,14 +111,3 @@ class Item(SAFRSBase, Base):
144
111
 
145
112
  # child relationships (access children)
146
113
 
147
- @jsonapi_attr
148
- def _check_sum_(self): # type: ignore [no-redef]
149
- return None if isinstance(self, flask_sqlalchemy.model.DefaultMeta) \
150
- else self._check_sum_property if hasattr(self,"_check_sum_property") \
151
- else None # property does not exist during initialization
152
-
153
- @_check_sum_.setter
154
- def _check_sum_(self, value): # type: ignore [no-redef]
155
- self._check_sum_property = value
156
-
157
- S_CheckSum = _check_sum_
@@ -20,19 +20,16 @@ def declare_logic():
20
20
  ''' Declarative multi-table derivations and constraints, extensible with Python.
21
21
 
22
22
  Brief background: see readme_declare_logic.md
23
-
24
- Your Code Goes Here - Use code completion (Rule.) to declare rules
25
23
 
26
- GenAI: Paste the following into Copilot Chat, and paste the result below.
24
+ GenAI: the following prompt was sent to GenAI-Logic, which translated it into the code below:
27
25
 
28
- Use Logic Bank to enforce these requirements:
26
+ Use case: Check Credit
29
27
 
30
- Enforce the Check Credit requirement (do not generate check constraints):
31
- 1. Customer.Balance <= CreditLimit
32
- 2. Customer.Balance = Sum(Order.AmountTotal where date shipped is null)
33
- 3. Order.AmountTotal = Sum(Items.Amount)
34
- 4. Items.Amount = Quantity * UnitPrice
35
- 5. Store the Items.UnitPrice as a copy from Product.UnitPrice
28
+ 1. The Customer's balance is less than the credit limit
29
+ 2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
30
+ 3. The Order's amount_total is the sum of the Item amount
31
+ 4. The Item amount is the quantity * unit_price
32
+ 5. The Item unit_price is copied from the Product unit_price
36
33
  '''
37
34
 
38
35
  from logic_bank.logic_bank import Rule
@@ -40,39 +37,50 @@ def declare_logic():
40
37
  from logic.logic_discovery.auto_discovery import discover_logic
41
38
  discover_logic()
42
39
 
43
- # Logic from GenAI: (or, use your IDE w/ code completion)n
40
+ # Logic from GenAI: (or, use your IDE w/ code completion)
41
+
42
+ # Ensures the customer's balance is less than the credit limit.
43
+ Rule.constraint(validate=Customer,
44
+ as_condition=lambda row: row.Balance <= row.CreditLimit,
45
+ error_msg="Customer balance ({row.Balance}) exceeds credit limit ({row.CreditLimit})")
46
+
47
+ # Computes the customer's balance as the sum of unshipped orders.
44
48
  Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal, where=lambda row: row.ShipDate is None)
49
+
50
+ # Computes the total amount of an order as the sum of item amounts.
45
51
  Rule.sum(derive=Order.AmountTotal, as_sum_of=Item.Amount)
52
+
53
+ # Calculates the item amount as the quantity times unit price. (original rule, prior to iteration)
46
54
  # Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)
55
+
56
+ # Copies the unit price from the parent product to the item.
47
57
  Rule.copy(derive=Item.UnitPrice, from_parent=Product.UnitPrice)
48
- Rule.constraint(validate=Customer,
49
- as_condition=lambda row: row.Balance <= row.CreditLimit,
50
- error_msg="Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})")
51
58
 
52
59
  # End Logic from GenAI
53
60
 
61
+
62
+ #als: Demonstrate that logic == Rules + Python (for extensibility)
63
+
64
+ # 4. Items.Amount = Quantity * UnitPrice, altered with IDE for CarbonNeutral discount
54
65
  def derive_amount(row: Item, old_row: Item, logic_row: LogicRow):
55
66
  amount = row.Quantity * row.UnitPrice
56
67
  if row.Product.CarbonNeutral == True and row.Quantity >= 10:
57
68
  amount = amount * Decimal(0.9) # breakpoint here
58
69
  return amount
59
-
60
- # 4. Items.Amount = Quantity * UnitPrice
61
- Rule.formula(derive=Item.Amount, calling=derive_amount)
62
-
63
- #als: Demonstrate that logic == Rules + Python (for extensibility)
70
+ # now register function; note logic ordering is automatic
71
+ Rule.formula(derive=Item.Amount, calling=derive_amount)
64
72
 
65
73
  def send_order_to_shipping(row: Order, old_row: Order, logic_row: LogicRow):
66
74
  """ #als: Send Kafka message formatted by OrderShipping RowDictMapper
67
75
 
68
76
  Format row per shipping requirements, and send (e.g., a message)
69
77
 
70
- NB: the after_flush event makes Order.Id avaible. Contrast to congratulate_sales_rep().
78
+ NB: the after_flush event makes Order.Id avaible.
71
79
 
72
80
  Args:
73
81
  row (Order): inserted Order
74
82
  old_row (Order): n/a
75
- logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt logic
83
+ logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt (etc) state
76
84
  """
77
85
  if logic_row.is_inserted():
78
86
  kafka_producer.send_kafka_message(logic_row=logic_row,
@@ -5,7 +5,7 @@
5
5
  "version": "0.2.0",
6
6
  "configurations": [
7
7
  {
8
- "name": "1. GENAI - Create a project from one of the system/genai/examples",
8
+ "name": "1. GENAI - Create genai_logic demo project",
9
9
  "type": "debugpy",
10
10
  "request": "launch",
11
11
  "program": "${workspaceFolder}/venv/lib/python3.12/site-packages/api_logic_server_cli/cli.py",
@@ -18,8 +18,8 @@
18
18
  "APILOGICSERVER_DEBUG": "False",
19
19
  "OPT_LOCKING": "optional"},
20
20
  "justMyCode": false,
21
- "args": [ "genai", "--retries=-1",
22
- "--using=${workspaceFolder}/system/genai/examples/${input:inputGenaiProjectName}"],
21
+ "args": [ "genai", "--retries=-1", "--project-name=genai_demo",
22
+ "--using=${workspaceFolder}/system/genai/examples/genai_demo/genai_demo_informal.prompt"],
23
23
  "console": "internalConsole",
24
24
  "internalConsoleOptions": "openOnSessionStart"
25
25
  },
@@ -101,7 +101,7 @@ Then, try your own databases [(db-url examples here)](https://apilogicserver.git
101
101
  1. If you have signed up, this will create and open a project called `genai_demo` from `genai_demo.prompt` (available in left Explorer pane):
102
102
 
103
103
  ```bash
104
- als genai --using=system/genai/examples/genai_demo/genai_demo.prompt
104
+ als genai --using=system/genai/examples/genai_demo/genai_demo.prompt --project-name=genai_demo
105
105
  ```
106
106
 
107
107
 
@@ -109,7 +109,7 @@ als genai --using=system/genai/examples/genai_demo/genai_demo.prompt
109
109
 
110
110
 
111
111
  ```bash
112
- als genai --using=genai_demo.prompt --repaired-response=system/genai/examples/genai_demo/genai_demo_iteration/005_create_db_models.response-example
112
+ als genai --repaired-response=system/genai/examples/genai_demo/genai_demo_iteration/005_create_db_models.response-example --project-name=genai_demo
113
113
  ```
114
114
 
115
115
  Verify it's operating properly:
@@ -140,7 +140,7 @@ Verify it's operating properly:
140
140
 
141
141
  2. Your created project is opened in your IDE, ready to execute and customize.
142
142
 
143
- a. Review `Sample-Genai.md`, Explore Customizations.
143
+ a. Review `Tutorial.md`, Explore Customizations.
144
144
 
145
145
  ![GenAI Automation](system/images/genai.png)
146
146
 
@@ -149,9 +149,22 @@ Verify it's operating properly:
149
149
 
150
150
  <details markdown>
151
151
 
152
- <summary> You can iterate the data model and logic</summary>
152
+ <summary> You can iterate the logic and data model</summary>
153
153
 
154
- <br>You can add new columns/tables, while keeping the prior model intact:
154
+ <br>Logic iterations are particuarly useful. For example, here we take the basic check-credit logic, and add:
155
+
156
+ > Provide a 10% discount when buying more than 10 carbon neutral products.<br><br>The Item carbon neutral is copied from the Product carbon neutral
157
+
158
+ Explore [genai_demo_iteration_discount](system/genai/examples/genai_demo/genai_demo_iteration_discount). This will add carbon_neutral to the data model, and update the logic to provide the discount:
159
+
160
+ ```bash title='Iterate Business Logic'
161
+ # Iterate with data model and logic
162
+ als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
163
+ # open Docs/db.dbml
164
+ ```
165
+ <br>
166
+
167
+ You can add new columns/tables, while keeping the prior model intact:
155
168
 
156
169
  ```bash title='Iterate Without Logic'
157
170
  # Step 1 - create without logic
@@ -164,7 +177,9 @@ als genai --project-name='genai_demo_no_logic' --using=system/genai/examples/gen
164
177
  als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
165
178
  # open Docs/db.dbml
166
179
  ```
167
- > Explore [genai_demo_iteration](system/genai/examples/genai_demo/genai_demo_iteration) - observe the `--using` is a *directory* of prompts. These include the prompts from the first example, plus an *iteration prompt* (`004_iteration_renames_logic.prompt`) to rename tables and add logic.
180
+
181
+ Explore [genai_demo_iteration](system/genai/examples/genai_demo/genai_demo_iteration) - observe the `--using` is a *directory* of prompts. These include the prompts from the first example, plus an *iteration prompt* (`004_iteration_renames_logic.prompt`) to rename tables and add logic.
182
+
168
183
 
169
184
  </details>
170
185
  </br>
@@ -274,7 +289,7 @@ After starting the [Manager](https://apilogicserver.github.io/Docs/Manager):
274
289
 
275
290
  ```bash title="0. Create Project Requiring Fixup"
276
291
  # 0. Create a project requiring fixup
277
- als genai --using=genai_demo.prompt --repaired-response=system/genai/examples/genai_demo/genai_demo_fixup_required.json --project-name=genai_demo_fixup_required
292
+ als genai --repaired-response=system/genai/examples/genai_demo/genai_demo_fixup_required.json --project-name=genai_demo_fixup_required
278
293
  ```
279
294
 
280
295
  If you run this project, you will observe that it fails with:
@@ -298,7 +313,7 @@ Finally, use the created [fixup files](genai_demo_fixup_required/docs/fixup/) to
298
313
  ```bash title="2. Rebuild the project from the fixup response data model"
299
314
  # 2. Rebuild the project from the fixup response data model
300
315
  cd ../
301
- als genai --using=genai_demo.prompt --repaired-response=genai_demo_fixup_required/docs/fixup/response_fixup.json --project-name=fixed_project
316
+ als genai --repaired-response=genai_demo_fixup_required/docs/fixup/response_fixup.json --project-name=fixed_project
302
317
  ```
303
318
 
304
319
  &nbsp;
@@ -390,7 +405,7 @@ als create --project-name=genai_demo --from-model=system/genai/temp/create_db_mo
390
405
  Or, correct the chatgpt response, and
391
406
 
392
407
  ```bash
393
- als genai --using=genai_demo.prompt --repaired-response=system/genai/examples/genai_demo/genai_demo.response_example --project-name=genai_demo
408
+ als genai --repaired-response=system/genai/examples/genai_demo/genai_demo.response_example --project-name=genai_demo
394
409
  ```
395
410
 
396
411
  We have seen failures such as:
@@ -583,7 +598,7 @@ als genai --using=system/genai/examples/genai_demo/genai_demo.prompt
583
598
 
584
599
  # Or, Microservice Automation from Saved Response
585
600
  # Admin App, API, Project
586
- als genai --using=genai_demo.prompt --repaired-response=system/genai/temp/chatgpt_retry.response
601
+ als genai --repaired-response=system/genai/temp/chatgpt_retry.response
587
602
 
588
603
  # Logic and Security
589
604
  # - see logic (logic/declare_logic.py, logic/cocktail-napkin.jpg); add an Order and Item
@@ -7,6 +7,7 @@ import decimal
7
7
  import logging
8
8
  import sqlalchemy
9
9
  from sqlalchemy.sql import func
10
+ from decimal import Decimal
10
11
  from logic_bank.logic_bank import Rule
11
12
  from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Date, DateTime, Numeric, Boolean, Text, DECIMAL
12
13
  from sqlalchemy.types import *
@@ -2,62 +2,63 @@
2
2
  "models": [
3
3
  {
4
4
  "classname": "Customer",
5
- "code": "class Customer(Base):\n __tablename__ = 'customers'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n balance = Column(Integer, default=0)\n credit_limit = Column(Integer, nullable=False)\n\n def __repr__(self):\n return f\"Customer(id={self.id}, name='{self.name}', balance={self.balance}, credit_limit={self.credit_limit})\"",
6
- "sqlite_create": "CREATE TABLE customers (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n name VARCHAR NOT NULL, \n balance INTEGER DEFAULT 0, \n credit_limit INTEGER NOT NULL\n)",
7
- "description": "description: Customers table",
8
- "name": "customers"
5
+ "code": "class Customer(Base):\n __tablename__ = 'customer'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n balance = Column(DECIMAL)\n credit_limit = Column(DECIMAL)",
6
+ "description": "Represents a customer in the system with unique name, balance, and credit limit attributes.",
7
+ "name": "Customer"
9
8
  },
10
9
  {
11
10
  "classname": "Order",
12
- "code": "class Order(Base):\n __tablename__ = 'orders'\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customers.id'))\n notes = Column(String)\n date_shipped = Column(Date)\n amount_total = Column(Integer, default=0)\n\n def __repr__(self):\n return f\"Order(id={self.id}, customer_id={self.customer_id}, notes='{self.notes}', amount_total={self.amount_total}, date_shipped={self.date_shipped})\"",
13
- "sqlite_create": "CREATE TABLE orders (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n customer_id INTEGER, \n notes VARCHAR, \n date_shipped DATE, \n amount_total INTEGER DEFAULT 0, \n FOREIGN KEY(customer_id) REFERENCES customers (id)\n)",
14
- "description": "description: Orders table",
15
- "name": "orders"
11
+ "code": "class Order(Base):\n __tablename__ = 'order'\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customer.id'))\n date_shipped = Column(Date)\n amount_total = Column(DECIMAL)\n notes = Column(String)",
12
+ "description": "Represents an order made by a customer, including a notes field.",
13
+ "name": "Order"
16
14
  },
17
15
  {
18
16
  "classname": "Item",
19
- "code": "class Item(Base):\n __tablename__ = 'items'\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('orders.id'))\n product_id = Column(Integer, ForeignKey('products.id'))\n quantity = Column(Integer, nullable=False)\n unit_price = Column(Integer, nullable=False)\n amount = Column(Integer, default=0)\n\n def __repr__(self):\n return f\"Item(id={self.id}, order_id={self.order_id}, product_id={self.product_id}, quantity={self.quantity}, unit_price={self.unit_price}, amount={self.amount})\"",
20
- "sqlite_create": "CREATE TABLE items (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n order_id INTEGER, \n product_id INTEGER, \n quantity INTEGER NOT NULL, \n unit_price INTEGER NOT NULL, \n amount INTEGER DEFAULT 0, \n FOREIGN KEY(order_id) REFERENCES orders (id), \n FOREIGN KEY(product_id) REFERENCES products (id)\n)",
21
- "description": "description: Items table",
22
- "name": "items"
17
+ "code": "class Item(Base):\n __tablename__ = 'item'\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'))\n quantity = Column(Integer, nullable=False)\n unit_price = Column(DECIMAL)\n amount = Column(DECIMAL)",
18
+ "description": "Represents an item in an order, including quantity and pricing details.",
19
+ "name": "Item"
23
20
  },
24
21
  {
25
22
  "classname": "Product",
26
- "code": "class Product(Base):\n __tablename__ = 'products'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n unit_price = Column(Integer, nullable=False)\n\n def __repr__(self):\n return f\"Product(id={self.id}, name='{self.name}', unit_price={self.unit_price})\"",
27
- "sqlite_create": "CREATE TABLE products (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n name VARCHAR NOT NULL, \n unit_price INTEGER NOT NULL\n)",
28
- "description": "description: Products table",
29
- "name": "products"
23
+ "code": "class Product(Base):\n __tablename__ = 'product'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String)\n unit_price = Column(DECIMAL)",
24
+ "description": "Represents a product available in the system with a unit price.",
25
+ "name": "Product"
30
26
  }
31
27
  ],
32
28
  "rules": [
33
29
  {
34
30
  "name": "Customer Balance Constraint",
35
- "description": "Ensures the customer's balance does not exceed the credit limit.",
31
+ "description": "Ensures the customer's balance is aligned with the credit limit.",
36
32
  "use_case": "Customer.balance <= credit_limit",
37
- "code": "Rule.constraint(validate=Customer,\n as_condition=lambda row: row.balance <= row.credit_limit,\n error_msg=\"Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})\")"
33
+ "entity": "Customer",
34
+ "code": "Rule.constraint(validate=Customer,\n as_condition=lambda row: row.balance <= row.credit_limit,\n error_msg='Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})')"
38
35
  },
39
36
  {
40
37
  "name": "Customer Balance Derivation",
41
38
  "description": "Calculates the customer's balance as the sum of orders' amount_total where date_shipped is null.",
42
39
  "use_case": "Customer.balance = Sum(Order.amount_total where date_shipped is null)",
40
+ "entity": "Customer",
43
41
  "code": "Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)"
44
42
  },
45
43
  {
46
44
  "name": "Order Amount Total Derivation",
47
45
  "description": "Calculates order's amount_total as the sum of item amounts.",
48
46
  "use_case": "Order.amount_total = Sum(Item.amount)",
47
+ "entity": "Order",
49
48
  "code": "Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)"
50
49
  },
51
50
  {
52
51
  "name": "Item Amount Derivation",
53
52
  "description": "Calculates item amount as quantity multiplied by unit price.",
54
53
  "use_case": "Item.amount = quantity * unit_price",
54
+ "entity": "Item",
55
55
  "code": "Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)"
56
56
  },
57
57
  {
58
58
  "name": "Copy Item Unit Price",
59
59
  "description": "Copies the product's unit price to the item.",
60
60
  "use_case": "Store the Item.unit_price as a copy from Product.unit_price",
61
+ "entity": "Item",
61
62
  "code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
62
63
  }
63
64
  ],
@@ -0,0 +1 @@
1
+ You are a data modelling expert and python software architect who expands on user input ideas. You create data models with at least 4 tables