ApiLogicServer 15.0.28__py3-none-any.whl → 15.0.33__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 +4 -4
- api_logic_server_cli/api_logic_server.py +20 -5
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +61 -10
- api_logic_server_cli/cli_args_base.py +1 -1
- api_logic_server_cli/create_from_model/__pycache__/dbml.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/dbml.py +1 -1
- api_logic_server_cli/create_from_model/ont_create.py +6 -1
- api_logic_server_cli/database/mcp.sqlite +0 -0
- api_logic_server_cli/fragments/mcp_admin.yml +11 -0
- api_logic_server_cli/genai/genai_admin_app.py +67 -19
- api_logic_server_cli/genai/genai_mcp.py +43 -0
- api_logic_server_cli/genai/genai_svcs.py +13 -12
- api_logic_server_cli/manager.py +29 -2
- api_logic_server_cli/prototypes/base/config/default.env +3 -0
- api_logic_server_cli/prototypes/base/devops/docker-compose-dev-azure/azure-deploy.sh +3 -3
- api_logic_server_cli/prototypes/base/devops/docker-compose-dev-local/docker-compose.sh +1 -1
- api_logic_server_cli/prototypes/base/ui/admin/admin_loader.py +2 -0
- api_logic_server_cli/prototypes/basic_demo/README.md +1 -1
- api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/models.py +0 -16
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +0 -11
- api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/iteration/ui/admin/admin.yaml +4 -4
- api_logic_server_cli/prototypes/manager/README.md +1 -1
- api_logic_server_cli/prototypes/manager/samples/dbs/readme_samples.md +5 -0
- api_logic_server_cli/prototypes/manager/samples/readme_samples.md +3 -0
- api_logic_server_cli/prototypes/manager/system/app_model_editor/devops/docker-compose-dev-azure/azure-deploy.sh +1 -1
- api_logic_server_cli/prototypes/manager/system/app_model_editor/devops/docker-compose-dev-local-nginx/docker-compose.sh +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/devops/docker-compose-dev-azure/azure-deploy.sh +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/devops/docker-compose-dev-local/docker-compose.sh +1 -1
- api_logic_server_cli/prototypes/nw_no_cust/Tutorial.md +2 -2
- api_logic_server_cli/prototypes/sqlite/devops/docker-compose-dev-azure/azure-deploy.sh +1 -1
- api_logic_server_cli/{prototypes/basic_demo/customizations/logic/logic_discovery → templates}/mcp_client_executor_request.py +4 -2
- {apilogicserver-15.0.28.dist-info → apilogicserver-15.0.33.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.28.dist-info → apilogicserver-15.0.33.dist-info}/RECORD +41 -40
- apilogicserver-15.0.33.dist-info/entry_points.txt +7 -0
- api_logic_server_cli/genai/genai_admin_app copy.py +0 -150
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt copy.md +0 -203
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/notes.md +0 -7
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/z-unused-Admin-App-Learning-Prompt.md +0 -179
- apilogicserver-15.0.28.dist-info/entry_points.txt +0 -3
- {apilogicserver-15.0.28.dist-info → apilogicserver-15.0.33.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.28.dist-info → apilogicserver-15.0.33.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.28.dist-info → apilogicserver-15.0.33.dist-info}/top_level.txt +0 -0
|
@@ -158,7 +158,7 @@ def add_basic_demo_customizations(project: Project, do_show_messages: bool = Tru
|
|
|
158
158
|
# log.info(".. curl -X 'POST' 'http://localhost:5656/api/SysMcp/' -H 'accept: application/vnd.api+json' -H 'Content-Type: application/json' -d '{ \"data\": { \"attributes\": {\"request\": \"List the orders date_shipped is null and CreatedOn before 2023-07-14, and send a discount email (subject: '\\''Discount Offer'\\'') to the customer for each one.\"}, \"type\": \"SysMcp\"}}'")
|
|
159
159
|
log.info('')
|
|
160
160
|
log.info(f'Next Steps: activate security')
|
|
161
|
-
log.info(f'..
|
|
161
|
+
log.info(f'..genai-logic add-auth --db_url=auth')
|
|
162
162
|
if project.is_tutorial == False:
|
|
163
163
|
log.info(".. complete\n")
|
|
164
164
|
|
|
@@ -178,7 +178,7 @@ def add_basic_demo_iteration(project: Project, do_show_messages: bool = True, do
|
|
|
178
178
|
create_utils.recursive_overwrite(nw_path, project.project_directory) # ~/dev/ApiLogicServer/ApiLogicServer-dev/servers/basic_demo
|
|
179
179
|
if do_show_messages:
|
|
180
180
|
log.info("\nNext Step:")
|
|
181
|
-
log.info(f'..
|
|
181
|
+
log.info(f'..genai-logic rebuild-from-database --db_url=sqlite:///database/db.sqlite')
|
|
182
182
|
log.info(".. complete\n")
|
|
183
183
|
|
|
184
184
|
|
|
@@ -210,7 +210,7 @@ def add_sample_ai_customizations(project: Project, do_show_messages: bool = True
|
|
|
210
210
|
log.info(f'..logic/declare_logic.py')
|
|
211
211
|
log.info(f'..security/declare_security.py\n')
|
|
212
212
|
log.info(f'Next Steps: activate security')
|
|
213
|
-
log.info(f'..
|
|
213
|
+
log.info(f'..genai-logic add-auth --db_url=auth')
|
|
214
214
|
if project.is_tutorial == False:
|
|
215
215
|
log.info(".. complete\n")
|
|
216
216
|
|
|
@@ -230,7 +230,7 @@ def add_sample_ai_iteration(project: Project, do_show_messages: bool = True, do_
|
|
|
230
230
|
create_utils.recursive_overwrite(nw_path, project.project_directory) # '/Users/val/dev/ApiLogicServer/ApiLogicServer-dev/org_git/tutorial/1. Instant_Creation'
|
|
231
231
|
if do_show_messages:
|
|
232
232
|
log.info("\nNext Step:")
|
|
233
|
-
log.info(f'..
|
|
233
|
+
log.info(f'..genai-logic rebuild-from-database --project_name=./ --db_url=sqlite:///database/db.sqlite')
|
|
234
234
|
log.info(".. complete\n")
|
|
235
235
|
|
|
236
236
|
|
|
@@ -12,10 +12,10 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
|
|
|
12
12
|
Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
|
-
__version__ = "15.00.
|
|
15
|
+
__version__ = "15.00.33" # last public release: 15.00.25 (15.00.12)
|
|
16
16
|
recent_changes = \
|
|
17
17
|
f'\n\nRecent Changes:\n' +\
|
|
18
|
-
"\t06/
|
|
18
|
+
"\t06/30/2024 - 15.00.33: Tech Preview: genai-logic genai-add-app --vibe, bug [96, 97] \n"\
|
|
19
19
|
"\t06/10/2024 - 15.00.12: MCP Security, win fixes for readme, graphics quotes \n"\
|
|
20
20
|
"\t06/08/2024 - 15.00.10: MCP, optional shortening of stacktrace lines, bugfix[92] \n"\
|
|
21
21
|
"\t05/16/2024 - 14.05.00: safrs 3.1.7, running mcp preview \n"\
|
|
@@ -946,9 +946,16 @@ class ProjectRun(Project):
|
|
|
946
946
|
defaultInterpreterPath = self.api_logic_server_dir_path.parent.parent.parent.joinpath('clean/ApiLogicServer/venv/bin/python')
|
|
947
947
|
self.default_interpreter_path = defaultInterpreterPath
|
|
948
948
|
""" used to compute manager_path """
|
|
949
|
-
self.
|
|
950
|
-
|
|
951
|
-
|
|
949
|
+
self.venv_path = Path(sys.prefix) if is_docker() == False else Path('/home/api_logic_server/api_logic_server_cli')
|
|
950
|
+
self.manager_path = self.venv_path.parent
|
|
951
|
+
check_system_genai = self.manager_path.joinpath('system/genai/temp')
|
|
952
|
+
if not check_system_genai.exists():
|
|
953
|
+
self.manager_path = (self.venv_path / '../api_logic_server_cli/prototypes/manager').resolve()
|
|
954
|
+
log.debug(f'.. ..Manager path from dev env - customizations not active') # eg ...ApiLogicServer-src/api_logic_server_cli/prototypes/manager
|
|
955
|
+
log.debug(f'.. ..Manager path: {self.manager_path}')
|
|
956
|
+
# log.debug(f'.. ..Interp path: {self.manager_path / 'venv/bin/python'}')
|
|
957
|
+
if sys.prefix == sys.base_prefix:
|
|
958
|
+
log.warning(f'.. ..Warning - venv not being used: {self.venv_path}')
|
|
952
959
|
|
|
953
960
|
self.api_logic_server_home = self.api_logic_server_dir_path.parent
|
|
954
961
|
|
|
@@ -1591,6 +1598,14 @@ from database import <project.bind_key>_models
|
|
|
1591
1598
|
log.debug("1. Not Deleting Existing Project")
|
|
1592
1599
|
log.debug("2. Using Existing Project")
|
|
1593
1600
|
if self.command == "add_db":
|
|
1601
|
+
check_bind_key_exists = 'DATABASE_URI_' + self.bind_key.upper()
|
|
1602
|
+
config_path = self.project_directory_path / 'config/config.py'
|
|
1603
|
+
bind_key_exists = create_utils.does_file_contain(in_file=config_path,
|
|
1604
|
+
search_for=check_bind_key_exists)
|
|
1605
|
+
if bind_key_exists and self.bind_key != 'authentication':
|
|
1606
|
+
log.error(f'\nLooks like database already added')
|
|
1607
|
+
log.error(f'..`{check_bind_key_exists}` found in `config/config.py`\n\n')
|
|
1608
|
+
sys.exit(1)
|
|
1594
1609
|
self.abs_db_url = self.update_config_and_copy_sqlite_db(
|
|
1595
1610
|
f".. ..Adding Database [{self.bind_key}] to existing project")
|
|
1596
1611
|
else: # normal path - clone, [overlay nw]
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
last_created_date: June
|
|
2
|
-
last_created_project_name:
|
|
3
|
-
last_created_version: 15.00.
|
|
1
|
+
last_created_date: June 30, 2025 09:36:49
|
|
2
|
+
last_created_project_name: samples/nw_sample_nocust
|
|
3
|
+
last_created_version: 15.00.32
|
api_logic_server_cli/cli.py
CHANGED
|
@@ -12,6 +12,8 @@ To add a new arg:
|
|
|
12
12
|
* update Project.run()
|
|
13
13
|
|
|
14
14
|
Main code is api_logic_server.py (PR)
|
|
15
|
+
|
|
16
|
+
To expand commands: ctx.forward(existing_command))
|
|
15
17
|
'''
|
|
16
18
|
|
|
17
19
|
from contextlib import closing
|
|
@@ -447,7 +449,7 @@ def curl_test(ctx, message):
|
|
|
447
449
|
help="App directory name")
|
|
448
450
|
@click.option('--admin-app', 'admin_app',
|
|
449
451
|
default='admin',
|
|
450
|
-
help="Input admin app")
|
|
452
|
+
help="Input admin app (schema)")
|
|
451
453
|
@click.pass_context
|
|
452
454
|
def app_create(ctx, project_name, app, admin_app):
|
|
453
455
|
"""
|
|
@@ -778,13 +780,16 @@ def genai_graphics(ctx, using, genai_version: str, replace_with: str):
|
|
|
778
780
|
pass
|
|
779
781
|
log.info("")
|
|
780
782
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
@main.command("genai-app", cls=HideDunderCommand)
|
|
783
|
+
@main.command("genai-add-app", cls=HideDunderCommand)
|
|
785
784
|
@click.option('--app-name', 'app_name',
|
|
786
785
|
default='react_app',
|
|
787
786
|
help="Name of generated app in ui/")
|
|
787
|
+
@click.option('--vibe/--no-vibe',
|
|
788
|
+
default=True, is_flag=True,
|
|
789
|
+
help="Show vibe docs")
|
|
790
|
+
@click.option('--retries',
|
|
791
|
+
default=1,
|
|
792
|
+
help="lint retries - 1 means none (see setup)")
|
|
788
793
|
@click.option('--schema',
|
|
789
794
|
default='admin.yaml',
|
|
790
795
|
help="Model file in ui/admin/")
|
|
@@ -792,9 +797,9 @@ def genai_graphics(ctx, using, genai_version: str, replace_with: str):
|
|
|
792
797
|
default='gpt-4o',
|
|
793
798
|
help="Eg, gpt-3.5-turbo, gpt-4o")
|
|
794
799
|
@click.pass_context
|
|
795
|
-
def
|
|
800
|
+
def genai_add_app(ctx, app_name: str, vibe: click.BOOL, retries: int, schema: str, genai_version: str):
|
|
796
801
|
"""
|
|
797
|
-
|
|
802
|
+
Creates a customizable react app in ui/, ready for vibe
|
|
798
803
|
"""
|
|
799
804
|
global command
|
|
800
805
|
project_dir = resolve_blank_project_name('')
|
|
@@ -817,11 +822,57 @@ def genai_admin_app(ctx, app_name: str, schema: str, genai_version: str):
|
|
|
817
822
|
log.info(f'... Typical usage - cd into project, use --project_name=. \n')
|
|
818
823
|
exit (1)
|
|
819
824
|
from api_logic_server_cli.genai.genai_admin_app import GenAIAdminApp
|
|
820
|
-
genai_admin = GenAIAdminApp(project=project, app_name=app_name, schema=schema, genai_version=genai_version)
|
|
825
|
+
genai_admin = GenAIAdminApp(project=project, app_name=app_name, vibe=vibe, schema=schema, retries=retries, genai_version=genai_version)
|
|
826
|
+
pass
|
|
827
|
+
log.info("")
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
@main.command("genai-add-mcp-client", cls=HideDunderCommand)
|
|
831
|
+
@click.option('--admin-app', is_flag=True,
|
|
832
|
+
default=True,
|
|
833
|
+
help="Update Admin App")
|
|
834
|
+
@click.pass_context
|
|
835
|
+
def genai_add_mcp_client(ctx, admin_app: click.BOOL):
|
|
836
|
+
"""
|
|
837
|
+
Adds mcp-client to project: db, logic, admin app
|
|
838
|
+
"""
|
|
839
|
+
global command
|
|
840
|
+
|
|
841
|
+
project_name = resolve_blank_project_name('')
|
|
842
|
+
log.info("")
|
|
843
|
+
|
|
844
|
+
mcp_db_path = get_api_logic_server_path().joinpath("database/mcp.sqlite")
|
|
845
|
+
assert mcp_db_path.exists(), "Unable to find api_logic_server_cli/database/mcp.sqlite"
|
|
846
|
+
mcp_uri = fr"sqlite:////{str(mcp_db_path)}"
|
|
847
|
+
project = PR.ProjectRun(command="add_db",
|
|
848
|
+
project_name=project_name,
|
|
849
|
+
api_name='api',
|
|
850
|
+
db_url=mcp_uri,
|
|
851
|
+
bind_key='mcp',
|
|
852
|
+
bind_key_url_separator=default_bind_key_url_separator
|
|
853
|
+
)
|
|
854
|
+
print("MCP DB Added")
|
|
855
|
+
|
|
856
|
+
project.project_directory, project.api_name, project.merge_into_prototype = \
|
|
857
|
+
create_utils.get_project_directory_and_api_name(project)
|
|
858
|
+
project.project_directory_actual = os.path.abspath(os.getcwd()) # make path absolute, not relative (no /../)
|
|
859
|
+
project.project_directory_path = Path(project.project_directory_actual)
|
|
860
|
+
models_py_path = project.project_directory_path.joinpath('database/models.py')
|
|
861
|
+
project.abs_db_url, project.nw_db_status, project.model_file_name = \
|
|
862
|
+
create_utils.get_abs_db_url("0. Using Sample DB", project, is_auth=True)
|
|
863
|
+
|
|
864
|
+
if not models_py_path.exists():
|
|
865
|
+
log.info(f'... Error - does not appear to be a project: {str(project.project_directory_path)}')
|
|
866
|
+
log.info(f'... Typical usage - cd into project, use --project_name=. \n')
|
|
867
|
+
exit (1)
|
|
868
|
+
from api_logic_server_cli.genai.genai_mcp import GenMCP
|
|
869
|
+
genai_mcp = GenMCP(project=project, admin_app=admin_app, api_logic_server_path=get_api_logic_server_path())
|
|
821
870
|
pass
|
|
871
|
+
|
|
822
872
|
log.info("")
|
|
823
873
|
|
|
824
874
|
|
|
875
|
+
|
|
825
876
|
@main.command("genai-create", cls=HideDunderCommand)
|
|
826
877
|
@click.option('--project-name', 'project_name',
|
|
827
878
|
default=f'{last_created_project_name}',
|
|
@@ -1386,7 +1437,7 @@ def rebuild_from_database(ctx, project_name: str, db_url: str, api_name: str, no
|
|
|
1386
1437
|
\b
|
|
1387
1438
|
ex
|
|
1388
1439
|
\b
|
|
1389
|
-
|
|
1440
|
+
genai-logic rebuild-from-database --project_name=~/dev/servers/ApiLogicProject --db_url=nw
|
|
1390
1441
|
|
|
1391
1442
|
"""
|
|
1392
1443
|
db_types = ""
|
|
@@ -2053,7 +2104,7 @@ def check_ports():
|
|
|
2053
2104
|
|
|
2054
2105
|
|
|
2055
2106
|
def start(): # target of setup.py
|
|
2056
|
-
sys.stdout.write("\nWelcome to
|
|
2107
|
+
sys.stdout.write("\nWelcome to Genai-Logic " + PR.__version__ + "\n\n")
|
|
2057
2108
|
hostname, local_ip = check_ports() # = socket.gethostname()
|
|
2058
2109
|
# sys.stdout.write(" SQLAlchemy Database URI help: https://docs.sqlalchemy.org/en/14/core/engines.html\n")
|
|
2059
2110
|
main(obj={})
|
|
Binary file
|
|
Binary file
|
|
@@ -210,7 +210,7 @@ class DBMLCreator(object):
|
|
|
210
210
|
# copy mcp learning from manager (to enable user to extend)
|
|
211
211
|
docs_path = Path(self.mod_gen.project_directory).joinpath('docs')
|
|
212
212
|
docs_path.mkdir(parents=True, exist_ok=True)
|
|
213
|
-
mcp_learning_src = genai_svcs.get_manager_path(
|
|
213
|
+
mcp_learning_src = genai_svcs.get_manager_path(project=self.mod_gen.project).joinpath('system/genai/mcp_learning')
|
|
214
214
|
mcp_learning_dst = Path(self.mod_gen.project_directory).joinpath('docs/mcp_learning')
|
|
215
215
|
if mcp_learning_dst.exists():
|
|
216
216
|
shutil.rmtree(mcp_learning_dst)
|
|
@@ -120,6 +120,11 @@ class OntCreator(object):
|
|
|
120
120
|
if each_resource["hidden"] == True:
|
|
121
121
|
continue
|
|
122
122
|
each_entity = self.create_model_entity(each_resource, resources=resources)
|
|
123
|
+
is_missing = not each_resource_name in resources
|
|
124
|
+
if is_missing: # might occur with add-db
|
|
125
|
+
log.warning(f"\n⚠️ Warning - ont_create() finds admin.yaml resource '{each_resource_name}' - not present in database model")
|
|
126
|
+
log.warning(f"..Can occur when using multiple databases - update your ontimize app as required")
|
|
127
|
+
continue
|
|
123
128
|
app_model_out.entities[each_resource_name] = each_entity
|
|
124
129
|
|
|
125
130
|
app_model_out.entities[each_resource_name].columns = []
|
|
@@ -249,7 +254,7 @@ class OntCreator(object):
|
|
|
249
254
|
if compute_type:
|
|
250
255
|
is_missing = not each_resource_name in resources
|
|
251
256
|
if is_missing: # might occur with add-db, using wrong model
|
|
252
|
-
sys.exit(f"Sys Err - ont_create missing resource: {each_resource_name}\n\n")
|
|
257
|
+
sys.exit(f"❌ Sys Err - ont_create missing resource: {each_resource_name}\n\n")
|
|
253
258
|
else:
|
|
254
259
|
resource = resources[each_resource_name]
|
|
255
260
|
resource_attributes = resource.attributes
|
|
Binary file
|
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
import importlib
|
|
7
7
|
from api_logic_server_cli.genai.genai_utils import call_chatgpt
|
|
8
8
|
import requests
|
|
9
|
-
import os, time
|
|
9
|
+
import os, time, sys
|
|
10
10
|
import datetime
|
|
11
11
|
import create_from_model.api_logic_server_utils as utils
|
|
12
12
|
import time
|
|
@@ -27,6 +27,7 @@ import json
|
|
|
27
27
|
from pathlib import Path
|
|
28
28
|
from openai import OpenAI
|
|
29
29
|
import yaml
|
|
30
|
+
import subprocess
|
|
30
31
|
import api_logic_server_cli.genai.genai_svcs as genai_svcs
|
|
31
32
|
|
|
32
33
|
log = logging.getLogger(__name__)
|
|
@@ -38,12 +39,15 @@ class JSResponseFormat(BaseModel): # must match system/genai/prompt_inserts/res
|
|
|
38
39
|
|
|
39
40
|
class GenAIAdminApp:
|
|
40
41
|
|
|
41
|
-
def __init__(self, project: Project, app_name: str, schema: str, genai_version: str):
|
|
42
|
+
def __init__(self, project: Project, app_name: str, vibe: bool, schema: str, genai_version: str, retries: int):
|
|
42
43
|
self.start_time = time.time()
|
|
43
44
|
|
|
45
|
+
self.project = project
|
|
44
46
|
self.api_version = genai_version
|
|
47
|
+
self.retries = retries
|
|
48
|
+
|
|
45
49
|
self.project_root = project.project_directory_path
|
|
46
|
-
self.app_templates_path = genai_svcs.get_manager_path(
|
|
50
|
+
self.app_templates_path = genai_svcs.get_manager_path(project=project).joinpath('system/genai/app_templates')
|
|
47
51
|
|
|
48
52
|
log.info(f'\ngenai_app here..')
|
|
49
53
|
log.info(f'..model: {schema}')
|
|
@@ -56,13 +60,18 @@ class GenAIAdminApp:
|
|
|
56
60
|
self.admin_yaml_path = self.project_root / f"ui/admin/{schema}"
|
|
57
61
|
self.admin_config_prompt_path = self.app_templates_path / f"app_learning/Admin-config-prompt.md"
|
|
58
62
|
self.admin_json_api_model_prompt_path = self.app_templates_path / f"app_learning/Admin-json-api-model-prompt.md"
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
if not self.admin_config_prompt_path.exists():
|
|
64
|
+
log.error('\nUnable to find Manager for app_learning/Admin-config-prompt.md')
|
|
65
|
+
log.error('..Please set env variable APILOGICSERVER_HOME to manager root\n')
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
if not self.admin_json_api_model_prompt_path.exists():
|
|
68
|
+
log.error('\nUnable to find Manager for app_learning/Admin-json-api-model-prompt.md')
|
|
69
|
+
log.error('..Please set env variable APILOGICSERVER_HOME to manager root\n')
|
|
70
|
+
sys.exit(1)
|
|
61
71
|
|
|
62
72
|
self.ui_project_path = self.project_root / f"ui/{app_name}"
|
|
63
73
|
self.ui_src_path = self.ui_project_path / "src"
|
|
64
74
|
|
|
65
|
-
self.app_templates_path = genai_svcs.get_manager_path(use_env=True).joinpath('system/genai/app_templates')
|
|
66
75
|
self.react_admin_template_path = self.app_templates_path / 'react-admin-template'
|
|
67
76
|
self.prompts_path = self.app_templates_path / "app_learning"
|
|
68
77
|
# self.admin_app_learning = utils.read_file(self.prompts_path / "Admin-App-Learning-Prompt.md")
|
|
@@ -99,6 +108,8 @@ class GenAIAdminApp:
|
|
|
99
108
|
log.info(f'> cd ui/{app_name}')
|
|
100
109
|
log.info('> npm install')
|
|
101
110
|
log.info('> npm start\n')
|
|
111
|
+
if vibe:
|
|
112
|
+
log.info('\n💡 Suggestion: Customize with Vibe: https://apilogicserver.github.io/Docs/Admin-Vibe/#vibe-customization')
|
|
102
113
|
|
|
103
114
|
def read_standard_imports(self) -> List[str]:
|
|
104
115
|
'''grr
|
|
@@ -127,7 +138,6 @@ class GenAIAdminApp:
|
|
|
127
138
|
def fix_resource(genai_app: GenAIAdminApp, raw_source: str) -> str:
|
|
128
139
|
''' Remove occasional begin/end code markers <br>
|
|
129
140
|
And horrific override of ChatGPT refusal to generate imports AS DIRECTED!<br>
|
|
130
|
-
ToDo: lint, and repeat generation if errors detected
|
|
131
141
|
'''
|
|
132
142
|
|
|
133
143
|
source_lines = raw_source.splitlines()
|
|
@@ -140,13 +150,38 @@ class GenAIAdminApp:
|
|
|
140
150
|
continue
|
|
141
151
|
else:
|
|
142
152
|
break
|
|
143
|
-
if do_mandatory_imports := True and not imports_done and '
|
|
153
|
+
if do_mandatory_imports := True and not imports_done and 'props' in each_line:
|
|
144
154
|
result_lines = list(genai_app.standard_imports)
|
|
145
155
|
imports_done = True
|
|
146
156
|
result_lines.append(each_line)
|
|
157
|
+
parse_result = True
|
|
147
158
|
# return source_lines as a string
|
|
148
159
|
return "\n".join(result_lines)
|
|
149
160
|
|
|
161
|
+
def js_lint_source_code(target_file: Path):
|
|
162
|
+
# js lint target_file: npx eslint target_file.js
|
|
163
|
+
# needs: eslint
|
|
164
|
+
# needs: npm install eslint-plugin-jsdoc
|
|
165
|
+
# works manually: npx eslint /Users/val/dev/ApiLogicServer/ApiLogicServer-dev/servers/basic_demo/ui/basic_demo_app/src/Customer.js -c .eslintrc.js
|
|
166
|
+
# failing: Value for 'config' of type 'path::String' required.\nYou're using eslint.config.js
|
|
167
|
+
config = self.project.api_logic_server_dir_path / 'tools/.eslintrc.js'
|
|
168
|
+
assert config.exists()
|
|
169
|
+
try:
|
|
170
|
+
result = subprocess.run(
|
|
171
|
+
["npx", "eslint", str(target_file), '-c ' + str(config)[1:]],
|
|
172
|
+
capture_output=True,
|
|
173
|
+
text=True
|
|
174
|
+
)
|
|
175
|
+
if result.returncode == 0:
|
|
176
|
+
source_code_fixed = True
|
|
177
|
+
else:
|
|
178
|
+
log.warning(f"ESLint issues in {target_file}:\n{result.stdout}\n{result.stderr}")
|
|
179
|
+
source_code_fixed = False
|
|
180
|
+
except Exception as e:
|
|
181
|
+
log.warning(f"Could not lint {target_file}: {e}")
|
|
182
|
+
# If linting fails, assume code is okay to proceed
|
|
183
|
+
source_code_fixed = True
|
|
184
|
+
return source_code_fixed
|
|
150
185
|
|
|
151
186
|
for each_resource_name, each_resource in self.resources.items():
|
|
152
187
|
learning = self.admin_app_resource_learning
|
|
@@ -154,20 +189,33 @@ class GenAIAdminApp:
|
|
|
154
189
|
messages = [
|
|
155
190
|
{"role": "user", "content": "You are a helpful expert in react and JavaScript"},
|
|
156
191
|
{"role": "user", "content": learning},
|
|
157
|
-
# {"role": "user", "content": example_image_content},
|
|
158
|
-
# {"role": "user", "content": f'Schema:\n{self.schema_yaml}'},
|
|
159
192
|
{"role": "user", "content": f'Schema:\n{self.schema}'},
|
|
160
193
|
{"role": "user", "content": f'Generate the full javascript source code for the `{each_resource_name}.js` React Admin file, formatted as a JSResponseFormat'}]
|
|
161
194
|
save_response = self.project_root / f"docs/admin_app/{each_resource_name}"
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
195
|
+
retry_number = 0
|
|
196
|
+
|
|
197
|
+
max_retries = 2
|
|
198
|
+
while retry_number <= self.retries: # loop until lint succeeds, max retry_number times
|
|
199
|
+
retry_number += 1
|
|
200
|
+
output = genai_svcs.call_chatgpt(
|
|
201
|
+
messages=messages,
|
|
202
|
+
api_version=self.api_version,
|
|
203
|
+
using=save_response,
|
|
204
|
+
response_as=JSResponseFormat
|
|
205
|
+
)
|
|
206
|
+
response_dict = json.loads(output)
|
|
207
|
+
target_file = self.ui_src_path / f"{each_resource_name}.js"
|
|
208
|
+
source_code = fix_resource(self, response_dict['code'])
|
|
209
|
+
utils.write_file(target_file, source_code)
|
|
210
|
+
source_code_fixed = True
|
|
211
|
+
if self.retries > 1: # 1 retry (current , per setup issues) means no lint
|
|
212
|
+
source_code_fixed = js_lint_source_code(target_file=target_file)
|
|
213
|
+
if source_code_fixed:
|
|
214
|
+
break
|
|
215
|
+
if source_code_fixed:
|
|
216
|
+
log.info(f"..✅ Wrote: {each_resource_name}.js")
|
|
217
|
+
else:
|
|
218
|
+
log.warning(f"..❌ {self.retries} retries did not fix: {each_resource_name}.js")
|
|
171
219
|
|
|
172
220
|
|
|
173
221
|
def b_generate_app_js(self):
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
import requests
|
|
8
|
+
import os, time
|
|
9
|
+
import datetime
|
|
10
|
+
import json
|
|
11
|
+
from typing import List, Dict
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
import create_from_model.api_logic_server_utils as create_utils
|
|
14
|
+
import json
|
|
15
|
+
|
|
16
|
+
log = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class JSResponseFormat(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
|
|
20
|
+
code : str # generated javascript code (only)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class GenMCP:
|
|
24
|
+
|
|
25
|
+
def __init__(self, project: Project, admin_app: bool, api_logic_server_path: Path):
|
|
26
|
+
self.start_time = time.time()
|
|
27
|
+
|
|
28
|
+
self.project_root = project.project_directory_path
|
|
29
|
+
|
|
30
|
+
log.info(f'\ngenai_mcp here..')
|
|
31
|
+
|
|
32
|
+
shutil.copyfile(api_logic_server_path / 'templates/mcp_client_executor_request.py',
|
|
33
|
+
project.project_directory_path / 'logic/logic_discovery/mcp_client_executor_request.py')
|
|
34
|
+
|
|
35
|
+
if admin_app:
|
|
36
|
+
lines = create_utils.read_file(path = api_logic_server_path / 'fragments/mcp_admin.yml')
|
|
37
|
+
admin_yaml_path = project.project_directory_path / 'ui/admin/admin.yaml'
|
|
38
|
+
create_utils.insert_lines_at(lines = lines,
|
|
39
|
+
at = 'settings:',
|
|
40
|
+
file_name = admin_yaml_path)
|
|
41
|
+
pass
|
|
42
|
+
pass
|
|
43
|
+
|
|
@@ -966,7 +966,7 @@ def call_chatgpt(messages: List[Dict[str, str]], api_version: str, using: str, r
|
|
|
966
966
|
log.error(f"\n\nError: ChatGPT call failed\n- please see https://apilogicserver.github.io/Docs/WebGenAI-CLI/#configuratio\n{inst}\n\n")
|
|
967
967
|
sys.exit(1)
|
|
968
968
|
|
|
969
|
-
def get_manager_path(
|
|
969
|
+
def get_manager_path(project: object = None) -> Path:
|
|
970
970
|
""" Checks cwd, parent, and grandparent for system/genai
|
|
971
971
|
|
|
972
972
|
* Possibly could add cli arg later
|
|
@@ -978,46 +978,47 @@ def get_manager_path(use_env: bool = False) -> Path:
|
|
|
978
978
|
Path: Manager path (contains system/genai)
|
|
979
979
|
"""
|
|
980
980
|
|
|
981
|
-
if
|
|
982
|
-
result_path =
|
|
981
|
+
if project is not None:
|
|
982
|
+
result_path = project.manager_path
|
|
983
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
984
|
+
if check_system_genai.exists():
|
|
985
|
+
return result_path
|
|
983
986
|
return result_path
|
|
984
987
|
|
|
985
988
|
result_path = Path(os.getcwd()) # normal case - project at manager root
|
|
986
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
989
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
987
990
|
if check_system_genai.exists():
|
|
988
991
|
return result_path
|
|
989
992
|
|
|
990
993
|
result_path = result_path.parent # try pwd parent
|
|
991
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
994
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
992
995
|
if check_system_genai.exists():
|
|
993
996
|
return result_path
|
|
994
997
|
|
|
995
998
|
result_path = result_path.parent # try pwd grandparent
|
|
996
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
999
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
997
1000
|
if check_system_genai.exists():
|
|
998
1001
|
return result_path
|
|
999
1002
|
|
|
1000
1003
|
result_path = result_path.parent
|
|
1001
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
1004
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
1002
1005
|
if check_system_genai.exists():
|
|
1003
1006
|
return result_path
|
|
1004
1007
|
|
|
1005
1008
|
result_path = result_path.parent
|
|
1006
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
1009
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
1007
1010
|
if check_system_genai.exists():
|
|
1008
1011
|
return result_path
|
|
1009
1012
|
|
|
1010
1013
|
result_path = result_path.parent
|
|
1011
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
1014
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
1012
1015
|
if check_system_genai.exists():
|
|
1013
1016
|
return result_path
|
|
1014
1017
|
|
|
1015
1018
|
result_path = result_path.parent # try ancestors - this is for import testing
|
|
1016
|
-
check_system_genai = result_path.joinpath('system/genai')
|
|
1019
|
+
check_system_genai = result_path.joinpath('system/genai/temp')
|
|
1017
1020
|
|
|
1018
1021
|
if not check_system_genai.exists():
|
|
1019
|
-
if use_env:
|
|
1020
|
-
result_path = Path(create_utils.get_api_logic_server_dir()).joinpath('prototypes/manager')
|
|
1021
1022
|
check_system_genai.exists(), f"Manager Directory not found and APILOGICSERVER_HOME not set: {check_system_genai}"
|
|
1022
1023
|
return result_path
|
|
1023
1024
|
|
api_logic_server_cli/manager.py
CHANGED
|
@@ -31,10 +31,35 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
31
31
|
clean (bool): Overlay existing manager (projects and web_genai retained)
|
|
32
32
|
open_with (str): IDE to use
|
|
33
33
|
api_logic_server_path (Path): _description_
|
|
34
|
-
volume (str, optional):
|
|
34
|
+
volume (str, optional): for docker. Defaults to "".
|
|
35
35
|
open_manager (bool, optional): Whether to open IDE at Manager. Defaults to True.
|
|
36
|
+
samples (bool, optional): Whether to create large samples (prevent win max file length)
|
|
36
37
|
"""
|
|
37
38
|
|
|
39
|
+
def create_sym_links(cli_path: Path, mgr_path: Path):
|
|
40
|
+
"""
|
|
41
|
+
Creates symbolic links to sample dbs and prompts (clearer than db abbreviations).
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
cli_path (Path): loc of cli.py in the manager's venv
|
|
45
|
+
mgr_path (Path): path of manager being created
|
|
46
|
+
|
|
47
|
+
Side Effects:
|
|
48
|
+
Creates a symbolic link from 'cli_path/database/basic_demo.sqlite' to 'mgr_path/samples/dbs/basic_demo'.
|
|
49
|
+
Prints a confirmation message upon successful creation.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
OSError: If the symbolic link cannot be created (e.g., due to permissions or existing link).
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# create symbolic link - thanks https://www.geeksforgeeks.org/python/python-os-symlink-method/
|
|
56
|
+
try:
|
|
57
|
+
os.symlink(cli_path.parent / 'database/basic_demo.sqlite', mgr_path / 'samples/db/basic_demo.sqlite')
|
|
58
|
+
print("Link created")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
38
63
|
log = logging.getLogger(__name__)
|
|
39
64
|
|
|
40
65
|
project = PR.ProjectRun(command= "start", project_name='ApiLogicServer', db_url='sqlite', execute=False)
|
|
@@ -55,6 +80,7 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
55
80
|
log.info(f"\nStarting manager at: {os.getcwd()}") # eg, ...ApiLogicServer-dev/clean/ApiLogicServer
|
|
56
81
|
|
|
57
82
|
docker_volume = ''
|
|
83
|
+
''' normally volume " '/' '''
|
|
58
84
|
if project.is_docker:
|
|
59
85
|
# volume typically /ApiLogicServer... % docker run -it --name api_logic_server --rm --net dev-network -p 5656:5656 -p 5002:5002 -v ${PWD}:/ApiLogicServer apilogicserver/api_logic_server
|
|
60
86
|
if do_local_docker_test == False: # normal path
|
|
@@ -161,7 +187,7 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
161
187
|
codegen_logger.setLevel(codegen_logger_save_level)
|
|
162
188
|
pass
|
|
163
189
|
|
|
164
|
-
# find cli in subdirectories of the lib path for manager run launches, and update
|
|
190
|
+
# find cli in subdirectories of the lib path for manager run launches, and update `.vscode/launch.json`
|
|
165
191
|
if manager_exists or project.is_docker:
|
|
166
192
|
log.debug(f" docker -- not updating .env and launch.json\n\n")
|
|
167
193
|
else:
|
|
@@ -187,6 +213,7 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
187
213
|
create_utils.replace_string_in_file(search_for = 'cli_path',
|
|
188
214
|
replace_with=str(cli_str),
|
|
189
215
|
in_file=vscode_launch_path)
|
|
216
|
+
create_sym_links(cli_path=cli_path, mgr_path=to_dir)
|
|
190
217
|
|
|
191
218
|
if env_path.exists():
|
|
192
219
|
create_utils.replace_string_in_file(search_for = 'APILOGICSERVER_AUTO_OPEN=code',
|
|
@@ -6,6 +6,9 @@ SQLAlCHEMY_ECHO = False
|
|
|
6
6
|
# APILOGICPROJECT_KAFKA_PRODUCER = "{\"bootstrap.servers\": \"localhost:9092\"}"
|
|
7
7
|
# SQLALCHEMY_DATABASE_URI=db.sqlite
|
|
8
8
|
|
|
9
|
+
# required if you are not running from venv or docker apilogicserver/api_logic_server (eg, azure)
|
|
10
|
+
# APILOGICPROJECT_APILOGICSERVERHOME=src/ApiLogicServer-src
|
|
11
|
+
|
|
9
12
|
SECURITY_ENABLED = false
|
|
10
13
|
|
|
11
14
|
# if using tunnel for mcp, function, or ai_plugin
|
|
@@ -55,9 +55,9 @@ echo " "
|
|
|
55
55
|
if [ ! -f "./database/authentication_models.py" ]
|
|
56
56
|
then
|
|
57
57
|
echo "\nYou need to activate security first. With you database running, ...\n"
|
|
58
|
-
echo "
|
|
59
|
-
echo "
|
|
60
|
-
echo "
|
|
58
|
+
echo "genai-logic add-auth --project_name=. --db_url=mysql+pymysql://root:p@localhost:3306/authdb, or..."
|
|
59
|
+
echo "genai-logic add-auth --project_name=. --db_url=postgresql://postgres:p@localhost/authdb", or...
|
|
60
|
+
echo "genai-logic add-auth --project_name=. --db_url=authdb"
|
|
61
61
|
echo "\nRebuild your image"
|
|
62
62
|
echo "\nThen, stop mysql/postgres containers to avoid port conflicts with services\n"
|
|
63
63
|
exit 1
|
|
@@ -21,7 +21,7 @@ pwd
|
|
|
21
21
|
if [ ! -f "./../../database/database_discovery/authentication_models.py" ]
|
|
22
22
|
then
|
|
23
23
|
echo "\nYou need to activate security first. With mysql-container running...\n"
|
|
24
|
-
echo "
|
|
24
|
+
echo "genai-logic add-auth --project_name=. --db_url=mysql+pymysql://root:p@localhost:3306/authdb"
|
|
25
25
|
echo "\nRebuild your image"
|
|
26
26
|
echo "\nThen, stop mysql-container\n"
|
|
27
27
|
exit 1
|