@kapeta/local-cluster-service 0.71.3 → 0.71.5
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 +16 -0
- package/dist/cjs/src/storm/events.d.ts +10 -1
- package/dist/cjs/src/storm/events.js +1 -0
- package/dist/cjs/src/storm/routes.js +52 -8
- package/dist/cjs/src/storm/stormClient.d.ts +3 -2
- package/dist/cjs/src/storm/stormClient.js +17 -8
- package/dist/cjs/src/storm/stream.d.ts +12 -1
- package/dist/cjs/src/storm/stream.js +6 -1
- package/dist/cjs/src/storm/utils.d.ts +3 -2
- package/dist/cjs/src/storm/utils.js +20 -10
- package/dist/esm/src/storm/events.d.ts +10 -1
- package/dist/esm/src/storm/events.js +1 -0
- package/dist/esm/src/storm/routes.js +52 -8
- package/dist/esm/src/storm/stormClient.d.ts +3 -2
- package/dist/esm/src/storm/stormClient.js +17 -8
- package/dist/esm/src/storm/stream.d.ts +12 -1
- package/dist/esm/src/storm/stream.js +6 -1
- package/dist/esm/src/storm/utils.d.ts +3 -2
- package/dist/esm/src/storm/utils.js +20 -10
- package/package.json +1 -1
- package/src/storm/events.ts +12 -1
- package/src/storm/routes.ts +67 -15
- package/src/storm/stormClient.ts +20 -9
- package/src/storm/stream.ts +16 -2
- package/src/storm/utils.ts +19 -12
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## [0.71.5](https://github.com/kapetacom/local-cluster-service/compare/v0.71.4...v0.71.5) (2024-09-19)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* adds create-system-simple route ([fea005a](https://github.com/kapetacom/local-cluster-service/commit/fea005a183b45a2caf6811ae6d0d7019386a21ef))
|
7
|
+
* review comments ([17f8192](https://github.com/kapetacom/local-cluster-service/commit/17f819237efff8bb57dfdb9b2f53431d5dc44021))
|
8
|
+
* send html + images etc. to endpoint ([bdb5e81](https://github.com/kapetacom/local-cluster-service/commit/bdb5e818d66fff6983f126d872fdf228e97bc5d1))
|
9
|
+
|
10
|
+
## [0.71.4](https://github.com/kapetacom/local-cluster-service/compare/v0.71.3...v0.71.4) (2024-09-19)
|
11
|
+
|
12
|
+
|
13
|
+
### Bug Fixes
|
14
|
+
|
15
|
+
* Making implementing APIs from faster ([33f4f1c](https://github.com/kapetacom/local-cluster-service/commit/33f4f1c071eb6c248e4912bfceffc820496c6edd))
|
16
|
+
|
1
17
|
## [0.71.3](https://github.com/kapetacom/local-cluster-service/compare/v0.71.2...v0.71.3) (2024-09-18)
|
2
18
|
|
3
19
|
|
@@ -273,6 +273,7 @@ export interface StormEventDefinitionChange {
|
|
273
273
|
export declare enum StormEventPhaseType {
|
274
274
|
IMPLEMENT_APIS = "IMPLEMENT_APIS",// Implement APIs in the html pages
|
275
275
|
COMPOSE_SYSTEM_PROMPT = "COMPOSE_SYSTEM_PROMPT",// Compose system prompt for bottom-up approach
|
276
|
+
COMPOSE_SYSTEM = "COMPOSE_SYSTEM",
|
276
277
|
META = "META",
|
277
278
|
DEFINITIONS = "DEFINITIONS",
|
278
279
|
IMPLEMENTATION = "IMPLEMENTATION",
|
@@ -395,5 +396,13 @@ export interface StormEventUIStarted {
|
|
395
396
|
resetUrl: string;
|
396
397
|
};
|
397
398
|
}
|
398
|
-
export
|
399
|
+
export interface StormEventSystemReady {
|
400
|
+
type: 'SYSTEM_READY';
|
401
|
+
reason: string;
|
402
|
+
created: number;
|
403
|
+
payload: {
|
404
|
+
systemUrl: string;
|
405
|
+
};
|
406
|
+
}
|
407
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileFailed | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases | StormEventBlockStatus | StormEventCreateDSLRetry | StormEventUserJourney | StormEventUIShell | StormEventPage | StormEventPageUrl | StormEventPromptImprove | StormEventLandingPage | StormEventReferenceClassification | StormEventApiBase | StormEventUIStarted | StormImage | StormEventSystemReady;
|
399
408
|
export {};
|
@@ -13,6 +13,7 @@ var StormEventPhaseType;
|
|
13
13
|
(function (StormEventPhaseType) {
|
14
14
|
StormEventPhaseType["IMPLEMENT_APIS"] = "IMPLEMENT_APIS";
|
15
15
|
StormEventPhaseType["COMPOSE_SYSTEM_PROMPT"] = "COMPOSE_SYSTEM_PROMPT";
|
16
|
+
StormEventPhaseType["COMPOSE_SYSTEM"] = "COMPOSE_SYSTEM";
|
16
17
|
StormEventPhaseType["META"] = "META";
|
17
18
|
StormEventPhaseType["DEFINITIONS"] = "DEFINITIONS";
|
18
19
|
StormEventPhaseType["IMPLEMENTATION"] = "IMPLEMENTATION";
|
@@ -13,6 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const cors_1 = require("../middleware/cors");
|
15
15
|
const stringBody_1 = require("../middleware/stringBody");
|
16
|
+
const stream_1 = require("./stream");
|
16
17
|
const stormClient_1 = require("./stormClient");
|
17
18
|
const events_1 = require("./events");
|
18
19
|
const event_parser_1 = require("./event-parser");
|
@@ -76,17 +77,22 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
76
77
|
res.set('Access-Control-Expose-Headers', stormClient_1.ConversationIdHeader);
|
77
78
|
res.set(stormClient_1.ConversationIdHeader, systemId);
|
78
79
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
81
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
82
|
+
pages: pagesFromDisk,
|
83
|
+
});
|
84
|
+
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
85
|
+
// find the page from result1 and write the content to the file
|
86
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
87
|
+
return page ? page.content : content;
|
85
88
|
});
|
86
89
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
87
90
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
88
|
-
|
89
|
-
const
|
91
|
+
// get the content of the pages
|
92
|
+
const pageContents = pagesWithImplementation.map((page) => {
|
93
|
+
return page.content;
|
94
|
+
});
|
95
|
+
const prompt = await stormClient_1.stormClient.generatePrompt(pageContents);
|
90
96
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
91
97
|
req.query.systemId = systemId;
|
92
98
|
const promptRequest = {
|
@@ -96,6 +102,44 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
96
102
|
req.stringBody = JSON.stringify(promptRequest);
|
97
103
|
await handleAll(req, res);
|
98
104
|
});
|
105
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
106
|
+
const handle = req.params.handle;
|
107
|
+
const systemId = req.params.systemId;
|
108
|
+
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
109
|
+
res.set('Content-Type', 'application/x-ndjson');
|
110
|
+
res.set('Access-Control-Expose-Headers', stormClient_1.ConversationIdHeader);
|
111
|
+
res.set(stormClient_1.ConversationIdHeader, systemId);
|
112
|
+
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
113
|
+
try {
|
114
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
115
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
116
|
+
pages: pagesFromDisk,
|
117
|
+
});
|
118
|
+
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
119
|
+
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM));
|
120
|
+
const allFiles = (0, utils_1.readFilesAndContent)(srcDir, false).map((page) => {
|
121
|
+
if (page.encoding == stream_1.HTMLPageEncoding.TEXT) {
|
122
|
+
const matchingFile = pagesWithImplementation.find((pageWithImpl) => pageWithImpl.fileName === page.fileName);
|
123
|
+
if (matchingFile) {
|
124
|
+
return matchingFile;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
return page;
|
128
|
+
});
|
129
|
+
const systemUrl = await stormClient_1.stormClient.createSimpleBackend(handle, systemId, { pages: allFiles });
|
130
|
+
sendEvent(res, { type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl } });
|
131
|
+
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM));
|
132
|
+
sendDone(res);
|
133
|
+
}
|
134
|
+
catch (err) {
|
135
|
+
sendError(err, res);
|
136
|
+
}
|
137
|
+
finally {
|
138
|
+
if (!res.closed) {
|
139
|
+
res.end();
|
140
|
+
}
|
141
|
+
}
|
142
|
+
});
|
99
143
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
100
144
|
const systemId = req.params.systemId;
|
101
145
|
if (!systemId) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
import { ConversationItem,
|
2
|
+
import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
3
3
|
import { Page, StormEventPageUrl } from './events';
|
4
4
|
export declare const STORM_ID = "storm";
|
5
5
|
export declare const ConversationIdHeader = "Conversation-Id";
|
@@ -70,8 +70,9 @@ declare class StormClient {
|
|
70
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
71
71
|
vote: -1 | 0 | 1;
|
72
72
|
}>;
|
73
|
-
|
73
|
+
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]>;
|
74
74
|
generatePrompt(pages: string[]): Promise<string>;
|
75
|
+
createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest): Promise<string>;
|
75
76
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
76
77
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
77
78
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -133,17 +133,13 @@ class StormClient {
|
|
133
133
|
const response = await fetch(options.url, options);
|
134
134
|
return response.json();
|
135
135
|
}
|
136
|
-
async
|
137
|
-
const u = `${this._baseUrl}/v2/ui/implement-api-clients`;
|
136
|
+
async replaceMockWithAPICall(prompt) {
|
137
|
+
const u = `${this._baseUrl}/v2/ui/implement-api-clients-all`;
|
138
138
|
const response = await fetch(u, {
|
139
139
|
method: 'POST',
|
140
|
-
body: JSON.stringify(
|
141
|
-
fileName: prompt.fileName,
|
142
|
-
content: prompt.content,
|
143
|
-
}),
|
140
|
+
body: JSON.stringify(prompt.pages),
|
144
141
|
});
|
145
|
-
|
146
|
-
return data;
|
142
|
+
return await response.json();
|
147
143
|
}
|
148
144
|
async generatePrompt(pages) {
|
149
145
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
@@ -155,6 +151,19 @@ class StormClient {
|
|
155
151
|
});
|
156
152
|
return await response.text();
|
157
153
|
}
|
154
|
+
async createSimpleBackend(handle, systemId, input) {
|
155
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
156
|
+
const response = await fetch(u, {
|
157
|
+
method: 'POST',
|
158
|
+
body: JSON.stringify({
|
159
|
+
pages: input.pages,
|
160
|
+
}),
|
161
|
+
});
|
162
|
+
if (!response.ok) {
|
163
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
164
|
+
}
|
165
|
+
return await response.text();
|
166
|
+
}
|
158
167
|
classifyUIReferences(prompt, conversationId) {
|
159
168
|
return this.send('/v2/ui/references', {
|
160
169
|
prompt: prompt,
|
@@ -72,7 +72,18 @@ export interface StormUIListPrompt {
|
|
72
72
|
blockName: string;
|
73
73
|
prompt: string;
|
74
74
|
}
|
75
|
-
export
|
75
|
+
export declare enum HTMLPageEncoding {
|
76
|
+
TEXT = "TEXT",
|
77
|
+
BINARY = "BINARY"
|
78
|
+
}
|
79
|
+
export interface ImplementAPIClients {
|
80
|
+
pages: HTMLPage[];
|
81
|
+
}
|
82
|
+
export interface HTMLPage {
|
76
83
|
fileName: string;
|
77
84
|
content: string;
|
85
|
+
encoding: HTMLPageEncoding;
|
86
|
+
}
|
87
|
+
export interface CreateSimpleBackendRequest {
|
88
|
+
pages: HTMLPage[];
|
78
89
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.StormStream = void 0;
|
3
|
+
exports.HTMLPageEncoding = exports.StormStream = void 0;
|
4
4
|
/**
|
5
5
|
* Copyright 2023 Kapeta Inc.
|
6
6
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -74,3 +74,8 @@ class StormStream extends node_events_1.EventEmitter {
|
|
74
74
|
}
|
75
75
|
}
|
76
76
|
exports.StormStream = StormStream;
|
77
|
+
var HTMLPageEncoding;
|
78
|
+
(function (HTMLPageEncoding) {
|
79
|
+
HTMLPageEncoding["TEXT"] = "TEXT";
|
80
|
+
HTMLPageEncoding["BINARY"] = "BINARY";
|
81
|
+
})(HTMLPageEncoding || (exports.HTMLPageEncoding = HTMLPageEncoding = {}));
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
export declare function
|
1
|
+
import { HTMLPage } from './stream';
|
2
|
+
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => string): Promise<void>;
|
3
|
+
export declare function readFilesAndContent(directoryPath: string, htmlExclusive?: boolean): HTMLPage[];
|
3
4
|
export declare function createFuture<T = void>(): {
|
4
5
|
promise: Promise<T>;
|
5
6
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -3,13 +3,14 @@ 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.
|
6
|
+
exports.createFuture = exports.readFilesAndContent = exports.copyDirectory = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
10
10
|
*/
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
+
const stream_1 = require("./stream");
|
13
14
|
async function copyDirectory(src, dest, modifyHtml) {
|
14
15
|
await fs_extra_1.default.promises.mkdir(dest, { recursive: true });
|
15
16
|
const entries = await fs_extra_1.default.promises.readdir(src, { withFileTypes: true });
|
@@ -22,33 +23,42 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
22
23
|
else if (entry.isFile()) {
|
23
24
|
let content = await fs_extra_1.default.promises.readFile(srcPath, 'utf-8');
|
24
25
|
if (path_1.default.extname(srcPath) === '.html') {
|
25
|
-
content =
|
26
|
+
content = modifyHtml(srcPath, content);
|
26
27
|
}
|
27
28
|
await fs_extra_1.default.promises.writeFile(destPath, content, 'utf-8');
|
28
29
|
}
|
29
30
|
}
|
30
31
|
}
|
31
32
|
exports.copyDirectory = copyDirectory;
|
32
|
-
function
|
33
|
+
function readFilesAndContent(directoryPath, htmlExclusive = true) {
|
33
34
|
const htmlFiles = [];
|
34
35
|
function traverseDirectory(currentPath) {
|
35
36
|
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
37
|
for (const file of files) {
|
37
|
-
const
|
38
|
-
const
|
38
|
+
const fileName = path_1.default.join(currentPath, file);
|
39
|
+
const relativeFilename = path_1.default.relative(directoryPath, fileName);
|
40
|
+
const stats = fs_extra_1.default.statSync(fileName);
|
39
41
|
if (stats.isDirectory()) {
|
40
|
-
traverseDirectory(
|
42
|
+
traverseDirectory(fileName);
|
41
43
|
}
|
42
|
-
else if (stats.isFile()
|
43
|
-
|
44
|
-
|
44
|
+
else if (stats.isFile()) {
|
45
|
+
if (path_1.default.extname(fileName) === '.html') {
|
46
|
+
const content = fs_extra_1.default.readFileSync(fileName, 'utf8');
|
47
|
+
htmlFiles.push({ fileName: relativeFilename, content: content, encoding: stream_1.HTMLPageEncoding.TEXT });
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
if (!htmlExclusive) {
|
51
|
+
const content = fs_extra_1.default.readFileSync(fileName);
|
52
|
+
htmlFiles.push({ fileName: relativeFilename, content: content.toString('base64'), encoding: stream_1.HTMLPageEncoding.BINARY });
|
53
|
+
}
|
54
|
+
}
|
45
55
|
}
|
46
56
|
}
|
47
57
|
}
|
48
58
|
traverseDirectory(directoryPath);
|
49
59
|
return htmlFiles;
|
50
60
|
}
|
51
|
-
exports.
|
61
|
+
exports.readFilesAndContent = readFilesAndContent;
|
52
62
|
function createFuture() {
|
53
63
|
let resolve = () => { };
|
54
64
|
let reject = () => { };
|
@@ -273,6 +273,7 @@ export interface StormEventDefinitionChange {
|
|
273
273
|
export declare enum StormEventPhaseType {
|
274
274
|
IMPLEMENT_APIS = "IMPLEMENT_APIS",// Implement APIs in the html pages
|
275
275
|
COMPOSE_SYSTEM_PROMPT = "COMPOSE_SYSTEM_PROMPT",// Compose system prompt for bottom-up approach
|
276
|
+
COMPOSE_SYSTEM = "COMPOSE_SYSTEM",
|
276
277
|
META = "META",
|
277
278
|
DEFINITIONS = "DEFINITIONS",
|
278
279
|
IMPLEMENTATION = "IMPLEMENTATION",
|
@@ -395,5 +396,13 @@ export interface StormEventUIStarted {
|
|
395
396
|
resetUrl: string;
|
396
397
|
};
|
397
398
|
}
|
398
|
-
export
|
399
|
+
export interface StormEventSystemReady {
|
400
|
+
type: 'SYSTEM_READY';
|
401
|
+
reason: string;
|
402
|
+
created: number;
|
403
|
+
payload: {
|
404
|
+
systemUrl: string;
|
405
|
+
};
|
406
|
+
}
|
407
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileFailed | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases | StormEventBlockStatus | StormEventCreateDSLRetry | StormEventUserJourney | StormEventUIShell | StormEventPage | StormEventPageUrl | StormEventPromptImprove | StormEventLandingPage | StormEventReferenceClassification | StormEventApiBase | StormEventUIStarted | StormImage | StormEventSystemReady;
|
399
408
|
export {};
|
@@ -13,6 +13,7 @@ var StormEventPhaseType;
|
|
13
13
|
(function (StormEventPhaseType) {
|
14
14
|
StormEventPhaseType["IMPLEMENT_APIS"] = "IMPLEMENT_APIS";
|
15
15
|
StormEventPhaseType["COMPOSE_SYSTEM_PROMPT"] = "COMPOSE_SYSTEM_PROMPT";
|
16
|
+
StormEventPhaseType["COMPOSE_SYSTEM"] = "COMPOSE_SYSTEM";
|
16
17
|
StormEventPhaseType["META"] = "META";
|
17
18
|
StormEventPhaseType["DEFINITIONS"] = "DEFINITIONS";
|
18
19
|
StormEventPhaseType["IMPLEMENTATION"] = "IMPLEMENTATION";
|
@@ -13,6 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const cors_1 = require("../middleware/cors");
|
15
15
|
const stringBody_1 = require("../middleware/stringBody");
|
16
|
+
const stream_1 = require("./stream");
|
16
17
|
const stormClient_1 = require("./stormClient");
|
17
18
|
const events_1 = require("./events");
|
18
19
|
const event_parser_1 = require("./event-parser");
|
@@ -76,17 +77,22 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
76
77
|
res.set('Access-Control-Expose-Headers', stormClient_1.ConversationIdHeader);
|
77
78
|
res.set(stormClient_1.ConversationIdHeader, systemId);
|
78
79
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
81
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
82
|
+
pages: pagesFromDisk,
|
83
|
+
});
|
84
|
+
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
85
|
+
// find the page from result1 and write the content to the file
|
86
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
87
|
+
return page ? page.content : content;
|
85
88
|
});
|
86
89
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
87
90
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
88
|
-
|
89
|
-
const
|
91
|
+
// get the content of the pages
|
92
|
+
const pageContents = pagesWithImplementation.map((page) => {
|
93
|
+
return page.content;
|
94
|
+
});
|
95
|
+
const prompt = await stormClient_1.stormClient.generatePrompt(pageContents);
|
90
96
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
91
97
|
req.query.systemId = systemId;
|
92
98
|
const promptRequest = {
|
@@ -96,6 +102,44 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
96
102
|
req.stringBody = JSON.stringify(promptRequest);
|
97
103
|
await handleAll(req, res);
|
98
104
|
});
|
105
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
106
|
+
const handle = req.params.handle;
|
107
|
+
const systemId = req.params.systemId;
|
108
|
+
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
109
|
+
res.set('Content-Type', 'application/x-ndjson');
|
110
|
+
res.set('Access-Control-Expose-Headers', stormClient_1.ConversationIdHeader);
|
111
|
+
res.set(stormClient_1.ConversationIdHeader, systemId);
|
112
|
+
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
113
|
+
try {
|
114
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
115
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
116
|
+
pages: pagesFromDisk,
|
117
|
+
});
|
118
|
+
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
119
|
+
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM));
|
120
|
+
const allFiles = (0, utils_1.readFilesAndContent)(srcDir, false).map((page) => {
|
121
|
+
if (page.encoding == stream_1.HTMLPageEncoding.TEXT) {
|
122
|
+
const matchingFile = pagesWithImplementation.find((pageWithImpl) => pageWithImpl.fileName === page.fileName);
|
123
|
+
if (matchingFile) {
|
124
|
+
return matchingFile;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
return page;
|
128
|
+
});
|
129
|
+
const systemUrl = await stormClient_1.stormClient.createSimpleBackend(handle, systemId, { pages: allFiles });
|
130
|
+
sendEvent(res, { type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl } });
|
131
|
+
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM));
|
132
|
+
sendDone(res);
|
133
|
+
}
|
134
|
+
catch (err) {
|
135
|
+
sendError(err, res);
|
136
|
+
}
|
137
|
+
finally {
|
138
|
+
if (!res.closed) {
|
139
|
+
res.end();
|
140
|
+
}
|
141
|
+
}
|
142
|
+
});
|
99
143
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
100
144
|
const systemId = req.params.systemId;
|
101
145
|
if (!systemId) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
import { ConversationItem,
|
2
|
+
import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
3
3
|
import { Page, StormEventPageUrl } from './events';
|
4
4
|
export declare const STORM_ID = "storm";
|
5
5
|
export declare const ConversationIdHeader = "Conversation-Id";
|
@@ -70,8 +70,9 @@ declare class StormClient {
|
|
70
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
71
71
|
vote: -1 | 0 | 1;
|
72
72
|
}>;
|
73
|
-
|
73
|
+
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]>;
|
74
74
|
generatePrompt(pages: string[]): Promise<string>;
|
75
|
+
createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest): Promise<string>;
|
75
76
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
76
77
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
77
78
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -133,17 +133,13 @@ class StormClient {
|
|
133
133
|
const response = await fetch(options.url, options);
|
134
134
|
return response.json();
|
135
135
|
}
|
136
|
-
async
|
137
|
-
const u = `${this._baseUrl}/v2/ui/implement-api-clients`;
|
136
|
+
async replaceMockWithAPICall(prompt) {
|
137
|
+
const u = `${this._baseUrl}/v2/ui/implement-api-clients-all`;
|
138
138
|
const response = await fetch(u, {
|
139
139
|
method: 'POST',
|
140
|
-
body: JSON.stringify(
|
141
|
-
fileName: prompt.fileName,
|
142
|
-
content: prompt.content,
|
143
|
-
}),
|
140
|
+
body: JSON.stringify(prompt.pages),
|
144
141
|
});
|
145
|
-
|
146
|
-
return data;
|
142
|
+
return await response.json();
|
147
143
|
}
|
148
144
|
async generatePrompt(pages) {
|
149
145
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
@@ -155,6 +151,19 @@ class StormClient {
|
|
155
151
|
});
|
156
152
|
return await response.text();
|
157
153
|
}
|
154
|
+
async createSimpleBackend(handle, systemId, input) {
|
155
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
156
|
+
const response = await fetch(u, {
|
157
|
+
method: 'POST',
|
158
|
+
body: JSON.stringify({
|
159
|
+
pages: input.pages,
|
160
|
+
}),
|
161
|
+
});
|
162
|
+
if (!response.ok) {
|
163
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
164
|
+
}
|
165
|
+
return await response.text();
|
166
|
+
}
|
158
167
|
classifyUIReferences(prompt, conversationId) {
|
159
168
|
return this.send('/v2/ui/references', {
|
160
169
|
prompt: prompt,
|
@@ -72,7 +72,18 @@ export interface StormUIListPrompt {
|
|
72
72
|
blockName: string;
|
73
73
|
prompt: string;
|
74
74
|
}
|
75
|
-
export
|
75
|
+
export declare enum HTMLPageEncoding {
|
76
|
+
TEXT = "TEXT",
|
77
|
+
BINARY = "BINARY"
|
78
|
+
}
|
79
|
+
export interface ImplementAPIClients {
|
80
|
+
pages: HTMLPage[];
|
81
|
+
}
|
82
|
+
export interface HTMLPage {
|
76
83
|
fileName: string;
|
77
84
|
content: string;
|
85
|
+
encoding: HTMLPageEncoding;
|
86
|
+
}
|
87
|
+
export interface CreateSimpleBackendRequest {
|
88
|
+
pages: HTMLPage[];
|
78
89
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.StormStream = void 0;
|
3
|
+
exports.HTMLPageEncoding = exports.StormStream = void 0;
|
4
4
|
/**
|
5
5
|
* Copyright 2023 Kapeta Inc.
|
6
6
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -74,3 +74,8 @@ class StormStream extends node_events_1.EventEmitter {
|
|
74
74
|
}
|
75
75
|
}
|
76
76
|
exports.StormStream = StormStream;
|
77
|
+
var HTMLPageEncoding;
|
78
|
+
(function (HTMLPageEncoding) {
|
79
|
+
HTMLPageEncoding["TEXT"] = "TEXT";
|
80
|
+
HTMLPageEncoding["BINARY"] = "BINARY";
|
81
|
+
})(HTMLPageEncoding || (exports.HTMLPageEncoding = HTMLPageEncoding = {}));
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
export declare function
|
1
|
+
import { HTMLPage } from './stream';
|
2
|
+
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => string): Promise<void>;
|
3
|
+
export declare function readFilesAndContent(directoryPath: string, htmlExclusive?: boolean): HTMLPage[];
|
3
4
|
export declare function createFuture<T = void>(): {
|
4
5
|
promise: Promise<T>;
|
5
6
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -3,13 +3,14 @@ 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.
|
6
|
+
exports.createFuture = exports.readFilesAndContent = exports.copyDirectory = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
10
10
|
*/
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
+
const stream_1 = require("./stream");
|
13
14
|
async function copyDirectory(src, dest, modifyHtml) {
|
14
15
|
await fs_extra_1.default.promises.mkdir(dest, { recursive: true });
|
15
16
|
const entries = await fs_extra_1.default.promises.readdir(src, { withFileTypes: true });
|
@@ -22,33 +23,42 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
22
23
|
else if (entry.isFile()) {
|
23
24
|
let content = await fs_extra_1.default.promises.readFile(srcPath, 'utf-8');
|
24
25
|
if (path_1.default.extname(srcPath) === '.html') {
|
25
|
-
content =
|
26
|
+
content = modifyHtml(srcPath, content);
|
26
27
|
}
|
27
28
|
await fs_extra_1.default.promises.writeFile(destPath, content, 'utf-8');
|
28
29
|
}
|
29
30
|
}
|
30
31
|
}
|
31
32
|
exports.copyDirectory = copyDirectory;
|
32
|
-
function
|
33
|
+
function readFilesAndContent(directoryPath, htmlExclusive = true) {
|
33
34
|
const htmlFiles = [];
|
34
35
|
function traverseDirectory(currentPath) {
|
35
36
|
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
37
|
for (const file of files) {
|
37
|
-
const
|
38
|
-
const
|
38
|
+
const fileName = path_1.default.join(currentPath, file);
|
39
|
+
const relativeFilename = path_1.default.relative(directoryPath, fileName);
|
40
|
+
const stats = fs_extra_1.default.statSync(fileName);
|
39
41
|
if (stats.isDirectory()) {
|
40
|
-
traverseDirectory(
|
42
|
+
traverseDirectory(fileName);
|
41
43
|
}
|
42
|
-
else if (stats.isFile()
|
43
|
-
|
44
|
-
|
44
|
+
else if (stats.isFile()) {
|
45
|
+
if (path_1.default.extname(fileName) === '.html') {
|
46
|
+
const content = fs_extra_1.default.readFileSync(fileName, 'utf8');
|
47
|
+
htmlFiles.push({ fileName: relativeFilename, content: content, encoding: stream_1.HTMLPageEncoding.TEXT });
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
if (!htmlExclusive) {
|
51
|
+
const content = fs_extra_1.default.readFileSync(fileName);
|
52
|
+
htmlFiles.push({ fileName: relativeFilename, content: content.toString('base64'), encoding: stream_1.HTMLPageEncoding.BINARY });
|
53
|
+
}
|
54
|
+
}
|
45
55
|
}
|
46
56
|
}
|
47
57
|
}
|
48
58
|
traverseDirectory(directoryPath);
|
49
59
|
return htmlFiles;
|
50
60
|
}
|
51
|
-
exports.
|
61
|
+
exports.readFilesAndContent = readFilesAndContent;
|
52
62
|
function createFuture() {
|
53
63
|
let resolve = () => { };
|
54
64
|
let reject = () => { };
|
package/package.json
CHANGED
package/src/storm/events.ts
CHANGED
@@ -331,6 +331,7 @@ export interface StormEventDefinitionChange {
|
|
331
331
|
export enum StormEventPhaseType {
|
332
332
|
IMPLEMENT_APIS = 'IMPLEMENT_APIS', // Implement APIs in the html pages
|
333
333
|
COMPOSE_SYSTEM_PROMPT = 'COMPOSE_SYSTEM_PROMPT', // Compose system prompt for bottom-up approach
|
334
|
+
COMPOSE_SYSTEM = 'COMPOSE_SYSTEM',
|
334
335
|
META = 'META',
|
335
336
|
DEFINITIONS = 'DEFINITIONS',
|
336
337
|
IMPLEMENTATION = 'IMPLEMENTATION',
|
@@ -473,6 +474,15 @@ export interface StormEventUIStarted {
|
|
473
474
|
};
|
474
475
|
}
|
475
476
|
|
477
|
+
export interface StormEventSystemReady {
|
478
|
+
type: 'SYSTEM_READY';
|
479
|
+
reason: string;
|
480
|
+
created: number;
|
481
|
+
payload: {
|
482
|
+
systemUrl: string;
|
483
|
+
}
|
484
|
+
}
|
485
|
+
|
476
486
|
export type StormEvent =
|
477
487
|
| StormEventCreateBlock
|
478
488
|
| StormEventCreateConnection
|
@@ -507,4 +517,5 @@ export type StormEvent =
|
|
507
517
|
| StormEventReferenceClassification
|
508
518
|
| StormEventApiBase
|
509
519
|
| StormEventUIStarted
|
510
|
-
| StormImage
|
520
|
+
| StormImage
|
521
|
+
| StormEventSystemReady;
|
package/src/storm/routes.ts
CHANGED
@@ -11,7 +11,7 @@ import _ from 'lodash';
|
|
11
11
|
import { corsHandler } from '../middleware/cors';
|
12
12
|
import { stringBody } from '../middleware/stringBody';
|
13
13
|
import { KapetaBodyRequest } from '../types';
|
14
|
-
import { StormCodegenRequest, StormContextRequest, StormCreateBlockRequest, StormStream
|
14
|
+
import {HTMLPageEncoding, StormCodegenRequest, StormContextRequest, StormCreateBlockRequest, StormStream} from './stream';
|
15
15
|
|
16
16
|
import {
|
17
17
|
ConversationIdHeader,
|
@@ -22,7 +22,7 @@ import {
|
|
22
22
|
UIPageVoteRequest,
|
23
23
|
UIPageGetVoteRequest,
|
24
24
|
} from './stormClient';
|
25
|
-
import {
|
25
|
+
import { StormEvent, StormEventPage, StormEventPhaseType, UserJourneyScreen } from './events';
|
26
26
|
|
27
27
|
import {
|
28
28
|
createPhaseEndEvent,
|
@@ -37,16 +37,14 @@ import uuid from 'node-uuid';
|
|
37
37
|
import {
|
38
38
|
getSystemBaseDir,
|
39
39
|
getSystemBaseImplDir,
|
40
|
-
readPageFromDisk,
|
41
|
-
resolveReadPath,
|
42
40
|
SystemIdHeader,
|
43
41
|
writeAssetToDisk,
|
44
42
|
writePageToDisk,
|
45
43
|
} from './page-utils';
|
46
44
|
import { UIServer } from './UIServer';
|
47
45
|
import { randomUUID } from 'crypto';
|
48
|
-
import {
|
49
|
-
import { copyDirectory, createFuture,
|
46
|
+
import { PageQueue } from './PageGenerator';
|
47
|
+
import { copyDirectory, createFuture, readFilesAndContent } from './utils';
|
50
48
|
|
51
49
|
const UI_SERVERS: { [key: string]: UIServer } = {};
|
52
50
|
const router = Router();
|
@@ -111,20 +109,28 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
111
109
|
|
112
110
|
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
113
111
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
112
|
+
const pagesFromDisk = readFilesAndContent(srcDir);
|
113
|
+
const pagesWithImplementation = await stormClient.replaceMockWithAPICall({
|
114
|
+
pages: pagesFromDisk,
|
115
|
+
},
|
116
|
+
);
|
117
|
+
await copyDirectory(srcDir, destDir, (fileName, content) => {
|
118
|
+
// find the page from result1 and write the content to the file
|
119
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
120
|
+
return page ? page.content : content;
|
120
121
|
});
|
121
122
|
|
123
|
+
|
122
124
|
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
123
125
|
|
124
126
|
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
125
127
|
|
126
|
-
|
127
|
-
const
|
128
|
+
// get the content of the pages
|
129
|
+
const pageContents = pagesWithImplementation.map((page) => {
|
130
|
+
return page.content
|
131
|
+
})
|
132
|
+
|
133
|
+
const prompt = await stormClient.generatePrompt(pageContents);
|
128
134
|
|
129
135
|
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
130
136
|
|
@@ -134,10 +140,56 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
134
140
|
skipImprovement: true,
|
135
141
|
};
|
136
142
|
req.stringBody = JSON.stringify(promptRequest);
|
137
|
-
|
138
143
|
await handleAll(req, res);
|
139
144
|
});
|
140
145
|
|
146
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
147
|
+
const handle = req.params.handle as string;
|
148
|
+
const systemId = req.params.systemId as string;
|
149
|
+
const srcDir = getSystemBaseDir(systemId);
|
150
|
+
|
151
|
+
res.set('Content-Type', 'application/x-ndjson');
|
152
|
+
res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
153
|
+
res.set(ConversationIdHeader, systemId);
|
154
|
+
|
155
|
+
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
156
|
+
|
157
|
+
try {
|
158
|
+
const pagesFromDisk = readFilesAndContent(srcDir);
|
159
|
+
const pagesWithImplementation = await stormClient.replaceMockWithAPICall({
|
160
|
+
pages: pagesFromDisk,
|
161
|
+
},
|
162
|
+
);
|
163
|
+
|
164
|
+
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
165
|
+
|
166
|
+
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
167
|
+
|
168
|
+
const allFiles = readFilesAndContent(srcDir, false).map((page) => {
|
169
|
+
if (page.encoding == HTMLPageEncoding.TEXT) {
|
170
|
+
const matchingFile = pagesWithImplementation.find((pageWithImpl) => pageWithImpl.fileName === page.fileName);
|
171
|
+
if (matchingFile) {
|
172
|
+
return matchingFile;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
return page;
|
176
|
+
});
|
177
|
+
|
178
|
+
const systemUrl = await stormClient.createSimpleBackend(handle, systemId, {pages: allFiles});
|
179
|
+
sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
180
|
+
|
181
|
+
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
182
|
+
|
183
|
+
sendDone(res);
|
184
|
+
} catch (err: any) {
|
185
|
+
sendError(err, res);
|
186
|
+
} finally {
|
187
|
+
if (!res.closed) {
|
188
|
+
res.end();
|
189
|
+
}
|
190
|
+
}
|
191
|
+
});
|
192
|
+
|
141
193
|
router.delete('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
142
194
|
const systemId = req.params.systemId as string | undefined;
|
143
195
|
if (!systemId) {
|
package/src/storm/stormClient.ts
CHANGED
@@ -8,7 +8,8 @@ import readLine from 'node:readline/promises';
|
|
8
8
|
import { Readable } from 'node:stream';
|
9
9
|
import {
|
10
10
|
ConversationItem,
|
11
|
-
|
11
|
+
CreateSimpleBackendRequest, HTMLPage,
|
12
|
+
ImplementAPIClients,
|
12
13
|
StormContextRequest,
|
13
14
|
StormFileImplementationPrompt,
|
14
15
|
StormStream,
|
@@ -238,17 +239,13 @@ class StormClient {
|
|
238
239
|
return response.json() as Promise<{ vote: -1 | 0 | 1 }>;
|
239
240
|
}
|
240
241
|
|
241
|
-
public async
|
242
|
-
const u = `${this._baseUrl}/v2/ui/implement-api-clients`;
|
242
|
+
public async replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]> {
|
243
|
+
const u = `${this._baseUrl}/v2/ui/implement-api-clients-all`;
|
243
244
|
const response = await fetch(u, {
|
244
245
|
method: 'POST',
|
245
|
-
body: JSON.stringify(
|
246
|
-
fileName: prompt.fileName,
|
247
|
-
content: prompt.content,
|
248
|
-
}),
|
246
|
+
body: JSON.stringify(prompt.pages),
|
249
247
|
});
|
250
|
-
|
251
|
-
return data;
|
248
|
+
return await response.json() as HTMLPage[];
|
252
249
|
}
|
253
250
|
|
254
251
|
public async generatePrompt(pages: string[]): Promise<string> {
|
@@ -262,6 +259,20 @@ class StormClient {
|
|
262
259
|
return await response.text();
|
263
260
|
}
|
264
261
|
|
262
|
+
public async createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest) {
|
263
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
264
|
+
const response = await fetch(u, {
|
265
|
+
method: 'POST',
|
266
|
+
body: JSON.stringify({
|
267
|
+
pages: input.pages,
|
268
|
+
}),
|
269
|
+
});
|
270
|
+
if (!response.ok) {
|
271
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
272
|
+
}
|
273
|
+
return await response.text();
|
274
|
+
}
|
275
|
+
|
265
276
|
public classifyUIReferences(prompt: string, conversationId?: string) {
|
266
277
|
return this.send('/v2/ui/references', {
|
267
278
|
prompt: prompt,
|
package/src/storm/stream.ts
CHANGED
@@ -143,7 +143,21 @@ export interface StormUIListPrompt {
|
|
143
143
|
prompt: string;
|
144
144
|
}
|
145
145
|
|
146
|
-
export
|
146
|
+
export enum HTMLPageEncoding {
|
147
|
+
TEXT = 'TEXT',
|
148
|
+
BINARY = 'BINARY',
|
149
|
+
}
|
150
|
+
|
151
|
+
export interface ImplementAPIClients {
|
152
|
+
pages: HTMLPage[];
|
153
|
+
}
|
154
|
+
|
155
|
+
export interface HTMLPage {
|
147
156
|
fileName: string;
|
148
|
-
content: string
|
157
|
+
content: string;
|
158
|
+
encoding: HTMLPageEncoding;
|
159
|
+
}
|
160
|
+
|
161
|
+
export interface CreateSimpleBackendRequest {
|
162
|
+
pages: HTMLPage[];
|
149
163
|
}
|
package/src/storm/utils.ts
CHANGED
@@ -4,11 +4,12 @@
|
|
4
4
|
*/
|
5
5
|
import FS from 'fs-extra';
|
6
6
|
import Path from 'path';
|
7
|
+
import { HTMLPage, HTMLPageEncoding } from './stream';
|
7
8
|
|
8
9
|
export async function copyDirectory(
|
9
10
|
src: string,
|
10
11
|
dest: string,
|
11
|
-
modifyHtml: (fileName: string, content: string) =>
|
12
|
+
modifyHtml: (fileName: string, content: string) => string
|
12
13
|
): Promise<void> {
|
13
14
|
await FS.promises.mkdir(dest, { recursive: true });
|
14
15
|
const entries = await FS.promises.readdir(src, { withFileTypes: true });
|
@@ -23,7 +24,7 @@ export async function copyDirectory(
|
|
23
24
|
let content = await FS.promises.readFile(srcPath, 'utf-8');
|
24
25
|
|
25
26
|
if (Path.extname(srcPath) === '.html') {
|
26
|
-
content =
|
27
|
+
content = modifyHtml(srcPath, content);
|
27
28
|
}
|
28
29
|
|
29
30
|
await FS.promises.writeFile(destPath, content, 'utf-8');
|
@@ -31,21 +32,27 @@ export async function copyDirectory(
|
|
31
32
|
}
|
32
33
|
}
|
33
34
|
|
34
|
-
export function
|
35
|
-
const htmlFiles:
|
35
|
+
export function readFilesAndContent(directoryPath: string, htmlExclusive: boolean = true): HTMLPage[] {
|
36
|
+
const htmlFiles:HTMLPage[] = [];
|
36
37
|
|
37
38
|
function traverseDirectory(currentPath: string) {
|
38
39
|
const files = FS.readdirSync(currentPath);
|
39
|
-
|
40
40
|
for (const file of files) {
|
41
|
-
const
|
42
|
-
const
|
43
|
-
|
41
|
+
const fileName = Path.join(currentPath, file);
|
42
|
+
const relativeFilename = Path.relative(directoryPath, fileName);
|
43
|
+
const stats = FS.statSync(fileName);
|
44
44
|
if (stats.isDirectory()) {
|
45
|
-
traverseDirectory(
|
46
|
-
} else if (stats.isFile()
|
47
|
-
|
48
|
-
|
45
|
+
traverseDirectory(fileName);
|
46
|
+
} else if (stats.isFile()) {
|
47
|
+
if (Path.extname(fileName) === '.html') {
|
48
|
+
const content = FS.readFileSync(fileName, 'utf8');
|
49
|
+
htmlFiles.push({fileName: relativeFilename, content: content, encoding: HTMLPageEncoding.TEXT });
|
50
|
+
} else {
|
51
|
+
if (!htmlExclusive) {
|
52
|
+
const content = FS.readFileSync(fileName);
|
53
|
+
htmlFiles.push({fileName: relativeFilename, content: content.toString('base64'), encoding: HTMLPageEncoding.BINARY })
|
54
|
+
}
|
55
|
+
}
|
49
56
|
}
|
50
57
|
}
|
51
58
|
}
|