ApiLogicServer 14.3.20__py3-none-any.whl → 14.4.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/api_logic_server.py +5 -14
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +52 -5
- 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__/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/create_db_from_model.py +2 -0
- api_logic_server_cli/create_from_model/ont_build.py +19 -14
- api_logic_server_cli/create_from_model/ont_create.py +5 -5
- api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +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/fragments/docker-compose.yml +27 -0
- api_logic_server_cli/genai/genai.py +43 -11
- api_logic_server_cli/genai/genai_graphics.py +379 -0
- api_logic_server_cli/genai/genai_logic_builder.py +2 -2
- api_logic_server_cli/genai/genai_svcs.py +24 -8
- api_logic_server_cli/manager.py +19 -10
- 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 +19 -0
- 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 +95 -24
- 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 +3 -1
- api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
- api_logic_server_cli/prototypes/base/docs/graphics/readme.md +12 -0
- 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 +7 -3
- api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
- api_logic_server_cli/prototypes/base/security/authentication_provider/keycloak/auth_provider.py +1 -1
- api_logic_server_cli/prototypes/base/security/declare_security.py +4 -0
- api_logic_server_cli/prototypes/base/ui/admin/admin_loader.py +3 -1
- api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
- api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
- api_logic_server_cli/prototypes/manager/README.md +56 -5
- 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 -8
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +90 -60
- 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_api_xxx.py +32 -0
- 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/graphics_templates/html_template.jinja +76 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/index.html +19 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/sales_by_region.jinja +63 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +22 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics_request.prompt +5 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +15 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/sqlite_inserts.prompt +2 -0
- 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/docs/graphics/count_orders_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/request copy.json +892 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/request.json +6 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/response.json +17 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/response.yaml +59 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_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/nw_no_cust/integration/mcp/1_langchain_loader.py +19 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/3_executor_test_agent.py +38 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/README.md +17 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/curl.txt +4 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
- api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/run_executor.py +23 -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.json +6 -6
- 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/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/detail_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
- apilogicserver-14.4.0.dist-info/METADATA +76 -0
- {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/RECORD +102 -59
- {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/WHEEL +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/zsqlite_inserts_iterations.prompt +0 -29
- api_logic_server_cli/prototypes/manager/webgenai/docker-compose-webg.yml +0 -33
- api_logic_server_cli/prototypes/manager/webgenai/webg_config/license.json +0 -6
- api_logic_server_cli/prototypes/manager/webgenai/webg_config/web_genai.txt +0 -13
- apilogicserver-14.3.20.dist-info/METADATA +0 -167
- {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/entry_points.txt +0 -0
- {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from typing import Dict, List
|
|
3
|
+
from api_logic_server_cli.cli_args_project import Project
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import importlib
|
|
7
|
+
from api_logic_server_cli.genai.genai_utils import call_chatgpt
|
|
8
|
+
import requests
|
|
9
|
+
import os, time
|
|
10
|
+
import datetime
|
|
11
|
+
import create_from_model.api_logic_server_utils as utils
|
|
12
|
+
import time
|
|
13
|
+
from openai import OpenAI
|
|
14
|
+
from api_logic_server_cli.genai.genai_svcs import WGResult
|
|
15
|
+
from api_logic_server_cli.genai.genai_svcs import Rule
|
|
16
|
+
import api_logic_server_cli.genai.genai_svcs as genai_svcs
|
|
17
|
+
import json
|
|
18
|
+
from typing import List, Dict
|
|
19
|
+
from pydantic import BaseModel
|
|
20
|
+
from dotmap import DotMap
|
|
21
|
+
from natsort import natsorted
|
|
22
|
+
import glob
|
|
23
|
+
import create_from_model.api_logic_server_utils as create_utils
|
|
24
|
+
from jinja2 import Environment, FileSystemLoader
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
K_data_model_prompt = "Use SQLAlchemy to create"
|
|
28
|
+
|
|
29
|
+
log = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
class GenAIGraphics(object):
|
|
32
|
+
""" 4/3/2025
|
|
33
|
+
Adds Graphics to projects (genai project or als project):
|
|
34
|
+
* adds `database/database_discovery` file to project (methods on database.models classes)
|
|
35
|
+
* adds `api/api_discovery` file to project (dashboard services - calls db methods, above)
|
|
36
|
+
* adds `docs/graphics` prompt files to **wg** project (graphics prompt files)
|
|
37
|
+
|
|
38
|
+
Invoked from:
|
|
39
|
+
1. **New GenAI Project:** for newly created project (e,g, mgr system/genai/examples/genai_demo/genai_demo.prompt)
|
|
40
|
+
* `--using` is None ==> Docs folder already has WGResponse.graphics[]
|
|
41
|
+
* see api_logic_server_cli/genai/genai_svcs.py#insert_logic_into_created_project
|
|
42
|
+
2. **Existing Project:** `als genai-graphics [--using]` # existing project
|
|
43
|
+
* `--using` ==> Call ChatGPT for WGResponse.graphics, default = `<project>/docs/graphics/*.prompt`
|
|
44
|
+
* note: dbml not rebuilt after rebuild-from-db
|
|
45
|
+
3. **Existing WG Project:** in-place (do not create new project with new test data)
|
|
46
|
+
* Same as #1, but requires WG UI change ('in place', 'graphics' button, ...) to use genai_graphics cmd
|
|
47
|
+
|
|
48
|
+
Testing:
|
|
49
|
+
* BLT to create manager
|
|
50
|
+
* Test from source: launch.json (in group 3) has `Add Graphics to blt/samples/nw...`
|
|
51
|
+
* Note: uses `<mgr>/system/genai/graphics_templates`
|
|
52
|
+
* Don't forget to copy these back to `api_logic_server_cli/prototypes/manager/system/genai/graphics_templates`
|
|
53
|
+
* Optionally: update `bypass_for_debug` to True to skip ChatGPT call
|
|
54
|
+
|
|
55
|
+
Persistence model for graphics: docs/response.json (also in docs/graphics/response.json, for als customization)
|
|
56
|
+
* Requirements:
|
|
57
|
+
1. Fail-safe: do not let WG projects fail due to graphics - but alert user, just once
|
|
58
|
+
2. Iterable: do not lose graphics on WG iteration
|
|
59
|
+
* Running design: 4/12
|
|
60
|
+
* Fail-safe: implemented in dashboard_service.py -- for each <graphic.name> query:
|
|
61
|
+
1. if exists(docs/graphics/<graphics.name>.err), bypass the query
|
|
62
|
+
2. wrap each dashboard_service query in a try/except block
|
|
63
|
+
3. if exception,
|
|
64
|
+
* return "graphics failed" to iFrame so user can see it
|
|
65
|
+
* create docs/graphics/<graphics>.err to inhibit future calls
|
|
66
|
+
* For wg (--using == None):
|
|
67
|
+
* iterations build on docs/response.json, so graphics are preserved
|
|
68
|
+
* todo: verify add-rules
|
|
69
|
+
* this code creates docs/graphics/<graphics.name>.prompt
|
|
70
|
+
* preserves graphics when opening project in als mode
|
|
71
|
+
* ALS developers manage their own docs/graphics
|
|
72
|
+
|
|
73
|
+
Open Issues
|
|
74
|
+
* How to enforce licensing? eg, create stubbed api/api_discovery/dashboard_services.py
|
|
75
|
+
* How can user delete or alter the graphics? Activate the Project Summary Graphics button [replace]
|
|
76
|
+
* Graphics for wg projects (not showing)
|
|
77
|
+
* No Graphics (just shows {} )
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, project: Project, using: str, genai_version: str, replace_with: str):
|
|
82
|
+
"""
|
|
83
|
+
Add graphics to existing projects - [see docs](https://apilogicserver.github.io/Docs/WebGenAI-CLI/#add-graphics-to-existing-projects)
|
|
84
|
+
|
|
85
|
+
Called to inject graphics into existing project, by:
|
|
86
|
+
1. genai#insert_logic for NEW WG projects (--replace_with = '!new-wg', using already-built docs dir)
|
|
87
|
+
2. cli for EXISTING projects (add from docs/graphics, or update per replace_with)
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
project (Project): Project object
|
|
91
|
+
using (str): path to graphics prompt files (set by genai#insert_logic, or None, for existing project)
|
|
92
|
+
replace_with (str): (request type): '!using' (default), '!new-wg', '!delete', '!retry`, or '!request'
|
|
93
|
+
genai_version (str): GenAI version to use
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
self.project = project
|
|
97
|
+
self.using = using
|
|
98
|
+
self.manager_path = genai_svcs.get_manager_path()
|
|
99
|
+
self.start_time = time.time()
|
|
100
|
+
self.replace_with = replace_with
|
|
101
|
+
''' '!using', '!new-wg', '!delete', '!retry`, or '!request Graph Sales... '''
|
|
102
|
+
graphics_response_path = self.project.project_directory_path.joinpath('docs/graphics/response.json') # assume existing project
|
|
103
|
+
if replace_with == '!new-wg': # if new webgenai, response already prepared here
|
|
104
|
+
graphics_response_path = self.project.project_directory_path.joinpath('docs/response.json')
|
|
105
|
+
|
|
106
|
+
log.info(f"\nGenAIGraphics start...")
|
|
107
|
+
log.info(f"... args:")
|
|
108
|
+
log.info(f"..... self.replace_with: {self.replace_with}")
|
|
109
|
+
log.info(f"..... self.using: {self.using}")
|
|
110
|
+
log.info(f"..... graphics_response_path: {graphics_response_path}")
|
|
111
|
+
log.info(f"..... self.project.project_directory_actual: {self.project.project_directory_actual}")
|
|
112
|
+
log.info(f"..... self.project.project_directory_path: {str(self.project.project_directory_path)}")
|
|
113
|
+
|
|
114
|
+
if self.replace_with != '!new-wg' and self.replace_with != '!using' : # update existing genai project
|
|
115
|
+
replaced_graphics = self.graphics_replace_with_in_existing_project()
|
|
116
|
+
if self.replace_with == '!delete': # we are done (else create docs/graphics prompts for processing below)
|
|
117
|
+
log.info(f"... update existing genai project - delete graphics")
|
|
118
|
+
return
|
|
119
|
+
log.info(f"... update genai existing project - from docs/graphics prompts with {replaced_graphics}")
|
|
120
|
+
|
|
121
|
+
if replace_with == '!new-wg':
|
|
122
|
+
log.info(f"... NEW WG project - already built: docs/002_create_db_models.prompt")
|
|
123
|
+
else:
|
|
124
|
+
log.info(f"... EXISTING project - process prompts in docs/graphics")
|
|
125
|
+
if bypass_for_debug := False:
|
|
126
|
+
pass # uses already-built docs/graphics/response.json
|
|
127
|
+
else:
|
|
128
|
+
prompt = genai_svcs.read_and_expand_prompt(self.manager_path.joinpath('system/genai/prompt_inserts/graphics_request.prompt'))
|
|
129
|
+
prompt_lines = prompt.split('\n') # ChatGPT instructions
|
|
130
|
+
prompt_lines.extend(self.append_data_model()) # add data model
|
|
131
|
+
prompt_lines.extend(self.append_graphics_files()) # and the users's requests from graphics files
|
|
132
|
+
prompt_str = "\n".join(prompt_lines)
|
|
133
|
+
|
|
134
|
+
prompt_messages : List[ Dict[str, str] ] = [] # prompt/response conversation to be sent to ChatGPT
|
|
135
|
+
prompt = genai_svcs.get_prompt_you_are()
|
|
136
|
+
prompt["content"] = prompt_str
|
|
137
|
+
prompt_messages.append( prompt )
|
|
138
|
+
genai_svcs.call_chatgpt(messages = prompt_messages,
|
|
139
|
+
using = self.project.project_directory_path.joinpath('docs/graphics'),
|
|
140
|
+
api_version=genai_version)
|
|
141
|
+
|
|
142
|
+
self.create_data_class_methods(graphics_response_path)
|
|
143
|
+
self.create_graphics_dashboard_service(graphics_response_path)
|
|
144
|
+
self.create_genai_graphics_prompts(graphics_response_path)
|
|
145
|
+
log.info(f"\ngenai-graphics completed in [{str(int(time.time() - self.start_time))} secs] \n")
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
def create_data_class_methods(self, graphics_response_path: Path):
|
|
149
|
+
""" Process graphics response from ChatGPT docs/graphics/response.json
|
|
150
|
+
* 'graphics' attributes map directly (by name) to <mgr>/system/genai/graphics_templates
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
shutil.copy(self.manager_path.joinpath('system/genai/graphics_templates/graphics_services_db.jinja'),
|
|
154
|
+
self.project.project_directory_path.joinpath('database/database_discovery/graphics_services.py')) # all the db-class methods are created in this file
|
|
155
|
+
|
|
156
|
+
# open and read the graphics_response_path json file
|
|
157
|
+
assert graphics_response_path.exists(), f'Graphics response file not found: {graphics_response_path}'
|
|
158
|
+
with open(graphics_response_path, 'r') as file:
|
|
159
|
+
graphics_response = json.load(file)
|
|
160
|
+
log.info(f'... create_data_class_methods - from {graphics_response_path}')
|
|
161
|
+
graphics = graphics_response['graphics']
|
|
162
|
+
for each_graphic in graphics: # add each service to api/api_discovery
|
|
163
|
+
self.fix_sqlalchemy_query(each_graphic)
|
|
164
|
+
env = Environment(loader=FileSystemLoader(self.manager_path.joinpath('system/genai/graphics_templates')))
|
|
165
|
+
|
|
166
|
+
template = env.get_template('graphics_services_db_each_method.jinja')
|
|
167
|
+
rendered_result = template.render( **each_graphic )
|
|
168
|
+
with open(self.project.project_directory_path.joinpath(f'database/database_discovery/graphics_services.py'), 'a') as out_file:
|
|
169
|
+
out_file.write(rendered_result)
|
|
170
|
+
|
|
171
|
+
log.info(f'..... added db class method: {each_graphic['name']} to database_discovery')
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
""" note it needs the /1 - what is that about?
|
|
176
|
+
curl -X 'GET' \
|
|
177
|
+
'http://localhost:5656/api/Category/sales_by_category' \
|
|
178
|
+
-H 'accept: application/vnd.api+json' \
|
|
179
|
+
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MzY5MTc3OCwianRpIjoiNDBlYzZkNGMtMzk4My00OGEwLTgxMjQtYzQwY2RmYWFiZWRhIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6InUxIiwibmJmIjoxNzQzNjkxNzc4LCJleHAiOjE3NDM3MDUwOTh9.WLDxdkp3PIsgUqR0t9-ymQDR0eOAECdQsgS_3YTqAQ0'
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def create_graphics_dashboard_service(self, graphics_response_path: Path):
|
|
183
|
+
""" Process graphics response from ChatGPT graphics_response_path """
|
|
184
|
+
|
|
185
|
+
# open and read the graphics_response_path json file
|
|
186
|
+
assert graphics_response_path.exists(), f'Graphics response file not found: {graphics_response_path}'
|
|
187
|
+
with open(graphics_response_path, 'r') as file:
|
|
188
|
+
graphics_response = json.load(file)
|
|
189
|
+
if 'graphics' not in graphics_response:
|
|
190
|
+
log.error(f'No graphics found in {graphics_response_path}')
|
|
191
|
+
return
|
|
192
|
+
graphics = graphics_response['graphics']
|
|
193
|
+
|
|
194
|
+
env = Environment(loader=FileSystemLoader(self.manager_path.joinpath('system/genai/graphics_templates')))
|
|
195
|
+
iframe_templates= []
|
|
196
|
+
has_iframe = False
|
|
197
|
+
iframe_links = []
|
|
198
|
+
dashboards = []
|
|
199
|
+
cnt = 0
|
|
200
|
+
template = env.get_template('dashboard_services.jinja')
|
|
201
|
+
for each_graphic in graphics: # add each service to api/api_discovery
|
|
202
|
+
cnt += 1
|
|
203
|
+
server = '{server}'
|
|
204
|
+
iframe = f'iframe_{cnt} = iframe_template.format(url=f"{server}chart_graphics/{each_graphic['name']}")\n'
|
|
205
|
+
iframe_templates.append(iframe)
|
|
206
|
+
link = "{"+ f'iframe_{cnt}' + "}"
|
|
207
|
+
iframe_links.append(f'{link}')
|
|
208
|
+
sqlalchemy_query = each_graphic['class_x_axis']
|
|
209
|
+
|
|
210
|
+
# create the dashboard service query (skip if .err file exists, create .err file if query fails)
|
|
211
|
+
# typical failure: xxx
|
|
212
|
+
db = f"""
|
|
213
|
+
previously_failed = Path('docs/graphics/{each_graphic['name']}.err').exists()
|
|
214
|
+
if previously_failed:
|
|
215
|
+
pass # query has previously failed, so skip it
|
|
216
|
+
else:
|
|
217
|
+
try:
|
|
218
|
+
results = models.{sqlalchemy_query}.{each_graphic['name']}(None)
|
|
219
|
+
color = 'rgba(75, 192, 192, 0.2)'
|
|
220
|
+
dashboard{cnt} = template.render(result=results, color=color)
|
|
221
|
+
dashboard_result['{each_graphic['name']}']= dashboard{cnt}
|
|
222
|
+
except Exception as e:
|
|
223
|
+
msg = f"GenAI query creation error on models.{sqlalchemy_query}.{each_graphic['name']}: " + str(e)
|
|
224
|
+
dashboard_result['{each_graphic['name']}'] = msg
|
|
225
|
+
app_logger.error(msg)
|
|
226
|
+
with open('docs/graphics//{each_graphic['name']}.err', 'w') as err_file:
|
|
227
|
+
err_file.write(msg) # this logs the error to prevent future calls
|
|
228
|
+
|
|
229
|
+
"""
|
|
230
|
+
dashboards.append(db)
|
|
231
|
+
|
|
232
|
+
rendered_result = template.render(iframe_templates=iframe_templates, iframe_links=" ".join(iframe_links), has_iframe=cnt > 0 , dashboards= dashboards)
|
|
233
|
+
with open(self.project.project_directory_path.joinpath(f'api/api_discovery/dashboard_services.py'), 'w') as out_file:
|
|
234
|
+
out_file.write(rendered_result)
|
|
235
|
+
log.info(f'... create_graphics_dashboard_service - created api/api_discovery/dashboard_services.py')
|
|
236
|
+
|
|
237
|
+
for each_graphic in graphics:
|
|
238
|
+
self.fix_sqlalchemy_query(each_graphic)
|
|
239
|
+
template = env.get_template('html_template.jinja')
|
|
240
|
+
rendered_result = template.render( **each_graphic )
|
|
241
|
+
with open(self.project.project_directory_path.joinpath(f'api/api_discovery/{each_graphic['name']}.html'), 'w') as out_file:
|
|
242
|
+
out_file.write(rendered_result)
|
|
243
|
+
|
|
244
|
+
with open(self.project.project_directory_path.joinpath(f'api/api_discovery/{each_graphic['name']}.sql'), 'w') as out_file:
|
|
245
|
+
sql_query = "System Error: missing sql_query - check WGResult format"
|
|
246
|
+
if 'sql_query' in each_graphic:
|
|
247
|
+
sql_query = each_graphic['sql_query']
|
|
248
|
+
out_file.write(sql_query)
|
|
249
|
+
|
|
250
|
+
log.info(f'..... added dashboard query: {each_graphic['name']} to api_discovery')
|
|
251
|
+
|
|
252
|
+
pass
|
|
253
|
+
|
|
254
|
+
def create_genai_graphics_prompts(self, graphics_response_path: Path):
|
|
255
|
+
""" if genai project, create graphics prompt file: docs/graphics/wg_graphics.prompt
|
|
256
|
+
"""
|
|
257
|
+
if self.using is not None:
|
|
258
|
+
return # it's an als request, not a genai project (todo: confirm this works on iterations)
|
|
259
|
+
|
|
260
|
+
# open and read the graphics_response_path json file
|
|
261
|
+
assert graphics_response_path.exists(), f'Graphics response file not found: {graphics_response_path}'
|
|
262
|
+
with open(graphics_response_path, 'r') as file:
|
|
263
|
+
graphics_response = json.load(file)
|
|
264
|
+
log.info(f'... create_genai_graphics_prompts - from {graphics_response_path}')
|
|
265
|
+
graphics = graphics_response['graphics']
|
|
266
|
+
graphics_prompt = ''
|
|
267
|
+
graphics_prompt_count = 0
|
|
268
|
+
for each_graphic in graphics: # add each prompt to docs/graphics
|
|
269
|
+
graphics_prompt_count += 1
|
|
270
|
+
graphics_prompt += each_graphic['prompt'] + '\n'
|
|
271
|
+
with open(self.project.project_directory_path.joinpath(f'docs/graphics/wg_graphics.prompt'), 'w') as out_file:
|
|
272
|
+
out_file.write(graphics_prompt)
|
|
273
|
+
log.info(f'..... added docs/graphics/wg_graphics.prompt')
|
|
274
|
+
pass
|
|
275
|
+
|
|
276
|
+
def graphics_replace_with_in_existing_project(self) -> str:
|
|
277
|
+
"""
|
|
278
|
+
Delete graphics for wg project (als projects - just delete the docs/graphics files)
|
|
279
|
+
1. Update docs/*.prompt to remove lines starting with Graphics
|
|
280
|
+
* Prevents reappearance on iteration
|
|
281
|
+
2. Presume (!) not necessary to delete the graphics[] in docs/*.response files
|
|
282
|
+
3. If delete, rename the api/api_discovery/dashboard_services.py file so it won't be called
|
|
283
|
+
|
|
284
|
+
This does not rebuild / create a new project - operates on current project.
|
|
285
|
+
|
|
286
|
+
If self.replace_with is retry or request, build docs/graphics/wg_graphics.prompt
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
# for all docs/*.prompt files, alter lines where the first characters are 'Graph' (case insensitive)
|
|
290
|
+
docs_dir = self.project.project_directory_path.joinpath('docs')
|
|
291
|
+
replaced_count = 0
|
|
292
|
+
replaced_prompts = ''
|
|
293
|
+
log.info(f"... graphics_replace_with_in_existing_project - self.replace_with: {self.replace_with}")
|
|
294
|
+
|
|
295
|
+
for prompt_file in docs_dir.glob('*.prompt'):
|
|
296
|
+
with open(prompt_file, 'r') as file:
|
|
297
|
+
lines = file.readlines()
|
|
298
|
+
line_number = 0
|
|
299
|
+
with open(prompt_file, 'w') as file:
|
|
300
|
+
for line in lines:
|
|
301
|
+
line_number += 1
|
|
302
|
+
if not line.strip().lower().startswith('graph '):
|
|
303
|
+
file.write(line)
|
|
304
|
+
else:
|
|
305
|
+
replaced_prompts += line
|
|
306
|
+
replaced_count += 1
|
|
307
|
+
if self.replace_with == '!retry': # we are just doing retry - don't replace, use existing wg_graphics
|
|
308
|
+
file.write(line)
|
|
309
|
+
continue
|
|
310
|
+
elif self.replace_with.startswith('!request'): # replacing - replace ==> docs and doc/graphics
|
|
311
|
+
if replaced_count == 1:
|
|
312
|
+
file.write(self.replace_with + '\n')
|
|
313
|
+
graphics_prompt = self.replace_with[8:]
|
|
314
|
+
with open(self.project.project_directory_path.joinpath(f'docs/graphics/wg_graphics.prompt'), 'w') as out_file:
|
|
315
|
+
out_file.write(self.replace_with)
|
|
316
|
+
else:
|
|
317
|
+
assert self.replace_with == '!delete', f"genai_graphics - expected !delete, got: {self.replace_with}"
|
|
318
|
+
pass # removing line
|
|
319
|
+
|
|
320
|
+
log.info(f"..... completed - processed {replaced_count} graph line(s).")
|
|
321
|
+
|
|
322
|
+
# Stop graphics: rename the old dashboard_services.py file to dashboard_services.pyZ
|
|
323
|
+
dashboard_service_path = self.project.project_directory_path.joinpath('api/api_discovery/dashboard_services.py')
|
|
324
|
+
if dashboard_service_path.exists():
|
|
325
|
+
renamed_path = dashboard_service_path.with_suffix('.pyZ')
|
|
326
|
+
dashboard_service_path.rename(renamed_path)
|
|
327
|
+
log.info(f"..... Renamed existing dashboard_services.py to {renamed_path}")
|
|
328
|
+
else:
|
|
329
|
+
log.info(f'.. Note: {dashboard_service_path} not found')
|
|
330
|
+
return replaced_prompts
|
|
331
|
+
|
|
332
|
+
def fix_sqlalchemy_query(self, graphic: Dict):
|
|
333
|
+
""" Fix the SQLAlchemy query for the graphic """
|
|
334
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'].replace('\\n', '\n')
|
|
335
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'].replace('\"', '"')
|
|
336
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'].replace('.isnot', '.is_not')
|
|
337
|
+
|
|
338
|
+
# this part is for readability, not 'fixing'
|
|
339
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'].replace('session.query', '(session.query')
|
|
340
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'] + ')'
|
|
341
|
+
graphic['sqlalchemy_query'] = graphic['sqlalchemy_query'].replace(').', ')\n .')
|
|
342
|
+
pass
|
|
343
|
+
|
|
344
|
+
def append_data_model(self) -> List[str]:
|
|
345
|
+
""" Get the data model
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
list[str]: the data model lines
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
data_model_lines = []
|
|
352
|
+
data_model_lines.extend(['Here is the data model - please use it to create the graphics:'])
|
|
353
|
+
data_model_path = self.project.project_directory_path.joinpath('database/models.py')
|
|
354
|
+
assert data_model_path.exists(), f"Data model file not found: {data_model_path}"
|
|
355
|
+
with open(data_model_path, 'r') as file:
|
|
356
|
+
prompt_lines = file.readlines()
|
|
357
|
+
data_model_lines.extend(prompt_lines)
|
|
358
|
+
data_model_lines.extend(['End of data model'])
|
|
359
|
+
return data_model_lines
|
|
360
|
+
|
|
361
|
+
def append_graphics_files(self) -> List[str]:
|
|
362
|
+
""" Get graphics files (typically from project/docs/graphics)
|
|
363
|
+
* 1 file per graphic
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
list: logic_files
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
graphics_lines = []
|
|
370
|
+
if Path(self.using).is_dir(): # conversation from directory
|
|
371
|
+
for each_file in sorted(Path(self.using).iterdir()):
|
|
372
|
+
if each_file.is_file() and each_file.suffix == '.prompt':
|
|
373
|
+
# read lines from each_file, and append to prompt
|
|
374
|
+
with open(each_file, 'r') as file:
|
|
375
|
+
prompt_lines = file.readlines()
|
|
376
|
+
graphics_lines.extend(prompt_lines)
|
|
377
|
+
return graphics_lines
|
|
378
|
+
|
|
379
|
+
|
|
@@ -27,7 +27,7 @@ log = logging.getLogger(__name__)
|
|
|
27
27
|
|
|
28
28
|
class GenAILogic(object):
|
|
29
29
|
"""
|
|
30
|
-
Called by cli for *existing* project
|
|
30
|
+
Called by cli for *existing* project (must be wg project with docs models)
|
|
31
31
|
|
|
32
32
|
* **Create logic** from *logic files* eg `<project>/docs/logic/check_credit.prompt`
|
|
33
33
|
|
|
@@ -113,7 +113,7 @@ class GenAILogic(object):
|
|
|
113
113
|
return learning_requests # TODO - what if no learning requests?
|
|
114
114
|
|
|
115
115
|
def get_learnings_and_data_model(self) -> List[Dict[str, str]]:
|
|
116
|
-
""" Get prompts from the docs dir (so GPT knows model, learnings)
|
|
116
|
+
""" Get prompts from the docs dir (so GPT knows model, learnings) -- **not** from database/models.py
|
|
117
117
|
|
|
118
118
|
Most often, adding logic to new project, which looks like:
|
|
119
119
|
|
|
@@ -42,6 +42,20 @@ class Model(BaseModel):
|
|
|
42
42
|
description: str
|
|
43
43
|
name: str
|
|
44
44
|
|
|
45
|
+
class Graphic(BaseModel):
|
|
46
|
+
sqlalchemy_query: str # sqlalchemy query using group by, returns result = { "result": [ ("name", "value") ] }
|
|
47
|
+
sql_query: str # sql query using group by, returns result = { "result": [ ("name", "value") ] }
|
|
48
|
+
classes_used: str # comma-delimited list of classes used in sqlalchemy_query
|
|
49
|
+
class_x_axis: str # name of class for x axis
|
|
50
|
+
name: str # suggested Python name for sqlalchemy_query - unique
|
|
51
|
+
prompt: str # prompt used to create the graphic
|
|
52
|
+
title: str # expanded name
|
|
53
|
+
xAxis: str # caption for x axis
|
|
54
|
+
yAxis: str # caption for y axis
|
|
55
|
+
dashboard: bool # whether appears on home page
|
|
56
|
+
graph_type: str # Bar, Line, Pie
|
|
57
|
+
html_code: str # create a java script app to show a bar chart from sqlalchemy_query result
|
|
58
|
+
|
|
45
59
|
class TestDataRow(BaseModel):
|
|
46
60
|
test_data_row_variable: str # the Python test data row variable
|
|
47
61
|
code: str # Python code to create a test data row instance
|
|
@@ -50,6 +64,7 @@ class WGResult(BaseModel): # must match system/genai/prompt_inserts/response_fo
|
|
|
50
64
|
# response: str # result
|
|
51
65
|
models : List[Model] # list of sqlalchemy classes in the response
|
|
52
66
|
rules : List[Rule] # list rule declarations
|
|
67
|
+
graphics: List[Graphic] # list of graphs
|
|
53
68
|
test_data: str
|
|
54
69
|
test_data_rows: List[TestDataRow] # list of test data rows
|
|
55
70
|
test_data_sqlite: str # test data as sqlite INSERT statements
|
|
@@ -729,10 +744,10 @@ def get_create_prompt__with_inserts(arg_prompt_inserts: str='', raw_prompt: str=
|
|
|
729
744
|
pre_post = file.read() # eg, Use SQLAlchemy to create a sqlite database named system/genai/temp/create_db_models.sqlite, with
|
|
730
745
|
prompt_result = pre_post.replace('{{prompt}}', raw_prompt)
|
|
731
746
|
if for_iteration:
|
|
732
|
-
# Update the prior response - be sure not to lose classes and test data already created.
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
log.debug(f'.. iteration inserted: Update the prior response')
|
|
747
|
+
# Update the prior response - be sure not to lose classes, attributes, rules and test data already created.
|
|
748
|
+
iteration_prompt = read_and_expand_prompt(get_manager_path().joinpath(f'system/genai/prompt_inserts/iteration.prompt'))
|
|
749
|
+
prompt_result = iteration_prompt + '\n\n' + prompt_result
|
|
750
|
+
log.debug(f'.. iteration inserted: Update the prior response, using prompt_inserts/iteration.prompt')
|
|
736
751
|
#log.debug(f'.... iteration prompt result: {prompt_result}')
|
|
737
752
|
|
|
738
753
|
prompt_lines = prompt_result.split('\n')
|
|
@@ -758,10 +773,11 @@ def get_create_prompt__with_inserts(arg_prompt_inserts: str='', raw_prompt: str=
|
|
|
758
773
|
do_logic = False
|
|
759
774
|
prompt_line_number += 1
|
|
760
775
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
776
|
+
if format_not_requested := False: # FIXME - double format definition on create; others??
|
|
777
|
+
response_format_file_name = get_manager_path().joinpath(f'system/genai/prompt_inserts/response_format.prompt')
|
|
778
|
+
with open(response_format_file_name, 'r') as file:
|
|
779
|
+
response_format = file.readlines()
|
|
780
|
+
prompt_lines.extend(response_format)
|
|
765
781
|
|
|
766
782
|
prompt_result = "\n".join(prompt_lines) # back to a string
|
|
767
783
|
pass
|
api_logic_server_cli/manager.py
CHANGED
|
@@ -12,7 +12,7 @@ import api_logic_server_cli.api_logic_server as PR
|
|
|
12
12
|
|
|
13
13
|
def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
14
14
|
volume: str = "", open_manager: bool = True, samples: bool = True):
|
|
15
|
-
"""Implements als start to create manager - called from api_logic_server_cli/cli.py
|
|
15
|
+
"""Implements `als start` to create manager - called from api_logic_server_cli/cli.py
|
|
16
16
|
|
|
17
17
|
create Manager at os.getcwd(), including:
|
|
18
18
|
|
|
@@ -27,11 +27,11 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
27
27
|
Bit tricky to find find cli in subdirectories of the lib path for manager run launches
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
|
-
clean (bool):
|
|
31
|
-
open_with (str):
|
|
30
|
+
clean (bool): Overlay existing manager (projects and web_genai retained)
|
|
31
|
+
open_with (str): IDE to use
|
|
32
32
|
api_logic_server_path (Path): _description_
|
|
33
33
|
volume (str, optional): _description_. Defaults to "".
|
|
34
|
-
open_manager (bool, optional):
|
|
34
|
+
open_manager (bool, optional): Whether to open IDE at Manager. Defaults to True.
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
37
|
log = logging.getLogger(__name__)
|
|
@@ -68,8 +68,9 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
68
68
|
docker_volume = volume + '/'
|
|
69
69
|
|
|
70
70
|
to_dir = Path(os.getcwd())
|
|
71
|
+
""" location for creating (cleaning) the Manager """
|
|
71
72
|
path = Path(__file__)
|
|
72
|
-
|
|
73
|
+
from_dir_proto_mgr = api_logic_server_path.joinpath('prototypes/manager')
|
|
73
74
|
to_dir_str = str(to_dir)
|
|
74
75
|
to_dir_check = Path(to_dir).joinpath('venv')
|
|
75
76
|
if not Path(to_dir).joinpath('venv').exists():
|
|
@@ -85,12 +86,12 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
85
86
|
if to_dir_check.exists() and not clean:
|
|
86
87
|
manager_exists = True
|
|
87
88
|
if env_path.exists():
|
|
88
|
-
log.info(f" Using manager at: {to_dir}\n\n")
|
|
89
|
+
log.info(f" Using existing manager (update .env APILOGICSERVER_AUTO_OPEN, only) at: {to_dir}\n\n")
|
|
89
90
|
else:
|
|
90
91
|
log.info(f" Refreshing .env in manager at: {to_dir}\n\n")
|
|
91
|
-
copied_env = shutil.copy(src=
|
|
92
|
+
copied_env = shutil.copy(src=from_dir_proto_mgr.joinpath('settings.txt'), dst=to_dir.joinpath('.env'))
|
|
92
93
|
os.remove(to_dir.joinpath('settings.txt'))
|
|
93
|
-
else:
|
|
94
|
+
else: # new Manager, or clean existing manager
|
|
94
95
|
mgr_save_level = log.level
|
|
95
96
|
codegen_logger = logging.getLogger('sqlacodegen_wrapper.sqlacodegen.sqlacodegen.codegen')
|
|
96
97
|
codegen_logger_save_level= codegen_logger.level
|
|
@@ -99,8 +100,16 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
99
100
|
if to_dir_check.exists():
|
|
100
101
|
log.info(f" Cleaning manager at: {to_dir}\n\n")
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
# create the manager system files and shell scripts (samples created below).
|
|
104
|
+
copied_path = shutil.copytree(src=from_dir_proto_mgr, dst=to_dir, dirs_exist_ok=True, ) # issue: not permitted
|
|
105
|
+
copied_env = shutil.copy(src=from_dir_proto_mgr.joinpath('settings.txt'), dst=to_dir.joinpath('.env'))
|
|
106
|
+
web_genai_docker = to_dir.joinpath('webgenai/docker-compose.yml')
|
|
107
|
+
if web_genai_docker.exists():
|
|
108
|
+
log.debug(' .. WebGenAI docker_compose unaltered (license preserved)')
|
|
109
|
+
else:
|
|
110
|
+
log.debug(' .. WebGenAI docker_compose created')
|
|
111
|
+
copied_env = shutil.copy(src=api_logic_server_path.joinpath('fragments/docker-compose.yml'),
|
|
112
|
+
dst=web_genai_docker)
|
|
104
113
|
os.remove(to_dir.joinpath('settings.txt'))
|
|
105
114
|
log.debug(f" .. created manager\n")
|
|
106
115
|
|
|
Binary file
|
|
Binary file
|
|
@@ -22,6 +22,25 @@
|
|
|
22
22
|
"console": "internalConsole",
|
|
23
23
|
"internalConsoleOptions": "openOnSessionStart"
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
"name": "ApiLogicServer DEBUG",
|
|
27
|
+
"type": "debugpy",
|
|
28
|
+
"cwd": "${workspaceFolder}",
|
|
29
|
+
"env": {
|
|
30
|
+
"PYTHONPATH": "",
|
|
31
|
+
"EXPERIMENT": "",
|
|
32
|
+
"PYTHONHASHSEED": "0",
|
|
33
|
+
"APILOGICPROJECT_LOGGING_CONFIG": "config/logging.yml",
|
|
34
|
+
"APILOGICPROJECT_STOP_OK": "True",
|
|
35
|
+
"APILOGICPROJECT_DEBUG": "False"},
|
|
36
|
+
"request": "launch",
|
|
37
|
+
"program": "api_logic_server_run.py",
|
|
38
|
+
"redirectOutput": true,
|
|
39
|
+
"justMyCode": false,
|
|
40
|
+
"args": ["--flask_host=localhost", "--port=5656", "--swagger_port=5656", "--swagger_host=localhost", "--verbose=False"],
|
|
41
|
+
"console": "internalConsole",
|
|
42
|
+
"internalConsoleOptions": "openOnSessionStart"
|
|
43
|
+
},
|
|
25
44
|
{
|
|
26
45
|
"name": " - API Logic Server - VERBOSE",
|
|
27
46
|
"type": "debugpy",
|
|
@@ -4,6 +4,8 @@ import importlib
|
|
|
4
4
|
import pathlib
|
|
5
5
|
import logging as logging
|
|
6
6
|
import flask_sqlalchemy
|
|
7
|
+
from config.config import Args
|
|
8
|
+
from config import config
|
|
7
9
|
|
|
8
10
|
# use absolute path import for easier multi-{app,model,db} support
|
|
9
11
|
database = __import__('database')
|
|
@@ -40,7 +42,7 @@ def expose_models(api, method_decorators = []):
|
|
|
40
42
|
"""
|
|
41
43
|
|
|
42
44
|
debug_inspect_list = inspect.getmembers(database.models)
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
# Get all the subclasses of the Base class and expose them in the api
|
|
45
47
|
for name, obj in inspect.getmembers(database.models):
|
|
46
48
|
if inspect.isclass(obj) and issubclass(obj, database.models.SAFRSBaseX) and obj is not database.models.SAFRSBaseX:
|
|
@@ -31,7 +31,7 @@ import os, logging, logging.config, sys, yaml # failure here means venv probabl
|
|
|
31
31
|
from flask_sqlalchemy import SQLAlchemy
|
|
32
32
|
import json
|
|
33
33
|
from pathlib import Path
|
|
34
|
-
from config.config import Args
|
|
34
|
+
from config.config import Args # sets up logging
|
|
35
35
|
from config import server_setup
|
|
36
36
|
|
|
37
37
|
current_path = os.path.abspath(os.path.dirname(__file__))
|
|
@@ -68,8 +68,11 @@ import ui.admin.admin_loader as AdminLoader
|
|
|
68
68
|
from security.system.authentication import configure_auth
|
|
69
69
|
import oracledb
|
|
70
70
|
|
|
71
|
+
if os.getenv("EXPERIMENT") == '+':
|
|
72
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
73
|
+
else:
|
|
74
|
+
app_logger = server_setup.logging_setup()
|
|
71
75
|
|
|
72
|
-
app_logger = server_setup.logging_setup()
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
# ==================================
|
|
@@ -40,6 +40,7 @@ def activate_logicbank(session, constraint_handler):
|
|
|
40
40
|
app_logger.exception(e)
|
|
41
41
|
if not os.environ.get("WG_PROJECT") == "True":
|
|
42
42
|
# Continue if inside WebGenAI
|
|
43
|
+
# see: https://apilogicserver.github.io/Docs/WebGenAI-CLI/#wg_rules-and-ide-rules
|
|
43
44
|
raise e
|
|
44
45
|
logic_logger.setLevel(logic_logger_level)
|
|
45
46
|
|