botdocs 0.4.0 → 0.5.0
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 +20 -2
- package/dist/src/builder/chunker.d.ts +18 -0
- package/dist/src/builder/chunker.js +62 -1
- package/dist/src/builder/embedder.js +4 -1
- package/dist/src/builder/index-size.d.ts +3 -0
- package/dist/src/builder/index-size.js +16 -0
- package/dist/src/builder/index.js +16 -3
- package/dist/src/builder/paths.d.ts +6 -0
- package/dist/src/builder/paths.js +13 -0
- package/dist/src/builder/site-generator.d.ts +2 -0
- package/dist/src/builder/site-generator.js +39 -11
- package/dist/src/builder/template-engine.d.ts +4 -4
- package/dist/src/builder/template-engine.js +5 -1
- package/dist/src/builder/vector-db-builder.d.ts +1 -0
- package/dist/src/builder/vector-db-builder.js +1 -0
- package/dist/src/cli/index.js +60 -17
- package/dist/src/cli/options.d.ts +2 -0
- package/dist/src/cli/options.js +2 -0
- package/dist/src/cli/server.d.ts +6 -0
- package/dist/src/cli/server.js +79 -0
- package/dist/src/cli/watcher.d.ts +7 -0
- package/dist/src/cli/watcher.js +40 -0
- package/dist/src/shared/site-root.d.ts +2 -0
- package/dist/src/shared/site-root.js +9 -0
- package/dist/src/types/config.d.ts +3 -0
- package/dist/src/types/config.js +2 -0
- package/dist/src/types/document.d.ts +1 -1
- package/dist-client/assets/chatbox-Dw_HFrfR.js +8 -0
- package/dist-client/assets/rag-engine-B9wYRzqT.js +1 -0
- package/dist-client/bundle.js +1 -1
- package/man/botdocs.1 +74 -3
- package/package.json +10 -1
- package/src/styles/chat.css +13 -0
- package/src/templates/layout.html +14 -2
- package/dist-client/assets/chatbox-P1j6YP1y.js +0 -7
- package/dist-client/assets/rag-engine-CU9vjCAg.js +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import { join, resolve, sep, extname } from 'path';
|
|
4
|
+
const MIME_TYPES = {
|
|
5
|
+
'.html': 'text/html; charset=utf-8',
|
|
6
|
+
'.css': 'text/css; charset=utf-8',
|
|
7
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
8
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
9
|
+
'.json': 'application/json; charset=utf-8',
|
|
10
|
+
'.map': 'application/json; charset=utf-8',
|
|
11
|
+
'.svg': 'image/svg+xml',
|
|
12
|
+
'.png': 'image/png',
|
|
13
|
+
'.jpg': 'image/jpeg',
|
|
14
|
+
'.jpeg': 'image/jpeg',
|
|
15
|
+
'.gif': 'image/gif',
|
|
16
|
+
'.webp': 'image/webp',
|
|
17
|
+
'.ico': 'image/x-icon',
|
|
18
|
+
'.xml': 'application/xml; charset=utf-8',
|
|
19
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
20
|
+
'.woff': 'font/woff',
|
|
21
|
+
'.woff2': 'font/woff2',
|
|
22
|
+
};
|
|
23
|
+
export async function startServer(rootDir, port = 0) {
|
|
24
|
+
const root = resolve(rootDir);
|
|
25
|
+
const server = createServer((req, res) => {
|
|
26
|
+
handleRequest(req, res, root).catch(() => {
|
|
27
|
+
respond(res, 500, 'text/plain; charset=utf-8', 'Internal server error');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return new Promise((resolveStart, rejectStart) => {
|
|
31
|
+
server.once('error', rejectStart);
|
|
32
|
+
server.listen(port, '127.0.0.1', () => {
|
|
33
|
+
const address = server.address();
|
|
34
|
+
const actualPort = typeof address === 'object' && address ? address.port : port;
|
|
35
|
+
resolveStart({
|
|
36
|
+
url: `http://127.0.0.1:${actualPort}`,
|
|
37
|
+
port: actualPort,
|
|
38
|
+
close: () => new Promise((done) => server.close(() => done())),
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function handleRequest(req, res, root) {
|
|
44
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
45
|
+
respond(res, 405, 'text/plain; charset=utf-8', 'Method not allowed');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let urlPath;
|
|
49
|
+
try {
|
|
50
|
+
urlPath = decodeURIComponent(new URL(req.url ?? '/', 'http://localhost').pathname);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
respond(res, 400, 'text/plain; charset=utf-8', 'Bad request');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Complete mediation: every request resolves inside the site root or it
|
|
57
|
+
// never touches the filesystem.
|
|
58
|
+
const filePath = resolve(root, `.${sep}${urlPath}`);
|
|
59
|
+
if (filePath !== root && !filePath.startsWith(root + sep)) {
|
|
60
|
+
respond(res, 403, 'text/plain; charset=utf-8', 'Forbidden');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
let target = filePath;
|
|
64
|
+
try {
|
|
65
|
+
const stat = await fs.stat(target);
|
|
66
|
+
if (stat.isDirectory()) {
|
|
67
|
+
target = join(target, 'index.html');
|
|
68
|
+
}
|
|
69
|
+
const body = await fs.readFile(target);
|
|
70
|
+
respond(res, 200, MIME_TYPES[extname(target).toLowerCase()] ?? 'application/octet-stream', body);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
respond(res, 404, 'text/plain; charset=utf-8', 'Not found');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function respond(res, status, contentType, body) {
|
|
77
|
+
res.writeHead(status, { 'Content-Type': contentType });
|
|
78
|
+
res.end(body);
|
|
79
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { watch } from 'fs';
|
|
2
|
+
const WATCHED_EXTENSIONS = ['.md', '.markdown'];
|
|
3
|
+
const WATCHED_FILES = ['botdocs.config.json'];
|
|
4
|
+
function isWatchedPath(path) {
|
|
5
|
+
if (WATCHED_EXTENSIONS.some((ext) => path.endsWith(ext)))
|
|
6
|
+
return true;
|
|
7
|
+
return WATCHED_FILES.some((file) => path === file || path.endsWith(`/${file}`));
|
|
8
|
+
}
|
|
9
|
+
export function watchDocs(inputDir, onChange, debounceMs = 300) {
|
|
10
|
+
let pending = new Map();
|
|
11
|
+
let timer;
|
|
12
|
+
const flush = () => {
|
|
13
|
+
timer = undefined;
|
|
14
|
+
const changes = [...pending.values()];
|
|
15
|
+
pending = new Map();
|
|
16
|
+
if (changes.length > 0) {
|
|
17
|
+
onChange(changes);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const schedule = (path) => {
|
|
21
|
+
pending.set(path, { path });
|
|
22
|
+
if (!timer) {
|
|
23
|
+
timer = setTimeout(flush, debounceMs);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const watcher = watch(inputDir, { recursive: true }, (_eventType, filename) => {
|
|
27
|
+
const path = filename ?? '';
|
|
28
|
+
// Some platforms report no filename — treat as a full rebuild trigger.
|
|
29
|
+
if (!path || isWatchedPath(path)) {
|
|
30
|
+
schedule(path);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
close: () => {
|
|
35
|
+
if (timer)
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
watcher.close();
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function rootPrefix(pageUrl) {
|
|
2
|
+
const depth = pageUrl.split('/').length - 2;
|
|
3
|
+
return depth <= 0 ? './' : '../'.repeat(depth);
|
|
4
|
+
}
|
|
5
|
+
export function relativeUrl(root, url) {
|
|
6
|
+
if (!url.startsWith('/') || url.startsWith('//'))
|
|
7
|
+
return url;
|
|
8
|
+
return root + (url === '/' ? 'index.html' : url.slice(1));
|
|
9
|
+
}
|
|
@@ -5,6 +5,7 @@ export interface BotdocsConfig {
|
|
|
5
5
|
theme?: Theme;
|
|
6
6
|
customCss?: string;
|
|
7
7
|
attribution?: boolean;
|
|
8
|
+
baseUrl?: string;
|
|
8
9
|
chat?: {
|
|
9
10
|
enabled?: boolean;
|
|
10
11
|
welcomeMessage?: string;
|
|
@@ -12,7 +13,9 @@ export interface BotdocsConfig {
|
|
|
12
13
|
build?: {
|
|
13
14
|
chunkSize?: number;
|
|
14
15
|
chunkOverlap?: number;
|
|
16
|
+
minChunkSize?: number;
|
|
15
17
|
topK?: number;
|
|
18
|
+
minScore?: number;
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
21
|
export interface BuildOptions {
|
package/dist/src/types/config.js
CHANGED