ApiLogicServer 14.3.25__py3-none-any.whl → 14.5.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.
- api_logic_server_cli/add_cust/add_cust.py +283 -0
- api_logic_server_cli/api_logic_server.py +18 -250
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +54 -35
- api_logic_server_cli/create_from_model/__pycache__/api_logic_server_utils.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/create_db_from_model.cpython-312.pyc +0 -0
- 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/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/api_logic_server_utils.py +47 -0
- api_logic_server_cli/create_from_model/create_db_from_model.py +2 -0
- api_logic_server_cli/create_from_model/dbml.py +113 -58
- api_logic_server_cli/create_from_model/ont_build.py +102 -74
- api_logic_server_cli/create_from_model/ont_create.py +7 -6
- api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +0 -0
- api_logic_server_cli/database/basic_demo.sqlite +0 -0
- api_logic_server_cli/database/basic_demo.txt +1 -0
- api_logic_server_cli/database/basic_demo_wg.sqlite +0 -0
- api_logic_server_cli/database/nw-gold-fix.sql +62 -0
- api_logic_server_cli/database/nw-gold.sqlite +0 -0
- api_logic_server_cli/{prototypes/manager/webgenai → fragments}/docker-compose.yml +1 -1
- api_logic_server_cli/genai/genai.py +42 -11
- api_logic_server_cli/genai/genai_graphics.py +252 -38
- api_logic_server_cli/genai/genai_svcs.py +20 -12
- api_logic_server_cli/manager.py +22 -12
- api_logic_server_cli/prototypes/.DS_Store +0 -0
- api_logic_server_cli/prototypes/base/.DS_Store +0 -0
- api_logic_server_cli/prototypes/base/.vscode/launch.json +22 -2
- api_logic_server_cli/prototypes/base/api/expose_api_models.py +3 -1
- api_logic_server_cli/prototypes/base/api_logic_server_run.py +5 -2
- api_logic_server_cli/prototypes/base/config/activate_logicbank.py +1 -0
- api_logic_server_cli/prototypes/base/config/config.py +123 -25
- api_logic_server_cli/prototypes/base/config/default.env +7 -1
- api_logic_server_cli/prototypes/base/config/logging.yml +1 -0
- api_logic_server_cli/prototypes/base/config/server_setup.py +33 -1
- api_logic_server_cli/prototypes/base/database/test_data/readme.md +5 -2
- api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
- api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +314 -0
- api_logic_server_cli/prototypes/base/docs/training/logic_example.py +41 -0
- api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +12 -5
- api_logic_server_cli/prototypes/base/integration/n8n/n8n_producer.py +68 -21
- api_logic_server_cli/prototypes/base/integration/n8n/n8n_readme.md +19 -0
- api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
- api_logic_server_cli/prototypes/base/test/basic/server_test.py +1 -1
- api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
- api_logic_server_cli/prototypes/basic_demo/README.md +29 -52
- api_logic_server_cli/prototypes/basic_demo/customizations/api/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_server_executor.py +138 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/openapi.py +92 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/proper_update_def.json +71 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/config/default.env +13 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/models.py +131 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/.DS_Store +0 -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/1_langchain_loader.py +71 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +13 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_client_executor.py +295 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +47 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +9 -0
- 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 +49 -0
- 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 +73 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/curl.txt +5 -0
- 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 +10 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/2 - completion_tool_context.json +12 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/llm_schema.txt +38 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_2.yaml +17393 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3_relaxed.yaml +109 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_server.py +51 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_serverZ.py +72 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/validate_jsonapi.py +64 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/run_executor.py +23 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/swagger_converter.py +65 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/z_old/3_executor_test_agent.py +52 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/3_executor_test_agent.py +52 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/README_functon.md +201 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/ai_plugin.json +17 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/nw-swagger_3.json +1731 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/snippets.txt +5 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3 genai_demo_with_get.json +1731 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3.json +1782 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo.json +264 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo_with_update.json +1782 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +62 -44
- api_logic_server_cli/prototypes/basic_demo/customizations/security/declare_security.py +11 -12
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +166 -0
- api_logic_server_cli/prototypes/basic_demo/iteration/api/{customize_api.py → api_discovery/order_b2b.py} +17 -23
- api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderB2B.py +6 -5
- api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderShipping.py +4 -4
- api_logic_server_cli/prototypes/basic_demo/iteration/logic/declare_logic.py +69 -43
- api_logic_server_cli/prototypes/basic_demo/iteration/ui/admin/admin.yaml +125 -50
- api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
- api_logic_server_cli/prototypes/manager/README.md +30 -4
- api_logic_server_cli/prototypes/manager/README_X.md +663 -0
- api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +0 -10
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +32 -10
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/002_create_db_models.prompt +4 -4
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/003_create_db_models.response +77 -47
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja +83 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py +34 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/{graphics_services.py → graphics_services_api_xxx.py} +0 -9
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja +46 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db_each_method.jinja +36 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +7 -3
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +8 -1
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +100 -0
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.sh +116 -0
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/readme.md +7 -0
- api_logic_server_cli/prototypes/manager/system/style-guide.yaml +2 -2
- api_logic_server_cli/prototypes/manager/webgenai/README.md +6 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/count_orders_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/order_count_by_month.prompt +1 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/request copy.json +892 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/request.json +6 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/response.json +17 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/response.yaml +59 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/sales_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -4
- api_logic_server_cli/prototypes/nw/ui/app_model_custom.yaml +851 -1082
- api_logic_server_cli/prototypes/nw_no_cust/Tutorial.md +45 -26
- api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/openapi.py +130 -0
- api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/proper_update_def.json +71 -0
- api_logic_server_cli/prototypes/nw_no_cust/config/default.env +13 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/count_orders_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_employee.prompt +1 -0
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/nginx/nginx.conf +2 -2
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/package-lock.json +9725 -1180
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +6 -9
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/app.config.ts +2 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/shared/app.services.config.ts +1 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/css/app.scss +4 -0
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/en.json +1 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/es.json +14 -12
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.prod.ts +5 -5
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.ts +5 -5
- api_logic_server_cli/prototypes/ont_app/templates/app_config.jinja +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/date_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/detail_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
- api_logic_server_cli/prototypes/ont_app/templates/textarea_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/timestamp_template.html +1 -1
- api_logic_server_cli/prototypes/sample_ai/logic/declare_logic.py +30 -13
- apilogicserver-14.5.0.dist-info/METADATA +76 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/RECORD +160 -88
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/WHEEL +1 -1
- api_logic_server_cli/prototypes/basic_demo/apply_customizations.ps1 +0 -17
- api_logic_server_cli/prototypes/basic_demo/apply_customizations.sh +0 -14
- api_logic_server_cli/prototypes/basic_demo/apply_iteration.ps1 +0 -20
- api_logic_server_cli/prototypes/basic_demo/apply_iteration.sh +0 -15
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_jsonapi_rpc.jinja +0 -37
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_unused.jinja +0 -38
- apilogicserver-14.3.25.dist-info/METADATA +0 -167
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/entry_points.txt +0 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/top_level.txt +0 -0
api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example
CHANGED
|
@@ -71,25 +71,47 @@
|
|
|
71
71
|
],
|
|
72
72
|
"graphics": [
|
|
73
73
|
{
|
|
74
|
-
"sqlalchemy_query": "
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
74
|
+
"sqlalchemy_query": "session.query(Product.name, func.sum(Item.amount).label('TotalSales')).join(Item, Product.id == Item.product_id).filter(Order.date_shipped.isnot(None)).group_by(Product.name).order_by(func.sum(Item.amount).desc())",
|
|
75
|
+
"sql_query": "SELECT Product.name, SUM(Item.amount) AS TotalSales FROM Product JOIN Item ON Product.id = Item.product_id JOIN Order ON Item.order_id = Order.id WHERE Order.date_shipped IS NOT NULL GROUP BY Product.name ORDER BY TotalSales DESC",
|
|
76
|
+
"classes_used": "Product, Item, Order",
|
|
77
|
+
"class_x_axis": "Product",
|
|
78
|
+
"name": "sales_by_product",
|
|
79
|
+
"prompt": "Graph Sales by Product",
|
|
80
|
+
"title": "Sales by Product",
|
|
81
|
+
"xAxis": "Product",
|
|
82
|
+
"yAxis": "Total Sales",
|
|
83
|
+
"dashboard": true,
|
|
84
|
+
"graph_type": "Bar",
|
|
85
|
+
"html_code": "var data = result.result; var categories = data.map(item => item[0]); var totals = data.map(item => item[1]); var ctx = document.getElementById('salesByProductChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: categories, datasets: [{label: 'Sales by Product', data: totals}]}});"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"sqlalchemy_query": "session.query(Customer.name, func.sum(Order.amount_total).label('TotalCustomerSales')).join(Order, Customer.id == Order.customer_id).filter(Order.date_shipped.isnot(None)).group_by(Customer.name).order_by(func.sum(Order.amount_total).desc())",
|
|
89
|
+
"sql_query": "SELECT Customer.name, SUM(Order.amount_total) AS TotalCustomerSales FROM Customer JOIN Order ON Customer.id = Order.customer_id WHERE Order.date_shipped IS NOT NULL GROUP BY Customer.name ORDER BY TotalCustomerSales DESC",
|
|
90
|
+
"classes_used": "Customer, Order",
|
|
91
|
+
"class_x_axis": "Customer",
|
|
92
|
+
"name": "sales_by_customer",
|
|
93
|
+
"prompt": "Graph Sales by Customer",
|
|
94
|
+
"title": "Sales by Customer",
|
|
95
|
+
"xAxis": "Customer",
|
|
96
|
+
"yAxis": "Total Sales",
|
|
97
|
+
"dashboard": true,
|
|
98
|
+
"graph_type": "Bar",
|
|
99
|
+
"html_code": "var data = result.result; var customers = data.map(item => item[0]); var sales = data.map(item => item[1]); var ctx = document.getElementById('salesByCustomerChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: customers, datasets: [{label: 'Sales by Customer', data: sales}]}});"
|
|
78
100
|
}
|
|
79
101
|
],
|
|
80
102
|
"test_data": "This is the test data generated for Customers, Orders, Items, and Products in the new system.",
|
|
81
103
|
"test_data_rows": [
|
|
82
104
|
{
|
|
83
105
|
"test_data_row_variable": "customer1",
|
|
84
|
-
"code": "customer1 = Customer(name=\"Alice\", balance=
|
|
106
|
+
"code": "customer1 = Customer(name=\"Alice\", balance=90.00, credit_limit=5000.00)"
|
|
85
107
|
},
|
|
86
108
|
{
|
|
87
109
|
"test_data_row_variable": "customer2",
|
|
88
|
-
"code": "customer2 = Customer(name=\"Bob\", balance=
|
|
110
|
+
"code": "customer2 = Customer(name=\"Bob\", balance=0.00, credit_limit=3000.00)"
|
|
89
111
|
},
|
|
90
112
|
{
|
|
91
113
|
"test_data_row_variable": "customer3",
|
|
92
|
-
"code": "customer3 = Customer(name=\"Charlie\", balance=
|
|
114
|
+
"code": "customer3 = Customer(name=\"Charlie\", balance=220.00, credit_limit=2000.00)"
|
|
93
115
|
},
|
|
94
116
|
{
|
|
95
117
|
"test_data_row_variable": "customer4",
|
|
@@ -113,15 +135,15 @@
|
|
|
113
135
|
},
|
|
114
136
|
{
|
|
115
137
|
"test_data_row_variable": "order1",
|
|
116
|
-
"code": "order1 = Order(notes=\"First Order\", customer_id=
|
|
138
|
+
"code": "order1 = Order(notes=\"First Order\", customer_id=2, date_shipped=date(2023, 3, 22), amount_total=300.00)"
|
|
117
139
|
},
|
|
118
140
|
{
|
|
119
141
|
"test_data_row_variable": "order2",
|
|
120
|
-
"code": "order2 = Order(notes=\"Second Order\", customer_id=
|
|
142
|
+
"code": "order2 = Order(notes=\"Second Order\", customer_id=1, date_shipped=None, amount_total=90.00)"
|
|
121
143
|
},
|
|
122
144
|
{
|
|
123
145
|
"test_data_row_variable": "order3",
|
|
124
|
-
"code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=
|
|
146
|
+
"code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=220.00)"
|
|
125
147
|
},
|
|
126
148
|
{
|
|
127
149
|
"test_data_row_variable": "order4",
|
|
@@ -5,8 +5,6 @@ Create a system with customers, orders, items and products.
|
|
|
5
5
|
|
|
6
6
|
Include a notes field for orders.
|
|
7
7
|
|
|
8
|
-
Use LogicBank to enforce these requirements (do not generate check constraints); be sure to update the data model and *all* test data with any attributes used in the logic:
|
|
9
|
-
|
|
10
8
|
Use case: Check Credit
|
|
11
9
|
1. The Customer's balance is less than the credit limit
|
|
12
10
|
2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
|
|
@@ -17,12 +15,14 @@ Use case: Check Credit
|
|
|
17
15
|
Use case: App Integration
|
|
18
16
|
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
|
|
19
17
|
|
|
20
|
-
Ensure each customer
|
|
18
|
+
Ensure each customer has a unique name.
|
|
21
19
|
|
|
22
20
|
Ensure each Item quantity is not null.
|
|
23
21
|
|
|
24
22
|
Ensure each order has a valid customer_id that exists in the Customer table.
|
|
25
|
-
|
|
23
|
+
|
|
24
|
+
Graph sales by month, for dashboard.
|
|
25
|
+
Graph Sales by Product, for dashboard.
|
|
26
26
|
</Requirements>
|
|
27
27
|
|
|
28
28
|
Hints: use autonum keys (for all tables - including for link/join/junction/intersection tables), allow nulls, foreign keys, no check constraints.
|
|
@@ -2,140 +2,170 @@
|
|
|
2
2
|
"models": [
|
|
3
3
|
{
|
|
4
4
|
"classname": "Customer",
|
|
5
|
-
"code": "class Customer(Base):\n __tablename__ = 'customer'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String
|
|
6
|
-
"description": "
|
|
7
|
-
"name": "
|
|
5
|
+
"code": "class Customer(Base):\n __tablename__ = 'customer'\n\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": "Defines the Customer entity with a unique name, balance, and credit limit.",
|
|
7
|
+
"name": "Customer"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"classname": "Order",
|
|
11
|
-
"code": "class Order(Base):\n __tablename__ = 'order'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customer.id'))\n date_shipped = Column(
|
|
12
|
-
"description": "
|
|
13
|
-
"name": "
|
|
11
|
+
"code": "class Order(Base):\n __tablename__ = 'order'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n notes = Column(String)\n customer_id = Column(Integer, ForeignKey('customer.id'), nullable=False)\n date_shipped = Column(Date)\n amount_total = Column(DECIMAL)",
|
|
12
|
+
"description": "Defines the Order entity which belongs to a customer. Includes notes and amount total.",
|
|
13
|
+
"name": "Order"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"classname": "Item",
|
|
17
|
-
"code": "class Item(Base):\n __tablename__ = 'item'\n\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
|
|
18
|
-
"description": "
|
|
19
|
-
"name": "
|
|
17
|
+
"code": "class Item(Base):\n __tablename__ = 'item'\n\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'), nullable=False)\n quantity = Column(Integer, nullable=False)\n amount = Column(DECIMAL)\n unit_price = Column(DECIMAL)",
|
|
18
|
+
"description": "Defines the Item entity with quantity, amounts, and unit price details.",
|
|
19
|
+
"name": "Item"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"classname": "Product",
|
|
23
|
-
"code": "class Product(Base):\n __tablename__ = 'product'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String
|
|
24
|
-
"description": "
|
|
25
|
-
"name": "
|
|
23
|
+
"code": "class Product(Base):\n __tablename__ = 'product'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n unit_price = Column(DECIMAL)",
|
|
24
|
+
"description": "Defines the Product entity with a unique name and unit price.",
|
|
25
|
+
"name": "Product"
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
28
|
"rules": [
|
|
29
29
|
{
|
|
30
|
-
"name": "
|
|
31
|
-
"description": "Ensure customer balance is
|
|
30
|
+
"name": "Customer Balance Constraint",
|
|
31
|
+
"description": "Ensure the customer's balance is less than their credit limit.",
|
|
32
32
|
"use_case": "Check Credit",
|
|
33
33
|
"entity": "Customer",
|
|
34
|
-
"code": "Rule.constraint(validate=Customer,
|
|
34
|
+
"code": "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})\")"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
"name": "Customer Balance
|
|
38
|
-
"description": "
|
|
37
|
+
"name": "Customer Balance Derivation",
|
|
38
|
+
"description": "Derive the customer's balance as the sum of order totals where not yet shipped.",
|
|
39
39
|
"use_case": "Check Credit",
|
|
40
40
|
"entity": "Customer",
|
|
41
|
-
"code": "Rule.sum(derive=Customer.balance,
|
|
41
|
+
"code": "Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)"
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
"name": "Order
|
|
45
|
-
"description": "
|
|
44
|
+
"name": "Order Total Derivation",
|
|
45
|
+
"description": "Derive the order's total amount from the sum of item amounts.",
|
|
46
46
|
"use_case": "Check Credit",
|
|
47
47
|
"entity": "Order",
|
|
48
|
-
"code": "Rule.sum(derive=Order.amount_total,
|
|
48
|
+
"code": "Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)"
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
"name": "Item Amount
|
|
52
|
-
"description": "Calculate item amount
|
|
51
|
+
"name": "Item Amount Calculation",
|
|
52
|
+
"description": "Calculate item amount based on quantity and unit price.",
|
|
53
53
|
"use_case": "Check Credit",
|
|
54
54
|
"entity": "Item",
|
|
55
|
-
"code": "Rule.formula(derive=Item.amount,
|
|
55
|
+
"code": "Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
"name": "
|
|
58
|
+
"name": "Item Unit Price Copy",
|
|
59
59
|
"description": "Copy unit price from product to item.",
|
|
60
60
|
"use_case": "Check Credit",
|
|
61
61
|
"entity": "Item",
|
|
62
|
-
"code": "Rule.copy(derive=Item.unit_price,
|
|
62
|
+
"code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
"name": "Order
|
|
66
|
-
"description": "Send
|
|
65
|
+
"name": "Order Kafka Notification",
|
|
66
|
+
"description": "Send order details to Kafka if order is shipped.",
|
|
67
67
|
"use_case": "App Integration",
|
|
68
68
|
"entity": "Order",
|
|
69
|
-
"code": "Rule.after_flush_row_event(on_class=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'})"
|
|
70
70
|
}
|
|
71
71
|
],
|
|
72
|
-
"
|
|
72
|
+
"graphics": [
|
|
73
|
+
{
|
|
74
|
+
"sqlalchemy_query": "session.query(Product.name, func.sum(Item.amount).label('TotalSales')).join(Item, Product.id == Item.product_id).filter(Order.date_shipped.isnot(None)).group_by(Product.name).order_by(func.sum(Item.amount).desc())",
|
|
75
|
+
"sql_query": "SELECT Product.name, SUM(Item.amount) AS TotalSales FROM Product JOIN Item ON Product.id = Item.product_id JOIN Order ON Item.order_id = Order.id WHERE Order.date_shipped IS NOT NULL GROUP BY Product.name ORDER BY TotalSales DESC",
|
|
76
|
+
"classes_used": "Product, Item, Order",
|
|
77
|
+
"class_x_axis": "Product",
|
|
78
|
+
"name": "sales_by_product",
|
|
79
|
+
"prompt": "Graph Sales by Product",
|
|
80
|
+
"title": "Sales by Product",
|
|
81
|
+
"xAxis": "Product",
|
|
82
|
+
"yAxis": "Total Sales",
|
|
83
|
+
"dashboard": true,
|
|
84
|
+
"graph_type": "Bar",
|
|
85
|
+
"html_code": "var data = result.result; var categories = data.map(item => item[0]); var totals = data.map(item => item[1]); var ctx = document.getElementById('salesByProductChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: categories, datasets: [{label: 'Sales by Product', data: totals}]}});"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"sqlalchemy_query": "session.query(Customer.name, func.sum(Order.amount_total).label('TotalCustomerSales')).join(Order, Customer.id == Order.customer_id).filter(Order.date_shipped.isnot(None)).group_by(Customer.name).order_by(func.sum(Order.amount_total).desc())",
|
|
89
|
+
"sql_query": "SELECT Customer.name, SUM(Order.amount_total) AS TotalCustomerSales FROM Customer JOIN Order ON Customer.id = Order.customer_id WHERE Order.date_shipped IS NOT NULL GROUP BY Customer.name ORDER BY TotalCustomerSales DESC",
|
|
90
|
+
"classes_used": "Customer, Order",
|
|
91
|
+
"class_x_axis": "Customer",
|
|
92
|
+
"name": "sales_by_customer",
|
|
93
|
+
"prompt": "Graph Sales by Customer",
|
|
94
|
+
"title": "Sales by Customer",
|
|
95
|
+
"xAxis": "Customer",
|
|
96
|
+
"yAxis": "Total Sales",
|
|
97
|
+
"dashboard": true,
|
|
98
|
+
"graph_type": "Bar",
|
|
99
|
+
"html_code": "var data = result.result; var customers = data.map(item => item[0]); var sales = data.map(item => item[1]); var ctx = document.getElementById('salesByCustomerChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: customers, datasets: [{label: 'Sales by Customer', data: sales}]}});"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"test_data": "This is the test data generated for Customers, Orders, Items, and Products in the new system.",
|
|
73
103
|
"test_data_rows": [
|
|
74
104
|
{
|
|
75
105
|
"test_data_row_variable": "customer1",
|
|
76
|
-
"code": "customer1 = Customer(
|
|
106
|
+
"code": "customer1 = Customer(name=\"Alice\", balance=1000.00, credit_limit=5000.00)"
|
|
77
107
|
},
|
|
78
108
|
{
|
|
79
109
|
"test_data_row_variable": "customer2",
|
|
80
|
-
"code": "customer2 = Customer(
|
|
110
|
+
"code": "customer2 = Customer(name=\"Bob\", balance=2000.00, credit_limit=3000.00)"
|
|
81
111
|
},
|
|
82
112
|
{
|
|
83
113
|
"test_data_row_variable": "customer3",
|
|
84
|
-
"code": "customer3 = Customer(
|
|
114
|
+
"code": "customer3 = Customer(name=\"Charlie\", balance=500.00, credit_limit=2000.00)"
|
|
85
115
|
},
|
|
86
116
|
{
|
|
87
117
|
"test_data_row_variable": "customer4",
|
|
88
|
-
"code": "customer4 = Customer(
|
|
118
|
+
"code": "customer4 = Customer(name=\"Diana\", balance=0.00, credit_limit=1000.00)"
|
|
89
119
|
},
|
|
90
120
|
{
|
|
91
121
|
"test_data_row_variable": "product1",
|
|
92
|
-
"code": "product1 = Product(
|
|
122
|
+
"code": "product1 = Product(name=\"Gadget\", unit_price=150.00)"
|
|
93
123
|
},
|
|
94
124
|
{
|
|
95
125
|
"test_data_row_variable": "product2",
|
|
96
|
-
"code": "product2 = Product(
|
|
126
|
+
"code": "product2 = Product(name=\"Widget\", unit_price=90.00)"
|
|
97
127
|
},
|
|
98
128
|
{
|
|
99
129
|
"test_data_row_variable": "product3",
|
|
100
|
-
"code": "product3 = Product(
|
|
130
|
+
"code": "product3 = Product(name=\"Thingamajig\", unit_price=75.00)"
|
|
101
131
|
},
|
|
102
132
|
{
|
|
103
133
|
"test_data_row_variable": "product4",
|
|
104
|
-
"code": "product4 = Product(
|
|
134
|
+
"code": "product4 = Product(name=\"Doodad\", unit_price=110.00)"
|
|
105
135
|
},
|
|
106
136
|
{
|
|
107
137
|
"test_data_row_variable": "order1",
|
|
108
|
-
"code": "order1 = Order(
|
|
138
|
+
"code": "order1 = Order(notes=\"First Order\", customer_id=1, date_shipped=date(2023, 3, 22), amount_total=300.00)"
|
|
109
139
|
},
|
|
110
140
|
{
|
|
111
141
|
"test_data_row_variable": "order2",
|
|
112
|
-
"code": "order2 = Order(
|
|
142
|
+
"code": "order2 = Order(notes=\"Second Order\", customer_id=2, date_shipped=None, amount_total=0.00)"
|
|
113
143
|
},
|
|
114
144
|
{
|
|
115
145
|
"test_data_row_variable": "order3",
|
|
116
|
-
"code": "order3 = Order(
|
|
146
|
+
"code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=300.00)"
|
|
117
147
|
},
|
|
118
148
|
{
|
|
119
149
|
"test_data_row_variable": "order4",
|
|
120
|
-
"code": "order4 = Order(
|
|
150
|
+
"code": "order4 = Order(notes=\"Urgent Order\", customer_id=4, date_shipped=date(2023, 7, 15), amount_total=220.00)"
|
|
121
151
|
},
|
|
122
152
|
{
|
|
123
153
|
"test_data_row_variable": "item1",
|
|
124
|
-
"code": "item1 = Item(
|
|
154
|
+
"code": "item1 = Item(order_id=1, product_id=1, quantity=2, amount=300.00, unit_price=150.00)"
|
|
125
155
|
},
|
|
126
156
|
{
|
|
127
157
|
"test_data_row_variable": "item2",
|
|
128
|
-
"code": "item2 = Item(
|
|
158
|
+
"code": "item2 = Item(order_id=2, product_id=2, quantity=1, amount=90.00, unit_price=90.00)"
|
|
129
159
|
},
|
|
130
160
|
{
|
|
131
161
|
"test_data_row_variable": "item3",
|
|
132
|
-
"code": "item3 = Item(
|
|
162
|
+
"code": "item3 = Item(order_id=3, product_id=4, quantity=2, amount=220.00, unit_price=110.00)"
|
|
133
163
|
},
|
|
134
164
|
{
|
|
135
165
|
"test_data_row_variable": "item4",
|
|
136
|
-
"code": "item4 = Item(
|
|
166
|
+
"code": "item4 = Item(order_id=4, product_id=3, quantity=4, amount=300.00, unit_price=75.00)"
|
|
137
167
|
}
|
|
138
168
|
],
|
|
139
|
-
"test_data_sqlite": "INSERT INTO customer (
|
|
169
|
+
"test_data_sqlite": "INSERT INTO customer (name, balance, credit_limit) VALUES ('Alice', 1000.00, 5000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Bob', 2000.00, 3000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Charlie', 500.00, 2000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Diana', 0.00, 1000.00);\n\nINSERT INTO product (name, unit_price) VALUES ('Gadget', 150.00);\nINSERT INTO product (name, unit_price) VALUES ('Widget', 90.00);\nINSERT INTO product (name, unit_price) VALUES ('Thingamajig', 75.00);\nINSERT INTO product (name, unit_price) VALUES ('Doodad', 110.00);\n\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('First Order', 1, '2023-03-22', 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Second Order', 2, NULL, 0.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Pending Shipment', 3, NULL, 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Urgent Order', 4, '2023-07-15', 220.00);\n\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (1, 1, 2, 300.00, 150.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (2, 2, 1, 90.00, 90.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (3, 4, 2, 220.00, 110.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (4, 3, 4, 300.00, 75.00);",
|
|
140
170
|
"name": "CustomerOrderSystem"
|
|
141
171
|
}
|
api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from database import models
|
|
2
|
+
import logging
|
|
3
|
+
from safrs import jsonapi_attr
|
|
4
|
+
from sqlalchemy.orm import relationship, remote, foreign
|
|
5
|
+
from functools import wraps # This convenience func preserves name and docstring
|
|
6
|
+
import decimal as decimal
|
|
7
|
+
from sqlalchemy import extract, func
|
|
8
|
+
from flask import request, jsonify
|
|
9
|
+
from safrs import jsonapi_rpc, SAFRSAPI
|
|
10
|
+
from database import models
|
|
11
|
+
import safrs
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
Called by iFrame in home.js when admin app is loaded
|
|
16
|
+
|
|
17
|
+
Returns iFrame for ui/admin/home.js, with entries like this to populate the dashboard:
|
|
18
|
+
<iframe src="http://localhost:5656/chart_graphics/sales_per_category" style="flex: 1; border: none; width: 90%; height: 200px;">
|
|
19
|
+
|
|
20
|
+
curl -X GET "http://localhost:5656/dashboard"
|
|
21
|
+
|
|
22
|
+
You typically do not alter this file - it is rebuilt on `als genai-graphics`
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
app_logger = logging.getLogger(__name__)
|
|
27
|
+
dashboard_result = {}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@app.route('/dashboard', methods=['GET','OPTIONS'])
|
|
34
|
+
def dashboard():
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if request.method == 'OPTIONS':
|
|
38
|
+
return jsonify({"result": "ok"})
|
|
39
|
+
|
|
40
|
+
server = request.host_url
|
|
41
|
+
|
|
42
|
+
iframe_template = '<div class="dashboard-iframe"><iframe src="{url}" style="flex: 1; border: none; width: 90%; height: 200px;"></iframe></div>'
|
|
43
|
+
{% for iframe in iframe_templates %}
|
|
44
|
+
{{iframe}}
|
|
45
|
+
{% endfor %}
|
|
46
|
+
|
|
47
|
+
{% if has_iframe %}
|
|
48
|
+
return f'<div style="display: flex; flex-direction: row; gap: 10px; border: none; ">{{ iframe_links }}</div>'
|
|
49
|
+
{% endif %}
|
|
50
|
+
{% if has_iframe == false %}
|
|
51
|
+
return jsonify({})
|
|
52
|
+
{% endif %}
|
|
53
|
+
|
|
54
|
+
@app.route('/chart_graphics/<path:path>', methods=['GET','OPTIONS'])
|
|
55
|
+
def chart_graphics(path):
|
|
56
|
+
if request.method == 'OPTIONS':
|
|
57
|
+
return jsonify({"result": "ok"})
|
|
58
|
+
|
|
59
|
+
dashboards = get_dashboards()
|
|
60
|
+
if len(dashboards) == 0:
|
|
61
|
+
return jsonify({"result": "No dashboards Found"}), 404
|
|
62
|
+
if path in dashboards:
|
|
63
|
+
return dashboards[path]
|
|
64
|
+
return jsonify({"result": "not found"}), 404
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
##############################
|
|
68
|
+
# generated queries follow
|
|
69
|
+
##############################
|
|
70
|
+
|
|
71
|
+
def get_dashboards():
|
|
72
|
+
if len(dashboard_result) > 0:
|
|
73
|
+
return dashboard_result
|
|
74
|
+
|
|
75
|
+
from jinja2 import Environment, FileSystemLoader
|
|
76
|
+
env = Environment(loader = FileSystemLoader('ui/templates'))
|
|
77
|
+
template = env.get_template('bar_chart.jinja')
|
|
78
|
+
|
|
79
|
+
{% for dashboard in dashboards %}
|
|
80
|
+
{{dashboard}}
|
|
81
|
+
{% endfor %}
|
|
82
|
+
|
|
83
|
+
return dashboard_result
|
api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
import logging
|
|
3
|
+
from flask_jwt_extended import get_jwt, jwt_required, verify_jwt_in_request
|
|
4
|
+
from config.config import Config, Args
|
|
5
|
+
from security.system.authorization import Security
|
|
6
|
+
import api.system.api_utils as api_utils
|
|
7
|
+
from typing import List
|
|
8
|
+
import safrs
|
|
9
|
+
import sqlalchemy
|
|
10
|
+
from flask import request, jsonify
|
|
11
|
+
from safrs import jsonapi_rpc, SAFRSAPI
|
|
12
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
13
|
+
from sqlalchemy.orm import object_mapper
|
|
14
|
+
from sqlalchemy import extract, func
|
|
15
|
+
from database import models
|
|
16
|
+
from flask_cors import cross_origin
|
|
17
|
+
from logic_bank.rule_bank.rule_bank import RuleBank
|
|
18
|
+
import integration.system.RowDictMapper as row_dict_mapper
|
|
19
|
+
|
|
20
|
+
# called by home.js to populate dashboard iFrame with results of all dsahboard queries
|
|
21
|
+
|
|
22
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
23
|
+
|
|
24
|
+
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
api.expose_object(GraphicsDashboard) # Swagger-visible services
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class GraphicsDashboard(safrs.JABase):
|
|
31
|
+
"""GraphicsDashboard service - results of all dsahboard queries"""
|
|
32
|
+
result = []
|
|
33
|
+
|
|
34
|
+
{{dashboard_lines}}
|
|
@@ -29,13 +29,4 @@ app_logger = logging.getLogger("api_logic_server_app")
|
|
|
29
29
|
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
30
30
|
pass
|
|
31
31
|
|
|
32
|
-
api.expose_object(GraphicsServices) # Swagger-visible services
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
Illustrates #als: apis for graphics
|
|
37
|
-
|
|
38
|
-
* Custom service - visible in swagger
|
|
39
|
-
"""
|
|
40
|
-
class GraphicsServices(safrs.JABase):
|
|
41
|
-
pass
|
api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from database import models
|
|
2
|
+
import logging
|
|
3
|
+
from safrs import jsonapi_attr
|
|
4
|
+
from sqlalchemy.orm import relationship, remote, foreign
|
|
5
|
+
from functools import wraps # This convenience func preserves name and docstring
|
|
6
|
+
import decimal as decimal
|
|
7
|
+
from sqlalchemy import extract, func
|
|
8
|
+
from flask import request, jsonify
|
|
9
|
+
from safrs import jsonapi_rpc, SAFRSAPI
|
|
10
|
+
import safrs
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
Graphics methods for database classes, created when:
|
|
14
|
+
* `als genai create` contains prompts like: 'Graph Sales by Category', etc.
|
|
15
|
+
* `als add-graphics` --using the docs/graphics directory
|
|
16
|
+
|
|
17
|
+
Called by api/api_discovery/dashboard_services.py when admin app loaded
|
|
18
|
+
|
|
19
|
+
You typically do not alter this file - rebuilt on als genai--graphics.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
app_logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_method(cls):
|
|
27
|
+
"""
|
|
28
|
+
Decorator to add method to class, e.g., db class group by query method
|
|
29
|
+
|
|
30
|
+
Thanks to: https://mgarod.medium.com/dynamically-add-a-method-to-a-class-in-python-c49204b85bd6
|
|
31
|
+
"""
|
|
32
|
+
def decorator(func):
|
|
33
|
+
@wraps(func)
|
|
34
|
+
def wrapper(self, *args, **kwargs):
|
|
35
|
+
return func(*args, **kwargs)
|
|
36
|
+
|
|
37
|
+
setattr(cls, func.__name__, wrapper)
|
|
38
|
+
# Note we are not binding func, but wrapper which accepts self but does exactly the same as func
|
|
39
|
+
return func # returning func means func can still be used normally
|
|
40
|
+
return decorator
|
|
41
|
+
|
|
42
|
+
##############################
|
|
43
|
+
# generated services follow
|
|
44
|
+
##############################
|
|
45
|
+
|
|
46
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
@classmethod
|
|
3
|
+
@add_method(models.{{class_x_axis}})
|
|
4
|
+
@jsonapi_rpc(http_methods=['GET', 'OPTIONS'])
|
|
5
|
+
def {{name}}(*args, **kwargs):
|
|
6
|
+
"""
|
|
7
|
+
Complex query with multiple joins, for graphics, from 'Graph Sales by Category', etc.
|
|
8
|
+
Test with Swagger.
|
|
9
|
+
"""
|
|
10
|
+
if request.method == 'OPTIONS':
|
|
11
|
+
return jsonify({ "result": "ok" })
|
|
12
|
+
|
|
13
|
+
from database.models import {{classes_used}}
|
|
14
|
+
db = safrs.DB
|
|
15
|
+
session = db.session # sqlalchemy.orm.scoping.scoped_session
|
|
16
|
+
# Security.set_user_sa() # an endpoint that requires no auth header (see also @bypass_security)
|
|
17
|
+
|
|
18
|
+
# SQLAlchemy query
|
|
19
|
+
query = {{ sqlalchemy_query }}
|
|
20
|
+
# Execute query and fetch results
|
|
21
|
+
results = query.all()
|
|
22
|
+
from decimal import Decimal
|
|
23
|
+
columns = ['{{ xAxis }}' , '{{ yAxis }}']
|
|
24
|
+
results = [{columns[0]: row[0], columns[1]: round(float(row[1]), 2)} for row in results]
|
|
25
|
+
title = '{{ title }}'
|
|
26
|
+
graph_type = '{{ graph_type }}'.lower()
|
|
27
|
+
json_results = {
|
|
28
|
+
"results": results,
|
|
29
|
+
"columns": columns,
|
|
30
|
+
"title": title,
|
|
31
|
+
"chart_type": graph_type,
|
|
32
|
+
"xAxis": columns[0],
|
|
33
|
+
"yAxis": columns[1],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return json_results
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
Create WGResult Graphics for prompts like 'graph sales by region'.
|
|
3
|
-
*
|
|
2
|
+
Create WGResult Graphics, with graphics elements for each prompts like 'graph sales by region'.
|
|
3
|
+
* do not create graphics elements unless explicitly requested.
|
|
4
|
+
* query results should always return exactly 2 columns.
|
|
5
|
+
* use 'sales by region' to create a WGResult Graphic.sqlalchemy_query for *each* such line
|
|
4
6
|
* Be sure to use class names, not table names
|
|
5
|
-
* for
|
|
7
|
+
* Create joins for only explicitly defined foreign key relationships
|
|
8
|
+
* for example, using Northwind - important! note the 2 right parens closing label("Total Sales"):
|
|
6
9
|
# SQLAlchemy query for Sales by Category
|
|
7
10
|
sales_by_category = (
|
|
8
11
|
session.query(
|
|
@@ -16,3 +19,4 @@ Create WGResult Graphics for prompts like 'graph sales by region'.
|
|
|
16
19
|
.group_by(Category.CategoryName)
|
|
17
20
|
.order_by(func.sum(OrderDetail.Quantity * OrderDetail.UnitPrice * (1 - OrderDetail.Discount)).desc())
|
|
18
21
|
)
|
|
22
|
+
|
|
@@ -21,7 +21,14 @@ class Graphic(BaseModel):
|
|
|
21
21
|
sqlalchemy_query: str # sqlalchemy query using group by, returns result = { "result": [ ("name", "value") ] }
|
|
22
22
|
sql_query: str # sql query using group by, returns result = { "result": [ ("name", "value") ] }
|
|
23
23
|
classes_used: str # comma-delimited list of classes used in sqlalchemy_query
|
|
24
|
-
|
|
24
|
+
class_x_axis: str # name of class for x axis
|
|
25
|
+
name: str # suggested Python name for sqlalchemy_query - unique
|
|
26
|
+
prompt: str # prompt used to create the graphic
|
|
27
|
+
title: str # expanded name
|
|
28
|
+
xAxis: str # caption for x axis
|
|
29
|
+
yAxis: str # caption for y axis
|
|
30
|
+
dashboard: bool # whether appears on home page
|
|
31
|
+
graph_type: str # Bar, Line, Pie
|
|
25
32
|
html_code: str # create a java script app to show a bar chart from sqlalchemy_query result
|
|
26
33
|
|
|
27
34
|
class WGResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
|