youtube-knowledge-mcp 2.0.2 → 2.1.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 +66 -4
- package/dist/brain-schemas.d.ts +502 -0
- package/dist/brain-schemas.d.ts.map +1 -0
- package/dist/brain-schemas.js +113 -0
- package/dist/brain-schemas.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +42 -0
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +66 -0
- package/dist/resources.js.map +1 -1
- package/dist/schemas.d.ts +67 -56
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +25 -4
- package/dist/schemas.js.map +1 -1
- package/dist/tools/ask-brain.d.ts +62 -0
- package/dist/tools/ask-brain.d.ts.map +1 -0
- package/dist/tools/ask-brain.js +70 -0
- package/dist/tools/ask-brain.js.map +1 -0
- package/dist/tools/batch.d.ts +10 -10
- package/dist/tools/batch.js +2 -2
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/brain-info.d.ts +180 -0
- package/dist/tools/brain-info.d.ts.map +1 -0
- package/dist/tools/brain-info.js +108 -0
- package/dist/tools/brain-info.js.map +1 -0
- package/dist/tools/build-brain.d.ts +120 -0
- package/dist/tools/build-brain.d.ts.map +1 -0
- package/dist/tools/build-brain.js +123 -0
- package/dist/tools/build-brain.js.map +1 -0
- package/dist/tools/clips.d.ts +4 -4
- package/dist/tools/fetch-videos.d.ts +8 -8
- package/dist/tools/get-chapters.d.ts +2 -2
- package/dist/tools/get-comments.d.ts +2 -2
- package/dist/tools/get-transcript.d.ts +2 -2
- package/dist/tools/library.d.ts +9 -7
- package/dist/tools/library.d.ts.map +1 -1
- package/dist/tools/library.js +10 -4
- package/dist/tools/library.js.map +1 -1
- package/dist/tools/list-library.d.ts +4 -4
- package/dist/tools/manage-brain.d.ts +39 -0
- package/dist/tools/manage-brain.d.ts.map +1 -0
- package/dist/tools/manage-brain.js +53 -0
- package/dist/tools/manage-brain.js.map +1 -0
- package/dist/tools/search-channels.d.ts +4 -4
- package/dist/tools/search-transcript.d.ts +2 -2
- package/dist/tools/search-videos.d.ts +8 -8
- package/dist/utils/brain-build.d.ts +40 -0
- package/dist/utils/brain-build.d.ts.map +1 -0
- package/dist/utils/brain-build.js +211 -0
- package/dist/utils/brain-build.js.map +1 -0
- package/dist/utils/brain-chunks.d.ts +33 -0
- package/dist/utils/brain-chunks.d.ts.map +1 -0
- package/dist/utils/brain-chunks.js +87 -0
- package/dist/utils/brain-chunks.js.map +1 -0
- package/dist/utils/brain-index.d.ts +27 -0
- package/dist/utils/brain-index.d.ts.map +1 -0
- package/dist/utils/brain-index.js +100 -0
- package/dist/utils/brain-index.js.map +1 -0
- package/dist/utils/brain-ingest.d.ts +57 -0
- package/dist/utils/brain-ingest.d.ts.map +1 -0
- package/dist/utils/brain-ingest.js +127 -0
- package/dist/utils/brain-ingest.js.map +1 -0
- package/dist/utils/brain-lock.d.ts +20 -0
- package/dist/utils/brain-lock.d.ts.map +1 -0
- package/dist/utils/brain-lock.js +93 -0
- package/dist/utils/brain-lock.js.map +1 -0
- package/dist/utils/brain-lookup.d.ts +3 -0
- package/dist/utils/brain-lookup.d.ts.map +1 -0
- package/dist/utils/brain-lookup.js +62 -0
- package/dist/utils/brain-lookup.js.map +1 -0
- package/dist/utils/brain-paths.d.ts +19 -0
- package/dist/utils/brain-paths.d.ts.map +1 -0
- package/dist/utils/brain-paths.js +34 -0
- package/dist/utils/brain-paths.js.map +1 -0
- package/dist/utils/brain-phrases.d.ts +31 -0
- package/dist/utils/brain-phrases.d.ts.map +1 -0
- package/dist/utils/brain-phrases.js +116 -0
- package/dist/utils/brain-phrases.js.map +1 -0
- package/dist/utils/brain-stats.d.ts +25 -0
- package/dist/utils/brain-stats.d.ts.map +1 -0
- package/dist/utils/brain-stats.js +64 -0
- package/dist/utils/brain-stats.js.map +1 -0
- package/dist/utils/brain-storage.d.ts +28 -0
- package/dist/utils/brain-storage.d.ts.map +1 -0
- package/dist/utils/brain-storage.js +87 -0
- package/dist/utils/brain-storage.js.map +1 -0
- package/dist/utils/clips.js +4 -4
- package/dist/utils/clips.js.map +1 -1
- package/dist/utils/json-file.d.ts +36 -0
- package/dist/utils/json-file.d.ts.map +1 -0
- package/dist/utils/json-file.js +45 -0
- package/dist/utils/json-file.js.map +1 -0
- package/dist/utils/paths.d.ts +9 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +13 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/search-index.d.ts +22 -7
- package/dist/utils/search-index.d.ts.map +1 -1
- package/dist/utils/search-index.js +17 -4
- package/dist/utils/search-index.js.map +1 -1
- package/dist/utils/storage.d.ts +14 -44
- package/dist/utils/storage.d.ts.map +1 -1
- package/dist/utils/storage.js +37 -80
- package/dist/utils/storage.js.map +1 -1
- package/dist/utils/transcript.d.ts +5 -4
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js +3 -0
- package/dist/utils/transcript.js.map +1 -1
- package/dist/utils/validate.d.ts +1 -0
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +18 -0
- package/dist/utils/validate.js.map +1 -1
- package/dist/utils/youtube.d.ts +14 -0
- package/dist/utils/youtube.d.ts.map +1 -1
- package/dist/utils/youtube.js +19 -13
- package/dist/utils/youtube.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/library.d.ts
CHANGED
|
@@ -22,21 +22,21 @@ export declare const getLibraryItemOutputSchema: {
|
|
|
22
22
|
hasSummary: z.ZodBoolean;
|
|
23
23
|
hasSkill: z.ZodBoolean;
|
|
24
24
|
}, "strip", z.ZodTypeAny, {
|
|
25
|
-
url: string;
|
|
26
25
|
title: string;
|
|
27
|
-
|
|
26
|
+
url: string;
|
|
28
27
|
channel: string;
|
|
29
28
|
tags: string[];
|
|
29
|
+
videoId: string;
|
|
30
30
|
dateSaved: string;
|
|
31
31
|
hasTranscript: boolean;
|
|
32
32
|
hasSummary: boolean;
|
|
33
33
|
hasSkill: boolean;
|
|
34
34
|
}, {
|
|
35
|
-
url: string;
|
|
36
35
|
title: string;
|
|
37
|
-
|
|
36
|
+
url: string;
|
|
38
37
|
channel: string;
|
|
39
38
|
tags: string[];
|
|
39
|
+
videoId: string;
|
|
40
40
|
dateSaved: string;
|
|
41
41
|
hasTranscript: boolean;
|
|
42
42
|
hasSummary: boolean;
|
|
@@ -52,6 +52,7 @@ export declare function getLibraryItemHandler({ videoId, contentType, }: {
|
|
|
52
52
|
export declare const searchLibrarySchema: {
|
|
53
53
|
query: z.ZodString;
|
|
54
54
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
55
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
55
56
|
};
|
|
56
57
|
export declare const searchLibraryOutputSchema: {
|
|
57
58
|
total: z.ZodNumber;
|
|
@@ -68,21 +69,22 @@ export declare const searchLibraryOutputSchema: {
|
|
|
68
69
|
excerpt: z.ZodString;
|
|
69
70
|
}, "strip", z.ZodTypeAny, {
|
|
70
71
|
title: string;
|
|
71
|
-
videoId: string;
|
|
72
72
|
kind: string;
|
|
73
|
+
videoId: string;
|
|
73
74
|
score: number;
|
|
74
75
|
excerpt: string;
|
|
75
76
|
}, {
|
|
76
77
|
title: string;
|
|
77
|
-
videoId: string;
|
|
78
78
|
kind: string;
|
|
79
|
+
videoId: string;
|
|
79
80
|
score: number;
|
|
80
81
|
excerpt: string;
|
|
81
82
|
}>, "many">;
|
|
82
83
|
};
|
|
83
|
-
export declare function searchLibraryHandler({ query, limit, }: {
|
|
84
|
+
export declare function searchLibraryHandler({ query, limit, offset, }: {
|
|
84
85
|
query: string;
|
|
85
86
|
limit: number;
|
|
87
|
+
offset: number;
|
|
86
88
|
}): Promise<CallToolResult>;
|
|
87
89
|
export declare const deleteLibraryItemSchema: {
|
|
88
90
|
videoId: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/tools/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;GAKG;AAIH,eAAO,MAAM,oBAAoB;;;CAMhC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAItC,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,EAC1C,OAAO,EACP,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,cAAc,CAAC,CAoB1B;AAID,eAAO,MAAM,mBAAmB
|
|
1
|
+
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/tools/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;GAKG;AAIH,eAAO,MAAM,oBAAoB;;;CAMhC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAItC,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,EAC1C,OAAO,EACP,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,cAAc,CAAC,CAoB1B;AAID,eAAO,MAAM,mBAAmB;;;;CAY/B,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;CAIrC,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,EACzC,KAAK,EACL,KAAK,EACL,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CA6B1B;AAID,eAAO,MAAM,uBAAuB;;;CAMnC,CAAC;AAEF,eAAO,MAAM,6BAA6B;;;CAGzC,CAAC;AAEF,wBAAsB,wBAAwB,CAAC,EAC7C,OAAO,EACP,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,cAAc,CAAC,CAG1B;AAID,eAAO,MAAM,uBAAuB;;;;;CAQnC,CAAC;AAEF,eAAO,MAAM,6BAA6B;;;;;;;;;;CAA8B,CAAC;AAEzE,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,GAAG,OAAO,CAAC,cAAc,CAAC,CAQ1B;AAID,eAAO,MAAM,yBAAyB,IAAK,CAAC;AAE5C,eAAO,MAAM,+BAA+B;;CAAkC,CAAC;AAE/E,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,cAAc,CAAC,CAG1E"}
|
package/dist/tools/library.js
CHANGED
|
@@ -48,18 +48,24 @@ export const searchLibrarySchema = {
|
|
|
48
48
|
.min(1)
|
|
49
49
|
.describe('Words or phrase to search for across saved summaries and skills'),
|
|
50
50
|
limit: z.number().int().min(1).max(50).default(10).describe('Maximum results. Default: 10'),
|
|
51
|
+
offset: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(0)
|
|
55
|
+
.default(0)
|
|
56
|
+
.describe('Skip this many of the ranked results, for paging. Default: 0'),
|
|
51
57
|
};
|
|
52
58
|
export const searchLibraryOutputSchema = {
|
|
53
59
|
query: z.string(),
|
|
54
60
|
hits: z.array(librarySearchHitSchema),
|
|
55
61
|
...paginationShape,
|
|
56
62
|
};
|
|
57
|
-
export async function searchLibraryHandler({ query, limit, }) {
|
|
58
|
-
const hits = await searchLibrary(query, limit);
|
|
63
|
+
export async function searchLibraryHandler({ query, limit, offset, }) {
|
|
64
|
+
const { hits, total } = await searchLibrary(query, limit, offset);
|
|
59
65
|
const structured = {
|
|
60
66
|
query,
|
|
61
67
|
hits: hits.map(({ id: _id, ...hit }) => hit),
|
|
62
|
-
...pageInfo(hits.length,
|
|
68
|
+
...pageInfo(total, hits.length, offset),
|
|
63
69
|
};
|
|
64
70
|
if (hits.length === 0) {
|
|
65
71
|
return toolResult([
|
|
@@ -68,7 +74,7 @@ export async function searchLibraryHandler({ query, limit, }) {
|
|
|
68
74
|
'Try different words, or call list_library to see everything saved.',
|
|
69
75
|
].join('\n'), structured);
|
|
70
76
|
}
|
|
71
|
-
const lines = [`${hits.length} result${
|
|
77
|
+
const lines = [`${hits.length} of ${total} result${total === 1 ? '' : 's'}`, ''];
|
|
72
78
|
for (const hit of hits) {
|
|
73
79
|
lines.push(`${hit.title} (${hit.kind})`);
|
|
74
80
|
lines.push(` ${hit.excerpt}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"library.js","sourceRoot":"","sources":["../../src/tools/library.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"library.js","sourceRoot":"","sources":["../../src/tools/library.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,21 +20,21 @@ export declare const listLibraryOutputSchema: {
|
|
|
20
20
|
hasSummary: z.ZodBoolean;
|
|
21
21
|
hasSkill: z.ZodBoolean;
|
|
22
22
|
}, "strip", z.ZodTypeAny, {
|
|
23
|
-
url: string;
|
|
24
23
|
title: string;
|
|
25
|
-
|
|
24
|
+
url: string;
|
|
26
25
|
channel: string;
|
|
27
26
|
tags: string[];
|
|
27
|
+
videoId: string;
|
|
28
28
|
dateSaved: string;
|
|
29
29
|
hasTranscript: boolean;
|
|
30
30
|
hasSummary: boolean;
|
|
31
31
|
hasSkill: boolean;
|
|
32
32
|
}, {
|
|
33
|
-
url: string;
|
|
34
33
|
title: string;
|
|
35
|
-
|
|
34
|
+
url: string;
|
|
36
35
|
channel: string;
|
|
37
36
|
tags: string[];
|
|
37
|
+
videoId: string;
|
|
38
38
|
dateSaved: string;
|
|
39
39
|
hasTranscript: boolean;
|
|
40
40
|
hasSummary: boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The two things that change a brain without reading YouTube: keeping the
|
|
5
|
+
* written account of a creator, and throwing the whole brain away.
|
|
6
|
+
*/
|
|
7
|
+
export declare const saveBrainProfileSchema: {
|
|
8
|
+
channel: z.ZodString;
|
|
9
|
+
content: z.ZodString;
|
|
10
|
+
};
|
|
11
|
+
export declare const saveBrainProfileOutputSchema: {
|
|
12
|
+
channelId: z.ZodString;
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
path: z.ZodString;
|
|
15
|
+
characters: z.ZodNumber;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Store the written account of a creator.
|
|
19
|
+
*
|
|
20
|
+
* The server cannot write this: it has no language model, and a profile is a
|
|
21
|
+
* reading of the corpus rather than a measurement of it. What it can do is keep
|
|
22
|
+
* the reading beside the passages it came from, and refuse to invent one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function saveBrainProfileHandler({ channel, content, }: {
|
|
25
|
+
channel: string;
|
|
26
|
+
content: string;
|
|
27
|
+
}): Promise<CallToolResult>;
|
|
28
|
+
export declare const deleteBrainSchema: {
|
|
29
|
+
channel: z.ZodString;
|
|
30
|
+
};
|
|
31
|
+
export declare const deleteBrainOutputSchema: {
|
|
32
|
+
channelId: z.ZodString;
|
|
33
|
+
name: z.ZodString;
|
|
34
|
+
deleted: z.ZodBoolean;
|
|
35
|
+
};
|
|
36
|
+
export declare function deleteBrainHandler({ channel, }: {
|
|
37
|
+
channel: string;
|
|
38
|
+
}): Promise<CallToolResult>;
|
|
39
|
+
//# sourceMappingURL=manage-brain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manage-brain.d.ts","sourceRoot":"","sources":["../../src/tools/manage-brain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAKzE;;;GAGG;AAIH,eAAO,MAAM,sBAAsB;;;CAQlC,CAAC;AAEF,eAAO,MAAM,4BAA4B;;;;;CAKxC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,cAAc,CAAC,CAU1B;AAID,eAAO,MAAM,iBAAiB;;CAE7B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;CAInC,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,EACvC,OAAO,GACR,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,cAAc,CAAC,CAW1B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolveBrain } from '../utils/brain-lookup.js';
|
|
3
|
+
import { deleteBrain, writeProfile } from '../utils/brain-storage.js';
|
|
4
|
+
import { fileResult, toolResult } from '../utils/format.js';
|
|
5
|
+
/**
|
|
6
|
+
* The two things that change a brain without reading YouTube: keeping the
|
|
7
|
+
* written account of a creator, and throwing the whole brain away.
|
|
8
|
+
*/
|
|
9
|
+
// -- save_brain_profile --------------------------------------------------
|
|
10
|
+
export const saveBrainProfileSchema = {
|
|
11
|
+
channel: z.string().describe('Channel URL, @handle, name, or channel id of an existing brain'),
|
|
12
|
+
content: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.describe('The profile, as markdown. Ground every claim in passages from ask_brain and cite them with [MM:SS] and a link, so a reader can check it against the video.'),
|
|
16
|
+
};
|
|
17
|
+
export const saveBrainProfileOutputSchema = {
|
|
18
|
+
channelId: z.string(),
|
|
19
|
+
name: z.string(),
|
|
20
|
+
path: z.string(),
|
|
21
|
+
characters: z.number().int(),
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Store the written account of a creator.
|
|
25
|
+
*
|
|
26
|
+
* The server cannot write this: it has no language model, and a profile is a
|
|
27
|
+
* reading of the corpus rather than a measurement of it. What it can do is keep
|
|
28
|
+
* the reading beside the passages it came from, and refuse to invent one.
|
|
29
|
+
*/
|
|
30
|
+
export async function saveBrainProfileHandler({ channel, content, }) {
|
|
31
|
+
const manifest = await resolveBrain(channel);
|
|
32
|
+
const { channelId, name } = manifest.channel;
|
|
33
|
+
const path = await writeProfile(channelId, content);
|
|
34
|
+
return fileResult(`Saved a profile for ${name} (${content.length.toLocaleString()} characters).`, { channelId, name, path, characters: content.length }, { path, name: `${name} profile`, mimeType: 'text/markdown' });
|
|
35
|
+
}
|
|
36
|
+
// -- delete_brain --------------------------------------------------------
|
|
37
|
+
export const deleteBrainSchema = {
|
|
38
|
+
channel: z.string().describe('Channel URL, @handle, name, or channel id of an existing brain'),
|
|
39
|
+
};
|
|
40
|
+
export const deleteBrainOutputSchema = {
|
|
41
|
+
channelId: z.string(),
|
|
42
|
+
name: z.string(),
|
|
43
|
+
deleted: z.boolean(),
|
|
44
|
+
};
|
|
45
|
+
export async function deleteBrainHandler({ channel, }) {
|
|
46
|
+
const manifest = await resolveBrain(channel);
|
|
47
|
+
const { channelId, name } = manifest.channel;
|
|
48
|
+
const deleted = await deleteBrain(channelId);
|
|
49
|
+
// `resolveBrain` already proved the brain was there, so there is no "nothing
|
|
50
|
+
// to delete" case to report — only the removal, and what survives it.
|
|
51
|
+
return toolResult(`Deleted the brain for ${name}. The transcripts it was built from are still cached, so rebuilding it is much faster than the first build was.`, { channelId, name, deleted });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=manage-brain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manage-brain.js","sourceRoot":"","sources":["../../src/tools/manage-brain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;GAGG;AAEH,2EAA2E;AAE3E,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;IAC9F,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,4JAA4J,CAC7J;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;CAC7B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAC5C,OAAO,EACP,OAAO,GAIR;IACC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAEpD,OAAO,UAAU,CACf,uBAAuB,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,eAAe,EAC9E,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,EACrD,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,CAC7D,CAAC;AACJ,CAAC;AAED,2EAA2E;AAE3E,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;CAC/F,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EACvC,OAAO,GAGR;IACC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;IAE7C,6EAA6E;IAC7E,sEAAsE;IACtE,OAAO,UAAU,CACf,yBAAyB,IAAI,iHAAiH,EAC9I,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAC7B,CAAC;AACJ,CAAC"}
|
|
@@ -21,17 +21,17 @@ export declare const searchChannelsOutputSchema: {
|
|
|
21
21
|
}, "strip", z.ZodTypeAny, {
|
|
22
22
|
description: string;
|
|
23
23
|
name: string;
|
|
24
|
-
handle: string;
|
|
25
|
-
channelUrl: string;
|
|
26
24
|
channelId: string;
|
|
25
|
+
handle: string;
|
|
27
26
|
subscriberCount: number;
|
|
27
|
+
channelUrl: string;
|
|
28
28
|
}, {
|
|
29
29
|
description: string;
|
|
30
30
|
name: string;
|
|
31
|
-
handle: string;
|
|
32
|
-
channelUrl: string;
|
|
33
31
|
channelId: string;
|
|
32
|
+
handle: string;
|
|
34
33
|
subscriberCount: number;
|
|
34
|
+
channelUrl: string;
|
|
35
35
|
}>, "many">;
|
|
36
36
|
};
|
|
37
37
|
export declare function searchChannelsHandler({ query, limit, }: {
|
|
@@ -20,14 +20,14 @@ export declare const searchTranscriptOutputSchema: {
|
|
|
20
20
|
url: z.ZodString;
|
|
21
21
|
}, "strip", z.ZodTypeAny, {
|
|
22
22
|
url: string;
|
|
23
|
-
text: string;
|
|
24
23
|
startSeconds: number;
|
|
25
24
|
startFormatted: string;
|
|
25
|
+
text: string;
|
|
26
26
|
}, {
|
|
27
27
|
url: string;
|
|
28
|
-
text: string;
|
|
29
28
|
startSeconds: number;
|
|
30
29
|
startFormatted: string;
|
|
30
|
+
text: string;
|
|
31
31
|
}>, "many">;
|
|
32
32
|
matchCount: z.ZodNumber;
|
|
33
33
|
segmentsSearched: z.ZodNumber;
|
|
@@ -21,23 +21,23 @@ export declare const searchVideosOutputSchema: {
|
|
|
21
21
|
viewCount: z.ZodOptional<z.ZodNumber>;
|
|
22
22
|
uploadDate: z.ZodOptional<z.ZodString>;
|
|
23
23
|
}, "strip", z.ZodTypeAny, {
|
|
24
|
-
url: string;
|
|
25
|
-
title: string;
|
|
26
24
|
id: string;
|
|
27
|
-
|
|
25
|
+
title: string;
|
|
28
26
|
durationSeconds: number;
|
|
27
|
+
durationFormatted: string;
|
|
28
|
+
url: string;
|
|
29
29
|
channel?: string | undefined;
|
|
30
|
-
uploadDate?: string | undefined;
|
|
31
30
|
viewCount?: number | undefined;
|
|
31
|
+
uploadDate?: string | undefined;
|
|
32
32
|
}, {
|
|
33
|
-
url: string;
|
|
34
|
-
title: string;
|
|
35
33
|
id: string;
|
|
36
|
-
|
|
34
|
+
title: string;
|
|
37
35
|
durationSeconds: number;
|
|
36
|
+
durationFormatted: string;
|
|
37
|
+
url: string;
|
|
38
38
|
channel?: string | undefined;
|
|
39
|
-
uploadDate?: string | undefined;
|
|
40
39
|
viewCount?: number | undefined;
|
|
40
|
+
uploadDate?: string | undefined;
|
|
41
41
|
}>, "many">;
|
|
42
42
|
};
|
|
43
43
|
export declare function searchVideosHandler({ query, limit, }: {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { BrainManifest } from '../brain-schemas.js';
|
|
2
|
+
import { type VideoFilters } from './brain-ingest.js';
|
|
3
|
+
import type { ChannelInfo, VideoListItem } from './youtube.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reading a channel into a brain.
|
|
6
|
+
*
|
|
7
|
+
* The shape of this is dictated by how long it takes. Several hundred videos is
|
|
8
|
+
* several hundred yt-dlp invocations, so a build is something that gets
|
|
9
|
+
* interrupted: cancelled by the client, throttled by YouTube, or killed along
|
|
10
|
+
* with the editor it was started from. Every choice below follows from that —
|
|
11
|
+
* per-video state rather than one "built" flag, checkpoints rather than a
|
|
12
|
+
* single write at the end, and a failed video costing only itself.
|
|
13
|
+
*
|
|
14
|
+
* Which is also why there is no separate refresh: a second build sees what it
|
|
15
|
+
* already has, skips it, and reads whatever is new.
|
|
16
|
+
*/
|
|
17
|
+
/** Frequent enough that little work is lost, rare enough not to dominate. */
|
|
18
|
+
export declare const CHECKPOINT_EVERY_VIDEOS = 10;
|
|
19
|
+
/** Past this many throttled videos in a row, YouTube means it. */
|
|
20
|
+
export declare const RATE_LIMIT_TOLERANCE = 3;
|
|
21
|
+
export interface BuildBrainOptions extends VideoFilters {
|
|
22
|
+
channel: ChannelInfo;
|
|
23
|
+
videos: VideoListItem[];
|
|
24
|
+
existing: BrainManifest | undefined;
|
|
25
|
+
/** Caption language to read. A brain is built from one language at a time. */
|
|
26
|
+
language: string;
|
|
27
|
+
}
|
|
28
|
+
export interface BuildBrainResult {
|
|
29
|
+
manifest: BrainManifest;
|
|
30
|
+
/** Videos the filters kept, whether or not this call had to read them. */
|
|
31
|
+
considered: number;
|
|
32
|
+
/** Videos read during this call, as opposed to carried over from an earlier one. */
|
|
33
|
+
processed: number;
|
|
34
|
+
skipped: number;
|
|
35
|
+
excluded: number;
|
|
36
|
+
stoppedEarly: boolean;
|
|
37
|
+
stopReason?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function buildBrain(options: BuildBrainOptions): Promise<BuildBrainResult>;
|
|
40
|
+
//# sourceMappingURL=brain-build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-build.d.ts","sourceRoot":"","sources":["../../src/utils/brain-build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,aAAa,EAAmB,MAAM,qBAAqB,CAAC;AAEtF,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/D;;;;;;;;;;;;GAYG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAc1C,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,CAAC;IACxB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4EtF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { readChunks, writeChunks } from './brain-index.js';
|
|
2
|
+
import { excluded, ingestVideo, isExcluded, pendingState, } from './brain-ingest.js';
|
|
3
|
+
import { computeStats } from './brain-stats.js';
|
|
4
|
+
import { BRAIN_MANIFEST_VERSION, writeManifest } from './brain-storage.js';
|
|
5
|
+
import { reportProgress, throwIfAborted } from './context.js';
|
|
6
|
+
import { concurrencyState } from './ytdlp.js';
|
|
7
|
+
/**
|
|
8
|
+
* Reading a channel into a brain.
|
|
9
|
+
*
|
|
10
|
+
* The shape of this is dictated by how long it takes. Several hundred videos is
|
|
11
|
+
* several hundred yt-dlp invocations, so a build is something that gets
|
|
12
|
+
* interrupted: cancelled by the client, throttled by YouTube, or killed along
|
|
13
|
+
* with the editor it was started from. Every choice below follows from that —
|
|
14
|
+
* per-video state rather than one "built" flag, checkpoints rather than a
|
|
15
|
+
* single write at the end, and a failed video costing only itself.
|
|
16
|
+
*
|
|
17
|
+
* Which is also why there is no separate refresh: a second build sees what it
|
|
18
|
+
* already has, skips it, and reads whatever is new.
|
|
19
|
+
*/
|
|
20
|
+
/** Frequent enough that little work is lost, rare enough not to dominate. */
|
|
21
|
+
export const CHECKPOINT_EVERY_VIDEOS = 10;
|
|
22
|
+
/**
|
|
23
|
+
* How many videos to read at once: whatever the yt-dlp limiter is actually set
|
|
24
|
+
* to, which `YOUTUBE_MCP_MAX_CONCURRENCY` can change.
|
|
25
|
+
*
|
|
26
|
+
* Read rather than copied. A second number that merely happened to match would
|
|
27
|
+
* stop matching the moment someone tuned the first, and would then either queue
|
|
28
|
+
* work behind a limit it could not see or batch below one it was allowed.
|
|
29
|
+
*/
|
|
30
|
+
function buildConcurrency() {
|
|
31
|
+
return concurrencyState().limit;
|
|
32
|
+
}
|
|
33
|
+
/** Past this many throttled videos in a row, YouTube means it. */
|
|
34
|
+
export const RATE_LIMIT_TOLERANCE = 3;
|
|
35
|
+
export async function buildBrain(options) {
|
|
36
|
+
const { channel, videos, existing, language, since, minDurationSeconds } = options;
|
|
37
|
+
const filters = { minDurationSeconds, ...(since === undefined ? {} : { since }) };
|
|
38
|
+
const createdAt = existing?.createdAt ?? new Date().toISOString();
|
|
39
|
+
const chunksByVideo = groupByVideo(await readChunks(channel.channelId));
|
|
40
|
+
const states = reconciled(existing, videos, chunksByVideo, filters);
|
|
41
|
+
const outstanding = videos.filter((video) => isOutstanding(states.get(video.id)));
|
|
42
|
+
/**
|
|
43
|
+
* `phrases` is the difference between a checkpoint and the end of a build:
|
|
44
|
+
* the phrase pass reads the whole corpus and takes seconds at the sizes a
|
|
45
|
+
* brain can reach, so it runs once, when there is a finished corpus to run it
|
|
46
|
+
* over. A checkpoint records what has been read, which is all it is for.
|
|
47
|
+
*/
|
|
48
|
+
const save = async (phrases) => {
|
|
49
|
+
const passages = flatten(states, chunksByVideo);
|
|
50
|
+
const manifest = toManifest(channel, states, passages, createdAt, language, phrases);
|
|
51
|
+
await writeChunks(channel.channelId, passages);
|
|
52
|
+
await writeManifest(manifest);
|
|
53
|
+
return manifest;
|
|
54
|
+
};
|
|
55
|
+
let attempted = 0;
|
|
56
|
+
let processed = 0;
|
|
57
|
+
let consecutiveThrottles = 0;
|
|
58
|
+
let stopReason;
|
|
59
|
+
try {
|
|
60
|
+
await inBatches(outstanding, buildConcurrency(), async (video) => {
|
|
61
|
+
if (stopReason !== undefined)
|
|
62
|
+
return;
|
|
63
|
+
throwIfAborted();
|
|
64
|
+
const { state, chunks } = await ingestVideo(video, countChunks(chunksByVideo), {
|
|
65
|
+
language,
|
|
66
|
+
...filters,
|
|
67
|
+
});
|
|
68
|
+
states.set(video.id, state);
|
|
69
|
+
if (chunks.length > 0)
|
|
70
|
+
chunksByVideo.set(video.id, chunks);
|
|
71
|
+
else
|
|
72
|
+
chunksByVideo.delete(video.id);
|
|
73
|
+
attempted++;
|
|
74
|
+
// A video the filters ruled out was looked at, not read.
|
|
75
|
+
if (state.state !== 'excluded')
|
|
76
|
+
processed++;
|
|
77
|
+
consecutiveThrottles = state.error === 'RATE_LIMITED' ? consecutiveThrottles + 1 : 0;
|
|
78
|
+
if (consecutiveThrottles >= RATE_LIMIT_TOLERANCE) {
|
|
79
|
+
stopReason = 'YouTube is rate limiting this client.';
|
|
80
|
+
}
|
|
81
|
+
reportProgress(attempted, outstanding.length, `Read ${attempted} of ${outstanding.length}`);
|
|
82
|
+
if (attempted % CHECKPOINT_EVERY_VIDEOS === 0)
|
|
83
|
+
await save(false);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// A cancelled build must not throw away the videos read since the last
|
|
88
|
+
// checkpoint. Saving first is what makes "interrupt it and call it again"
|
|
89
|
+
// true rather than nearly true — and it is a checkpoint, not a finished
|
|
90
|
+
// corpus, so it does not pay for the phrase pass either.
|
|
91
|
+
await save(false);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
const manifest = await save(true);
|
|
95
|
+
const excludedCount = videos.filter((video) => states.get(video.id)?.state === 'excluded').length;
|
|
96
|
+
return {
|
|
97
|
+
manifest,
|
|
98
|
+
considered: videos.length - excludedCount,
|
|
99
|
+
processed,
|
|
100
|
+
skipped: videos.length - excludedCount - processed,
|
|
101
|
+
excluded: excludedCount,
|
|
102
|
+
stoppedEarly: stopReason !== undefined,
|
|
103
|
+
...(stopReason === undefined ? {} : { stopReason }),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Per-video state, reconciled against the passages on disk and re-tested
|
|
108
|
+
* against the filters in force right now.
|
|
109
|
+
*
|
|
110
|
+
* Two corrections happen here, both for the same reason: what the manifest says
|
|
111
|
+
* was true when it was written, and neither the corpus nor the caller's filters
|
|
112
|
+
* are obliged to have stayed the same.
|
|
113
|
+
*
|
|
114
|
+
* The manifest and the passage file are two documents, and only one can be
|
|
115
|
+
* written first. A crash between them, a half-restored backup, or a
|
|
116
|
+
* `chunks.json` truncated by a full disk all end the same way — the manifest
|
|
117
|
+
* says a video was read and there is nothing to show for it. Left alone that
|
|
118
|
+
* brain is stranded for good: every build skips the video as already done while
|
|
119
|
+
* every search returns nothing. So the passages win, and a video the corpus
|
|
120
|
+
* cannot account for goes back to pending.
|
|
121
|
+
*
|
|
122
|
+
* A filter is re-applied rather than remembered. Narrowing one excludes videos
|
|
123
|
+
* already read; widening one brings excluded videos back. Both are decided from
|
|
124
|
+
* the dates and lengths already recorded, so changing your mind costs nothing
|
|
125
|
+
* until there is something new to fetch.
|
|
126
|
+
*/
|
|
127
|
+
function reconciled(existing, videos, chunksByVideo, filters) {
|
|
128
|
+
const states = new Map();
|
|
129
|
+
for (const [videoId, recorded] of Object.entries(existing?.videos ?? {})) {
|
|
130
|
+
const lost = recorded.state === 'indexed' && (chunksByVideo.get(videoId)?.length ?? 0) === 0;
|
|
131
|
+
const state = lost
|
|
132
|
+
? { ...recorded, state: 'pending', chunkCount: 0, wordCount: 0 }
|
|
133
|
+
: recorded;
|
|
134
|
+
states.set(videoId, refiltered(state, filters));
|
|
135
|
+
}
|
|
136
|
+
for (const video of videos) {
|
|
137
|
+
// The listing's own length is real data, so a filter that can be decided
|
|
138
|
+
// from it is decided here — before spending a request to learn what the
|
|
139
|
+
// listing already said.
|
|
140
|
+
if (!states.has(video.id))
|
|
141
|
+
states.set(video.id, refiltered(pendingState(video), filters));
|
|
142
|
+
}
|
|
143
|
+
return states;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* `undefined` — the filters cannot be decided from what is recorded — leaves the
|
|
147
|
+
* state alone, so the video is read and the question answered from the metadata
|
|
148
|
+
* that read fetches.
|
|
149
|
+
*/
|
|
150
|
+
function refiltered(state, filters) {
|
|
151
|
+
const ruledOut = isExcluded(state, filters);
|
|
152
|
+
if (ruledOut === true)
|
|
153
|
+
return excluded(state);
|
|
154
|
+
if (ruledOut === false && state.state === 'excluded') {
|
|
155
|
+
return { ...state, state: 'pending' };
|
|
156
|
+
}
|
|
157
|
+
return state;
|
|
158
|
+
}
|
|
159
|
+
/** Anything not already read: never attempted, or attempted and failed. */
|
|
160
|
+
function isOutstanding(state) {
|
|
161
|
+
return state === undefined || state.state === 'pending' || state.state === 'failed';
|
|
162
|
+
}
|
|
163
|
+
function groupByVideo(chunks) {
|
|
164
|
+
const grouped = new Map();
|
|
165
|
+
for (const chunk of chunks) {
|
|
166
|
+
grouped.set(chunk.videoId, [...(grouped.get(chunk.videoId) ?? []), chunk]);
|
|
167
|
+
}
|
|
168
|
+
return grouped;
|
|
169
|
+
}
|
|
170
|
+
function countChunks(chunksByVideo) {
|
|
171
|
+
let total = 0;
|
|
172
|
+
for (const chunks of chunksByVideo.values())
|
|
173
|
+
total += chunks.length;
|
|
174
|
+
return total;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* The corpus: every passage of every video the brain holds, in manifest order so
|
|
178
|
+
* the file changes as little as possible between builds.
|
|
179
|
+
*
|
|
180
|
+
* A video the filters exclude contributes nothing, which is what makes the
|
|
181
|
+
* filters mean something. Leaving its passages in would let `ask_brain` quote a
|
|
182
|
+
* video that `get_brain_info` says is not part of this brain, and no wording
|
|
183
|
+
* makes that defensible.
|
|
184
|
+
*/
|
|
185
|
+
function flatten(states, chunksByVideo) {
|
|
186
|
+
return [...states.entries()].flatMap(([videoId, state]) => state.state === 'excluded' ? [] : (chunksByVideo.get(videoId) ?? []));
|
|
187
|
+
}
|
|
188
|
+
function toManifest(channel, states, passages, createdAt, language, phrases) {
|
|
189
|
+
return {
|
|
190
|
+
version: BRAIN_MANIFEST_VERSION,
|
|
191
|
+
channel,
|
|
192
|
+
language,
|
|
193
|
+
createdAt,
|
|
194
|
+
updatedAt: new Date().toISOString(),
|
|
195
|
+
videos: Object.fromEntries(states),
|
|
196
|
+
stats: computeStats([...states.values()], passages, { phrases }),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Run `work` over the items, `size` at a time.
|
|
201
|
+
*
|
|
202
|
+
* Deliberately not a rolling window: a batch boundary is a natural place for
|
|
203
|
+
* the checkpoint and the cancellation check, and the limiter inside yt-dlp is
|
|
204
|
+
* what actually paces the network.
|
|
205
|
+
*/
|
|
206
|
+
async function inBatches(items, size, work) {
|
|
207
|
+
for (let start = 0; start < items.length; start += size) {
|
|
208
|
+
await Promise.all(items.slice(start, start + size).map(work));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=brain-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-build.js","sourceRoot":"","sources":["../../src/utils/brain-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { BrainChunk } from '../brain-schemas.js';
|
|
2
|
+
import { type TranscriptSegment } from './transcript.js';
|
|
3
|
+
import type { Chapter } from './youtube.js';
|
|
4
|
+
/**
|
|
5
|
+
* Transcripts cut into retrievable passages.
|
|
6
|
+
*
|
|
7
|
+
* A brain is searched, not read: a whole transcript is too long to rank
|
|
8
|
+
* usefully and far too long to return, while a single caption cue is too short
|
|
9
|
+
* to carry a thought. A passage of a few sentences is what BM25 scores well and
|
|
10
|
+
* what a reader can check against the video in one click.
|
|
11
|
+
*
|
|
12
|
+
* Chunks do not overlap. Overlap is worth its cost with embeddings, where a
|
|
13
|
+
* concept split across a boundary can be missed entirely; BM25 matches terms,
|
|
14
|
+
* and a duplicated passage would only mean two results saying the same thing.
|
|
15
|
+
*/
|
|
16
|
+
/** Where a passage stops being short enough to keep growing. */
|
|
17
|
+
export declare const CHUNK_TARGET_CHARS = 800;
|
|
18
|
+
/**
|
|
19
|
+
* Where it stops regardless. Speech without a pause for this long is rare, and
|
|
20
|
+
* an unbroken passage is worse than one broken in an awkward place.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CHUNK_MAX_CHARS = 1200;
|
|
23
|
+
/** A pause this long is a sentence or a thought ending. */
|
|
24
|
+
export declare const CHUNK_BREAK_GAP_SECONDS = 2;
|
|
25
|
+
export interface ChunkTranscriptOptions {
|
|
26
|
+
videoId: string;
|
|
27
|
+
title: string;
|
|
28
|
+
segments: TranscriptSegment[];
|
|
29
|
+
/** Chapter starts are always passage boundaries: a new chapter is a new subject. */
|
|
30
|
+
chapters?: Chapter[];
|
|
31
|
+
}
|
|
32
|
+
export declare function chunkTranscript(options: ChunkTranscriptOptions): BrainChunk[];
|
|
33
|
+
//# sourceMappingURL=brain-chunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-chunks.d.ts","sourceRoot":"","sources":["../../src/utils/brain-chunks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;;;;;GAWG;AAEH,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,2DAA2D;AAC3D,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,UAAU,EAAE,CAwC7E"}
|