@kapeta/local-cluster-service 0.70.7 → 0.70.9
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/CHANGELOG.md +14 -0
- package/dist/cjs/src/storm/codegen.d.ts +2 -1
- package/dist/cjs/src/storm/codegen.js +7 -1
- package/dist/cjs/src/storm/event-parser.d.ts +3 -1
- package/dist/cjs/src/storm/event-parser.js +5 -2
- package/dist/cjs/src/storm/page-utils.d.ts +1 -0
- package/dist/cjs/src/storm/page-utils.js +5 -1
- package/dist/cjs/src/storm/routes.js +18 -8
- package/dist/cjs/src/storm/stormClient.d.ts +1 -0
- package/dist/cjs/src/storm/stormClient.js +10 -0
- package/dist/cjs/src/storm/utils.d.ts +1 -0
- package/dist/cjs/src/storm/utils.js +21 -1
- package/dist/cjs/test/storm/event-parser.test.d.ts +1 -0
- package/dist/cjs/test/storm/event-parser.test.js +1 -0
- package/dist/esm/src/storm/codegen.d.ts +2 -1
- package/dist/esm/src/storm/codegen.js +7 -1
- package/dist/esm/src/storm/event-parser.d.ts +3 -1
- package/dist/esm/src/storm/event-parser.js +5 -2
- package/dist/esm/src/storm/page-utils.d.ts +1 -0
- package/dist/esm/src/storm/page-utils.js +5 -1
- package/dist/esm/src/storm/routes.js +18 -8
- package/dist/esm/src/storm/stormClient.d.ts +1 -0
- package/dist/esm/src/storm/stormClient.js +10 -0
- package/dist/esm/src/storm/utils.d.ts +1 -0
- package/dist/esm/src/storm/utils.js +21 -1
- package/dist/esm/test/storm/event-parser.test.d.ts +1 -0
- package/dist/esm/test/storm/event-parser.test.js +1 -0
- package/package.json +1 -1
- package/src/storm/codegen.ts +16 -3
- package/src/storm/event-parser.ts +10 -3
- package/src/storm/page-utils.ts +4 -0
- package/src/storm/routes.ts +24 -9
- package/src/storm/stormClient.ts +11 -0
- package/src/storm/utils.ts +23 -0
- package/test/storm/event-parser.test.ts +1 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.70.9](https://github.com/kapetacom/local-cluster-service/compare/v0.70.8...v0.70.9) (2024-09-12)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* converted pages are turned into a prompt and this is feed into bottoms up ([85e3c44](https://github.com/kapetacom/local-cluster-service/commit/85e3c448f3bab1b78ec4972572219b8f334d7345))
|
7
|
+
|
8
|
+
## [0.70.8](https://github.com/kapetacom/local-cluster-service/compare/v0.70.7...v0.70.8) (2024-09-12)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* use language-target-html if pre-existing systemId is specified ([0a38e0c](https://github.com/kapetacom/local-cluster-service/commit/0a38e0cb384a0954269c1b00ee1ef6660f979e42))
|
14
|
+
|
1
15
|
## [0.70.7](https://github.com/kapetacom/local-cluster-service/compare/v0.70.6...v0.70.7) (2024-09-12)
|
2
16
|
|
3
17
|
|
@@ -12,7 +12,8 @@ export declare class StormCodegen {
|
|
12
12
|
private readonly events;
|
13
13
|
private tmpDir;
|
14
14
|
private readonly conversationId;
|
15
|
-
|
15
|
+
private readonly uiSystemId?;
|
16
|
+
constructor(conversationId: string, userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[], uiSystemId?: string);
|
16
17
|
setTmpDir(tmpDir: string): void;
|
17
18
|
process(): Promise<void>;
|
18
19
|
isAborted(): boolean;
|
@@ -47,6 +47,7 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
47
47
|
const predefined_1 = require("./predefined");
|
48
48
|
const archetype_1 = require("./archetype");
|
49
49
|
const lodash_1 = __importDefault(require("lodash"));
|
50
|
+
const page_utils_1 = require("./page-utils");
|
50
51
|
const SIMULATED_DELAY = 1000;
|
51
52
|
const ENABLE_SIMULATED_DELAY = false;
|
52
53
|
class SimulatedFileDelay {
|
@@ -100,12 +101,14 @@ class StormCodegen {
|
|
100
101
|
events;
|
101
102
|
tmpDir;
|
102
103
|
conversationId;
|
103
|
-
|
104
|
+
uiSystemId;
|
105
|
+
constructor(conversationId, userPrompt, blocks, events, uiSystemId) {
|
104
106
|
this.userPrompt = userPrompt;
|
105
107
|
this.blocks = blocks;
|
106
108
|
this.events = events;
|
107
109
|
this.tmpDir = path_2.default.join(node_os_1.default.tmpdir(), conversationId);
|
108
110
|
this.conversationId = conversationId;
|
111
|
+
this.uiSystemId = uiSystemId;
|
109
112
|
}
|
110
113
|
setTmpDir(tmpDir) {
|
111
114
|
this.tmpDir = tmpDir;
|
@@ -794,6 +797,9 @@ class StormCodegen {
|
|
794
797
|
const basePath = this.getBasePath(yamlContent.metadata.name);
|
795
798
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
796
799
|
codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
|
800
|
+
if (this.uiSystemId) {
|
801
|
+
codeGenerator.withOption('AIStaticFiles', (0, page_utils_1.getSystemBaseImplDir)(this.uiSystemId));
|
802
|
+
}
|
797
803
|
const generatedResult = await codeGenerator.generate();
|
798
804
|
new codegen_1.CodeWriter(basePath).write(generatedResult);
|
799
805
|
return generatedResult;
|
@@ -26,6 +26,7 @@ export interface StormOptions {
|
|
26
26
|
serviceLanguage: string;
|
27
27
|
frontendKind: string;
|
28
28
|
frontendLanguage: string;
|
29
|
+
htmlLanguage: string;
|
29
30
|
exchangeKind: string;
|
30
31
|
queueKind: string;
|
31
32
|
publisherKind: string;
|
@@ -39,7 +40,8 @@ export interface StormOptions {
|
|
39
40
|
desktopKind: string;
|
40
41
|
desktopLanguage: string;
|
41
42
|
gatewayKind: string;
|
42
|
-
|
43
|
+
systemId?: string;
|
44
|
+
[key: string]: string | undefined;
|
43
45
|
}
|
44
46
|
export declare function createPhaseStartEvent(type: StormEventPhaseType): StormEventPhases;
|
45
47
|
export declare function createPhaseEndEvent(type: StormEventPhaseType): StormEventPhases;
|
@@ -67,6 +67,7 @@ async function resolveOptions() {
|
|
67
67
|
const javaLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
68
68
|
const reactLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
69
69
|
const nodejsLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
70
|
+
const htmlLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
70
71
|
const blockTypePubsub = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
71
72
|
const resourceTypePubsubSubscriber = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscriber');
|
72
73
|
const resourceTypePubsubSubscription = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscription');
|
@@ -83,6 +84,7 @@ async function resolveOptions() {
|
|
83
84
|
!postgresResource ||
|
84
85
|
!javaLanguage ||
|
85
86
|
!reactLanguage ||
|
87
|
+
!htmlLanguage ||
|
86
88
|
!webPageResource ||
|
87
89
|
!restApiResource ||
|
88
90
|
!restClientResource ||
|
@@ -105,6 +107,7 @@ async function resolveOptions() {
|
|
105
107
|
serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
106
108
|
frontendKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
107
109
|
frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
110
|
+
htmlLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
108
111
|
cliKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
109
112
|
cliLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
110
113
|
desktopKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
|
@@ -770,7 +773,7 @@ class StormEventParser {
|
|
770
773
|
case 'CLI':
|
771
774
|
return this.options.cliLanguage;
|
772
775
|
case 'FRONTEND':
|
773
|
-
return this.options.frontendLanguage;
|
776
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
774
777
|
case 'DESKTOP':
|
775
778
|
return this.options.desktopLanguage;
|
776
779
|
}
|
@@ -791,7 +794,7 @@ class StormEventParser {
|
|
791
794
|
for (const prop in options) {
|
792
795
|
if (options.hasOwnProperty(prop)) {
|
793
796
|
const value = options[prop];
|
794
|
-
if (value.indexOf(kind) > 0) {
|
797
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
795
798
|
return value;
|
796
799
|
}
|
797
800
|
}
|
@@ -19,6 +19,7 @@ export declare function writeImageToDisk(systemId: string, event: StormImage, pr
|
|
19
19
|
}>;
|
20
20
|
export declare function hasPageOnDisk(systemId: string, method: string, path: string): boolean;
|
21
21
|
export declare function getSystemBaseDir(systemId: string): string;
|
22
|
+
export declare function getSystemBaseImplDir(systemId: string): string;
|
22
23
|
export declare function resolveReadPath(systemId: string, path: string, method: string): string | null;
|
23
24
|
export declare function readPageFromDiskAsString(systemId: string, path: string, method: string): string | null;
|
24
25
|
export declare function readPageFromDisk(systemId: string, path: string, method: string, res: Response): void;
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.getSystemBaseDir = exports.hasPageOnDisk = exports.writeImageToDisk = exports.writeAssetToDisk = exports.writePageToDisk = exports.normalizePath = exports.SystemIdHeader = void 0;
|
6
|
+
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.getSystemBaseImplDir = exports.getSystemBaseDir = exports.hasPageOnDisk = exports.writeImageToDisk = exports.writeAssetToDisk = exports.writePageToDisk = exports.normalizePath = exports.SystemIdHeader = void 0;
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
8
8
|
const path_1 = __importDefault(require("path"));
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
@@ -63,6 +63,10 @@ function getSystemBaseDir(systemId) {
|
|
63
63
|
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems', systemId);
|
64
64
|
}
|
65
65
|
exports.getSystemBaseDir = getSystemBaseDir;
|
66
|
+
function getSystemBaseImplDir(systemId) {
|
67
|
+
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems-impl', systemId);
|
68
|
+
}
|
69
|
+
exports.getSystemBaseImplDir = getSystemBaseImplDir;
|
66
70
|
function getFilePath(method) {
|
67
71
|
// For HEAD requests, we assume we're serving looking for a GET resource
|
68
72
|
return path_1.default.join(method === 'HEAD' ? 'get' : method.toLowerCase(), 'index.html');
|
@@ -10,7 +10,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
-
const node_os_1 = __importDefault(require("node:os"));
|
14
13
|
const lodash_1 = __importDefault(require("lodash"));
|
15
14
|
const cors_1 = require("../middleware/cors");
|
16
15
|
const stringBody_1 = require("../middleware/stringBody");
|
@@ -69,10 +68,10 @@ router.post('/ui/serve/:systemId', async (req, res) => {
|
|
69
68
|
}
|
70
69
|
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
71
70
|
});
|
72
|
-
router.post('/ui/create-system/:systemId', async (req, res) => {
|
71
|
+
router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
73
72
|
const systemId = req.params.systemId;
|
74
73
|
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
75
|
-
const destDir =
|
74
|
+
const destDir = (0, page_utils_1.getSystemBaseImplDir)(systemId);
|
76
75
|
await (0, utils_1.copyDirectory)(srcDir, destDir, async (fileName, content) => {
|
77
76
|
const result = await stormClient_1.stormClient.implementAPIClients({
|
78
77
|
content: content,
|
@@ -80,8 +79,15 @@ router.post('/ui/create-system/:systemId', async (req, res) => {
|
|
80
79
|
});
|
81
80
|
return result;
|
82
81
|
});
|
83
|
-
|
84
|
-
|
82
|
+
const pages = (0, utils_1.readPages)(destDir);
|
83
|
+
const prompt = await stormClient_1.stormClient.generatePrompt(pages);
|
84
|
+
req.query.systemId = systemId;
|
85
|
+
const promptRequest = {
|
86
|
+
prompt: prompt,
|
87
|
+
skipImprovement: true,
|
88
|
+
};
|
89
|
+
req.stringBody = JSON.stringify(promptRequest);
|
90
|
+
await handleAll(req, res);
|
85
91
|
});
|
86
92
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
87
93
|
const systemId = req.params.systemId;
|
@@ -500,9 +506,13 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
500
506
|
}
|
501
507
|
});
|
502
508
|
router.post('/:handle/all', async (req, res) => {
|
509
|
+
await handleAll(req, res);
|
510
|
+
});
|
511
|
+
async function handleAll(req, res) {
|
503
512
|
const handle = req.params.handle;
|
513
|
+
const systemId = req.query.systemId ?? undefined;
|
504
514
|
try {
|
505
|
-
const stormOptions = await (0, event_parser_1.resolveOptions)();
|
515
|
+
const stormOptions = { ...(await (0, event_parser_1.resolveOptions)()), systemId: systemId };
|
506
516
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
507
517
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
508
518
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
@@ -571,7 +581,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
571
581
|
if (!req.query.skipCodegen) {
|
572
582
|
try {
|
573
583
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENTATION));
|
574
|
-
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents());
|
584
|
+
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents(), systemId);
|
575
585
|
onRequestAborted(req, res, () => {
|
576
586
|
stormCodegen.abort();
|
577
587
|
});
|
@@ -593,7 +603,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
593
603
|
res.end();
|
594
604
|
}
|
595
605
|
}
|
596
|
-
}
|
606
|
+
}
|
597
607
|
router.post('/block/create', async (req, res) => {
|
598
608
|
const createRequest = JSON.parse(req.stringBody ?? '{}');
|
599
609
|
try {
|
@@ -70,6 +70,7 @@ declare class StormClient {
|
|
70
70
|
vote: -1 | 0 | 1;
|
71
71
|
}>;
|
72
72
|
implementAPIClients(prompt: ImplementAPIClientsRequest): Promise<string>;
|
73
|
+
generatePrompt(pages: string[]): Promise<string>;
|
73
74
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
74
75
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
75
76
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -160,6 +160,16 @@ class StormClient {
|
|
160
160
|
const data = await response.text();
|
161
161
|
return data;
|
162
162
|
}
|
163
|
+
async generatePrompt(pages) {
|
164
|
+
const u = `${this._baseUrl}/v2/ui/prompt`;
|
165
|
+
const response = await (0, undici_1.fetch)(u, {
|
166
|
+
method: 'POST',
|
167
|
+
body: JSON.stringify({
|
168
|
+
pages: pages,
|
169
|
+
}),
|
170
|
+
});
|
171
|
+
return await response.text();
|
172
|
+
}
|
163
173
|
classifyUIReferences(prompt, conversationId) {
|
164
174
|
return this.send('/v2/ui/references', {
|
165
175
|
prompt: prompt,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => Promise<string>): Promise<void>;
|
2
|
+
export declare function readPages(directoryPath: string): string[];
|
2
3
|
export declare function createFuture<T = void>(): {
|
3
4
|
promise: Promise<T>;
|
4
5
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.createFuture = exports.copyDirectory = void 0;
|
6
|
+
exports.createFuture = exports.readPages = exports.copyDirectory = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -29,6 +29,26 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
29
29
|
}
|
30
30
|
}
|
31
31
|
exports.copyDirectory = copyDirectory;
|
32
|
+
function readPages(directoryPath) {
|
33
|
+
const htmlFiles = [];
|
34
|
+
function traverseDirectory(currentPath) {
|
35
|
+
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
|
+
for (const file of files) {
|
37
|
+
const filePath = path_1.default.join(currentPath, file);
|
38
|
+
const stats = fs_extra_1.default.statSync(filePath);
|
39
|
+
if (stats.isDirectory()) {
|
40
|
+
traverseDirectory(filePath);
|
41
|
+
}
|
42
|
+
else if (stats.isFile() && path_1.default.extname(filePath) === '.html') {
|
43
|
+
const content = fs_extra_1.default.readFileSync(filePath, 'utf8');
|
44
|
+
htmlFiles.push(content);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
traverseDirectory(directoryPath);
|
49
|
+
return htmlFiles;
|
50
|
+
}
|
51
|
+
exports.readPages = readPages;
|
32
52
|
function createFuture() {
|
33
53
|
let resolve = () => { };
|
34
54
|
let reject = () => { };
|
@@ -19,6 +19,7 @@ exports.parserOptions = {
|
|
19
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
20
20
|
frontendKind: 'kapeta/block-type-frontend:local',
|
21
21
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
22
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
22
23
|
cliKind: 'kapeta/block-type-cli:local',
|
23
24
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|
24
25
|
desktopKind: 'kapeta/block-type-desktop:local',
|
@@ -12,7 +12,8 @@ export declare class StormCodegen {
|
|
12
12
|
private readonly events;
|
13
13
|
private tmpDir;
|
14
14
|
private readonly conversationId;
|
15
|
-
|
15
|
+
private readonly uiSystemId?;
|
16
|
+
constructor(conversationId: string, userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[], uiSystemId?: string);
|
16
17
|
setTmpDir(tmpDir: string): void;
|
17
18
|
process(): Promise<void>;
|
18
19
|
isAborted(): boolean;
|
@@ -47,6 +47,7 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
47
47
|
const predefined_1 = require("./predefined");
|
48
48
|
const archetype_1 = require("./archetype");
|
49
49
|
const lodash_1 = __importDefault(require("lodash"));
|
50
|
+
const page_utils_1 = require("./page-utils");
|
50
51
|
const SIMULATED_DELAY = 1000;
|
51
52
|
const ENABLE_SIMULATED_DELAY = false;
|
52
53
|
class SimulatedFileDelay {
|
@@ -100,12 +101,14 @@ class StormCodegen {
|
|
100
101
|
events;
|
101
102
|
tmpDir;
|
102
103
|
conversationId;
|
103
|
-
|
104
|
+
uiSystemId;
|
105
|
+
constructor(conversationId, userPrompt, blocks, events, uiSystemId) {
|
104
106
|
this.userPrompt = userPrompt;
|
105
107
|
this.blocks = blocks;
|
106
108
|
this.events = events;
|
107
109
|
this.tmpDir = path_2.default.join(node_os_1.default.tmpdir(), conversationId);
|
108
110
|
this.conversationId = conversationId;
|
111
|
+
this.uiSystemId = uiSystemId;
|
109
112
|
}
|
110
113
|
setTmpDir(tmpDir) {
|
111
114
|
this.tmpDir = tmpDir;
|
@@ -794,6 +797,9 @@ class StormCodegen {
|
|
794
797
|
const basePath = this.getBasePath(yamlContent.metadata.name);
|
795
798
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
796
799
|
codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
|
800
|
+
if (this.uiSystemId) {
|
801
|
+
codeGenerator.withOption('AIStaticFiles', (0, page_utils_1.getSystemBaseImplDir)(this.uiSystemId));
|
802
|
+
}
|
797
803
|
const generatedResult = await codeGenerator.generate();
|
798
804
|
new codegen_1.CodeWriter(basePath).write(generatedResult);
|
799
805
|
return generatedResult;
|
@@ -26,6 +26,7 @@ export interface StormOptions {
|
|
26
26
|
serviceLanguage: string;
|
27
27
|
frontendKind: string;
|
28
28
|
frontendLanguage: string;
|
29
|
+
htmlLanguage: string;
|
29
30
|
exchangeKind: string;
|
30
31
|
queueKind: string;
|
31
32
|
publisherKind: string;
|
@@ -39,7 +40,8 @@ export interface StormOptions {
|
|
39
40
|
desktopKind: string;
|
40
41
|
desktopLanguage: string;
|
41
42
|
gatewayKind: string;
|
42
|
-
|
43
|
+
systemId?: string;
|
44
|
+
[key: string]: string | undefined;
|
43
45
|
}
|
44
46
|
export declare function createPhaseStartEvent(type: StormEventPhaseType): StormEventPhases;
|
45
47
|
export declare function createPhaseEndEvent(type: StormEventPhaseType): StormEventPhases;
|
@@ -67,6 +67,7 @@ async function resolveOptions() {
|
|
67
67
|
const javaLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
68
68
|
const reactLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
69
69
|
const nodejsLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
70
|
+
const htmlLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
70
71
|
const blockTypePubsub = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
71
72
|
const resourceTypePubsubSubscriber = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscriber');
|
72
73
|
const resourceTypePubsubSubscription = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscription');
|
@@ -83,6 +84,7 @@ async function resolveOptions() {
|
|
83
84
|
!postgresResource ||
|
84
85
|
!javaLanguage ||
|
85
86
|
!reactLanguage ||
|
87
|
+
!htmlLanguage ||
|
86
88
|
!webPageResource ||
|
87
89
|
!restApiResource ||
|
88
90
|
!restClientResource ||
|
@@ -105,6 +107,7 @@ async function resolveOptions() {
|
|
105
107
|
serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
106
108
|
frontendKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
107
109
|
frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
110
|
+
htmlLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
108
111
|
cliKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
109
112
|
cliLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
110
113
|
desktopKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
|
@@ -770,7 +773,7 @@ class StormEventParser {
|
|
770
773
|
case 'CLI':
|
771
774
|
return this.options.cliLanguage;
|
772
775
|
case 'FRONTEND':
|
773
|
-
return this.options.frontendLanguage;
|
776
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
774
777
|
case 'DESKTOP':
|
775
778
|
return this.options.desktopLanguage;
|
776
779
|
}
|
@@ -791,7 +794,7 @@ class StormEventParser {
|
|
791
794
|
for (const prop in options) {
|
792
795
|
if (options.hasOwnProperty(prop)) {
|
793
796
|
const value = options[prop];
|
794
|
-
if (value.indexOf(kind) > 0) {
|
797
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
795
798
|
return value;
|
796
799
|
}
|
797
800
|
}
|
@@ -19,6 +19,7 @@ export declare function writeImageToDisk(systemId: string, event: StormImage, pr
|
|
19
19
|
}>;
|
20
20
|
export declare function hasPageOnDisk(systemId: string, method: string, path: string): boolean;
|
21
21
|
export declare function getSystemBaseDir(systemId: string): string;
|
22
|
+
export declare function getSystemBaseImplDir(systemId: string): string;
|
22
23
|
export declare function resolveReadPath(systemId: string, path: string, method: string): string | null;
|
23
24
|
export declare function readPageFromDiskAsString(systemId: string, path: string, method: string): string | null;
|
24
25
|
export declare function readPageFromDisk(systemId: string, path: string, method: string, res: Response): void;
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.getSystemBaseDir = exports.hasPageOnDisk = exports.writeImageToDisk = exports.writeAssetToDisk = exports.writePageToDisk = exports.normalizePath = exports.SystemIdHeader = void 0;
|
6
|
+
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.getSystemBaseImplDir = exports.getSystemBaseDir = exports.hasPageOnDisk = exports.writeImageToDisk = exports.writeAssetToDisk = exports.writePageToDisk = exports.normalizePath = exports.SystemIdHeader = void 0;
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
8
8
|
const path_1 = __importDefault(require("path"));
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
@@ -63,6 +63,10 @@ function getSystemBaseDir(systemId) {
|
|
63
63
|
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems', systemId);
|
64
64
|
}
|
65
65
|
exports.getSystemBaseDir = getSystemBaseDir;
|
66
|
+
function getSystemBaseImplDir(systemId) {
|
67
|
+
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems-impl', systemId);
|
68
|
+
}
|
69
|
+
exports.getSystemBaseImplDir = getSystemBaseImplDir;
|
66
70
|
function getFilePath(method) {
|
67
71
|
// For HEAD requests, we assume we're serving looking for a GET resource
|
68
72
|
return path_1.default.join(method === 'HEAD' ? 'get' : method.toLowerCase(), 'index.html');
|
@@ -10,7 +10,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
-
const node_os_1 = __importDefault(require("node:os"));
|
14
13
|
const lodash_1 = __importDefault(require("lodash"));
|
15
14
|
const cors_1 = require("../middleware/cors");
|
16
15
|
const stringBody_1 = require("../middleware/stringBody");
|
@@ -69,10 +68,10 @@ router.post('/ui/serve/:systemId', async (req, res) => {
|
|
69
68
|
}
|
70
69
|
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
71
70
|
});
|
72
|
-
router.post('/ui/create-system/:systemId', async (req, res) => {
|
71
|
+
router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
73
72
|
const systemId = req.params.systemId;
|
74
73
|
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
75
|
-
const destDir =
|
74
|
+
const destDir = (0, page_utils_1.getSystemBaseImplDir)(systemId);
|
76
75
|
await (0, utils_1.copyDirectory)(srcDir, destDir, async (fileName, content) => {
|
77
76
|
const result = await stormClient_1.stormClient.implementAPIClients({
|
78
77
|
content: content,
|
@@ -80,8 +79,15 @@ router.post('/ui/create-system/:systemId', async (req, res) => {
|
|
80
79
|
});
|
81
80
|
return result;
|
82
81
|
});
|
83
|
-
|
84
|
-
|
82
|
+
const pages = (0, utils_1.readPages)(destDir);
|
83
|
+
const prompt = await stormClient_1.stormClient.generatePrompt(pages);
|
84
|
+
req.query.systemId = systemId;
|
85
|
+
const promptRequest = {
|
86
|
+
prompt: prompt,
|
87
|
+
skipImprovement: true,
|
88
|
+
};
|
89
|
+
req.stringBody = JSON.stringify(promptRequest);
|
90
|
+
await handleAll(req, res);
|
85
91
|
});
|
86
92
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
87
93
|
const systemId = req.params.systemId;
|
@@ -500,9 +506,13 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
500
506
|
}
|
501
507
|
});
|
502
508
|
router.post('/:handle/all', async (req, res) => {
|
509
|
+
await handleAll(req, res);
|
510
|
+
});
|
511
|
+
async function handleAll(req, res) {
|
503
512
|
const handle = req.params.handle;
|
513
|
+
const systemId = req.query.systemId ?? undefined;
|
504
514
|
try {
|
505
|
-
const stormOptions = await (0, event_parser_1.resolveOptions)();
|
515
|
+
const stormOptions = { ...(await (0, event_parser_1.resolveOptions)()), systemId: systemId };
|
506
516
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
507
517
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
508
518
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
@@ -571,7 +581,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
571
581
|
if (!req.query.skipCodegen) {
|
572
582
|
try {
|
573
583
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENTATION));
|
574
|
-
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents());
|
584
|
+
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents(), systemId);
|
575
585
|
onRequestAborted(req, res, () => {
|
576
586
|
stormCodegen.abort();
|
577
587
|
});
|
@@ -593,7 +603,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
593
603
|
res.end();
|
594
604
|
}
|
595
605
|
}
|
596
|
-
}
|
606
|
+
}
|
597
607
|
router.post('/block/create', async (req, res) => {
|
598
608
|
const createRequest = JSON.parse(req.stringBody ?? '{}');
|
599
609
|
try {
|
@@ -70,6 +70,7 @@ declare class StormClient {
|
|
70
70
|
vote: -1 | 0 | 1;
|
71
71
|
}>;
|
72
72
|
implementAPIClients(prompt: ImplementAPIClientsRequest): Promise<string>;
|
73
|
+
generatePrompt(pages: string[]): Promise<string>;
|
73
74
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
74
75
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
75
76
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -160,6 +160,16 @@ class StormClient {
|
|
160
160
|
const data = await response.text();
|
161
161
|
return data;
|
162
162
|
}
|
163
|
+
async generatePrompt(pages) {
|
164
|
+
const u = `${this._baseUrl}/v2/ui/prompt`;
|
165
|
+
const response = await (0, undici_1.fetch)(u, {
|
166
|
+
method: 'POST',
|
167
|
+
body: JSON.stringify({
|
168
|
+
pages: pages,
|
169
|
+
}),
|
170
|
+
});
|
171
|
+
return await response.text();
|
172
|
+
}
|
163
173
|
classifyUIReferences(prompt, conversationId) {
|
164
174
|
return this.send('/v2/ui/references', {
|
165
175
|
prompt: prompt,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => Promise<string>): Promise<void>;
|
2
|
+
export declare function readPages(directoryPath: string): string[];
|
2
3
|
export declare function createFuture<T = void>(): {
|
3
4
|
promise: Promise<T>;
|
4
5
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.createFuture = exports.copyDirectory = void 0;
|
6
|
+
exports.createFuture = exports.readPages = exports.copyDirectory = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -29,6 +29,26 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
29
29
|
}
|
30
30
|
}
|
31
31
|
exports.copyDirectory = copyDirectory;
|
32
|
+
function readPages(directoryPath) {
|
33
|
+
const htmlFiles = [];
|
34
|
+
function traverseDirectory(currentPath) {
|
35
|
+
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
|
+
for (const file of files) {
|
37
|
+
const filePath = path_1.default.join(currentPath, file);
|
38
|
+
const stats = fs_extra_1.default.statSync(filePath);
|
39
|
+
if (stats.isDirectory()) {
|
40
|
+
traverseDirectory(filePath);
|
41
|
+
}
|
42
|
+
else if (stats.isFile() && path_1.default.extname(filePath) === '.html') {
|
43
|
+
const content = fs_extra_1.default.readFileSync(filePath, 'utf8');
|
44
|
+
htmlFiles.push(content);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
traverseDirectory(directoryPath);
|
49
|
+
return htmlFiles;
|
50
|
+
}
|
51
|
+
exports.readPages = readPages;
|
32
52
|
function createFuture() {
|
33
53
|
let resolve = () => { };
|
34
54
|
let reject = () => { };
|
@@ -19,6 +19,7 @@ exports.parserOptions = {
|
|
19
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
20
20
|
frontendKind: 'kapeta/block-type-frontend:local',
|
21
21
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
22
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
22
23
|
cliKind: 'kapeta/block-type-cli:local',
|
23
24
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|
24
25
|
desktopKind: 'kapeta/block-type-desktop:local',
|
package/package.json
CHANGED
package/src/storm/codegen.ts
CHANGED
@@ -39,6 +39,7 @@ import YAML from 'yaml';
|
|
39
39
|
import { PREDEFINED_BLOCKS } from './predefined';
|
40
40
|
import { Archetype } from './archetype';
|
41
41
|
import _ from 'lodash';
|
42
|
+
import { getSystemBaseImplDir } from './page-utils';
|
42
43
|
|
43
44
|
type ImplementationGenerator<T = StormFileImplementationPrompt> = (
|
44
45
|
prompt: T,
|
@@ -108,13 +109,21 @@ export class StormCodegen {
|
|
108
109
|
private readonly events: StormEvent[];
|
109
110
|
private tmpDir: string;
|
110
111
|
private readonly conversationId: string;
|
111
|
-
|
112
|
-
|
112
|
+
private readonly uiSystemId?: string;
|
113
|
+
|
114
|
+
constructor(
|
115
|
+
conversationId: string,
|
116
|
+
userPrompt: string,
|
117
|
+
blocks: BlockDefinitionInfo[],
|
118
|
+
events: StormEvent[],
|
119
|
+
uiSystemId?: string
|
120
|
+
) {
|
113
121
|
this.userPrompt = userPrompt;
|
114
122
|
this.blocks = blocks;
|
115
123
|
this.events = events;
|
116
124
|
this.tmpDir = Path.join(os.tmpdir(), conversationId);
|
117
125
|
this.conversationId = conversationId;
|
126
|
+
this.uiSystemId = uiSystemId;
|
118
127
|
}
|
119
128
|
|
120
129
|
public setTmpDir(tmpDir: string) {
|
@@ -488,7 +497,6 @@ export class StormCodegen {
|
|
488
497
|
await writeFile(filePath, webRouterFile.content);
|
489
498
|
}
|
490
499
|
|
491
|
-
|
492
500
|
const blockRef = block.uri;
|
493
501
|
|
494
502
|
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.QA);
|
@@ -1009,6 +1017,11 @@ export class StormCodegen {
|
|
1009
1017
|
|
1010
1018
|
const codeGenerator = new BlockCodeGenerator(yamlContent as BlockDefinition);
|
1011
1019
|
codeGenerator.withOption('AIContext', STORM_ID);
|
1020
|
+
|
1021
|
+
if (this.uiSystemId) {
|
1022
|
+
codeGenerator.withOption('AIStaticFiles', getSystemBaseImplDir(this.uiSystemId));
|
1023
|
+
}
|
1024
|
+
|
1012
1025
|
const generatedResult = await codeGenerator.generate();
|
1013
1026
|
new CodeWriter(basePath).write(generatedResult);
|
1014
1027
|
return generatedResult;
|
@@ -67,6 +67,7 @@ export interface StormOptions {
|
|
67
67
|
serviceLanguage: string;
|
68
68
|
frontendKind: string;
|
69
69
|
frontendLanguage: string;
|
70
|
+
htmlLanguage: string;
|
70
71
|
exchangeKind: string;
|
71
72
|
queueKind: string;
|
72
73
|
publisherKind: string;
|
@@ -80,7 +81,10 @@ export interface StormOptions {
|
|
80
81
|
desktopKind: string;
|
81
82
|
desktopLanguage: string;
|
82
83
|
gatewayKind: string;
|
83
|
-
|
84
|
+
|
85
|
+
systemId?: string;
|
86
|
+
|
87
|
+
[key: string]: string | undefined;
|
84
88
|
}
|
85
89
|
|
86
90
|
function prettifyKaplang(source: string) {
|
@@ -143,6 +147,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
143
147
|
const javaLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
144
148
|
const reactLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
145
149
|
const nodejsLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
150
|
+
const htmlLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
146
151
|
|
147
152
|
const blockTypePubsub = await definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
148
153
|
const resourceTypePubsubSubscriber = await definitionsManager.getLatestDefinition(
|
@@ -170,6 +175,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
170
175
|
!postgresResource ||
|
171
176
|
!javaLanguage ||
|
172
177
|
!reactLanguage ||
|
178
|
+
!htmlLanguage ||
|
173
179
|
!webPageResource ||
|
174
180
|
!restApiResource ||
|
175
181
|
!restClientResource ||
|
@@ -195,6 +201,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
195
201
|
|
196
202
|
frontendKind: normalizeKapetaUri(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
197
203
|
frontendLanguage: normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
204
|
+
htmlLanguage: normalizeKapetaUri(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
198
205
|
|
199
206
|
cliKind: normalizeKapetaUri(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
200
207
|
cliLanguage: normalizeKapetaUri(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
@@ -997,7 +1004,7 @@ export class StormEventParser {
|
|
997
1004
|
case 'CLI':
|
998
1005
|
return this.options.cliLanguage;
|
999
1006
|
case 'FRONTEND':
|
1000
|
-
return this.options.frontendLanguage;
|
1007
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
1001
1008
|
case 'DESKTOP':
|
1002
1009
|
return this.options.desktopLanguage;
|
1003
1010
|
}
|
@@ -1027,7 +1034,7 @@ export class StormEventParser {
|
|
1027
1034
|
for (const prop in options) {
|
1028
1035
|
if (options.hasOwnProperty(prop)) {
|
1029
1036
|
const value = options[prop];
|
1030
|
-
if (value.indexOf(kind) > 0) {
|
1037
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
1031
1038
|
return value;
|
1032
1039
|
}
|
1033
1040
|
}
|
package/src/storm/page-utils.ts
CHANGED
@@ -78,6 +78,10 @@ export function getSystemBaseDir(systemId: string) {
|
|
78
78
|
return Path.join(os.tmpdir(), 'ai-systems', systemId);
|
79
79
|
}
|
80
80
|
|
81
|
+
export function getSystemBaseImplDir(systemId: string) {
|
82
|
+
return Path.join(os.tmpdir(), 'ai-systems-impl', systemId);
|
83
|
+
}
|
84
|
+
|
81
85
|
function getFilePath(method: string) {
|
82
86
|
// For HEAD requests, we assume we're serving looking for a GET resource
|
83
87
|
return Path.join(method === 'HEAD' ? 'get' : method.toLowerCase(), 'index.html');
|
package/src/storm/routes.ts
CHANGED
@@ -7,7 +7,6 @@ import Router from 'express-promise-router';
|
|
7
7
|
import FS from 'fs-extra';
|
8
8
|
import { Response } from 'express';
|
9
9
|
import Path from 'path';
|
10
|
-
import os from 'node:os';
|
11
10
|
import _ from 'lodash';
|
12
11
|
import { corsHandler } from '../middleware/cors';
|
13
12
|
import { stringBody } from '../middleware/stringBody';
|
@@ -37,6 +36,7 @@ import { assetManager } from '../assetManager';
|
|
37
36
|
import uuid from 'node-uuid';
|
38
37
|
import {
|
39
38
|
getSystemBaseDir,
|
39
|
+
getSystemBaseImplDir,
|
40
40
|
readPageFromDisk,
|
41
41
|
resolveReadPath,
|
42
42
|
SystemIdHeader,
|
@@ -47,7 +47,7 @@ import {
|
|
47
47
|
import { UIServer } from './UIServer';
|
48
48
|
import { randomUUID } from 'crypto';
|
49
49
|
import { ImagePrompt, PageQueue } from './PageGenerator';
|
50
|
-
import { copyDirectory, createFuture } from './utils';
|
50
|
+
import { copyDirectory, createFuture, readPages } from './utils';
|
51
51
|
|
52
52
|
const UI_SERVERS: { [key: string]: UIServer } = {};
|
53
53
|
const router = Router();
|
@@ -101,10 +101,10 @@ router.post('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response)
|
|
101
101
|
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
102
102
|
});
|
103
103
|
|
104
|
-
router.post('/ui/create-system/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
104
|
+
router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
105
105
|
const systemId = req.params.systemId as string;
|
106
106
|
const srcDir = getSystemBaseDir(systemId);
|
107
|
-
const destDir =
|
107
|
+
const destDir = getSystemBaseImplDir(systemId);
|
108
108
|
|
109
109
|
await copyDirectory(srcDir, destDir, async (fileName, content) => {
|
110
110
|
const result = await stormClient.implementAPIClients({
|
@@ -114,8 +114,17 @@ router.post('/ui/create-system/:systemId', async (req: KapetaBodyRequest, res: R
|
|
114
114
|
return result;
|
115
115
|
});
|
116
116
|
|
117
|
-
|
118
|
-
|
117
|
+
const pages = readPages(destDir);
|
118
|
+
const prompt = await stormClient.generatePrompt(pages);
|
119
|
+
|
120
|
+
req.query.systemId = systemId;
|
121
|
+
const promptRequest: BasePromptRequest = {
|
122
|
+
prompt: prompt,
|
123
|
+
skipImprovement: true,
|
124
|
+
};
|
125
|
+
req.stringBody = JSON.stringify(promptRequest);
|
126
|
+
|
127
|
+
await handleAll(req, res);
|
119
128
|
});
|
120
129
|
|
121
130
|
router.delete('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
@@ -613,10 +622,15 @@ router.post('/ui/get-vote', async (req: KapetaBodyRequest, res: Response) => {
|
|
613
622
|
});
|
614
623
|
|
615
624
|
router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
|
625
|
+
await handleAll(req, res);
|
626
|
+
});
|
627
|
+
|
628
|
+
async function handleAll(req: KapetaBodyRequest, res: Response) {
|
616
629
|
const handle = req.params.handle as string;
|
630
|
+
const systemId = (req.query.systemId as string) ?? undefined;
|
617
631
|
|
618
632
|
try {
|
619
|
-
const stormOptions = await resolveOptions();
|
633
|
+
const stormOptions = { ...(await resolveOptions()), systemId: systemId };
|
620
634
|
|
621
635
|
const eventParser = new StormEventParser(stormOptions);
|
622
636
|
|
@@ -703,7 +717,8 @@ router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
|
|
703
717
|
metaStream.getConversationId(),
|
704
718
|
aiRequest.prompt,
|
705
719
|
result.blocks,
|
706
|
-
eventParser.getEvents()
|
720
|
+
eventParser.getEvents(),
|
721
|
+
systemId
|
707
722
|
);
|
708
723
|
|
709
724
|
onRequestAborted(req, res, () => {
|
@@ -729,7 +744,7 @@ router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
|
|
729
744
|
res.end();
|
730
745
|
}
|
731
746
|
}
|
732
|
-
}
|
747
|
+
}
|
733
748
|
|
734
749
|
router.post('/block/create', async (req: KapetaBodyRequest, res: Response) => {
|
735
750
|
const createRequest: StormCreateBlockRequest = JSON.parse(req.stringBody ?? '{}');
|
package/src/storm/stormClient.ts
CHANGED
@@ -267,6 +267,17 @@ class StormClient {
|
|
267
267
|
return data;
|
268
268
|
}
|
269
269
|
|
270
|
+
public async generatePrompt(pages: string[]): Promise<string> {
|
271
|
+
const u = `${this._baseUrl}/v2/ui/prompt`;
|
272
|
+
const response = await fetch(u, {
|
273
|
+
method: 'POST',
|
274
|
+
body: JSON.stringify({
|
275
|
+
pages: pages,
|
276
|
+
}),
|
277
|
+
});
|
278
|
+
return await response.text();
|
279
|
+
}
|
280
|
+
|
270
281
|
public classifyUIReferences(prompt: string, conversationId?: string) {
|
271
282
|
return this.send('/v2/ui/references', {
|
272
283
|
prompt: prompt,
|
package/src/storm/utils.ts
CHANGED
@@ -31,6 +31,29 @@ export async function copyDirectory(
|
|
31
31
|
}
|
32
32
|
}
|
33
33
|
|
34
|
+
export function readPages(directoryPath: string): string[] {
|
35
|
+
const htmlFiles: string[] = [];
|
36
|
+
|
37
|
+
function traverseDirectory(currentPath: string) {
|
38
|
+
const files = FS.readdirSync(currentPath);
|
39
|
+
|
40
|
+
for (const file of files) {
|
41
|
+
const filePath = Path.join(currentPath, file);
|
42
|
+
const stats = FS.statSync(filePath);
|
43
|
+
|
44
|
+
if (stats.isDirectory()) {
|
45
|
+
traverseDirectory(filePath);
|
46
|
+
} else if (stats.isFile() && Path.extname(filePath) === '.html') {
|
47
|
+
const content = FS.readFileSync(filePath, 'utf8');
|
48
|
+
htmlFiles.push(content);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
traverseDirectory(directoryPath);
|
54
|
+
return htmlFiles;
|
55
|
+
}
|
56
|
+
|
34
57
|
export function createFuture<T = void>() {
|
35
58
|
let resolve: (value: T | PromiseLike<T>) => void = () => {};
|
36
59
|
let reject: (reason?: any) => void = () => {};
|
@@ -17,6 +17,7 @@ export const parserOptions = {
|
|
17
17
|
|
18
18
|
frontendKind: 'kapeta/block-type-frontend:local',
|
19
19
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
20
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
20
21
|
|
21
22
|
cliKind: 'kapeta/block-type-cli:local',
|
22
23
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|