openkbs 0.0.53 → 0.0.59
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 +1490 -202
- package/package.json +2 -1
- package/src/actions.js +1282 -1
- package/src/index.js +77 -1
- package/src/utils.js +5 -2
- package/templates/.openkbs/knowledge/examples/ai-copywriter-agent/app/instructions.txt +44 -9
- package/templates/.openkbs/knowledge/examples/ai-copywriter-agent/src/Events/actions.js +43 -42
- package/templates/.openkbs/knowledge/examples/ai-copywriter-agent/src/Events/handler.js +14 -8
- package/templates/.openkbs/knowledge/examples/ai-copywriter-agent/src/Frontend/contentRender.js +95 -12
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/README.md +64 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/app/instructions.txt +160 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/app/settings.json +7 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Events/actions.js +258 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Events/onRequest.js +13 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Events/onRequest.json +3 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Events/onResponse.js +13 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Events/onResponse.json +3 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Frontend/contentRender.js +170 -0
- package/templates/.openkbs/knowledge/examples/ai-marketing-agent/src/Frontend/contentRender.json +3 -0
- package/templates/.openkbs/knowledge/metadata.json +1 -1
- package/templates/CLAUDE.md +593 -222
- package/templates/app/instructions.txt +13 -1
- package/templates/app/settings.json +5 -6
- package/templates/src/Events/actions.js +43 -9
- package/templates/src/Events/handler.js +24 -25
- package/templates/webpack.contentRender.config.js +8 -2
- package/version.json +3 -3
- package/MODIFY.md +0 -132
package/src/index.js
CHANGED
|
@@ -13,7 +13,12 @@ const {
|
|
|
13
13
|
deleteFileAction,
|
|
14
14
|
describeAction, deployAction, createByTemplateAction, initByTemplateAction,
|
|
15
15
|
logoutAction, installFrontendPackageAction, modifyAction, downloadModifyAction,
|
|
16
|
-
updateKnowledgeAction, updateCliAction, publishAction, unpublishAction
|
|
16
|
+
updateKnowledgeAction, updateCliAction, publishAction, unpublishAction,
|
|
17
|
+
fnAction,
|
|
18
|
+
siteAction,
|
|
19
|
+
storageAction,
|
|
20
|
+
postgresAction,
|
|
21
|
+
pulseAction
|
|
17
22
|
} = require('./actions');
|
|
18
23
|
|
|
19
24
|
|
|
@@ -197,4 +202,75 @@ Examples:
|
|
|
197
202
|
This will unpublish your KB from the domain example.com
|
|
198
203
|
`);
|
|
199
204
|
|
|
205
|
+
program
|
|
206
|
+
.command('fn [subCommand] [args...]')
|
|
207
|
+
.description('Manage Elastic Functions (serverless Lambda functions)')
|
|
208
|
+
.allowUnknownOption()
|
|
209
|
+
.action((subCommand, args) => fnAction(subCommand, args))
|
|
210
|
+
.addHelpText('after', `
|
|
211
|
+
Examples:
|
|
212
|
+
$ openkbs fn list List all functions
|
|
213
|
+
$ openkbs fn deploy hello --region us-east-1 Deploy function from ./functions/hello/
|
|
214
|
+
$ openkbs fn delete hello Delete a function
|
|
215
|
+
$ openkbs fn logs hello View function logs
|
|
216
|
+
$ openkbs fn env hello View environment variables
|
|
217
|
+
$ openkbs fn env hello API_KEY=secret Set environment variable
|
|
218
|
+
$ openkbs fn invoke hello '{"test": true}' Invoke a function
|
|
219
|
+
`);
|
|
220
|
+
|
|
221
|
+
program
|
|
222
|
+
.command('site [subCommand] [args...]')
|
|
223
|
+
.description('Manage static site files for whitelabel domains')
|
|
224
|
+
.action((subCommand, args) => siteAction(subCommand, args))
|
|
225
|
+
.addHelpText('after', `
|
|
226
|
+
Examples:
|
|
227
|
+
$ openkbs site deploy Deploy all files to S3
|
|
228
|
+
|
|
229
|
+
Run from a directory containing settings.json with kbId.
|
|
230
|
+
Files are uploaded to the whitelabel domain's files bucket.
|
|
231
|
+
`);
|
|
232
|
+
|
|
233
|
+
program
|
|
234
|
+
.command('storage [subCommand] [args...]')
|
|
235
|
+
.description('Manage Elastic Storage (S3 buckets for persistent file storage)')
|
|
236
|
+
.action((subCommand, args) => storageAction(subCommand, args))
|
|
237
|
+
.addHelpText('after', `
|
|
238
|
+
Examples:
|
|
239
|
+
$ openkbs storage enable Enable storage for current KB
|
|
240
|
+
$ openkbs storage status Show storage status
|
|
241
|
+
$ openkbs storage ls [prefix] List objects in bucket
|
|
242
|
+
$ openkbs storage put <file> <key> Upload a file
|
|
243
|
+
$ openkbs storage get <key> <file> Download a file
|
|
244
|
+
$ openkbs storage rm <key> Delete an object
|
|
245
|
+
$ openkbs storage disable Disable storage (delete bucket)
|
|
246
|
+
$ openkbs storage cloudfront media Add storage to CloudFront at /media/*
|
|
247
|
+
$ openkbs storage cloudfront remove media Remove storage from CloudFront
|
|
248
|
+
`);
|
|
249
|
+
|
|
250
|
+
program
|
|
251
|
+
.command('postgres [subCommand]')
|
|
252
|
+
.description('Manage Elastic Postgres (Neon PostgreSQL database)')
|
|
253
|
+
.action((subCommand) => postgresAction(subCommand))
|
|
254
|
+
.addHelpText('after', `
|
|
255
|
+
Examples:
|
|
256
|
+
$ openkbs postgres enable Enable Postgres for current KB
|
|
257
|
+
$ openkbs postgres status Show Postgres status
|
|
258
|
+
$ openkbs postgres connection Show connection string
|
|
259
|
+
$ openkbs postgres disable Disable Postgres (delete database)
|
|
260
|
+
`);
|
|
261
|
+
|
|
262
|
+
program
|
|
263
|
+
.command('pulse [subCommand] [args...]')
|
|
264
|
+
.description('Manage Elastic Pulse (real-time WebSocket pub/sub)')
|
|
265
|
+
.action((subCommand, args) => pulseAction(subCommand, args))
|
|
266
|
+
.addHelpText('after', `
|
|
267
|
+
Examples:
|
|
268
|
+
$ openkbs pulse enable Enable Pulse for current KB
|
|
269
|
+
$ openkbs pulse status Show Pulse status and endpoint
|
|
270
|
+
$ openkbs pulse channels List active channels
|
|
271
|
+
$ openkbs pulse presence chat Show clients connected to 'chat' channel
|
|
272
|
+
$ openkbs pulse publish chat "Hello!" Send message to 'chat' channel
|
|
273
|
+
$ openkbs pulse disable Disable Pulse
|
|
274
|
+
`);
|
|
275
|
+
|
|
200
276
|
program.parse(process.argv);
|
package/src/utils.js
CHANGED
|
@@ -164,8 +164,11 @@ function makePostRequest(url, data) {
|
|
|
164
164
|
resolve(data);
|
|
165
165
|
} else {
|
|
166
166
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
const parsed = JSON.parse(body);
|
|
168
|
+
if (parsed.error) {
|
|
169
|
+
console.red(parsed.error);
|
|
170
|
+
} else if (parsed.message) {
|
|
171
|
+
console.red(parsed.message);
|
|
169
172
|
} else {
|
|
170
173
|
console.red(`Invalid Request`);
|
|
171
174
|
}
|
|
@@ -38,24 +38,59 @@ Description: """
|
|
|
38
38
|
Output this JSON format if you can't extract the required data
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
LIST OF AVAILABLE COMMANDS:
|
|
42
|
+
To execute a command, output it as text and wait for system response.
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
<googleSearch>
|
|
45
|
+
{
|
|
46
|
+
"query": "search query"
|
|
47
|
+
}
|
|
48
|
+
</googleSearch>
|
|
44
49
|
Description: """
|
|
45
50
|
Get results from Google Search API.
|
|
46
51
|
"""
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
<youtubeSearch>
|
|
54
|
+
{
|
|
55
|
+
"query": "search query"
|
|
56
|
+
}
|
|
57
|
+
</youtubeSearch>
|
|
49
58
|
Description: """
|
|
50
|
-
Get results from
|
|
59
|
+
Get results from YouTube Search API.
|
|
51
60
|
"""
|
|
52
61
|
|
|
53
|
-
|
|
62
|
+
<googleImageSearch>
|
|
63
|
+
{
|
|
64
|
+
"query": "search query"
|
|
65
|
+
}
|
|
66
|
+
</googleImageSearch>
|
|
54
67
|
Description: """
|
|
55
|
-
Get results from
|
|
68
|
+
Get results from Google Image Search.
|
|
56
69
|
"""
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
<webpageToText>
|
|
72
|
+
{
|
|
73
|
+
"url": "https://example.com/page"
|
|
74
|
+
}
|
|
75
|
+
</webpageToText>
|
|
59
76
|
Description: """
|
|
60
|
-
Use this API to open/read
|
|
61
|
-
"""
|
|
77
|
+
Use this API to open/read web pages like product pages.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
<documentToText>
|
|
81
|
+
{
|
|
82
|
+
"url": "https://example.com/document.pdf"
|
|
83
|
+
}
|
|
84
|
+
</documentToText>
|
|
85
|
+
Description: """
|
|
86
|
+
Extract text from documents (PDF, DOC, etc.).
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
<imageToText>
|
|
90
|
+
{
|
|
91
|
+
"url": "https://example.com/image.png"
|
|
92
|
+
}
|
|
93
|
+
</imageToText>
|
|
94
|
+
Description: """
|
|
95
|
+
OCR - Extract text from images.
|
|
96
|
+
"""
|
|
@@ -15,7 +15,7 @@ const extractJSONFromText = (text) => {
|
|
|
15
15
|
return null;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export const getActions = () => [
|
|
18
|
+
export const getActions = (meta) => [
|
|
19
19
|
// IMPORTANT: Actions returning JOB_COMPLETED or JOB_FAILED stop agent execution and return final result
|
|
20
20
|
[/[\s\S]*"type"\s*:\s*"JOB_COMPLETED"[\s\S]*/, async (match, event) => {
|
|
21
21
|
const parsedData = extractJSONFromText(match[0]);
|
|
@@ -31,7 +31,6 @@ export const getActions = () => [
|
|
|
31
31
|
}
|
|
32
32
|
}],
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
[/[\s\S]*"type"\s*:\s*"JOB_FAILED"[\s\S]*/, async (match, event) => {
|
|
36
35
|
const parsedData = extractJSONFromText(match[0]);
|
|
37
36
|
if (parsedData && parsedData.type === "JOB_FAILED") {
|
|
@@ -45,24 +44,26 @@ export const getActions = () => [
|
|
|
45
44
|
}
|
|
46
45
|
}],
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
// Google Search with XML+JSON format
|
|
48
|
+
[/<googleSearch>([\s\S]*?)<\/googleSearch>/s, async (match) => {
|
|
50
49
|
try {
|
|
51
|
-
const
|
|
52
|
-
const
|
|
50
|
+
const data = JSON.parse(match[1].trim());
|
|
51
|
+
const response = await openkbs.googleSearch(data.query);
|
|
52
|
+
const results = response?.map(({ title, link, snippet, pagemap }) => ({
|
|
53
53
|
title, link, snippet, image: pagemap?.metatags?.[0]?.["og:image"]
|
|
54
54
|
}));
|
|
55
|
-
return { data };
|
|
55
|
+
return { data: results, ...meta };
|
|
56
56
|
} catch (e) {
|
|
57
|
-
return { error: e.message };
|
|
57
|
+
return { error: e.message, ...meta };
|
|
58
58
|
}
|
|
59
59
|
}],
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// YouTube Search with XML+JSON format
|
|
62
|
+
[/<youtubeSearch>([\s\S]*?)<\/youtubeSearch>/s, async (match) => {
|
|
63
63
|
try {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
64
|
+
const data = JSON.parse(match[1].trim());
|
|
65
|
+
const response = await openkbs.googleSearch(data.query + ' site:youtube.com', { videoOnly: true });
|
|
66
|
+
const results = response?.map(({ title, link, snippet, pagemap }) => ({
|
|
66
67
|
title,
|
|
67
68
|
link: link.replace('www.youtube.com/watch?v=', 'youtu.be/'),
|
|
68
69
|
snippet,
|
|
@@ -70,62 +71,62 @@ export const getActions = () => [
|
|
|
70
71
|
duration: pagemap?.videoobject?.[0]?.duration,
|
|
71
72
|
channel: pagemap?.metatags?.[0]?.["og:site_name"],
|
|
72
73
|
})).filter(item => item.link.includes('youtu'));
|
|
73
|
-
return { data };
|
|
74
|
+
return { data: results, ...meta };
|
|
74
75
|
} catch (e) {
|
|
75
|
-
return { error: e.message };
|
|
76
|
+
return { error: e.message, ...meta };
|
|
76
77
|
}
|
|
77
78
|
}],
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// Google Image Search with XML+JSON format
|
|
81
|
+
[/<googleImageSearch>([\s\S]*?)<\/googleImageSearch>/s, async (match) => {
|
|
81
82
|
try {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
83
|
+
const data = JSON.parse(match[1].trim());
|
|
84
|
+
const response = await openkbs.googleSearch(data.query, { searchType: 'image' });
|
|
85
|
+
const results = response?.map(({ title, link, snippet, pagemap }) => {
|
|
84
86
|
const imageObj = pagemap?.cse_image?.[0];
|
|
85
87
|
const thumbnail = imageObj?.src || pagemap?.metatags?.[0]?.["og:image"] || link;
|
|
86
|
-
return {
|
|
87
|
-
title,
|
|
88
|
-
link: link,
|
|
89
|
-
snippet,
|
|
90
|
-
image: thumbnail
|
|
91
|
-
};
|
|
88
|
+
return { title, link, snippet, image: thumbnail };
|
|
92
89
|
});
|
|
93
|
-
return { data };
|
|
90
|
+
return { data: results, ...meta };
|
|
94
91
|
} catch (e) {
|
|
95
|
-
return { error: e.message };
|
|
92
|
+
return { error: e.message, ...meta };
|
|
96
93
|
}
|
|
97
94
|
}],
|
|
98
95
|
|
|
99
|
-
|
|
96
|
+
// Webpage to Text with XML+JSON format
|
|
97
|
+
[/<webpageToText>([\s\S]*?)<\/webpageToText>/s, async (match) => {
|
|
100
98
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return { data:
|
|
99
|
+
const data = JSON.parse(match[1].trim());
|
|
100
|
+
let response = await openkbs.webpageToText(data.url);
|
|
101
|
+
if (!response?.url) return { data: { error: "Unable to read website" }, ...meta };
|
|
102
|
+
return { data: response, ...meta };
|
|
104
103
|
} catch (e) {
|
|
105
|
-
return { error: e.response?.data || e };
|
|
104
|
+
return { error: e.response?.data || e.message, ...meta };
|
|
106
105
|
}
|
|
107
106
|
}],
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
// Document to Text with XML+JSON format
|
|
109
|
+
[/<documentToText>([\s\S]*?)<\/documentToText>/s, async (match) => {
|
|
110
110
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const data = JSON.parse(match[1].trim());
|
|
112
|
+
let response = await openkbs.documentToText(data.url);
|
|
113
|
+
return { data: response, ...meta };
|
|
113
114
|
} catch (e) {
|
|
114
|
-
return { error: e.response
|
|
115
|
+
return { error: e.response?.data || e.message, ...meta };
|
|
115
116
|
}
|
|
116
117
|
}],
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
// Image to Text (OCR) with XML+JSON format
|
|
120
|
+
[/<imageToText>([\s\S]*?)<\/imageToText>/s, async (match) => {
|
|
119
121
|
try {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
const data = JSON.parse(match[1].trim());
|
|
123
|
+
let response = await openkbs.imageToText(data.url);
|
|
122
124
|
if (response?.detections?.[0]?.txt) {
|
|
123
125
|
response = { detections: response?.detections?.[0]?.txt };
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
return { data: response };
|
|
127
|
+
return { data: response, ...meta };
|
|
127
128
|
} catch (e) {
|
|
128
|
-
return { error: e.response
|
|
129
|
+
return { error: e.response?.data || e.message, ...meta };
|
|
129
130
|
}
|
|
130
131
|
}],
|
|
131
|
-
];
|
|
132
|
+
];
|
|
@@ -2,7 +2,14 @@ import {getActions} from './actions.js';
|
|
|
2
2
|
|
|
3
3
|
export const backendHandler = async (event) => {
|
|
4
4
|
const lastMessage = event.payload.messages[event.payload.messages.length - 1];
|
|
5
|
-
const
|
|
5
|
+
const reachedMessageLimit = event?.payload?.messages?.length > 60;
|
|
6
|
+
|
|
7
|
+
// Meta for continuing chat model requests
|
|
8
|
+
const meta = {
|
|
9
|
+
_meta_actions: reachedMessageLimit ? [] : ["REQUEST_CHAT_MODEL"]
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const actions = getActions(meta);
|
|
6
13
|
|
|
7
14
|
const matchingActions = actions.reduce((acc, [regex, action]) => {
|
|
8
15
|
const matches = [...lastMessage.content.matchAll(new RegExp(regex, 'g'))];
|
|
@@ -12,31 +19,30 @@ export const backendHandler = async (event) => {
|
|
|
12
19
|
return acc;
|
|
13
20
|
}, []);
|
|
14
21
|
|
|
15
|
-
const reachedMessageLimit = event?.payload?.messages?.length > 60;
|
|
16
|
-
|
|
17
22
|
if (matchingActions.length > 0) {
|
|
18
23
|
try {
|
|
19
24
|
const results = await Promise.all(matchingActions);
|
|
20
25
|
|
|
21
26
|
// IMPORTANT: Actions returning JOB_COMPLETED or JOB_FAILED stop agent execution and return final result
|
|
22
|
-
const isOnlyJobCompletion = results.length === 1 &&
|
|
27
|
+
const isOnlyJobCompletion = results.length === 1 &&
|
|
23
28
|
(results[0]?.type === 'JOB_COMPLETED' || results[0]?.type === 'JOB_FAILED');
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
// Override meta for job completion
|
|
31
|
+
const finalMeta = {
|
|
26
32
|
_meta_actions: (reachedMessageLimit || isOnlyJobCompletion) ? [] : ["REQUEST_CHAT_MODEL"]
|
|
27
33
|
};
|
|
28
34
|
|
|
29
35
|
if (results?.[0]?.data?.some?.(o => o?.type === 'image_url')) {
|
|
30
36
|
return {
|
|
31
37
|
...results[0],
|
|
32
|
-
...
|
|
38
|
+
...finalMeta
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
return {
|
|
37
43
|
type: 'RESPONSE',
|
|
38
44
|
data: results,
|
|
39
|
-
...
|
|
45
|
+
...finalMeta
|
|
40
46
|
};
|
|
41
47
|
} catch (error) {
|
|
42
48
|
return {
|
package/templates/.openkbs/knowledge/examples/ai-copywriter-agent/src/Frontend/contentRender.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import JsonView from '@uiw/react-json-view';
|
|
3
|
-
import { Chip } from '@mui/material';
|
|
3
|
+
import { Box, Tooltip, Chip } from '@mui/material';
|
|
4
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
5
|
+
import LanguageIcon from '@mui/icons-material/Language';
|
|
6
|
+
import ImageIcon from '@mui/icons-material/Image';
|
|
7
|
+
import YouTubeIcon from '@mui/icons-material/YouTube';
|
|
8
|
+
import ArticleIcon from '@mui/icons-material/Article';
|
|
4
9
|
|
|
5
10
|
const extractJSONFromText = (text) => {
|
|
6
11
|
let braceCount = 0, startIndex = text.indexOf('{');
|
|
@@ -19,24 +24,102 @@ const extractJSONFromText = (text) => {
|
|
|
19
24
|
return null;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
// Command patterns for XML+JSON format
|
|
28
|
+
const COMMAND_PATTERNS = [
|
|
29
|
+
/<googleSearch>[\s\S]*?<\/googleSearch>/,
|
|
30
|
+
/<youtubeSearch>[\s\S]*?<\/youtubeSearch>/,
|
|
31
|
+
/<googleImageSearch>[\s\S]*?<\/googleImageSearch>/,
|
|
32
|
+
/<webpageToText>[\s\S]*?<\/webpageToText>/,
|
|
33
|
+
/<documentToText>[\s\S]*?<\/documentToText>/,
|
|
34
|
+
/<imageToText>[\s\S]*?<\/imageToText>/
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
// Icon mapping for commands
|
|
38
|
+
const commandIcons = {
|
|
39
|
+
googleSearch: SearchIcon,
|
|
40
|
+
youtubeSearch: YouTubeIcon,
|
|
41
|
+
googleImageSearch: ImageIcon,
|
|
42
|
+
webpageToText: LanguageIcon,
|
|
43
|
+
documentToText: ArticleIcon,
|
|
44
|
+
imageToText: ImageIcon
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Parse commands from content
|
|
48
|
+
const parseCommands = (content) => {
|
|
49
|
+
const commands = [];
|
|
50
|
+
const regex = /<(\w+)>([\s\S]*?)<\/\1>/g;
|
|
51
|
+
let match;
|
|
52
|
+
while ((match = regex.exec(content)) !== null) {
|
|
53
|
+
try {
|
|
54
|
+
commands.push({
|
|
55
|
+
name: match[1],
|
|
56
|
+
data: JSON.parse(match[2].trim())
|
|
57
|
+
});
|
|
58
|
+
} catch (e) {
|
|
59
|
+
commands.push({ name: match[1], data: match[2].trim() });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return commands;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Render command as icon with tooltip
|
|
66
|
+
const CommandIcon = ({ command }) => {
|
|
67
|
+
const Icon = commandIcons[command.name] || SearchIcon;
|
|
68
|
+
return (
|
|
69
|
+
<Tooltip
|
|
70
|
+
title={
|
|
71
|
+
<Box sx={{ p: 1 }}>
|
|
72
|
+
<Box sx={{ fontWeight: 'bold', color: '#4CAF50', mb: 0.5 }}>{command.name}</Box>
|
|
73
|
+
<pre style={{ margin: 0, fontSize: '10px' }}>
|
|
74
|
+
{typeof command.data === 'object'
|
|
75
|
+
? JSON.stringify(command.data, null, 2)
|
|
76
|
+
: command.data}
|
|
77
|
+
</pre>
|
|
78
|
+
</Box>
|
|
79
|
+
}
|
|
80
|
+
arrow
|
|
81
|
+
>
|
|
82
|
+
<Box sx={{
|
|
83
|
+
display: 'inline-flex',
|
|
84
|
+
width: 32, height: 32,
|
|
85
|
+
borderRadius: '50%',
|
|
86
|
+
backgroundColor: 'rgba(76, 175, 80, 0.1)',
|
|
87
|
+
border: '2px solid rgba(76, 175, 80, 0.3)',
|
|
88
|
+
alignItems: 'center',
|
|
89
|
+
justifyContent: 'center',
|
|
90
|
+
mx: 0.5,
|
|
91
|
+
cursor: 'pointer',
|
|
92
|
+
'&:hover': {
|
|
93
|
+
backgroundColor: 'rgba(76, 175, 80, 0.2)',
|
|
94
|
+
transform: 'scale(1.1)'
|
|
95
|
+
},
|
|
96
|
+
transition: 'all 0.2s'
|
|
97
|
+
}}>
|
|
98
|
+
<Icon sx={{ fontSize: 16, color: '#4CAF50' }} />
|
|
99
|
+
</Box>
|
|
100
|
+
</Tooltip>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
25
103
|
|
|
26
104
|
// do NOT useState() directly in this function, it is not a React component
|
|
27
105
|
const onRenderChatMessage = async (params) => {
|
|
28
106
|
const { content } = params.messages[params.msgIndex];
|
|
29
107
|
const JSONData = extractJSONFromText(content);
|
|
30
|
-
|
|
31
|
-
|
|
108
|
+
|
|
109
|
+
// Render JOB_COMPLETED as JSON view
|
|
32
110
|
if (JSONData?.type === 'JOB_COMPLETED') {
|
|
33
111
|
return <JsonView value={JSONData} />
|
|
34
112
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
113
|
+
|
|
114
|
+
// Check for commands in content
|
|
115
|
+
const hasCommand = COMMAND_PATTERNS.some(p => p.test(content));
|
|
116
|
+
if (hasCommand) {
|
|
117
|
+
const commands = parseCommands(content);
|
|
118
|
+
return (
|
|
119
|
+
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
|
120
|
+
{commands.map((cmd, i) => <CommandIcon key={i} command={cmd} />)}
|
|
121
|
+
</Box>
|
|
122
|
+
);
|
|
40
123
|
}
|
|
41
124
|
|
|
42
125
|
// return undefined to use default message render
|
|
@@ -61,4 +144,4 @@ const Header = ({ setRenderSettings }) => {
|
|
|
61
144
|
|
|
62
145
|
const exports = { onRenderChatMessage, Header };
|
|
63
146
|
window.contentRender = exports;
|
|
64
|
-
export default exports;
|
|
147
|
+
export default exports;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# AI Marketing Agent
|
|
2
|
+
|
|
3
|
+
A comprehensive AI marketing assistant that can create content, generate images and videos, search the web, send emails, and schedule tasks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AI Image Generation**: Gemini 2.5 Flash Image and GPT-Image-1 models
|
|
8
|
+
- **AI Video Generation**: Sora 2 and Sora 2 Pro models
|
|
9
|
+
- **Web Search**: Google Search and Image Search
|
|
10
|
+
- **Email Marketing**: Send emails directly from chat
|
|
11
|
+
- **Task Scheduling**: Schedule future reminders and tasks
|
|
12
|
+
- **Web Publishing**: Create and publish HTML landing pages
|
|
13
|
+
- **Memory System**: Persistent storage for user preferences and content
|
|
14
|
+
|
|
15
|
+
## Command Format
|
|
16
|
+
|
|
17
|
+
All commands use XML tags with JSON content:
|
|
18
|
+
|
|
19
|
+
```xml
|
|
20
|
+
<commandName>
|
|
21
|
+
{
|
|
22
|
+
"param1": "value1",
|
|
23
|
+
"param2": "value2"
|
|
24
|
+
}
|
|
25
|
+
</commandName>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Available Commands
|
|
29
|
+
|
|
30
|
+
### Content Creation
|
|
31
|
+
- `<createAIImage>` - Generate images with AI
|
|
32
|
+
- `<createAIVideo>` - Generate videos with Sora 2
|
|
33
|
+
- `<publishWebPage>` - Publish HTML landing pages
|
|
34
|
+
|
|
35
|
+
### Search & Research
|
|
36
|
+
- `<googleSearch>` - Web search
|
|
37
|
+
- `<googleImageSearch>` - Image search
|
|
38
|
+
- `<webpageToText>` - Extract text from webpages
|
|
39
|
+
- `<viewImage>` - View image in context
|
|
40
|
+
|
|
41
|
+
### Communication
|
|
42
|
+
- `<sendMail>` - Send emails
|
|
43
|
+
|
|
44
|
+
### Task Management
|
|
45
|
+
- `<scheduleTask>` - Schedule future tasks
|
|
46
|
+
- `<getScheduledTasks/>` - List scheduled tasks
|
|
47
|
+
|
|
48
|
+
### Memory
|
|
49
|
+
- `<setMemory>` - Save to memory
|
|
50
|
+
- `<deleteItem>` - Delete from memory
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
- `src/Events/actions.js` - Command implementations
|
|
55
|
+
- `src/Events/onRequest.js` - User message handler
|
|
56
|
+
- `src/Events/onResponse.js` - LLM response handler
|
|
57
|
+
- `src/Frontend/contentRender.js` - UI customization
|
|
58
|
+
- `app/instructions.txt` - LLM instructions
|
|
59
|
+
|
|
60
|
+
## Deployment
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
openkbs push
|
|
64
|
+
```
|