create-aiaui-module 0.1.0 → 0.1.1-TEST
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.
- package/README.md +84 -17
- package/bin/create-aiaui-module.js +86 -22
- package/package.json +23 -6
- package/runtime/__init__.py +71 -28
- package/templates/HelloWorld/README.md +9 -1
- package/templates/JobInformation/README.md +4 -3
- package/templates/JobInformation/api.py +1 -1
package/README.md
CHANGED
|
@@ -1,35 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-aiaui-module
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
在 AIAUI Instance 根目录一键生成可编辑的模块目录(FastAPI 后端路由 + Vue 前端)。
|
|
4
|
+
通过 `npx` 运行,无需全局安装、无需克隆仓库,运行时无外部依赖(除 Instance
|
|
5
|
+
侧已声明的 Python 依赖)。
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
| 步骤 | 命令 | 说明 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| 查看可用模块 | `npx create-aiaui-module@latest --list` | 列出模块 ID 与 contractVersion |
|
|
10
|
+
| 生成模块 | `npx create-aiaui-module@latest JobInformation` | 在实例根目录生成 `PyAIAUI/JobInformation` |
|
|
11
|
+
| 机器可读 | `npx create-aiaui-module@latest JobInformation --json` | 生成结果输出 JSON(接 CI) |
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
## 环境要求
|
|
14
|
+
|
|
15
|
+
- 执行生成器的机器:Node.js >= 20
|
|
16
|
+
- Instance 运行侧:Python + `fastapi`、`uvicorn`(Instance 侧自备,`pip install fastapi uvicorn`)
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
在 Instance 根目录(含 `Config/` 的目录)下执行:
|
|
8
21
|
|
|
9
22
|
```bash
|
|
10
23
|
npx create-aiaui-module@latest JobInformation
|
|
11
|
-
npx create-aiaui-module@latest --list # show available template IDs
|
|
12
|
-
npx create-aiaui-module@latest JobInformation --json # machine-readable summary
|
|
13
24
|
```
|
|
14
25
|
|
|
15
|
-
`
|
|
16
|
-
|
|
26
|
+
生成后 `PyAIAUI/JobInformation/` 与 `PyAIAUI/_runtime/` 就位,`Config/AIAUIProtocol.json` 中登记该模块(默认 `enabled: false`、`port: null`)。
|
|
27
|
+
|
|
28
|
+
启用前需要调整的配置:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"schemaVersion": 1,
|
|
33
|
+
"port": 18901,
|
|
34
|
+
"modules": [
|
|
35
|
+
{ "name": "JobInformation", "enabled": true }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
把 Instance 启动/关闭流程接上(生成后 `PyAIAUI` 目录里就是这段代码的宿主实现):
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from PyAIAUI import AIAUI
|
|
44
|
+
|
|
45
|
+
# 业务对象就绪后
|
|
46
|
+
aiaui = AIAUI.start(services={"job_repository": repo})
|
|
47
|
+
# aiaui 为 None 表示没有任何模块启用
|
|
48
|
+
|
|
49
|
+
# ... Instance 正常运行 ...
|
|
50
|
+
|
|
51
|
+
# 关闭前
|
|
52
|
+
if aiaui is not None:
|
|
53
|
+
aiaui.stop()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`AIAUI.start()` 幂等(重复调用返回同一 handle),一个 handle 托管本 Instance 全部启用模块,共用一个 loopback 端口。后端接口由模块自己的 `api.py` 里的 `create_api(context)` 提供,`context.services` 就是上面注入的业务对象。
|
|
57
|
+
|
|
58
|
+
## 生成结果
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
<Instance root>/
|
|
62
|
+
├── Config/AIAUIProtocol.json # 运行协议:端口 + 模块启停(生成器只登记,不配置)
|
|
63
|
+
└── PyAIAUI/
|
|
64
|
+
├── __init__.py # 入口:AIAUI 类(AIAUI.start / aiaui.stop)
|
|
65
|
+
├── JobInformation/ # 模块目录,目录名 == 模块 ID
|
|
66
|
+
│ ├── api.py # 后端契约:create_api(context) -> APIRouter
|
|
67
|
+
│ ├── resources/src/ # Vue 前端源码
|
|
68
|
+
│ ├── resources/dist/ # 预构建产物(开箱即跑,改源码后 npm run build 重出)
|
|
69
|
+
│ └── {README.md, CUSTOMIZATION.md}# 模块说明与定制手册
|
|
70
|
+
└── _runtime/ # 内嵌模块宿主(零外部依赖)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
生成器不选端口、不装依赖、不启动进程、不覆盖已存在的模块目录;无效的既有协议会被拒绝且不留残留。
|
|
74
|
+
|
|
75
|
+
## 内置模块清单
|
|
17
76
|
|
|
18
|
-
|
|
77
|
+
| 模块 ID | 说明 | 组成 |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `JobInformation` | 工单 / 载具 / 工序信息面板 | FastAPI 后端 + Vue 前端;内置 `header`、`inputCarriers`、`outputCarriers`、`timeline`、`recipe` 五个可替换槽位;三级定制(默认 / 局部替换 / 全量自定义) |
|
|
80
|
+
| `HelloWorld` | 最小前端模块示例 | 自定义元素;验证挂载链路,无后端 |
|
|
81
|
+
自定义通过 `resources/src/customization.ts` 完成,槽位通信通过 `context.bus`(事件 / expose+peer),详见生成目录里的 `CUSTOMIZATION.md`。
|
|
19
82
|
|
|
20
|
-
|
|
83
|
+
## UIService 集成
|
|
21
84
|
|
|
22
85
|
```bash
|
|
23
|
-
|
|
24
|
-
|
|
86
|
+
npm i -g create-aiaui-module
|
|
87
|
+
export AIA_UI_MODULE_TEMPLATE_ROOT="$(npm root -g)/create-aiaui-module"
|
|
25
88
|
```
|
|
26
89
|
|
|
27
|
-
|
|
90
|
+
此后 UIService 调用包内 `bin/create-aiaui-module.js`(与 `npx` 行为一致),或在业务机上直接 `npx`。
|
|
28
91
|
|
|
29
|
-
|
|
92
|
+
## 常用命令
|
|
30
93
|
|
|
31
|
-
|
|
94
|
+
- `npx create-aiaui-module@latest --list` — 查看模板
|
|
95
|
+
- `npx create-aiaui-module@latest <ModuleId>` — 生成(`--instance-root` 指定根目录)
|
|
96
|
+
- `npx create-aiaui-module@latest --json --list` — 机器可读
|
|
32
97
|
|
|
33
|
-
##
|
|
98
|
+
## 维护者(发布新模板)
|
|
34
99
|
|
|
35
|
-
|
|
100
|
+
- 新增模块:在 `templates/<ModuleId>/` 下放实现(含 `contractVersion`、`README.md`、`resources/`)
|
|
101
|
+
- 前端模板发布前在 `resources/` 跑 `npm install && npm run build`,把产物一起随包发布;发布自动执行 `verify-dist` 校验每个模板的 `contractVersion`、入口、`dist/` 产物
|
|
102
|
+
- 发版流程:`npm test` → 改 `package.json` 版本号 → `npm publish`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
|
|
@@ -9,6 +10,79 @@ import {
|
|
|
9
10
|
} from "../src/generator.js";
|
|
10
11
|
|
|
11
12
|
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
13
|
+
const DIVIDER = "─".repeat(48);
|
|
14
|
+
|
|
15
|
+
function briefDescription(templateId) {
|
|
16
|
+
try {
|
|
17
|
+
const text = readFileSync(
|
|
18
|
+
path.join(packageRoot, "templates", templateId, "README.md"),
|
|
19
|
+
"utf8",
|
|
20
|
+
);
|
|
21
|
+
for (const line of text.split("\n")) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("---"))
|
|
24
|
+
continue;
|
|
25
|
+
// Keep the first sentence so the list stays scannable.
|
|
26
|
+
const sentence = trimmed.split(/(?<=\.)\s([A-Z])/)[0];
|
|
27
|
+
const clipped = sentence.length > 120 ? `${sentence.slice(0, 117)}…` : sentence;
|
|
28
|
+
return clipped.length > 0 ? clipped : trimmed;
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
/* template without README simply shows no description */
|
|
32
|
+
}
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function printTemplateList(entries) {
|
|
37
|
+
console.log();
|
|
38
|
+
console.log("AIAUI 模块模板");
|
|
39
|
+
console.log(DIVIDER);
|
|
40
|
+
if (entries.length === 0) console.log(" (none)");
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
console.log(` ${entry.id} · contract v${entry.contractVersion}`);
|
|
43
|
+
if (briefDescription(entry.id))
|
|
44
|
+
console.log(` ${briefDescription(entry.id)}`);
|
|
45
|
+
}
|
|
46
|
+
console.log(DIVIDER);
|
|
47
|
+
console.log("生成: npx create-aiaui-module <模块名> [--list] [--json]");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printSuccess(result) {
|
|
51
|
+
console.log();
|
|
52
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
53
|
+
console.log(" [AIAUI] 生成成功");
|
|
54
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
55
|
+
console.log();
|
|
56
|
+
console.log(` ✅ 生成路径 ${result.path} (${result.filesCopied} 个文件)`);
|
|
57
|
+
console.log(` ✅ 协议配置 ${result.configPath} (enabled: ${result.enabled})`);
|
|
58
|
+
console.log();
|
|
59
|
+
console.log("⚠️ 配置调整(需要你手动做)");
|
|
60
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
61
|
+
console.log(" 📌 修改 port 字段为 18901(或你选择的其他空闲端口)");
|
|
62
|
+
console.log(" 📌 将 enabled 改为 true");
|
|
63
|
+
console.log(" 📌 模块接入 Instance 启动流程后再启用");
|
|
64
|
+
console.log();
|
|
65
|
+
console.log("🔧 接下来要做:");
|
|
66
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
67
|
+
console.log(" 1. 配置端口");
|
|
68
|
+
console.log(" 修改 AIAUIProtocol.json 中 port 字段为 18901(示例值)");
|
|
69
|
+
console.log(" 2. 配置模块 enable");
|
|
70
|
+
console.log(" 修改 AIAUIProtocol.json 中对应模块的 enabled 为 true");
|
|
71
|
+
console.log(" 3. 接入 Instance 启动流程");
|
|
72
|
+
console.log(" · 启动时: aiaui = AIAUI.start(services={...})");
|
|
73
|
+
console.log(" · 关闭时: aiaui.stop()");
|
|
74
|
+
console.log(" 4. 打开 UIClient 对应页面查看效果(JobInformation → /jobs)");
|
|
75
|
+
console.log();
|
|
76
|
+
console.log("❌ 没有做的(请确认)");
|
|
77
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
78
|
+
console.log(" · 未启动服务(由 Instance 生命周期调用 AIAUI.start)");
|
|
79
|
+
console.log(" · 未安装依赖(模块运行需要 pip install fastapi uvicorn)");
|
|
80
|
+
console.log(" · 未选择/配置端口");
|
|
81
|
+
console.log(" · 未手动启用任何模块");
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(" 初始化目录已就绪,按上面的顺序操作即可上线。");
|
|
84
|
+
console.log();
|
|
85
|
+
}
|
|
12
86
|
|
|
13
87
|
function parseArgs(args) {
|
|
14
88
|
const options = {
|
|
@@ -42,28 +116,18 @@ function parseArgs(args) {
|
|
|
42
116
|
|
|
43
117
|
try {
|
|
44
118
|
const options = parseArgs(process.argv.slice(2));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.join("\n"),
|
|
58
|
-
);
|
|
59
|
-
else {
|
|
60
|
-
console.log(`Generated ${result.path} (${result.filesCopied} files)`);
|
|
61
|
-
console.log(
|
|
62
|
-
`Registered in ${result.configPath} (enabled: ${result.enabled}, port: ${result.port ?? "unset"})`,
|
|
63
|
-
);
|
|
64
|
-
console.log(
|
|
65
|
-
"Next: call PyAIAUI.start(services={...}) / PyAIAUI.stop() from the Instance lifecycle, set a free port, then enable the module. Generation does not start it.",
|
|
66
|
-
);
|
|
119
|
+
if (options.list) {
|
|
120
|
+
const entries = await listTemplates(packageRoot);
|
|
121
|
+
if (options.json) console.log(JSON.stringify(entries));
|
|
122
|
+
else printTemplateList(entries);
|
|
123
|
+
} else {
|
|
124
|
+
const result = await createModule({
|
|
125
|
+
templateId: options.templateId,
|
|
126
|
+
instanceRoot: options.instanceRoot,
|
|
127
|
+
root: packageRoot,
|
|
128
|
+
});
|
|
129
|
+
if (options.json) console.log(JSON.stringify(result));
|
|
130
|
+
else printSuccess(result);
|
|
67
131
|
}
|
|
68
132
|
} catch (error) {
|
|
69
133
|
const code =
|
package/package.json
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-aiaui-module",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
5
|
-
"keywords": [
|
|
3
|
+
"version": "0.1.1-TEST",
|
|
4
|
+
"description": "AIAUI Instance module scaffolder: generate editable module (FastAPI + Vue frontend) with one npx command",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"aiaui",
|
|
7
|
+
"scaffolding",
|
|
8
|
+
"generator",
|
|
9
|
+
"vue",
|
|
10
|
+
"fastapi",
|
|
11
|
+
"module",
|
|
12
|
+
"instance"
|
|
13
|
+
],
|
|
6
14
|
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
"bin": {
|
|
16
|
+
"create-aiaui-module": "./bin/create-aiaui-module.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"src",
|
|
21
|
+
"runtime",
|
|
22
|
+
"templates"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
10
27
|
"scripts": {
|
|
11
28
|
"test": "node tests/generator.test.js",
|
|
12
29
|
"verify-dist": "node scripts/verify-dist.mjs",
|
package/runtime/__init__.py
CHANGED
|
@@ -1,39 +1,82 @@
|
|
|
1
1
|
"""Instance-side entry point for enabled AIAUI modules.
|
|
2
2
|
|
|
3
|
-
The owning Instance calls start()
|
|
4
|
-
|
|
5
|
-
this file only delegates discovery and hosting to the
|
|
6
|
-
package (no external ``aiaui`` dependency is required).
|
|
3
|
+
The owning Instance calls ``AIAUI.start(services={...})`` once its business
|
|
4
|
+
objects are ready and ``aiaui.stop()`` during shutdown. Generated modules
|
|
5
|
+
remain editable; this file only delegates discovery and hosting to the
|
|
6
|
+
inlined ``_runtime`` package (no external ``aiaui`` dependency is required).
|
|
7
|
+
|
|
8
|
+
Typical use::
|
|
9
|
+
|
|
10
|
+
from PyAIAUI import AIAUI
|
|
11
|
+
|
|
12
|
+
aiaui = AIAUI.start(services={"job_repository": repo})
|
|
13
|
+
# ... run the Instance ...
|
|
14
|
+
aiaui.stop()
|
|
15
|
+
|
|
16
|
+
``AIAUI.start()`` returns ``None`` when no modules are enabled in
|
|
17
|
+
``Config/AIAUIProtocol.json``.
|
|
7
18
|
"""
|
|
8
19
|
|
|
9
20
|
from pathlib import Path
|
|
10
21
|
|
|
11
22
|
from ._runtime import attach
|
|
12
23
|
|
|
13
|
-
_host = None
|
|
14
24
|
|
|
25
|
+
class AIAUI:
|
|
26
|
+
"""Host handle for one Instance's enabled AIAUI modules.
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
backends (``create_api(context)``) can reach them via ``context.services``.
|
|
21
|
-
Returns None when no modules are enabled in ``Config/AIAUIProtocol.json``.
|
|
28
|
+
One handle hosts every enabled module of the Instance on a single
|
|
29
|
+
loopback HTTP port (see ``Config/AIAUIProtocol.json``). ``start()`` is
|
|
30
|
+
idempotent per Instance: a second call returns the same handle while the
|
|
31
|
+
host lives, and ``stop()`` tears everything down.
|
|
22
32
|
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
|
|
34
|
+
_current: "AIAUI | None" = None
|
|
35
|
+
|
|
36
|
+
def __init__(self, host):
|
|
37
|
+
self._host = host
|
|
38
|
+
self.closed = False
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def start(cls, *, services=None, logger=None) -> "AIAUI | None":
|
|
42
|
+
"""Start this Instance's enabled modules and return the handle.
|
|
43
|
+
|
|
44
|
+
``services`` are the Instance's live business objects; every module
|
|
45
|
+
backend (``create_api(context)``) reaches them through
|
|
46
|
+
``context.services``. Returns ``None`` when no modules are enabled.
|
|
47
|
+
|
|
48
|
+
``start()`` never selects a port, installs dependencies, or starts a
|
|
49
|
+
network socket outside the loopback interface; the port comes from
|
|
50
|
+
the Instance's ``Config/AIAUIProtocol.json``.
|
|
51
|
+
"""
|
|
52
|
+
current = cls._current
|
|
53
|
+
if current is not None and not current.closed:
|
|
54
|
+
return current
|
|
55
|
+
host = attach(
|
|
56
|
+
Path(__file__).resolve().parent.parent,
|
|
57
|
+
services=services,
|
|
58
|
+
logger=logger,
|
|
59
|
+
)
|
|
60
|
+
if host is None:
|
|
61
|
+
return None
|
|
62
|
+
handle = cls(host)
|
|
63
|
+
cls._current = handle
|
|
64
|
+
return handle
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def host(self):
|
|
68
|
+
"""The underlying loopback host, or ``None`` after ``stop()``.
|
|
69
|
+
|
|
70
|
+
Exposed for advanced inspection only; normal code should use
|
|
71
|
+
``stop()`` and let this handle the lifecycle.
|
|
72
|
+
"""
|
|
73
|
+
return None if self.closed else self._host
|
|
74
|
+
|
|
75
|
+
def stop(self) -> None:
|
|
76
|
+
"""Stop every module hosted for this Instance (usually at shutdown)."""
|
|
77
|
+
if self.closed:
|
|
78
|
+
return
|
|
79
|
+
self.closed = True
|
|
80
|
+
self._host.close()
|
|
81
|
+
if AIAUI._current is self:
|
|
82
|
+
AIAUI._current = None
|
|
@@ -2,4 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This frontend-only template shows a minimal AIAUI module. Edit `resources/src/Hello.ce.vue`, then run `npm install` and `npm run build` inside `resources/` to refresh the prebuilt file. `resources/src/index.ts` remains the module entry. There is intentionally no `api.py`.
|
|
4
4
|
|
|
5
|
-
Generation creates `PyAIAUI/HelloWorld/` and registers it as disabled in `Config/AIAUIProtocol.json`. Set a port and enable it after integrating the module host
|
|
5
|
+
Generation creates `PyAIAUI/HelloWorld/` and registers it as disabled in `Config/AIAUIProtocol.json`. Set a port and enable it after integrating the module host:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from PyAIAUI import AIAUI
|
|
9
|
+
|
|
10
|
+
aiaui = AIAUI.start(services={...})
|
|
11
|
+
# ... later ...
|
|
12
|
+
aiaui.stop()
|
|
13
|
+
```
|
|
@@ -84,16 +84,17 @@ For quick iteration, `npm run dev` runs `vite build --watch` and keeps
|
|
|
84
84
|
Call the generated entry point from your Instance's own startup method:
|
|
85
85
|
|
|
86
86
|
```python
|
|
87
|
-
from PyAIAUI import
|
|
87
|
+
from PyAIAUI import AIAUI
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
aiaui = AIAUI.start(services={
|
|
91
91
|
"secs_server": secs_server,
|
|
92
92
|
"job_repository": job_repository,
|
|
93
93
|
})
|
|
94
|
+
# aiaui is None when no modules are enabled
|
|
94
95
|
|
|
95
96
|
# ... later, during shutdown ...
|
|
96
|
-
stop()
|
|
97
|
+
aiaui.stop()
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
`start()` returns `None` when `JobInformation` is disabled in
|
|
@@ -8,7 +8,7 @@ from fastapi import APIRouter
|
|
|
8
8
|
def create_api(context) -> APIRouter:
|
|
9
9
|
"""Entry point invoked by the generated PyAIAUI host.
|
|
10
10
|
|
|
11
|
-
The Instance injects its live objects via ``PyAIAUI.start(services={...})``
|
|
11
|
+
The Instance injects its live objects via ``PyAIAUI.AIAUI.start(services={...})``
|
|
12
12
|
and they arrive here through ``context.services``.
|
|
13
13
|
"""
|
|
14
14
|
router = APIRouter()
|