ApiLogicServer 15.0.12__py3-none-any.whl → 15.0.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. api_logic_server_cli/api_logic_server.py +2 -1
  2. api_logic_server_cli/api_logic_server_info.yaml +2 -2
  3. api_logic_server_cli/cli.py +44 -1
  4. api_logic_server_cli/create_from_model/__pycache__/api_logic_server_utils.cpython-312.pyc +0 -0
  5. api_logic_server_cli/create_from_model/api_logic_server_utils.py +14 -0
  6. api_logic_server_cli/genai/genai_admin_app copy.py +150 -0
  7. api_logic_server_cli/genai/genai_admin_app.py +155 -0
  8. api_logic_server_cli/genai/genai_svcs.py +49 -10
  9. api_logic_server_cli/logging.yml +5 -0
  10. api_logic_server_cli/prototypes/base/config/config.py +9 -15
  11. api_logic_server_cli/prototypes/base/docs/training/admin_app_1_context.prompt.md +3 -0
  12. api_logic_server_cli/prototypes/base/docs/training/admin_app_2_functionality.prompt.md +69 -0
  13. api_logic_server_cli/prototypes/base/docs/training/admin_app_3_architecture.prompt.md +29 -0
  14. api_logic_server_cli/prototypes/base/docs/training/admin_app_unused.md +156 -0
  15. api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +15 -12
  16. api_logic_server_cli/prototypes/basic_demo/customizations/docs/mcp_learning/mcp_discovery.json +108 -0
  17. api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Learning-Prompt.md +154 -0
  18. api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/notes.md +7 -0
  19. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/.DS_Store +0 -0
  20. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/README.md +17 -0
  21. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/README_create_react_app.md +70 -0
  22. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/package-lock.json +18469 -0
  23. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/package.json +44 -0
  24. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/favicon.ico +0 -0
  25. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/index.html +43 -0
  26. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/logo192.png +0 -0
  27. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/logo512.png +0 -0
  28. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/manifest.json +25 -0
  29. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/public/robots.txt +3 -0
  30. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/App.css +38 -0
  31. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/App.js +25 -0
  32. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/App.test.js +8 -0
  33. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/dataProvider.js +110 -0
  34. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/index.css +13 -0
  35. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/index.js +17 -0
  36. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/logo.svg +1 -0
  37. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/reportWebVitals.js +13 -0
  38. api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/src/setupTests.js +5 -0
  39. api_logic_server_cli/prototypes/nw/ui/react_admin/.DS_Store +0 -0
  40. api_logic_server_cli/prototypes/nw/ui/react_admin/README.md +19 -0
  41. api_logic_server_cli/prototypes/nw/ui/react_admin/README_create_react_app.md +70 -0
  42. api_logic_server_cli/prototypes/nw/ui/react_admin/package-lock.json +18469 -0
  43. api_logic_server_cli/prototypes/nw/ui/react_admin/package.json +44 -0
  44. api_logic_server_cli/prototypes/nw/ui/react_admin/public/favicon.ico +0 -0
  45. api_logic_server_cli/prototypes/nw/ui/react_admin/public/index.html +43 -0
  46. api_logic_server_cli/prototypes/nw/ui/react_admin/public/logo192.png +0 -0
  47. api_logic_server_cli/prototypes/nw/ui/react_admin/public/logo512.png +0 -0
  48. api_logic_server_cli/prototypes/nw/ui/react_admin/public/manifest.json +25 -0
  49. api_logic_server_cli/prototypes/nw/ui/react_admin/public/robots.txt +3 -0
  50. api_logic_server_cli/prototypes/nw/ui/react_admin/src/App.css +38 -0
  51. api_logic_server_cli/prototypes/nw/ui/react_admin/src/App.js +59 -0
  52. api_logic_server_cli/prototypes/nw/ui/react_admin/src/App.test.js +8 -0
  53. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Category.js +82 -0
  54. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Customer.js +116 -0
  55. api_logic_server_cli/prototypes/nw/ui/react_admin/src/CustomerDemographic.js +74 -0
  56. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Department.js +99 -0
  57. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Employee.js +149 -0
  58. api_logic_server_cli/prototypes/nw/ui/react_admin/src/EmployeeAudit.js +94 -0
  59. api_logic_server_cli/prototypes/nw/ui/react_admin/src/EmployeeTerritory.js +98 -0
  60. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Location.js +91 -0
  61. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Order.js +116 -0
  62. api_logic_server_cli/prototypes/nw/ui/react_admin/src/OrderDetail.js +121 -0
  63. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Product.js +105 -0
  64. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Region.js +70 -0
  65. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Shipper.js +64 -0
  66. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Supplier.js +103 -0
  67. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Territory.js +84 -0
  68. api_logic_server_cli/prototypes/nw/ui/react_admin/src/Union.js +77 -0
  69. api_logic_server_cli/prototypes/nw/ui/react_admin/src/dataProvider.js +110 -0
  70. api_logic_server_cli/prototypes/nw/ui/react_admin/src/index.css +13 -0
  71. api_logic_server_cli/prototypes/nw/ui/react_admin/src/index.js +17 -0
  72. api_logic_server_cli/prototypes/nw/ui/react_admin/src/logo.svg +1 -0
  73. api_logic_server_cli/prototypes/nw/ui/react_admin/src/reportWebVitals.js +13 -0
  74. api_logic_server_cli/prototypes/nw/ui/react_admin/src/setupTests.js +5 -0
  75. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/METADATA +1 -1
  76. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/RECORD +80 -15
  77. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/WHEEL +0 -0
  78. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/entry_points.txt +0 -0
  79. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/licenses/LICENSE +0 -0
  80. {apilogicserver-15.0.12.dist-info → apilogicserver-15.0.19.dist-info}/top_level.txt +0 -0
@@ -12,9 +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.12" # last public release: 15.00.10 (15.00.00)
15
+ __version__ = "15.00.19" # last public release: 15.00.19 (15.00.12)
16
16
  recent_changes = \
17
17
  f'\n\nRecent Changes:\n' +\
18
+ "\t06/17/2024 - 15.00.19: Tech Preview: als genai-app \n"\
18
19
  "\t06/10/2024 - 15.00.12: MCP Security, win fixes for readme, graphics quotes \n"\
19
20
  "\t06/08/2024 - 15.00.10: MCP, optional shortening of stacktrace lines, bugfix[92] \n"\
20
21
  "\t05/16/2024 - 14.05.00: safrs 3.1.7, running mcp preview \n"\
@@ -1,3 +1,3 @@
1
- last_created_date: June 09, 2025 15:38:58
1
+ last_created_date: June 17, 2025 12:36:00
2
2
  last_created_project_name: ../../../servers/basic_demo
3
- last_created_version: 15.00.10
3
+ last_created_version: 15.00.18
@@ -751,7 +751,7 @@ def genai_logic(ctx, using, genai_version: str, retries: int, suggest: click.BOO
751
751
  @click.pass_context
752
752
  def genai_graphics(ctx, using, genai_version: str, replace_with: str):
753
753
  """
754
- Adds (or suggests) logic to current project.
754
+ Adds graphics to current project.
755
755
  """
756
756
  global command
757
757
  project_dir = resolve_blank_project_name('')
@@ -779,6 +779,49 @@ def genai_graphics(ctx, using, genai_version: str, replace_with: str):
779
779
  log.info("")
780
780
 
781
781
 
782
+
783
+
784
+ @main.command("genai-app", cls=HideDunderCommand)
785
+ @click.option('--app-name', 'app_name',
786
+ default='react_admin',
787
+ help="Name of generated app in ui/")
788
+ @click.option('--schema',
789
+ default='admin.yaml',
790
+ help="Model file in ui/admin/")
791
+ @click.option('--genai-version', 'genai_version',
792
+ default='gpt-4o',
793
+ help="Eg, gpt-3.5-turbo, gpt-4o")
794
+ @click.pass_context
795
+ def genai_admin_app(ctx, app_name: str, schema: str, genai_version: str):
796
+ """
797
+ Adds a customizable react app to project
798
+ """
799
+ global command
800
+ project_dir = resolve_blank_project_name('')
801
+ project_name = Path(project_dir).name
802
+ project = PR.ProjectRun(command="add_security",
803
+ project_name=project_name,
804
+ db_url="",
805
+ execute=False
806
+ )
807
+ project.project_directory, project.api_name, project.merge_into_prototype = \
808
+ create_utils.get_project_directory_and_api_name(project)
809
+ project.project_directory_actual = os.path.abspath(os.getcwd()) # make path absolute, not relative (no /../)
810
+ project.project_directory_path = Path(project.project_directory_actual)
811
+ models_py_path = project.project_directory_path.joinpath('database/models.py')
812
+ project.abs_db_url, project.nw_db_status, project.model_file_name = \
813
+ create_utils.get_abs_db_url("0. Using Sample DB", project, is_auth=True)
814
+
815
+ if not models_py_path.exists():
816
+ log.info(f'... Error - does not appear to be a project: {str(project.project_directory_path)}')
817
+ log.info(f'... Typical usage - cd into project, use --project_name=. \n')
818
+ exit (1)
819
+ 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)
821
+ pass
822
+ log.info("")
823
+
824
+
782
825
  @main.command("genai-create", cls=HideDunderCommand)
783
826
  @click.option('--project-name', 'project_name',
784
827
  default=f'{last_created_project_name}',
@@ -374,7 +374,21 @@ def get_ontimize_apps(project_dir_path):
374
374
  result.append(name)
375
375
  log.debug(f"Found {len(result)} Ontimize app(s)")
376
376
  return result
377
+ # genai_core/fs_utils.py
377
378
 
379
+
380
+ def ensure_dir(path):
381
+ os.makedirs(path, exist_ok=True)
382
+
383
+ def write_file(path, content):
384
+ ensure_dir(os.path.dirname(path))
385
+ with open(path, 'w', encoding='utf-8') as f:
386
+ f.write(content)
387
+
388
+ def read_file(path):
389
+ with open(path, 'r', encoding='utf-8') as f:
390
+ return f.read()
391
+
378
392
  def does_file_contain(search_for: str, in_file: str) -> bool:
379
393
  """ returns True if <search_for> is <in_file> """
380
394
  with open(Path(in_file), 'r+') as fp:
@@ -0,0 +1,150 @@
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
+ import os
26
+ import json
27
+ from pathlib import Path
28
+ from openai import OpenAI
29
+
30
+
31
+ K_data_model_prompt = "Use SQLAlchemy to create"
32
+
33
+ log = logging.getLogger(__name__)
34
+
35
+ class GenAIAdminApp:
36
+ """ 6/13/2025
37
+ Creates ui/admin_app_react.zip, a source version of ui/admin/admin.yaml.
38
+
39
+ Users without JS/HTML background can use Nat Lang to customize ("Vibe for dummies").
40
+
41
+ Called by CLI for existing projects.
42
+
43
+ * The constructor project arg provides project.project_directory_path, to provide meta data to ChatGPT:
44
+ * docs/db.dbml describes the schema
45
+ * docs/mcp_learning/mcp_discovery.json describes the JSON:API
46
+ * docs/training/admin_app.md describes the app functionality and architecture
47
+
48
+ * Basic steps
49
+ * Step 1 – Parse Schema
50
+ * Step 2 – Generate <each_resource.js> (per schema)
51
+ * Step 3 – Generate `App.js`
52
+ * Step 4 – Custom dataProvider.js
53
+ * provide alternative for React Admin's default data provider for REST APIs,
54
+ * believe that is: 'ra-data-simple-rest'
55
+
56
+ Testing:
57
+ * BLT to create manager
58
+ * Use basic_demo
59
+
60
+ """
61
+
62
+
63
+ def __init__(self, project: Project, genai_version: OpenAI):
64
+ self.project = project
65
+ self.schema_path = project.project_directory_path / "docs/db.dbml"
66
+ self.discovery_path = project.project_directory_path / "docs/mcp_learning/mcp_discovery.json"
67
+ self.genai_version = genai_version
68
+
69
+ self.manager_path = genai_svcs.get_manager_path()
70
+
71
+ self.start_time = time.time()
72
+ self.prompt = self.compose_prompt()
73
+ self.response = self.get_response(self.prompt)
74
+ self.content = self.response.choices[0].message.content
75
+ self.write_output(self.content)
76
+ return self.content
77
+
78
+
79
+
80
+ def compose_prompt(self) -> str:
81
+
82
+ def load_prompt_parts(self):
83
+ """
84
+ Step 2: load context, functionality, and architecture prompt sections
85
+ """
86
+ context = (self.project_path / "docs/prompts/context.md").read_text()
87
+ functionality = (self.project_path / "docs/prompts/functionality.md").read_text()
88
+ architecture = (self.project_path / "docs/prompts/architecture.md").read_text()
89
+ return context, functionality, architecture
90
+
91
+ def load_schema(self) -> str:
92
+ return self.schema_path.read_text()
93
+
94
+ def load_discovery(self) -> str:
95
+ return json.dumps(json.loads(self.discovery_path.read_text()), indent=4)
96
+
97
+ """
98
+ Step 3: compose the prompt by combining static prompt parts with schema and discovery
99
+ """
100
+ context, functionality, architecture = self.load_prompt_parts()
101
+ schema = self.load_schema()
102
+ discovery = self.load_discovery()
103
+
104
+ prompt = f"""
105
+ {context}
106
+
107
+ The JSON:API backend is described by:
108
+ docs/db.dbml describes the schema:
109
+
110
+ ```dbml
111
+ {schema}
112
+ ```
113
+
114
+ docs/mcp_learning/mcp_discovery.json describes the JSON:API:
115
+
116
+ ```json
117
+ {discovery}
118
+ ```
119
+
120
+ {functionality}
121
+
122
+ {architecture}
123
+ """
124
+ return prompt
125
+
126
+
127
+ def get_response(self):
128
+ """
129
+ Step 4: issue the prompt to the LLM to get generated source code
130
+ """
131
+ response = self.client.chat.completions.create(
132
+ model="gpt-4o",
133
+ messages=[
134
+ {"role": "system", "content": "You are a senior React Admin developer."},
135
+ {"role": "user", "content": self.prompt}
136
+ ],
137
+ temperature=0.3
138
+ )
139
+ return response
140
+
141
+
142
+ def write_output(self, output: str, output_file: str = "admin_app_generated.txt"):
143
+ """
144
+ Step 5: write generated source code to output file for inspection or extraction
145
+ """
146
+ output_path = self.project_path / output_file
147
+ output_path.write_text(output)
148
+ print(f"Output written to {output_path}")
149
+
150
+
@@ -0,0 +1,155 @@
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
+ import os
26
+ import json
27
+ from pathlib import Path
28
+ from openai import OpenAI
29
+ import yaml
30
+ import api_logic_server_cli.genai.genai_svcs as genai_svcs
31
+
32
+ log = logging.getLogger(__name__)
33
+
34
+
35
+ class JSResponseFormat(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
36
+ code : str # generated javascript code (only)
37
+
38
+
39
+ class GenAIAdminApp:
40
+
41
+ def __init__(self, project: Project, app_name: str, schema: str, genai_version: OpenAI): # TODO: type??
42
+ self.start_time = time.time()
43
+
44
+ self.api_version = genai_version
45
+ self.project_root = project.project_directory_path
46
+ self.dbml_path = self.project_root / "docs/db.dbml"
47
+ self.admin_yaml_path = self.project_root / f"ui/admin/{schema}"
48
+ self.discovery_path = self.project_root / "docs/mcp_learning/mcp_discovery.json"
49
+
50
+ self.ui_project_path = self.project_root / f"ui/{app_name}"
51
+ self.ui_src_path = self.ui_project_path / "src"
52
+
53
+ self.app_templates_path = genai_svcs.get_manager_path(use_env=True).joinpath('system/genai/app_templates')
54
+ self.react_admin_template_path = self.app_templates_path / 'react-admin-template'
55
+ self.prompts_path = self.app_templates_path / "app_learning"
56
+ self.admin_app_learning = utils.read_file(self.prompts_path / "Admin-App-Learning-Prompt.md")
57
+ self.image_url = self.prompts_path / 'Order-Page.png' # did not seem to help, made it 2x slower
58
+
59
+ # self.schema = utils.read_file(self.dbml_path)
60
+ self.schema_yaml = utils.read_file(self.admin_yaml_path)
61
+ self.schema = yaml.safe_load(self.schema_yaml)
62
+
63
+
64
+ self.resources = {}
65
+ ''' dict keyed by resource_name (todo: relns?) '''
66
+ self.resource_names = []
67
+ ''' array of resource names '''
68
+
69
+ shutil.copytree(self.react_admin_template_path, self.ui_project_path, dirs_exist_ok=True)
70
+
71
+ # self.parse_resources()
72
+ self.a_generate_resource_files()
73
+ self.b_generate_app_js()
74
+ # comes from copytree, above -- self.c_generate_data_provider()
75
+
76
+ log.info(f"✅ Completed in [{str(int(time.time() - self.start_time))} secs] \n\n")
77
+
78
+ log.info(f"✅ Next Steps:\n")
79
+ log.info('Start the API Logic Project: F5')
80
+ log.info('> cd ui/react-admin')
81
+ log.info('> npm install')
82
+ log.info('> npm start')
83
+
84
+
85
+ def a_generate_resource_files(self):
86
+
87
+ def fix_source(raw_source: str) -> str:
88
+ ''' remove code occasional begin/end code markers '''
89
+ source_lines = raw_source.splitlines()
90
+ result_lines = []
91
+ found_start_marker = False
92
+ for each_line in source_lines:
93
+ if each_line.startswith("```"):
94
+ if each_line.startswith("```jsx") or each_line.startswith("```javascript"):
95
+ result_lines = []
96
+ continue
97
+ else:
98
+ break
99
+ result_lines.append(each_line)
100
+
101
+ # return source_lines as a string
102
+ return "\n".join(result_lines)
103
+
104
+
105
+ for each_resource_name, each_resource in self.schema['resources'].items():
106
+ # image moves app gen time from 70 -> 130 secs
107
+ example_image_content_unused = [
108
+ {
109
+ "type": "text",
110
+ "text": "Here is a screenshot of the desired admin app layout. Use this as a visual guide to generate a React-Admin app that mimics the layout, structure, and joins."
111
+ },
112
+ {
113
+ "type": "image_url",
114
+ "image_url": {
115
+ "url": "https://apilogicserver.github.io/Docs/images/ui-admin/Order-Page-Learning.png"
116
+ # "url": f"attachment:/{str(self.image_url)}"
117
+ }
118
+ }
119
+ ]
120
+ messages = [
121
+ {"role": "user", "content": "You are a helpful expert in react and JavaScript"},
122
+ {"role": "user", "content": self.admin_app_learning},
123
+ # {"role": "user", "content": example_image_content},
124
+ {"role": "user", "content": f'Schema:\n{self.schema_yaml}'},
125
+ {"role": "user", "content": f'Generate the full javascript source code for the `{each_resource_name}.js` React Admin file, formatted as a JSResponseFormat'}]
126
+ save_response = self.project_root / f"docs/admin_app/{each_resource_name}"
127
+ output = genai_svcs.call_chatgpt(messages = messages,
128
+ api_version=self.api_version,
129
+ using=save_response,
130
+ response_as=JSResponseFormat)
131
+ response_dict = json.loads(output)
132
+ target_file = self.ui_src_path / f"{each_resource_name}.js"
133
+ source_code = fix_source(response_dict['code'])
134
+ utils.write_file(target_file, source_code)
135
+ log.info(f"\n✅ Wrote: {target_file}")
136
+
137
+
138
+ def b_generate_app_js(self):
139
+ messages = []
140
+ messages = [
141
+ {"role": "user", "content": "You are a helpful expert in react and JavaScript"},
142
+ {"role": "user", "content": self.admin_app_learning},
143
+ {"role": "user", "content": f'Schema:\n{self.schema_yaml}'},
144
+ {"role": "user", "content": f'Generate the complete App.js that wires together the above resources. for the `app.js` React Admin file, formatted as a JSResponseFormat.'}]
145
+ save_response = self.project_root / f"docs/admin_app/app.js"
146
+ output = genai_svcs.call_chatgpt(messages = messages,
147
+ api_version=self.api_version,
148
+ using=save_response,
149
+ response_as=JSResponseFormat)
150
+ response_dict = json.loads(output)
151
+ target_file = self.ui_src_path / "App.js"
152
+ utils.write_file(target_file, response_dict['code'])
153
+
154
+ log.info(f"✅ Wrote: {target_file}\n")
155
+
@@ -883,7 +883,7 @@ def select_messages(messages: List[Dict], messages_out: List[Dict], message_sele
883
883
  return result
884
884
 
885
885
 
886
- def call_chatgpt(messages: List[Dict[str, str]], api_version: str, using: str) -> str:
886
+ def call_chatgpt(messages: List[Dict[str, str]], api_version: str, using: str, response_as: dict=WGResult) -> str:
887
887
  """call ChatGPT with messages
888
888
 
889
889
  Args:
@@ -893,6 +893,25 @@ def call_chatgpt(messages: List[Dict[str, str]], api_version: str, using: str) -
893
893
  Returns:
894
894
  str: response from ChatGPT
895
895
  """
896
+
897
+ def admin_app_path(request_path: Path, suffix: str) -> Path:
898
+ '''
899
+ returns path = remove the last node of the path, and prepend that to _request.json
900
+ # Example: if request_path is /a/b/c/d/request.json, make it /a/b/c/d_request.json
901
+ '''
902
+ parent = request_path.parent
903
+ last_node = parent.name
904
+ grandparent = parent.parent
905
+ request_path = grandparent.joinpath(f"{last_node}_{suffix}.json")
906
+ request_path.parent.mkdir(parents=True, exist_ok=True)
907
+ return request_path
908
+
909
+ def string_to_lines(dict_long_string: dict) -> dict:
910
+ result = dict_long_string
911
+ if isinstance(result[1]['content'], str):
912
+ result[1]['content'] = result[1]['content'].split('\n')
913
+ return result
914
+
896
915
  try:
897
916
  start_time = time.time()
898
917
  model = api_version
@@ -901,26 +920,46 @@ def call_chatgpt(messages: List[Dict[str, str]], api_version: str, using: str) -
901
920
  if model is None or model == "*": # system default chatgpt model
902
921
  model = "gpt-4o-2024-08-06" # 33 sec
903
922
  # model = "o3-mini" # 130 sec
904
- with open(Path(using).joinpath('request.json'), "w") as request_file: # save for debug
905
- json.dump(messages, request_file, indent=4)
923
+ request_path = Path(using).joinpath('request.json')
924
+ if 'admin_app' in str(request_path):
925
+ request_path = admin_app_path(request_path, 'request_raw')
926
+ with open(request_path, "w") as request_file: # save for debug
927
+ json.dump(messages, request_file, indent=4)
928
+ request_path = admin_app_path(request_path, 'request')
929
+ messages_for_print = messages
930
+ # make the long string better for viewing - convert to lines.
931
+ messages_for_print = [msg.copy() if isinstance(msg, dict) else msg for msg in messages]
932
+ messages_for_print = string_to_lines(messages_for_print) # Removed to avoid altering messages
933
+ with open(request_path, "w") as request_file: # save for debug
934
+ json.dump(messages_for_print, request_file, indent=4)
906
935
  log.info(f'.. saved request: {using}/request.json')
907
936
  client = get_ai_client()
937
+ # response_format = "json_object" if wg_response else {"type": "text"}
908
938
  completion = client.beta.chat.completions.parse(
909
939
  messages=messages,
910
- response_format=WGResult,
940
+ response_format=response_as,
911
941
  # temperature=self.project.genai_temperature, values .1 and .7 made students / charges fail
912
942
  model=model # for own model, use "ft:gpt-4o-2024-08-06:personal:logicbank:ARY904vS"
913
943
  )
914
944
  log.info(f'ChatGPT ({str(int(time.time() - start_time))} secs) - response at: system/genai/temp/chatgpt_original.response')
915
945
 
916
946
  data = completion.choices[0].message.content
947
+
917
948
  response_dict = json.loads(data)
918
- with open(Path(using).joinpath('response.json'), "w") as response_file: # save for debug
919
- json.dump(response_dict, response_file, indent=4)
920
- with open(Path(using).joinpath('response.yaml'), "w") as response_file:
921
- yaml.dump(response_dict, response_file, default_flow_style=False, default_style='|')
922
- #yaml_string = yaml.dump(data, default_flow_style=False, default_style='|')
923
- #response_dict['yaml'] = yaml_string
949
+ request_path = Path(using).joinpath('request.json')
950
+ if 'admin_app' in str(request_path):
951
+ request_path = admin_app_path(request_path, 'response')
952
+ with open(request_path, "w") as request_file: # save for debug
953
+ json.dump(data, request_file, indent=4)
954
+ else:
955
+ with open(Path(using).joinpath('response.json'), "w") as response_file: # save for debug
956
+ json.dump(response_dict, response_file, indent=4)
957
+ with open(Path(using).joinpath('response.yaml'), "w") as response_file:
958
+ yaml.dump(response_dict, response_file, default_flow_style=False, default_style='|')
959
+ request_path = Path(using).joinpath('request.json')
960
+ request_path = admin_app_path(request_path, 'response_raw')
961
+ with open(Path(request_path), "w") as response_file: # save for debug
962
+ response_file.writelines(data)
924
963
  log.debug(f'.. call_chatgpt saved response: {using}/response.json')
925
964
  return data # this is a string...
926
965
  except Exception as inst:
@@ -72,6 +72,11 @@ loggers:
72
72
  handlers: [console]
73
73
  propagate: no
74
74
 
75
+ api_logic_server_cli.genai.genai_admin_app:
76
+ level: DEBUG
77
+ handlers: [console]
78
+ propagate: no
79
+
75
80
 
76
81
  api_logic_server_cli.genai.genai_logic_builder:
77
82
  level: DEBUG
@@ -162,24 +162,18 @@ class Config:
162
162
  ''' keycloak client id '''
163
163
 
164
164
  SECURITY_ENABLED = os.getenv("SECURITY_ENABLED",False)
165
- SECURITY_PROVIDER = None
165
+ SECURITY_PROVIDER = os.getenv('SECURITY_PROVIDER', None) # type: ignore # type: str
166
166
  if os.getenv('SECURITY_ENABLED'): # e.g. export SECURITY_ENABLED=true
167
- security_export = os.getenv('SECURITY_ENABLED') # type: ignore # type: str
168
- security_export = security_export.lower() # type: ignore
169
- if security_export in ["false", "no"]: # NO SEC
170
- SECURITY_ENABLED = False # to remove env: unset SECURITY_ENABLED
171
- else:
172
- SECURITY_ENABLED = True
173
- app_logger.debug(f'Security .. overridden from env variable: {SECURITY_ENABLED}')
167
+ security_export = os.getenv('SECURITY_ENABLED','false').lower() # type: ignore # type: str
168
+ SECURITY_ENABLED = security_export not in ["false", "no"] # NO SEC
169
+ app_logger.debug(f'Security .. overridden from env variable SECURITY_ENABLED: {SECURITY_ENABLED}')
174
170
  if SECURITY_ENABLED:
175
- from security.authentication_provider.sql.auth_provider import Authentication_Provider
171
+ from security.authentication_provider.sql.auth_provider import Authentication_Provider as SQL_Authentication_Provider
172
+ from security.authentication_provider.keycloak.auth_provider import Authentication_Provider as KC_Authentication_Provider
176
173
  # typically, authentication_provider is [ keycloak | sql ]
177
- SECURITY_PROVIDER = Authentication_Provider
178
- app_logger.debug(f'config.py - security enabled')
179
- else:
180
- app_logger.info(f'config.py - security disabled')
181
-
182
- app_logger.info(f'SECURITY_PROVIDER={SECURITY_PROVIDER}')
174
+ SECURITY_PROVIDER = KC_Authentication_Provider if "keycloak" in str(SECURITY_PROVIDER).lower() else SQL_Authentication_Provider
175
+
176
+ app_logger.info(f'config.py - security enabled: {SECURITY_ENABLED} using SECURITY_PROVIDER: {str(SECURITY_PROVIDER)}\n')
183
177
 
184
178
  # Begin Multi-Database URLs (from ApiLogicServer add-db...)
185
179
  auth_db_path = str(project_path.joinpath('database/authentication_db.sqlite'))
@@ -0,0 +1,3 @@
1
+
2
+ Generate a full React Admin application using the following instructions.
3
+ The result must be a runnable React app (`npm start`) that connects to the supplied JSON:API, with fully implemented components (no placeholders or empty files).
@@ -0,0 +1,69 @@
1
+
2
+
3
+ ## App Features
4
+
5
+ ### Multi-Page
6
+
7
+ For each resource:
8
+ - Create a **List page** showing 7 user-friendly columns
9
+ - Add **pagination**, **sorting**, and **filtering**
10
+ - Link each row to a **Display (Show) page**
11
+
12
+ ### Multi-Resource
13
+
14
+ Each **Display Page** should:
15
+ - Show all fields in a **multi-column layout**
16
+ - Include a **tab sheet** (`<TabbedShowLayout>`) for each related resource using `<ReferenceManyField>`
17
+ - Link child rows to their own display page
18
+
19
+ Example:
20
+ - Customer Display has tab for OrderList
21
+ - Each Order in the tab links to Order Display
22
+
23
+ ### Automatic Joins
24
+
25
+ For foreign keys:
26
+ - Display joined value (e.g., `product.name` instead of `product_id`)
27
+ - Use first string field from parent table containing `name`, `title`, or `description`
28
+
29
+ Primary key fields:
30
+ - Display at the end of forms/lists
31
+
32
+ ### Lookups (Foreign Keys)
33
+
34
+ For foreign key fields:
35
+ - Provide auto-complete dropdown (`<ReferenceInput>`)
36
+ - For numeric foreign keys, use the joined string field as lookup text
37
+
38
+
39
+ ---
40
+
41
+ ## Per-Resource Files (Required)
42
+
43
+ For each resource (`Customer`, `Order`, `Product`, `Item`):
44
+ - Create a source file under `src/`, e.g., `Customer.js`
45
+ - **Each file must fully implement**:
46
+ - `CustomerList`
47
+ - `CustomerShow`
48
+ - `CustomerCreate`
49
+ - `CustomerEdit`
50
+
51
+ Use:
52
+ - `<ReferenceField>` for foreign key displays
53
+ - `<ReferenceInput>` for foreign key input
54
+ - `<ReferenceManyField>` for tabbed child lists
55
+ - `<TabbedShowLayout>` for display pages
56
+
57
+ Do **not leave any file empty**.
58
+
59
+ ---
60
+
61
+ ## App Wiring
62
+
63
+ In `App.js`:
64
+ - Import each resource file
65
+ - Register them in `<Admin>` using:
66
+
67
+ ```jsx
68
+ <Resource name="Customer" list={CustomerList} show={CustomerShow} edit={CustomerEdit} create={CustomerCreate} />
69
+ ```
@@ -0,0 +1,29 @@
1
+
2
+ ## Architecture
3
+
4
+ - **Framework**: React 18 + react-admin 4.x
5
+ - **Data Provider**: Custom `dataProvider.js` using `fetchUtils` (no external `ra-jsonapi-client`)
6
+ - Must support: `getList`, `getOne`, `getMany`, `getManyReference`, `create`, `update`, `delete`
7
+ - Must support: filters, joins, sorting, pagination
8
+ - **Backend**: JSON:API per `mcp_discovery.json`
9
+ - **CORS**: Ensure API allows `http://localhost:3000`
10
+ ```py
11
+ from flask_cors import CORS
12
+ CORS(app, origins='*') # or restrict to localhost:3000
13
+ ```
14
+ - **Project Setup**:
15
+ - Use `create-react-app`
16
+ - Include: `react-admin`, `@mui/material`, `@emotion/react`, `@emotion/styled`, `react-router-dom`
17
+ - Do not use any deprecated or unmaintained libraries
18
+ - Include complete and correct `App.js`, `index.js`, `dataProvider.js`, and `index.html`
19
+
20
+ ---
21
+
22
+ ## Run Instructions
23
+
24
+ ```bash
25
+ npm install
26
+ npm start
27
+ ```
28
+
29
+ Then open in browser: `http://localhost:3000`