omnibot3000 1.8.2 → 1.8.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/.husky/commit-msg +12 -0
- package/.husky/pre-commit +1 -0
- package/README.md +30 -1
- package/api/server.ts +115 -35
- package/bin/omnibot.js +19 -0
- package/package.json +19 -9
- package/src/App.tsx +16 -12
- package/src/commons/OmnibotSpeak.module.css +1 -0
- package/src/commons/api/api.ts +99 -101
- package/src/commons/api/getStream.ts +93 -0
- package/src/commons/constants.ts +2 -1
- package/src/commons/layout/Container.module.css +4 -3
- package/src/commons/layout/Container.tsx +2 -2
- package/src/commons/layout/Footer.tsx +13 -13
- package/src/commons/layout/Menu.tsx +6 -6
- package/src/commons/persona.txt +38 -38
- package/src/commons/styles/main.css +10 -5
- package/src/features/chat/Chat.tsx +59 -89
- package/src/features/chat/components/Message.tsx +4 -4
- package/src/features/chat/components/Toolbar.tsx +2 -2
- package/src/features/cli/Cli.module.css +0 -1
- package/src/features/help/Help.tsx +14 -41
- package/src/features/home/Home.tsx +17 -40
- package/src/features/version/Version.tsx +5 -3
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# basic commit message validation
|
|
2
|
+
|
|
3
|
+
if ! head -1 "$1" | grep -qE '^\[(feat|fix|doc|style|perf|test|chore|misc)(\(.+\))?!?\]'; then
|
|
4
|
+
echo "❌ Commit message must follow format: [type] message"
|
|
5
|
+
echo ""
|
|
6
|
+
echo "Examples:"
|
|
7
|
+
echo " [feat] add new feature"
|
|
8
|
+
echo " [fix] resolve bug in component"
|
|
9
|
+
echo " [doc] update README"
|
|
10
|
+
echo " [chore] update dependencies"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pnpm lint && pnpm prettify
|
package/README.md
CHANGED
|
@@ -6,4 +6,33 @@ YOUR OMNISCIENT SOURCE OF TRUTH
|
|
|
6
6
|
|
|
7
7
|
### Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`pnpm i omnibot3000`
|
|
10
|
+
|
|
11
|
+
### Configuration
|
|
12
|
+
|
|
13
|
+
Create a `.env` file in the root of your project with the following content:
|
|
14
|
+
|
|
15
|
+
```env
|
|
16
|
+
DOMAIN=localhost
|
|
17
|
+
DEV_PORT=3000
|
|
18
|
+
API_PORT=3001
|
|
19
|
+
API_PATH=/api
|
|
20
|
+
|
|
21
|
+
MISTRAL_API_KEY=<your_mistral_api_key>
|
|
22
|
+
|
|
23
|
+
OPENAI_ORG_ID=<your_openai_org_id>
|
|
24
|
+
OPENAI_PROJECT_ID=<your_openai_project_id>
|
|
25
|
+
OPENAI_API_KEY=<your_openai_api_key>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Package
|
|
29
|
+
|
|
30
|
+
https://www.npmjs.com/package/omnibot3000
|
|
31
|
+
|
|
32
|
+
### Contributing
|
|
33
|
+
|
|
34
|
+
NO
|
|
35
|
+
|
|
36
|
+
### License
|
|
37
|
+
|
|
38
|
+
NO
|
package/api/server.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {createServer, IncomingMessage, ServerResponse} from "http";
|
|
|
11
11
|
import path from "path";
|
|
12
12
|
|
|
13
13
|
import "dotenv/config";
|
|
14
|
+
import {Mistral} from "@mistralai/mistralai";
|
|
15
|
+
import type {CompletionEvent} from "@mistralai/mistralai/models/components";
|
|
14
16
|
import OpenAI from "openai";
|
|
15
17
|
import type {ChatCompletionChunk} from "openai/resources/index.mjs";
|
|
16
18
|
import type {Stream} from "openai/streaming";
|
|
@@ -21,12 +23,23 @@ type Package = {
|
|
|
21
23
|
size: number;
|
|
22
24
|
};
|
|
23
25
|
|
|
26
|
+
const API: string = "mistral";
|
|
27
|
+
const MAX_TOKENS = 1000;
|
|
28
|
+
|
|
24
29
|
const DOMAIN = process.env.DOMAIN || "localhost";
|
|
25
30
|
const API_PATH = process.env.API_PATH || "/api";
|
|
26
31
|
const API_PORT = process.env.API_PORT || 3001;
|
|
27
32
|
const BASE_PATH = process.cwd();
|
|
28
33
|
const JSON_PATH = path.join(BASE_PATH, "dist", "packages.json");
|
|
29
34
|
|
|
35
|
+
const API_CONFIG_MISTRAL = {
|
|
36
|
+
model: "ministral-14b-latest",
|
|
37
|
+
//model: "mistral-small-latest",
|
|
38
|
+
temperature: 0.1 /* creativity */,
|
|
39
|
+
topP: 0.1 /* nucleus sampling */,
|
|
40
|
+
maxTokens: MAX_TOKENS,
|
|
41
|
+
};
|
|
42
|
+
|
|
30
43
|
const getFolderSize = (folder: string): number => {
|
|
31
44
|
let total = 0;
|
|
32
45
|
try {
|
|
@@ -67,44 +80,107 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
|
67
80
|
try {
|
|
68
81
|
const {messages, stream} = JSON.parse(body);
|
|
69
82
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
switch (API) {
|
|
84
|
+
case "openai":
|
|
85
|
+
/* https://openai.com/api/pricing/ */
|
|
86
|
+
{
|
|
87
|
+
const openai = new OpenAI({
|
|
88
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
89
|
+
organization: process.env.OPENAI_ORG_ID,
|
|
90
|
+
project: process.env.OPENAI_PROJECT_ID,
|
|
91
|
+
});
|
|
92
|
+
const response = await openai.chat.completions.create({
|
|
93
|
+
model: "gpt-4.1-mini",
|
|
94
|
+
//model: "gpt-5-mini",
|
|
95
|
+
temperature: 2.0 /* more creative */,
|
|
96
|
+
top_p: 0.2 /* use nucleus sampling */,
|
|
97
|
+
presence_penalty: 2.0 /* encourage new topics */,
|
|
98
|
+
frequency_penalty: 1.5 /* avoid repetition */,
|
|
99
|
+
max_completion_tokens: MAX_TOKENS,
|
|
100
|
+
messages,
|
|
101
|
+
stream,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (stream) {
|
|
105
|
+
/* server-sent events headers */
|
|
106
|
+
res.writeHead(200, {
|
|
107
|
+
"Content-Type": "text/event-stream",
|
|
108
|
+
"Cache-Control": "no-cache",
|
|
109
|
+
Connection: "keep-alive",
|
|
110
|
+
});
|
|
111
|
+
/* forward chunks to browser as SSE */
|
|
112
|
+
for await (const chunk of response as unknown as Stream<ChatCompletionChunk>) {
|
|
113
|
+
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
114
|
+
}
|
|
115
|
+
/* end the SSE stream */
|
|
116
|
+
res.write("data: [DONE]\n\n");
|
|
117
|
+
res.end();
|
|
118
|
+
} else {
|
|
119
|
+
res.writeHead(200, {"Content-Type": "application/json"});
|
|
120
|
+
res.end(JSON.stringify(response));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case "mistral":
|
|
125
|
+
/* https://mistral.ai/pricing#api-pricing */
|
|
126
|
+
{
|
|
127
|
+
const mistral = new Mistral({
|
|
128
|
+
apiKey: process.env.MISTRAL_API_KEY,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (stream) {
|
|
132
|
+
/* server-sent events headers */
|
|
133
|
+
res.writeHead(200, {
|
|
134
|
+
"Content-Type": "text/event-stream",
|
|
135
|
+
"Cache-Control": "no-cache",
|
|
136
|
+
Connection: "keep-alive",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const response = await mistral.chat.stream({
|
|
140
|
+
...API_CONFIG_MISTRAL,
|
|
141
|
+
messages,
|
|
142
|
+
});
|
|
143
|
+
/* forward chunks to browser as SSE */
|
|
144
|
+
for await (const chunk of response as AsyncIterable<CompletionEvent>) {
|
|
145
|
+
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
146
|
+
}
|
|
147
|
+
/* end the SSE stream */
|
|
148
|
+
res.write("data: [DONE]\n\n");
|
|
149
|
+
res.end();
|
|
150
|
+
} else {
|
|
151
|
+
const response = await mistral.chat.complete({
|
|
152
|
+
...API_CONFIG_MISTRAL,
|
|
153
|
+
messages,
|
|
154
|
+
});
|
|
155
|
+
res.writeHead(200, {"Content-Type": "application/json"});
|
|
156
|
+
res.end(JSON.stringify(response));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
throw new Error("Invalid API specified");
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error(
|
|
165
|
+
"API Error:",
|
|
166
|
+
error instanceof Error ? error.message : String(error),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
/* Only send response if headers haven't been sent yet */
|
|
170
|
+
if (!res.headersSent) {
|
|
171
|
+
const response = {
|
|
172
|
+
choices: [
|
|
173
|
+
{
|
|
174
|
+
message: {
|
|
175
|
+
role: "assistant",
|
|
176
|
+
content: "no signal",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
101
181
|
res.writeHead(200, {"Content-Type": "application/json"});
|
|
102
182
|
res.end(JSON.stringify(response));
|
|
103
183
|
}
|
|
104
|
-
} catch (err) {
|
|
105
|
-
const error = err instanceof Error ? err.message : "unknown error";
|
|
106
|
-
res.writeHead(500, {"Content-Type": "application/json"});
|
|
107
|
-
res.end(JSON.stringify({error}));
|
|
108
184
|
}
|
|
109
185
|
});
|
|
110
186
|
} else if (url.startsWith(`${API_PATH}/packages`)) {
|
|
@@ -137,6 +213,10 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
|
137
213
|
}
|
|
138
214
|
});
|
|
139
215
|
|
|
216
|
+
/* Increase max listeners to handle concurrent streaming requests */
|
|
217
|
+
server.setMaxListeners(0);
|
|
218
|
+
server.maxConnections = 100;
|
|
219
|
+
|
|
140
220
|
server.listen(API_PORT, () => {
|
|
141
221
|
console.log(
|
|
142
222
|
"\n\x1b[1m\x1b[32m%s\x1b[0m %s \x1b[36m%s\x1b[0m",
|
package/bin/omnibot.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {spawn} from "child_process";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import {fileURLToPath} from "url";
|
|
6
|
+
import process from "process";
|
|
7
|
+
|
|
8
|
+
const filename = fileURLToPath(import.meta.url);
|
|
9
|
+
|
|
10
|
+
const dir = path.dirname(filename);
|
|
11
|
+
const root = path.dirname(dir);
|
|
12
|
+
|
|
13
|
+
process.chdir(root);
|
|
14
|
+
|
|
15
|
+
const vite = spawn("pnpm", ["run", "start"], {stdio: "inherit"});
|
|
16
|
+
|
|
17
|
+
vite.on("close", (code) => {
|
|
18
|
+
process.exit(code);
|
|
19
|
+
});
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"x-display-name": "OMNIBOT 3000",
|
|
4
4
|
"description": "your omniscient source of truth",
|
|
5
5
|
"private": false,
|
|
6
|
-
"version": "1.8.
|
|
6
|
+
"version": "1.8.5",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "rez",
|
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
"url": "https://github.com/chiptune"
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://www.omnibot3000.com",
|
|
14
|
+
"repository": {
|
|
15
|
+
"url": "https://github.com/chiptune/omnibot3000",
|
|
16
|
+
"type": "github"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"omnibot": "./bin/omnibot.js"
|
|
20
|
+
},
|
|
14
21
|
"scripts": {
|
|
15
22
|
"start": "pnpm run-p start:dev start:api",
|
|
16
23
|
"start:dev": "pnpm run dev",
|
|
@@ -23,19 +30,21 @@
|
|
|
23
30
|
"build:client": "tsc -b && vite build",
|
|
24
31
|
"build:api": "tsc --project tsconfig.api.json",
|
|
25
32
|
"lint": "eslint --fix .",
|
|
26
|
-
"prettify": "prettier --write ."
|
|
33
|
+
"prettify": "prettier --write .",
|
|
34
|
+
"prepare": "husky"
|
|
27
35
|
},
|
|
28
36
|
"dependencies": {
|
|
29
|
-
"
|
|
37
|
+
"@mistralai/mistralai": "^1.11.0",
|
|
38
|
+
"openai": "^6.15.0",
|
|
30
39
|
"react": "^19.2.3",
|
|
31
40
|
"react-dom": "^19.2.3",
|
|
32
41
|
"react-markdown": "^10.1.0",
|
|
33
|
-
"react-router-dom": "^7.
|
|
42
|
+
"react-router-dom": "^7.11.0",
|
|
34
43
|
"zustand": "^5.0.9"
|
|
35
44
|
},
|
|
36
45
|
"devDependencies": {
|
|
37
46
|
"@eslint/js": "^9.39.2",
|
|
38
|
-
"@types/node": "^25.0.
|
|
47
|
+
"@types/node": "^25.0.3",
|
|
39
48
|
"@types/react": "^19.2.7",
|
|
40
49
|
"@types/react-dom": "^19.2.3",
|
|
41
50
|
"@vitejs/plugin-react": "^5.1.2",
|
|
@@ -44,15 +53,16 @@
|
|
|
44
53
|
"eslint": "^9.39.2",
|
|
45
54
|
"eslint-plugin-import": "^2.32.0",
|
|
46
55
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
47
|
-
"eslint-plugin-react-refresh": "^0.4.
|
|
56
|
+
"eslint-plugin-react-refresh": "^0.4.26",
|
|
48
57
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
49
58
|
"globals": "^16.5.0",
|
|
59
|
+
"husky": "^9.1.7",
|
|
50
60
|
"nodemon": "^3.1.11",
|
|
51
61
|
"npm-run-all": "^4.1.5",
|
|
52
62
|
"prettier": "^3.7.4",
|
|
53
63
|
"typescript": "^5.9.3",
|
|
54
|
-
"typescript-eslint": "^8.
|
|
55
|
-
"vite": "^7.
|
|
56
|
-
"vite-tsconfig-paths": "^
|
|
64
|
+
"typescript-eslint": "^8.50.0",
|
|
65
|
+
"vite": "^7.3.0",
|
|
66
|
+
"vite-tsconfig-paths": "^6.0.3"
|
|
57
67
|
}
|
|
58
68
|
}
|
package/src/App.tsx
CHANGED
|
@@ -86,19 +86,23 @@ const Layout = () => {
|
|
|
86
86
|
|
|
87
87
|
setWidth(Math.floor((vw - cw * 2) / cw) * cw);
|
|
88
88
|
setHeight(Math.floor((vh - cw * 4) / lh) * lh + cw * 2);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
const vw = window.innerWidth;
|
|
93
|
+
const vh = window.innerHeight;
|
|
89
94
|
|
|
90
95
|
let el = document.getElementById("debug-screen-size");
|
|
91
|
-
if (!el)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
w: ${w} | h: ${h}`;
|
|
96
|
+
if (!el) el = document.createElement("div");
|
|
97
|
+
|
|
98
|
+
el.id = "debug-screen-size";
|
|
99
|
+
el.className = "debug-info";
|
|
100
|
+
document.body.appendChild(el);
|
|
101
|
+
el.innerHTML = `viewport: ${vw}x${vh} | \
|
|
102
|
+
char: ${format(cw)}x${format(lh)} | \
|
|
103
|
+
w: ${w} | h: ${h}`;
|
|
100
104
|
el.style.display = debug ? "block" : "none";
|
|
101
|
-
};
|
|
105
|
+
}, [w, h]);
|
|
102
106
|
|
|
103
107
|
useLayoutEffect(() => {
|
|
104
108
|
const resizeObserver = new ResizeObserver(update);
|
|
@@ -162,9 +166,9 @@ const Layout = () => {
|
|
|
162
166
|
<div className={styles.content}>
|
|
163
167
|
<Header darkMode={darkMode} onThemeToggle={themeSwitchHandler} />
|
|
164
168
|
<Line variant="horizontal" className={styles["h-line"]} />
|
|
165
|
-
<
|
|
169
|
+
<main ref={bodyRef} className={styles.body}>
|
|
166
170
|
<Outlet />
|
|
167
|
-
</
|
|
171
|
+
</main>
|
|
168
172
|
<Line variant="horizontal" className={styles["h-line"]} />
|
|
169
173
|
<Footer renderTime={renderTime} />
|
|
170
174
|
</div>
|
package/src/commons/api/api.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChatCompletion,
|
|
3
|
-
ChatCompletionChunk,
|
|
4
3
|
ChatCompletionMessageParam,
|
|
5
4
|
} from "openai/resources/index.mjs";
|
|
6
|
-
import {Stream} from "openai/streaming.mjs";
|
|
7
5
|
|
|
8
6
|
import {NAME, VERSION} from "@commons/constants";
|
|
9
7
|
import persona from "@commons/persona.txt?raw";
|
|
10
8
|
import {getVariableFromCSS} from "@utils/styles";
|
|
11
9
|
|
|
12
10
|
export const getData = async (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
system?: string[],
|
|
12
|
+
query?: string[],
|
|
13
|
+
context?: ChatCompletionMessageParam[],
|
|
14
|
+
): Promise<ChatCompletion> => {
|
|
15
|
+
const messages: ChatCompletionMessageParam[] = [
|
|
16
|
+
getSystemConfig(),
|
|
17
|
+
{
|
|
18
|
+
role: "system",
|
|
19
|
+
content: system?.map((str) => str.trim()).join(". ") || "",
|
|
20
|
+
},
|
|
21
|
+
...(context?.filter((msg) => String(msg?.content || "").trim()) || []),
|
|
22
|
+
{
|
|
23
|
+
role: "user",
|
|
24
|
+
content: query?.map((str) => str.trim()).join(". ") || "",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
16
27
|
const response = await fetch("/api/completion", {
|
|
17
28
|
method: "POST",
|
|
18
29
|
headers: {
|
|
@@ -20,130 +31,117 @@ export const getData = async (
|
|
|
20
31
|
},
|
|
21
32
|
body: JSON.stringify({
|
|
22
33
|
messages,
|
|
23
|
-
stream,
|
|
34
|
+
stream: false,
|
|
24
35
|
}),
|
|
25
36
|
});
|
|
26
37
|
if (!response.ok) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
}
|
|
29
|
-
if (stream) {
|
|
30
|
-
if (!response.body) {
|
|
31
|
-
throw new Error("Response body is not readable");
|
|
32
|
-
}
|
|
33
|
-
return Stream.fromSSEResponse(response, new AbortController());
|
|
34
|
-
} else {
|
|
35
|
-
const data = await response.json();
|
|
36
|
-
return data as ChatCompletion;
|
|
38
|
+
throw new Error(response.statusText);
|
|
37
39
|
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
return data as ChatCompletion;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export const getSystemConfig = (): ChatCompletionMessageParam => {
|
|
41
45
|
const size = getVariableFromCSS("base-size");
|
|
42
46
|
const height = getVariableFromCSS("base-height");
|
|
43
|
-
const systemConfig =
|
|
44
|
-
current date: ${new Date().toLocaleDateString()}
|
|
45
|
-
current time: ${new Date().
|
|
46
|
-
current unix EPOCH time: ${Math.floor(Date.now() / 1000)}
|
|
47
|
-
a list of random number: ${Array.from({length: 32}, () =>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
current user agent: ${navigator.userAgent}
|
|
51
|
-
current color hue: ${getVariableFromCSS("h")}
|
|
52
|
-
current color saturation: ${getVariableFromCSS("s")}
|
|
53
|
-
current color lightness: ${getVariableFromCSS("l")}
|
|
54
|
-
current font base size: ${getVariableFromCSS("BASE-SIZE")}
|
|
55
|
-
user can change the color with the "/color [h|s|l] number" command
|
|
56
|
-
user can change the font size with the "/size number" command
|
|
57
|
-
the "/size" command without parameter will reset the value to ${size}
|
|
58
|
-
user can change the line height with the "/height number" command
|
|
59
|
-
the "/height" command without parameter will reset the value to ${height}
|
|
60
|
-
user can reset the settings with the "/reset" command
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
${
|
|
64
|
-
|
|
47
|
+
const systemConfig = [
|
|
48
|
+
`current date: ${new Date().toLocaleDateString()}`,
|
|
49
|
+
`current time: ${new Date().toLocaleTimeString()}`,
|
|
50
|
+
`current unix EPOCH time: ${Math.floor(Date.now() / 1000)}`,
|
|
51
|
+
`a list of random number: ${Array.from({length: 32}, () =>
|
|
52
|
+
Math.round(Math.random() * 100),
|
|
53
|
+
).join(", ")}`,
|
|
54
|
+
`current user agent: ${navigator.userAgent}`,
|
|
55
|
+
`current color hue: ${getVariableFromCSS("h")}°`,
|
|
56
|
+
`current color saturation: ${getVariableFromCSS("s")}%`,
|
|
57
|
+
`current color lightness: ${getVariableFromCSS("l")}%`,
|
|
58
|
+
`current font base size: ${getVariableFromCSS("BASE-SIZE")}`,
|
|
59
|
+
'user can change the color with the "/color [h|s|l] number" command',
|
|
60
|
+
'user can change the font size with the "/size number" command',
|
|
61
|
+
`the "/size" command without parameter will reset the value to ${size}`,
|
|
62
|
+
'user can change the line height with the "/height number" command',
|
|
63
|
+
`the "/height" command without parameter will reset the value to ${height}`,
|
|
64
|
+
'user can reset the settings with the "/reset" command',
|
|
65
|
+
'user can reload the page with "/reboot" (do no reset, just reload)',
|
|
66
|
+
...formatting,
|
|
67
|
+
`your name is ${NAME} and your version is ${VERSION.join(".")}`,
|
|
68
|
+
...persona.split("\n").map((line) => line.trim()),
|
|
69
|
+
];
|
|
70
|
+
return {role: "system", content: systemConfig.join(". ")};
|
|
65
71
|
};
|
|
66
72
|
|
|
67
|
-
export const formatting =
|
|
68
|
-
generate markdown text only, no HTML please! never
|
|
69
|
-
use only the 256 first ASCII character in your answers, no unicode
|
|
70
|
-
do not use any special characters or emojis or unicode > 0x00ff
|
|
71
|
-
make all links you provide clickable, give them a human readable name
|
|
72
|
-
very important: output only markdown
|
|
73
|
-
answer with the language used the most by the user in the chat
|
|
73
|
+
export const formatting = [
|
|
74
|
+
"generate markdown text only, no HTML please! never",
|
|
75
|
+
"use only the 256 first ASCII character in your answers, no unicode",
|
|
76
|
+
"do not use any special characters or emojis or unicode > 0x00ff",
|
|
77
|
+
"make all links you provide clickable, give them a human readable name",
|
|
78
|
+
"very important: output only text or markdown, no HTML please",
|
|
79
|
+
"answer with the language used the most by the user in the chat",
|
|
80
|
+
];
|
|
74
81
|
|
|
75
|
-
export const smallQueryFormatting = (max: number): string =>
|
|
76
|
-
no more than ${max} characters (including spaces)! NO MORE
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
export const smallQueryFormatting = (max: number): string[] => [
|
|
83
|
+
`no more than ${max} characters (including spaces)! NO MORE`,
|
|
84
|
+
`keep that ${max} characters limit AT ALL COST, PLEASE`,
|
|
85
|
+
"return just text without decoration or formatting",
|
|
86
|
+
"display just words, no markdown or html or any special tags",
|
|
87
|
+
"do not add any comments or punctuations, just words",
|
|
88
|
+
"there is no need to capitalize the first letter of every words",
|
|
89
|
+
"do not add any bullet point or numbered list, just plain text",
|
|
90
|
+
"it's not an answer to a query, make it compact and catchy",
|
|
91
|
+
"do not add any unnecessary comment, return a single line of text",
|
|
92
|
+
];
|
|
81
93
|
|
|
82
94
|
export const getChatTitle = async (
|
|
83
95
|
messages: ChatCompletionMessageParam[],
|
|
84
96
|
): Promise<string> => {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
];
|
|
97
|
-
const response = (await getData(updatedMessages, false)) as ChatCompletion;
|
|
97
|
+
const response = await getData(
|
|
98
|
+
[
|
|
99
|
+
"do not mention your name in the result",
|
|
100
|
+
"keep it as simple, short and descriptive as possible",
|
|
101
|
+
"exclude all reference to this request",
|
|
102
|
+
"use only use and assistant messages as context",
|
|
103
|
+
...smallQueryFormatting(28),
|
|
104
|
+
],
|
|
105
|
+
["make a title for this chat"],
|
|
106
|
+
messages,
|
|
107
|
+
);
|
|
98
108
|
return response.choices[0].message.content || "?";
|
|
99
109
|
};
|
|
100
110
|
|
|
101
111
|
export const getSubtitle = async (): Promise<string> => {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
${smallQueryFormatting(32)}`,
|
|
112
|
-
},
|
|
113
|
-
];
|
|
114
|
-
const response = (await getData(messages, false)) as ChatCompletion;
|
|
112
|
+
const response = await getData(
|
|
113
|
+
[
|
|
114
|
+
"do not mention your name in the result, it's a motto",
|
|
115
|
+
"emphasize on your infinite source of knowledge",
|
|
116
|
+
"boast yourself to the maximum, demonstrate that you are the best",
|
|
117
|
+
...smallQueryFormatting(32),
|
|
118
|
+
],
|
|
119
|
+
["make a list of 5 catch phrase to present you to the user"],
|
|
120
|
+
);
|
|
115
121
|
return response.choices[0].message.content || "?";
|
|
116
122
|
};
|
|
117
123
|
|
|
118
124
|
export const getPromptPlaceholder = async (): Promise<string> => {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
${smallQueryFormatting(25)}`,
|
|
128
|
-
},
|
|
129
|
-
];
|
|
130
|
-
const response = (await getData(messages, false)) as ChatCompletion;
|
|
125
|
+
const response = await getData(
|
|
126
|
+
[
|
|
127
|
+
"this input is where the user is asking you question",
|
|
128
|
+
"you are not inviting, you are imposing, user must comply",
|
|
129
|
+
...smallQueryFormatting(25),
|
|
130
|
+
],
|
|
131
|
+
["make a list of 10 imperatives input placeholder"],
|
|
132
|
+
);
|
|
131
133
|
return response.choices[0].message.content || "?";
|
|
132
134
|
};
|
|
133
135
|
|
|
134
136
|
export const getStartButton = async (): Promise<string> => {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
${smallQueryFormatting(25)}`,
|
|
144
|
-
},
|
|
145
|
-
];
|
|
146
|
-
const response = (await getData(messages, false)) as ChatCompletion;
|
|
137
|
+
const response = await getData(
|
|
138
|
+
[
|
|
139
|
+
"this button bring users to the page where they can make a query",
|
|
140
|
+
"you are not inviting, you are imposing, user must comply",
|
|
141
|
+
...smallQueryFormatting(25),
|
|
142
|
+
],
|
|
143
|
+
["name a button that order to start a chat in few words"],
|
|
144
|
+
);
|
|
147
145
|
return response.choices[0].message.content || "?";
|
|
148
146
|
};
|
|
149
147
|
|