@boldvideo/bold-js 1.5.0 → 1.6.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/AGENTS.md +18 -3
- package/CHANGELOG.md +18 -0
- package/README.md +199 -43
- package/dist/index.cjs +30 -5
- package/dist/index.d.ts +72 -1
- package/dist/index.js +30 -5
- package/llms.txt +82 -6
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -46,11 +46,23 @@ This project uses [Changesets](https://github.com/changesets/changesets) with au
|
|
|
46
46
|
- Removes the changeset files
|
|
47
47
|
- When you merge that Release PR, the workflow automatically publishes to npm
|
|
48
48
|
|
|
49
|
+
### Manual Release (when you need to publish immediately)
|
|
50
|
+
|
|
51
|
+
If you need to release immediately without waiting for the Release PR:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm changeset version # Consume changesets, bump version, update CHANGELOG
|
|
55
|
+
git add -A && git commit -m "chore: release vX.Y.Z"
|
|
56
|
+
git tag vX.Y.Z
|
|
57
|
+
git push origin main --tags
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The `release.yml` workflow will automatically publish to npm when it sees the `v*` tag.
|
|
61
|
+
|
|
49
62
|
### Important Notes
|
|
50
63
|
|
|
51
|
-
- **Never run `pnpm changeset version` or `pnpm changeset publish` locally** - the GitHub Action handles this automatically
|
|
52
64
|
- The CI workflow (`ci.yml`) runs `pnpm run build` which generates the `dist/` folder - this ensures compiled files are always included in the published package
|
|
53
|
-
- The `release.yml` workflow
|
|
65
|
+
- The `release.yml` workflow publishes when a `v*` tag is pushed
|
|
54
66
|
|
|
55
67
|
## Project Structure
|
|
56
68
|
|
|
@@ -84,7 +96,10 @@ bold.videos.search(query) // Search videos
|
|
|
84
96
|
bold.playlists.list() // List playlists
|
|
85
97
|
bold.playlists.get(id) // Get single playlist
|
|
86
98
|
bold.ai.coach(opts) // AI RAG assistant (streaming)
|
|
87
|
-
bold.ai.ask(
|
|
99
|
+
bold.ai.ask(opts) // AI RAG assistant (alias for coach)
|
|
100
|
+
bold.ai.search(opts) // Semantic search with synthesis
|
|
101
|
+
bold.ai.chat(videoId, opts) // Video-scoped Q&A
|
|
102
|
+
bold.ai.recommend(opts) // AI-powered recommendations
|
|
88
103
|
bold.trackEvent() // Track video events
|
|
89
104
|
bold.trackPageView() // Track page views
|
|
90
105
|
```
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @boldvideo/bold-js
|
|
2
2
|
|
|
3
|
+
## 1.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 71b3437: Add `bold.ai.recommend()` for AI-powered video recommendations
|
|
8
|
+
|
|
9
|
+
- New method `bold.ai.recommend({ topics, ...options })` returns personalized video recommendations based on topics
|
|
10
|
+
- Supports both streaming (default) and non-streaming modes
|
|
11
|
+
- Includes AI-generated guidance for learning paths
|
|
12
|
+
- New types: `RecommendOptions`, `RecommendResponse`, `Recommendation`, `RecommendationVideo`, `TopicInput`
|
|
13
|
+
- New `recommendations` event type in `AIEvent` union for streaming responses
|
|
14
|
+
|
|
15
|
+
## 1.5.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 21267d9: Fix SSE parsing to process final 'complete' event when stream closes without trailing newline
|
|
20
|
+
|
|
3
21
|
## 1.5.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -26,86 +26,242 @@
|
|
|
26
26
|
</a>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
---
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
## Installation
|
|
32
32
|
|
|
33
|
-
```
|
|
33
|
+
```bash
|
|
34
34
|
npm install @boldvideo/bold-js
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
import { createClient } from "@boldvideo/bold-js";
|
|
37
|
+
## Quick Start
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
```typescript
|
|
40
|
+
import { createClient } from '@boldvideo/bold-js';
|
|
41
|
+
|
|
42
|
+
const bold = createClient('your-api-key');
|
|
43
|
+
|
|
44
|
+
// Fetch videos
|
|
45
|
+
const videos = await bold.videos.list();
|
|
46
|
+
|
|
47
|
+
// Get AI-powered recommendations
|
|
48
|
+
const recs = await bold.ai.recommend({
|
|
49
|
+
topics: ['sales', 'negotiation'],
|
|
50
|
+
stream: false
|
|
51
|
+
});
|
|
52
|
+
console.log(recs.guidance);
|
|
42
53
|
```
|
|
43
54
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## API Reference
|
|
58
|
+
|
|
59
|
+
### Videos
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
// List latest videos
|
|
50
63
|
const videos = await bold.videos.list();
|
|
51
64
|
|
|
52
|
-
//
|
|
65
|
+
// Get a single video
|
|
66
|
+
const video = await bold.videos.get('video-id');
|
|
67
|
+
|
|
68
|
+
// Search videos
|
|
69
|
+
const results = await bold.videos.search('pricing strategies');
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Playlists
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// List all playlists
|
|
53
76
|
const playlists = await bold.playlists.list();
|
|
54
77
|
|
|
78
|
+
// Get a single playlist with videos
|
|
79
|
+
const playlist = await bold.playlists.get('playlist-id');
|
|
55
80
|
```
|
|
56
81
|
|
|
57
|
-
###
|
|
82
|
+
### Settings
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// Fetch channel settings, menus, and featured playlists
|
|
86
|
+
const settings = await bold.settings();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## AI Methods
|
|
58
92
|
|
|
59
|
-
|
|
93
|
+
All AI methods support both streaming (default) and non-streaming modes.
|
|
60
94
|
|
|
61
|
-
|
|
62
|
-
|
|
95
|
+
### Recommend
|
|
96
|
+
|
|
97
|
+
Get AI-powered video recommendations based on topics — ideal for personalized learning paths, exam prep, and content discovery.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Streaming (default)
|
|
101
|
+
const stream = await bold.ai.recommend({
|
|
102
|
+
topics: ['contract law', 'ethics', 'client management'],
|
|
103
|
+
context: 'I failed these topics on my certification exam'
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
for await (const event of stream) {
|
|
107
|
+
if (event.type === 'recommendations') {
|
|
108
|
+
event.recommendations.forEach(rec => {
|
|
109
|
+
console.log(`${rec.topic}:`);
|
|
110
|
+
rec.videos.forEach(v => console.log(` - ${v.title} (${v.relevance})`));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (event.type === 'text_delta') {
|
|
114
|
+
process.stdout.write(event.delta); // AI guidance
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Non-streaming
|
|
119
|
+
const response = await bold.ai.recommend({
|
|
120
|
+
topics: ['sales', 'marketing'],
|
|
121
|
+
stream: false
|
|
122
|
+
});
|
|
123
|
+
console.log(response.guidance);
|
|
124
|
+
console.log(response.recommendations);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Options:**
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Description |
|
|
130
|
+
|-----------|------|-------------|
|
|
131
|
+
| `topics` | `string[]` \| `string` | Topics to find content for (required) |
|
|
132
|
+
| `stream` | `boolean` | `true` (default) for SSE, `false` for JSON |
|
|
133
|
+
| `limit` | `number` | Max videos per topic (default: 5, max: 20) |
|
|
134
|
+
| `collectionId` | `string` | Filter to a specific collection |
|
|
135
|
+
| `tags` | `string[]` | Filter by tags |
|
|
136
|
+
| `synthesize` | `boolean` | Include AI guidance (default: true) |
|
|
137
|
+
| `context` | `string` | User context for personalized guidance |
|
|
138
|
+
|
|
139
|
+
### Coach / Ask
|
|
140
|
+
|
|
141
|
+
Library-wide RAG assistant for answering questions across your entire video library.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Streaming
|
|
145
|
+
const stream = await bold.ai.coach({ prompt: 'How do I price my SaaS?' });
|
|
146
|
+
|
|
147
|
+
for await (const event of stream) {
|
|
148
|
+
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
149
|
+
if (event.type === 'sources') console.log('Sources:', event.sources);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Non-streaming
|
|
153
|
+
const response = await bold.ai.ask({
|
|
154
|
+
prompt: 'What are the best closing techniques?',
|
|
155
|
+
stream: false
|
|
156
|
+
});
|
|
157
|
+
console.log(response.content);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Search
|
|
161
|
+
|
|
162
|
+
Semantic search with light synthesis.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const stream = await bold.ai.search({
|
|
166
|
+
prompt: 'pricing strategies',
|
|
167
|
+
limit: 10
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
for await (const event of stream) {
|
|
171
|
+
if (event.type === 'sources') {
|
|
172
|
+
console.log(`Found ${event.sources.length} results`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Chat
|
|
178
|
+
|
|
179
|
+
Video-scoped conversation for Q&A about a specific video.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const stream = await bold.ai.chat('video-id', {
|
|
183
|
+
prompt: 'What is discussed at the 5 minute mark?'
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
for await (const event of stream) {
|
|
187
|
+
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Multi-turn Conversations
|
|
192
|
+
|
|
193
|
+
Use the `context` parameter for follow-up questions:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
63
196
|
const first = await bold.ai.search({
|
|
64
|
-
prompt:
|
|
197
|
+
prompt: 'How do indie designers find clients?',
|
|
65
198
|
stream: false
|
|
66
199
|
});
|
|
67
|
-
console.log(first.content);
|
|
68
200
|
|
|
69
|
-
// Follow-up with context from previous response
|
|
70
201
|
const followUp = await bold.ai.search({
|
|
71
|
-
prompt:
|
|
202
|
+
prompt: 'What about cold outreach specifically?',
|
|
72
203
|
context: first.context,
|
|
73
204
|
stream: false
|
|
74
205
|
});
|
|
75
|
-
console.log(followUp.content);
|
|
76
206
|
```
|
|
77
207
|
|
|
78
|
-
|
|
208
|
+
---
|
|
79
209
|
|
|
80
|
-
|
|
210
|
+
## Analytics
|
|
81
211
|
|
|
82
|
-
|
|
212
|
+
Track video events and page views for analytics.
|
|
83
213
|
|
|
84
|
-
|
|
214
|
+
```typescript
|
|
215
|
+
// Track video events (play, pause, complete, etc.)
|
|
216
|
+
bold.trackEvent({
|
|
217
|
+
type: 'play',
|
|
218
|
+
videoId: 'video-id',
|
|
219
|
+
timestamp: 0
|
|
220
|
+
});
|
|
85
221
|
|
|
86
|
-
|
|
222
|
+
// Track page views
|
|
223
|
+
bold.trackPageView({
|
|
224
|
+
path: '/videos/my-video',
|
|
225
|
+
referrer: document.referrer
|
|
226
|
+
});
|
|
227
|
+
```
|
|
87
228
|
|
|
88
|
-
|
|
229
|
+
---
|
|
89
230
|
|
|
90
|
-
|
|
91
|
-
- NPM_TOKEN is only accessible to workflows on the main branch
|
|
92
|
-
- External contributors' PRs cannot access secrets
|
|
93
|
-
- Only maintainers with write access can merge to main
|
|
94
|
-
- The changeset-release workflow only runs after merge to main
|
|
231
|
+
## TypeScript
|
|
95
232
|
|
|
96
|
-
|
|
233
|
+
All types are exported for full TypeScript support:
|
|
97
234
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
235
|
+
```typescript
|
|
236
|
+
import type {
|
|
237
|
+
Video,
|
|
238
|
+
Playlist,
|
|
239
|
+
Settings,
|
|
240
|
+
AIEvent,
|
|
241
|
+
AIResponse,
|
|
242
|
+
RecommendOptions,
|
|
243
|
+
RecommendResponse,
|
|
244
|
+
Recommendation,
|
|
245
|
+
Source
|
|
246
|
+
} from '@boldvideo/bold-js';
|
|
247
|
+
```
|
|
104
248
|
|
|
105
|
-
|
|
249
|
+
---
|
|
106
250
|
|
|
107
|
-
|
|
251
|
+
## Related Links
|
|
252
|
+
|
|
253
|
+
- **[Bold API Documentation](https://docs.boldvideo.io/docs/api)**
|
|
254
|
+
- **[GitHub Repository](https://github.com/boldvideo/bold-js)**
|
|
255
|
+
- **[npm Package](https://www.npmjs.com/package/@boldvideo/bold-js)**
|
|
256
|
+
|
|
257
|
+
## Contributing
|
|
258
|
+
|
|
259
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
|
|
260
|
+
|
|
261
|
+
## Security
|
|
108
262
|
|
|
109
|
-
|
|
263
|
+
See [SECURITY.md](SECURITY.md) for security policies and reporting vulnerabilities.
|
|
110
264
|
|
|
265
|
+
## License
|
|
111
266
|
|
|
267
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -232,11 +232,14 @@ async function* parseSSE(response) {
|
|
|
232
232
|
try {
|
|
233
233
|
while (true) {
|
|
234
234
|
const { done, value } = await reader.read();
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
if (value) {
|
|
236
|
+
buffer += decoder.decode(value, { stream: true });
|
|
237
|
+
}
|
|
238
|
+
if (done) {
|
|
239
|
+
buffer += decoder.decode();
|
|
240
|
+
}
|
|
238
241
|
const lines = buffer.split(/\r?\n\r?\n/);
|
|
239
|
-
buffer = lines.pop() || "";
|
|
242
|
+
buffer = done ? "" : lines.pop() || "";
|
|
240
243
|
for (const line of lines) {
|
|
241
244
|
const trimmed = line.trim();
|
|
242
245
|
if (!trimmed || !trimmed.startsWith("data:"))
|
|
@@ -254,6 +257,8 @@ async function* parseSSE(response) {
|
|
|
254
257
|
} catch {
|
|
255
258
|
}
|
|
256
259
|
}
|
|
260
|
+
if (done)
|
|
261
|
+
break;
|
|
257
262
|
}
|
|
258
263
|
} finally {
|
|
259
264
|
reader.releaseLock();
|
|
@@ -336,11 +341,31 @@ function createAI(config) {
|
|
|
336
341
|
}
|
|
337
342
|
return streamRequest(path, body, config);
|
|
338
343
|
}
|
|
344
|
+
async function recommend(options) {
|
|
345
|
+
const path = "ai/recommend";
|
|
346
|
+
const body = { topics: options.topics };
|
|
347
|
+
if (options.limit)
|
|
348
|
+
body.limit = options.limit;
|
|
349
|
+
if (options.collectionId)
|
|
350
|
+
body.collection_id = options.collectionId;
|
|
351
|
+
if (options.tags)
|
|
352
|
+
body.tags = options.tags;
|
|
353
|
+
if (options.synthesize !== void 0)
|
|
354
|
+
body.synthesize = options.synthesize;
|
|
355
|
+
if (options.context)
|
|
356
|
+
body.context = options.context;
|
|
357
|
+
if (options.stream === false) {
|
|
358
|
+
body.stream = false;
|
|
359
|
+
return jsonRequest(path, body, config);
|
|
360
|
+
}
|
|
361
|
+
return streamRequest(path, body, config);
|
|
362
|
+
}
|
|
339
363
|
return {
|
|
340
364
|
ask,
|
|
341
365
|
coach,
|
|
342
366
|
search,
|
|
343
|
-
chat
|
|
367
|
+
chat,
|
|
368
|
+
recommend
|
|
344
369
|
};
|
|
345
370
|
}
|
|
346
371
|
|
package/dist/index.d.ts
CHANGED
|
@@ -223,6 +223,9 @@ type AIEvent = {
|
|
|
223
223
|
} | {
|
|
224
224
|
type: "clarification";
|
|
225
225
|
questions: string[];
|
|
226
|
+
} | {
|
|
227
|
+
type: "recommendations";
|
|
228
|
+
recommendations: Recommendation[];
|
|
226
229
|
} | {
|
|
227
230
|
type: "message_complete";
|
|
228
231
|
content: string;
|
|
@@ -288,6 +291,52 @@ interface ChatOptions {
|
|
|
288
291
|
stream?: boolean;
|
|
289
292
|
conversationId?: string;
|
|
290
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* A recommended video with relevance score
|
|
296
|
+
*/
|
|
297
|
+
interface RecommendationVideo {
|
|
298
|
+
video_id: string;
|
|
299
|
+
title: string;
|
|
300
|
+
playback_id: string;
|
|
301
|
+
relevance: number;
|
|
302
|
+
why: string;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* A topic recommendation with its videos
|
|
306
|
+
*/
|
|
307
|
+
interface Recommendation {
|
|
308
|
+
topic: string;
|
|
309
|
+
position: number;
|
|
310
|
+
videos: RecommendationVideo[];
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Topic input format for recommendations
|
|
314
|
+
*/
|
|
315
|
+
type TopicInput = string | {
|
|
316
|
+
q: string;
|
|
317
|
+
priority?: number;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Options for bold.ai.recommend()
|
|
321
|
+
*/
|
|
322
|
+
interface RecommendOptions {
|
|
323
|
+
topics: TopicInput[] | string;
|
|
324
|
+
stream?: boolean;
|
|
325
|
+
limit?: number;
|
|
326
|
+
collectionId?: string;
|
|
327
|
+
tags?: string[];
|
|
328
|
+
synthesize?: boolean;
|
|
329
|
+
context?: string;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Non-streaming response for recommend endpoint
|
|
333
|
+
*/
|
|
334
|
+
interface RecommendResponse {
|
|
335
|
+
id: string;
|
|
336
|
+
recommendations: Recommendation[];
|
|
337
|
+
guidance: string;
|
|
338
|
+
sources: Source[];
|
|
339
|
+
}
|
|
291
340
|
|
|
292
341
|
/**
|
|
293
342
|
* AI client interface for type-safe method overloading
|
|
@@ -357,6 +406,28 @@ interface AIClient {
|
|
|
357
406
|
stream?: true;
|
|
358
407
|
}): Promise<AsyncIterable<AIEvent>>;
|
|
359
408
|
chat(videoId: string, options: ChatOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
409
|
+
/**
|
|
410
|
+
* Recommend - AI-powered video recommendations
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* // Streaming (default)
|
|
414
|
+
* const stream = await bold.ai.recommend({ topics: ["sales", "negotiation"] });
|
|
415
|
+
* for await (const event of stream) {
|
|
416
|
+
* if (event.type === "recommendations") console.log(event.recommendations);
|
|
417
|
+
* }
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* // Non-streaming
|
|
421
|
+
* const response = await bold.ai.recommend({ topics: ["sales"], stream: false });
|
|
422
|
+
* console.log(response.guidance);
|
|
423
|
+
*/
|
|
424
|
+
recommend(options: RecommendOptions & {
|
|
425
|
+
stream: false;
|
|
426
|
+
}): Promise<RecommendResponse>;
|
|
427
|
+
recommend(options: RecommendOptions & {
|
|
428
|
+
stream?: true;
|
|
429
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
430
|
+
recommend(options: RecommendOptions): Promise<AsyncIterable<AIEvent> | RecommendResponse>;
|
|
360
431
|
}
|
|
361
432
|
|
|
362
433
|
type ClientOptions = {
|
|
@@ -401,4 +472,4 @@ declare const DEFAULT_API_BASE_URL = "https://app.boldvideo.io/api/v1/";
|
|
|
401
472
|
*/
|
|
402
473
|
declare const DEFAULT_INTERNAL_API_BASE_URL = "https://app.boldvideo.io/i/v1/";
|
|
403
474
|
|
|
404
|
-
export { AIContextMessage, AIEvent, AIResponse, AIUsage, Account, AccountAI, AskOptions, AssistantConfig, ChatOptions, ClientOptions, DEFAULT_API_BASE_URL, DEFAULT_INTERNAL_API_BASE_URL, MenuItem, Playlist, Portal, PortalDisplay, PortalLayout, PortalNavigation, PortalTheme, SearchOptions, Settings, Source, ThemeColors, ThemeConfig, Video, VideoAttachment, VideoDownloadUrls, VideoMetadata, VideoSubtitles, VideoTranscript, createClient };
|
|
475
|
+
export { AIContextMessage, AIEvent, AIResponse, AIUsage, Account, AccountAI, AskOptions, AssistantConfig, ChatOptions, ClientOptions, DEFAULT_API_BASE_URL, DEFAULT_INTERNAL_API_BASE_URL, MenuItem, Playlist, Portal, PortalDisplay, PortalLayout, PortalNavigation, PortalTheme, RecommendOptions, RecommendResponse, Recommendation, RecommendationVideo, SearchOptions, Settings, Source, ThemeColors, ThemeConfig, TopicInput, Video, VideoAttachment, VideoDownloadUrls, VideoMetadata, VideoSubtitles, VideoTranscript, createClient };
|
package/dist/index.js
CHANGED
|
@@ -194,11 +194,14 @@ async function* parseSSE(response) {
|
|
|
194
194
|
try {
|
|
195
195
|
while (true) {
|
|
196
196
|
const { done, value } = await reader.read();
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
if (value) {
|
|
198
|
+
buffer += decoder.decode(value, { stream: true });
|
|
199
|
+
}
|
|
200
|
+
if (done) {
|
|
201
|
+
buffer += decoder.decode();
|
|
202
|
+
}
|
|
200
203
|
const lines = buffer.split(/\r?\n\r?\n/);
|
|
201
|
-
buffer = lines.pop() || "";
|
|
204
|
+
buffer = done ? "" : lines.pop() || "";
|
|
202
205
|
for (const line of lines) {
|
|
203
206
|
const trimmed = line.trim();
|
|
204
207
|
if (!trimmed || !trimmed.startsWith("data:"))
|
|
@@ -216,6 +219,8 @@ async function* parseSSE(response) {
|
|
|
216
219
|
} catch {
|
|
217
220
|
}
|
|
218
221
|
}
|
|
222
|
+
if (done)
|
|
223
|
+
break;
|
|
219
224
|
}
|
|
220
225
|
} finally {
|
|
221
226
|
reader.releaseLock();
|
|
@@ -298,11 +303,31 @@ function createAI(config) {
|
|
|
298
303
|
}
|
|
299
304
|
return streamRequest(path, body, config);
|
|
300
305
|
}
|
|
306
|
+
async function recommend(options) {
|
|
307
|
+
const path = "ai/recommend";
|
|
308
|
+
const body = { topics: options.topics };
|
|
309
|
+
if (options.limit)
|
|
310
|
+
body.limit = options.limit;
|
|
311
|
+
if (options.collectionId)
|
|
312
|
+
body.collection_id = options.collectionId;
|
|
313
|
+
if (options.tags)
|
|
314
|
+
body.tags = options.tags;
|
|
315
|
+
if (options.synthesize !== void 0)
|
|
316
|
+
body.synthesize = options.synthesize;
|
|
317
|
+
if (options.context)
|
|
318
|
+
body.context = options.context;
|
|
319
|
+
if (options.stream === false) {
|
|
320
|
+
body.stream = false;
|
|
321
|
+
return jsonRequest(path, body, config);
|
|
322
|
+
}
|
|
323
|
+
return streamRequest(path, body, config);
|
|
324
|
+
}
|
|
301
325
|
return {
|
|
302
326
|
ask,
|
|
303
327
|
coach,
|
|
304
328
|
search,
|
|
305
|
-
chat
|
|
329
|
+
chat,
|
|
330
|
+
recommend
|
|
306
331
|
};
|
|
307
332
|
}
|
|
308
333
|
|
package/llms.txt
CHANGED
|
@@ -13,33 +13,109 @@ const bold = createClient('your-api-key');
|
|
|
13
13
|
const videos = await bold.videos.list();
|
|
14
14
|
const video = await bold.videos.get('video-id');
|
|
15
15
|
|
|
16
|
+
// AI-powered recommendations
|
|
17
|
+
const recs = await bold.ai.recommend({ topics: ['sales', 'negotiation'], stream: false });
|
|
18
|
+
console.log(recs.guidance);
|
|
19
|
+
|
|
16
20
|
// AI streaming
|
|
17
|
-
const stream = await bold.ai.coach({
|
|
21
|
+
const stream = await bold.ai.coach({ prompt: 'How do I price my SaaS?' });
|
|
18
22
|
for await (const event of stream) {
|
|
19
|
-
if (event.type === '
|
|
23
|
+
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
20
24
|
}
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
## API Reference
|
|
24
28
|
|
|
29
|
+
### Client
|
|
30
|
+
|
|
25
31
|
- `createClient(apiKey, options?)` - Create SDK instance
|
|
32
|
+
|
|
33
|
+
### Content
|
|
34
|
+
|
|
26
35
|
- `bold.settings()` - Channel settings, menus, featured playlists
|
|
27
36
|
- `bold.videos.list()` - List videos
|
|
28
37
|
- `bold.videos.get(id)` - Get video by ID
|
|
29
38
|
- `bold.videos.search(query)` - Search videos
|
|
30
39
|
- `bold.playlists.list()` - List playlists
|
|
31
40
|
- `bold.playlists.get(id)` - Get playlist by ID
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
|
|
42
|
+
### AI Methods
|
|
43
|
+
|
|
44
|
+
All AI methods return `AsyncIterable<AIEvent>` (streaming) or `Promise<AIResponse>` (non-streaming).
|
|
45
|
+
|
|
46
|
+
- `bold.ai.recommend(options)` - AI-powered video recommendations based on topics
|
|
47
|
+
- `bold.ai.coach(options)` - Library-wide RAG assistant (alias: `ask`)
|
|
48
|
+
- `bold.ai.ask(options)` - Library-wide RAG assistant
|
|
49
|
+
- `bold.ai.search(options)` - Semantic search with synthesis
|
|
50
|
+
- `bold.ai.chat(videoId, options)` - Video-scoped Q&A conversation
|
|
51
|
+
|
|
52
|
+
### Analytics
|
|
53
|
+
|
|
54
|
+
- `bold.trackEvent(event)` - Track video events (play, pause, complete)
|
|
35
55
|
- `bold.trackPageView(data)` - Track page views
|
|
36
56
|
|
|
57
|
+
## AI Options
|
|
58
|
+
|
|
59
|
+
### RecommendOptions
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
{
|
|
63
|
+
topics: string[] | string; // Topics to find content for (required)
|
|
64
|
+
stream?: boolean; // Default: true
|
|
65
|
+
limit?: number; // Max videos per topic (default: 5, max: 20)
|
|
66
|
+
collectionId?: string; // Filter to collection
|
|
67
|
+
tags?: string[]; // Filter by tags
|
|
68
|
+
synthesize?: boolean; // Include AI guidance (default: true)
|
|
69
|
+
context?: string; // User context for personalization
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### AskOptions / CoachOptions
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
{
|
|
77
|
+
prompt: string; // Question to ask (required)
|
|
78
|
+
stream?: boolean; // Default: true
|
|
79
|
+
conversationId?: string; // Continue existing conversation
|
|
80
|
+
collectionId?: string; // Filter to collection
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### SearchOptions
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
{
|
|
88
|
+
prompt: string; // Search query (required)
|
|
89
|
+
stream?: boolean; // Default: true
|
|
90
|
+
limit?: number; // Max results
|
|
91
|
+
collectionId?: string; // Filter to collection
|
|
92
|
+
videoId?: string; // Search within specific video
|
|
93
|
+
context?: AIContextMessage[]; // Conversation context
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### ChatOptions
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
{
|
|
101
|
+
prompt: string; // Question about the video (required)
|
|
102
|
+
stream?: boolean; // Default: true
|
|
103
|
+
conversationId?: string; // Continue existing conversation
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
37
107
|
## Types
|
|
38
108
|
|
|
39
|
-
Key types exported:
|
|
109
|
+
Key types exported:
|
|
110
|
+
|
|
111
|
+
- `Video`, `Playlist`, `Settings`, `Portal`
|
|
112
|
+
- `AIEvent`, `AIResponse`, `Source`, `AIUsage`
|
|
113
|
+
- `AskOptions`, `SearchOptions`, `ChatOptions`
|
|
114
|
+
- `RecommendOptions`, `RecommendResponse`, `Recommendation`, `RecommendationVideo`, `TopicInput`
|
|
40
115
|
|
|
41
116
|
## Links
|
|
42
117
|
|
|
43
118
|
- [GitHub](https://github.com/boldvideo/bold-js)
|
|
44
119
|
- [npm](https://www.npmjs.com/package/@boldvideo/bold-js)
|
|
120
|
+
- [API Docs](https://docs.boldvideo.io/docs/api)
|
|
45
121
|
- [Types Source](https://github.com/boldvideo/bold-js/blob/main/src/lib/types.ts)
|