@boldvideo/bold-js 1.6.0 → 1.7.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/CHANGELOG.md +49 -0
- package/README.md +80 -36
- package/dist/index.cjs +25 -18
- package/dist/index.d.ts +86 -74
- package/dist/index.js +25 -18
- package/llms.txt +23 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# @boldvideo/bold-js
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e6fb51b: Align SDK with Bold AI API v1 specification
|
|
8
|
+
|
|
9
|
+
**Breaking Changes:**
|
|
10
|
+
|
|
11
|
+
- Video-scoped chat: pass `videoId` in options instead of as separate arg: `bold.ai.chat({ videoId, prompt })`
|
|
12
|
+
- `Source.timestamp_end` and `Source.playback_id` are now required (were optional)
|
|
13
|
+
- `AIUsage` now uses `input_tokens`/`output_tokens` (was `prompt_tokens`/`completion_tokens`/`total_tokens`)
|
|
14
|
+
- Removed `TopicInput` type - `RecommendationsOptions.topics` now only accepts `string[]`
|
|
15
|
+
- `RecommendationsOptions.context` is now `AIContextMessage[]` (was `string`)
|
|
16
|
+
|
|
17
|
+
**New:**
|
|
18
|
+
|
|
19
|
+
- `bold.ai.chat(opts)` - Single method for all chat (pass `videoId` to scope to a video)
|
|
20
|
+
- `bold.ai.recommendations(opts)` - AI-powered video recommendations (replaces `recommend`)
|
|
21
|
+
- `ChatOptions.videoId` - Scope chat to a specific video
|
|
22
|
+
- `ChatOptions.currentTime` - Pass current playback position for context
|
|
23
|
+
|
|
24
|
+
**Deprecated (still work, will be removed in v2):**
|
|
25
|
+
|
|
26
|
+
- `bold.ai.ask()` → use `bold.ai.chat()`
|
|
27
|
+
- `bold.ai.coach()` → use `bold.ai.chat()`
|
|
28
|
+
- `bold.ai.recommend()` → use `bold.ai.recommendations()`
|
|
29
|
+
- `AskOptions` type → use `ChatOptions`
|
|
30
|
+
- `RecommendOptions` type → use `RecommendationsOptions`
|
|
31
|
+
- `RecommendResponse` type → use `RecommendationsResponse`
|
|
32
|
+
|
|
33
|
+
**Type Changes:**
|
|
34
|
+
|
|
35
|
+
- Added `Source.id` field (chunk identifier)
|
|
36
|
+
- Added `conversation_id` and `video_id` to `message_start` event
|
|
37
|
+
- Added `conversation_id`, `recommendations`, `guidance` to `message_complete` event
|
|
38
|
+
- Simplified `clarification` event to include `content` field
|
|
39
|
+
- Removed legacy event types: `token`, `answer`, `complete`
|
|
40
|
+
|
|
41
|
+
## 1.6.1
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- 7aff057: Align SDK with API specification
|
|
46
|
+
|
|
47
|
+
- Renamed `synthesize` to `includeGuidance` in `RecommendOptions` to match API
|
|
48
|
+
- Renamed `why` to `reason` in `RecommendationVideo` type to match API response
|
|
49
|
+
- Added `tags` filter to `AskOptions` and `SearchOptions`
|
|
50
|
+
- Added `currentTime` to `ChatOptions` for playback context
|
|
51
|
+
|
|
3
52
|
## 1.6.0
|
|
4
53
|
|
|
5
54
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -44,8 +44,8 @@ const bold = createClient('your-api-key');
|
|
|
44
44
|
// Fetch videos
|
|
45
45
|
const videos = await bold.videos.list();
|
|
46
46
|
|
|
47
|
-
//
|
|
48
|
-
const recs = await bold.ai.
|
|
47
|
+
// AI-powered recommendations
|
|
48
|
+
const recs = await bold.ai.recommendations({
|
|
49
49
|
topics: ['sales', 'negotiation'],
|
|
50
50
|
stream: false
|
|
51
51
|
});
|
|
@@ -92,15 +92,47 @@ const settings = await bold.settings();
|
|
|
92
92
|
|
|
93
93
|
All AI methods support both streaming (default) and non-streaming modes.
|
|
94
94
|
|
|
95
|
-
###
|
|
95
|
+
### Chat
|
|
96
|
+
|
|
97
|
+
Library-wide conversational AI for deep Q&A across your entire video library.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Streaming (default)
|
|
101
|
+
const stream = await bold.ai.chat({ prompt: 'How do I price my SaaS?' });
|
|
102
|
+
|
|
103
|
+
for await (const event of stream) {
|
|
104
|
+
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
105
|
+
if (event.type === 'sources') console.log('Sources:', event.sources);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Non-streaming
|
|
109
|
+
const response = await bold.ai.chat({
|
|
110
|
+
prompt: 'What are the best closing techniques?',
|
|
111
|
+
stream: false
|
|
112
|
+
});
|
|
113
|
+
console.log(response.content);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Options:**
|
|
117
|
+
|
|
118
|
+
| Parameter | Type | Description |
|
|
119
|
+
|-----------|------|-------------|
|
|
120
|
+
| `prompt` | `string` | The user's question (required) |
|
|
121
|
+
| `stream` | `boolean` | `true` (default) for SSE, `false` for JSON |
|
|
122
|
+
| `videoId` | `string` | If provided, scope to this video instead of whole library |
|
|
123
|
+
| `currentTime` | `number` | Current playback position (only with `videoId`) |
|
|
124
|
+
| `conversationId` | `string` | Pass to continue existing conversation |
|
|
125
|
+
| `collectionId` | `string` | Filter to a specific collection |
|
|
126
|
+
| `tags` | `string[]` | Filter by tags |
|
|
127
|
+
|
|
128
|
+
### Recommendations
|
|
96
129
|
|
|
97
130
|
Get AI-powered video recommendations based on topics — ideal for personalized learning paths, exam prep, and content discovery.
|
|
98
131
|
|
|
99
132
|
```typescript
|
|
100
133
|
// Streaming (default)
|
|
101
|
-
const stream = await bold.ai.
|
|
134
|
+
const stream = await bold.ai.recommendations({
|
|
102
135
|
topics: ['contract law', 'ethics', 'client management'],
|
|
103
|
-
context: 'I failed these topics on my certification exam'
|
|
104
136
|
});
|
|
105
137
|
|
|
106
138
|
for await (const event of stream) {
|
|
@@ -116,7 +148,7 @@ for await (const event of stream) {
|
|
|
116
148
|
}
|
|
117
149
|
|
|
118
150
|
// Non-streaming
|
|
119
|
-
const response = await bold.ai.
|
|
151
|
+
const response = await bold.ai.recommendations({
|
|
120
152
|
topics: ['sales', 'marketing'],
|
|
121
153
|
stream: false
|
|
122
154
|
});
|
|
@@ -128,38 +160,17 @@ console.log(response.recommendations);
|
|
|
128
160
|
|
|
129
161
|
| Parameter | Type | Description |
|
|
130
162
|
|-----------|------|-------------|
|
|
131
|
-
| `topics` | `string[]`
|
|
163
|
+
| `topics` | `string[]` | Topics to find content for (required) |
|
|
132
164
|
| `stream` | `boolean` | `true` (default) for SSE, `false` for JSON |
|
|
133
165
|
| `limit` | `number` | Max videos per topic (default: 5, max: 20) |
|
|
134
166
|
| `collectionId` | `string` | Filter to a specific collection |
|
|
135
167
|
| `tags` | `string[]` | Filter by tags |
|
|
136
|
-
| `
|
|
137
|
-
| `context` | `
|
|
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
|
-
```
|
|
168
|
+
| `includeGuidance` | `boolean` | Include AI learning path narrative (default: true) |
|
|
169
|
+
| `context` | `AIContextMessage[]` | Previous conversation turns for follow-ups |
|
|
159
170
|
|
|
160
171
|
### Search
|
|
161
172
|
|
|
162
|
-
|
|
173
|
+
Fast semantic search with a brief AI-generated summary.
|
|
163
174
|
|
|
164
175
|
```typescript
|
|
165
176
|
const stream = await bold.ai.search({
|
|
@@ -174,18 +185,26 @@ for await (const event of stream) {
|
|
|
174
185
|
}
|
|
175
186
|
```
|
|
176
187
|
|
|
177
|
-
### Chat
|
|
188
|
+
### Video-Scoped Chat
|
|
178
189
|
|
|
179
|
-
|
|
190
|
+
Chat about a specific video by passing `videoId`. Uses only that video's transcript as context.
|
|
180
191
|
|
|
181
192
|
```typescript
|
|
182
|
-
const stream = await bold.ai.chat(
|
|
193
|
+
const stream = await bold.ai.chat({
|
|
194
|
+
videoId: 'video-id',
|
|
183
195
|
prompt: 'What is discussed at the 5 minute mark?'
|
|
184
196
|
});
|
|
185
197
|
|
|
186
198
|
for await (const event of stream) {
|
|
187
199
|
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
188
200
|
}
|
|
201
|
+
|
|
202
|
+
// With playback context (coming soon)
|
|
203
|
+
const stream = await bold.ai.chat({
|
|
204
|
+
videoId: 'video-id',
|
|
205
|
+
prompt: 'What does she mean by that?',
|
|
206
|
+
currentTime: 847 // seconds
|
|
207
|
+
});
|
|
189
208
|
```
|
|
190
209
|
|
|
191
210
|
### Multi-turn Conversations
|
|
@@ -239,8 +258,10 @@ import type {
|
|
|
239
258
|
Settings,
|
|
240
259
|
AIEvent,
|
|
241
260
|
AIResponse,
|
|
242
|
-
|
|
243
|
-
|
|
261
|
+
ChatOptions,
|
|
262
|
+
SearchOptions,
|
|
263
|
+
RecommendationsOptions,
|
|
264
|
+
RecommendationsResponse,
|
|
244
265
|
Recommendation,
|
|
245
266
|
Source
|
|
246
267
|
} from '@boldvideo/bold-js';
|
|
@@ -248,6 +269,29 @@ import type {
|
|
|
248
269
|
|
|
249
270
|
---
|
|
250
271
|
|
|
272
|
+
## Migration from v1.6.x
|
|
273
|
+
|
|
274
|
+
### Method Changes
|
|
275
|
+
|
|
276
|
+
| Old | New | Notes |
|
|
277
|
+
|-----|-----|-------|
|
|
278
|
+
| `bold.ai.ask(opts)` | `bold.ai.chat(opts)` | `ask()` still works but is deprecated |
|
|
279
|
+
| `bold.ai.coach(opts)` | `bold.ai.chat(opts)` | `coach()` still works but is deprecated |
|
|
280
|
+
| `bold.ai.chat(videoId, opts)` | `bold.ai.chat({ videoId, ...opts })` | Pass `videoId` in options |
|
|
281
|
+
| `bold.ai.recommend(opts)` | `bold.ai.recommendations(opts)` | `recommend()` still works but is deprecated |
|
|
282
|
+
|
|
283
|
+
### Type Renames
|
|
284
|
+
|
|
285
|
+
| Old Type | New Type |
|
|
286
|
+
|----------|----------|
|
|
287
|
+
| `AskOptions` | `ChatOptions` |
|
|
288
|
+
| `RecommendOptions` | `RecommendationsOptions` |
|
|
289
|
+
| `RecommendResponse` | `RecommendationsResponse` |
|
|
290
|
+
|
|
291
|
+
The old types are still exported as aliases for backward compatibility.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
251
295
|
## Related Links
|
|
252
296
|
|
|
253
297
|
- **[Bold API Documentation](https://docs.boldvideo.io/docs/api)**
|
package/dist/index.cjs
CHANGED
|
@@ -250,7 +250,7 @@ async function* parseSSE(response) {
|
|
|
250
250
|
try {
|
|
251
251
|
const event = JSON.parse(json);
|
|
252
252
|
yield event;
|
|
253
|
-
if (event.type === "
|
|
253
|
+
if (event.type === "message_complete" || event.type === "error") {
|
|
254
254
|
await reader.cancel();
|
|
255
255
|
return;
|
|
256
256
|
}
|
|
@@ -301,19 +301,29 @@ async function jsonRequest(path, body, config) {
|
|
|
301
301
|
return response.json();
|
|
302
302
|
}
|
|
303
303
|
function createAI(config) {
|
|
304
|
-
async function
|
|
305
|
-
const
|
|
304
|
+
async function chat(options) {
|
|
305
|
+
const isVideoScoped = !!options.videoId;
|
|
306
|
+
const basePath = isVideoScoped ? `ai/videos/${options.videoId}/chat` : "ai/chat";
|
|
307
|
+
const path = options.conversationId ? `${basePath}/${options.conversationId}` : basePath;
|
|
306
308
|
const body = { prompt: options.prompt };
|
|
307
309
|
if (options.collectionId)
|
|
308
310
|
body.collection_id = options.collectionId;
|
|
311
|
+
if (options.tags)
|
|
312
|
+
body.tags = options.tags;
|
|
313
|
+
if (isVideoScoped && options.currentTime !== void 0) {
|
|
314
|
+
body.current_time = options.currentTime;
|
|
315
|
+
}
|
|
309
316
|
if (options.stream === false) {
|
|
310
317
|
body.stream = false;
|
|
311
318
|
return jsonRequest(path, body, config);
|
|
312
319
|
}
|
|
313
320
|
return streamRequest(path, body, config);
|
|
314
321
|
}
|
|
322
|
+
async function ask(options) {
|
|
323
|
+
return chat(options);
|
|
324
|
+
}
|
|
315
325
|
async function coach(options) {
|
|
316
|
-
return
|
|
326
|
+
return chat(options);
|
|
317
327
|
}
|
|
318
328
|
async function search(options) {
|
|
319
329
|
const path = "ai/search";
|
|
@@ -324,6 +334,8 @@ function createAI(config) {
|
|
|
324
334
|
body.collection_id = options.collectionId;
|
|
325
335
|
if (options.videoId)
|
|
326
336
|
body.video_id = options.videoId;
|
|
337
|
+
if (options.tags)
|
|
338
|
+
body.tags = options.tags;
|
|
327
339
|
if (options.context)
|
|
328
340
|
body.context = options.context;
|
|
329
341
|
if (options.stream === false) {
|
|
@@ -332,17 +344,8 @@ function createAI(config) {
|
|
|
332
344
|
}
|
|
333
345
|
return streamRequest(path, body, config);
|
|
334
346
|
}
|
|
335
|
-
async function
|
|
336
|
-
const path =
|
|
337
|
-
const body = { prompt: options.prompt };
|
|
338
|
-
if (options.stream === false) {
|
|
339
|
-
body.stream = false;
|
|
340
|
-
return jsonRequest(path, body, config);
|
|
341
|
-
}
|
|
342
|
-
return streamRequest(path, body, config);
|
|
343
|
-
}
|
|
344
|
-
async function recommend(options) {
|
|
345
|
-
const path = "ai/recommend";
|
|
347
|
+
async function recommendations(options) {
|
|
348
|
+
const path = "ai/recommendations";
|
|
346
349
|
const body = { topics: options.topics };
|
|
347
350
|
if (options.limit)
|
|
348
351
|
body.limit = options.limit;
|
|
@@ -350,8 +353,8 @@ function createAI(config) {
|
|
|
350
353
|
body.collection_id = options.collectionId;
|
|
351
354
|
if (options.tags)
|
|
352
355
|
body.tags = options.tags;
|
|
353
|
-
if (options.
|
|
354
|
-
body.
|
|
356
|
+
if (options.includeGuidance !== void 0)
|
|
357
|
+
body.include_guidance = options.includeGuidance;
|
|
355
358
|
if (options.context)
|
|
356
359
|
body.context = options.context;
|
|
357
360
|
if (options.stream === false) {
|
|
@@ -360,11 +363,15 @@ function createAI(config) {
|
|
|
360
363
|
}
|
|
361
364
|
return streamRequest(path, body, config);
|
|
362
365
|
}
|
|
366
|
+
async function recommend(options) {
|
|
367
|
+
return recommendations(options);
|
|
368
|
+
}
|
|
363
369
|
return {
|
|
370
|
+
chat,
|
|
364
371
|
ask,
|
|
365
372
|
coach,
|
|
366
373
|
search,
|
|
367
|
-
|
|
374
|
+
recommendations,
|
|
368
375
|
recommend
|
|
369
376
|
};
|
|
370
377
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -182,21 +182,21 @@ type Settings = {
|
|
|
182
182
|
* Source citation from AI responses
|
|
183
183
|
*/
|
|
184
184
|
interface Source {
|
|
185
|
+
id: string;
|
|
185
186
|
video_id: string;
|
|
186
187
|
title: string;
|
|
187
|
-
timestamp: number;
|
|
188
|
-
timestamp_end?: number;
|
|
189
188
|
text: string;
|
|
190
|
-
|
|
189
|
+
timestamp: number;
|
|
190
|
+
timestamp_end: number;
|
|
191
|
+
playback_id: string;
|
|
191
192
|
speaker?: string;
|
|
192
193
|
}
|
|
193
194
|
/**
|
|
194
195
|
* Token usage statistics
|
|
195
196
|
*/
|
|
196
197
|
interface AIUsage {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
total_tokens: number;
|
|
198
|
+
input_tokens: number;
|
|
199
|
+
output_tokens: number;
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
202
202
|
* SSE event types for AI streaming responses
|
|
@@ -204,42 +204,36 @@ interface AIUsage {
|
|
|
204
204
|
type AIEvent = {
|
|
205
205
|
type: "message_start";
|
|
206
206
|
id: string;
|
|
207
|
-
|
|
207
|
+
conversation_id?: string;
|
|
208
|
+
video_id?: string;
|
|
208
209
|
} | {
|
|
209
210
|
type: "sources";
|
|
210
211
|
sources: Source[];
|
|
211
|
-
query?: string;
|
|
212
212
|
} | {
|
|
213
213
|
type: "text_delta";
|
|
214
214
|
delta: string;
|
|
215
|
-
} | {
|
|
216
|
-
type: "token";
|
|
217
|
-
content: string;
|
|
218
|
-
} | {
|
|
219
|
-
type: "answer";
|
|
220
|
-
content: string;
|
|
221
|
-
response_id?: string;
|
|
222
|
-
context?: AIContextMessage[];
|
|
223
215
|
} | {
|
|
224
216
|
type: "clarification";
|
|
217
|
+
content: string;
|
|
225
218
|
questions: string[];
|
|
226
219
|
} | {
|
|
227
220
|
type: "recommendations";
|
|
228
221
|
recommendations: Recommendation[];
|
|
229
222
|
} | {
|
|
230
223
|
type: "message_complete";
|
|
224
|
+
id: string;
|
|
225
|
+
conversation_id?: string;
|
|
231
226
|
content: string;
|
|
232
227
|
sources: Source[];
|
|
233
228
|
usage?: AIUsage;
|
|
234
229
|
context?: AIContextMessage[];
|
|
235
|
-
|
|
236
|
-
|
|
230
|
+
recommendations?: Recommendation[];
|
|
231
|
+
guidance?: string;
|
|
237
232
|
} | {
|
|
238
233
|
type: "error";
|
|
239
234
|
code: string;
|
|
240
235
|
message: string;
|
|
241
236
|
retryable: boolean;
|
|
242
|
-
details?: Record<string, unknown>;
|
|
243
237
|
};
|
|
244
238
|
/**
|
|
245
239
|
* Non-streaming AI response
|
|
@@ -253,14 +247,31 @@ interface AIResponse {
|
|
|
253
247
|
context?: AIContextMessage[];
|
|
254
248
|
}
|
|
255
249
|
/**
|
|
256
|
-
* Options for bold.ai.
|
|
250
|
+
* Options for bold.ai.chat()
|
|
251
|
+
*
|
|
252
|
+
* If `videoId` is provided, scopes chat to that video (hits /ai/videos/:id/chat).
|
|
253
|
+
* Otherwise, searches your entire library (hits /ai/chat).
|
|
257
254
|
*/
|
|
258
|
-
interface
|
|
255
|
+
interface ChatOptions {
|
|
259
256
|
prompt: string;
|
|
260
257
|
stream?: boolean;
|
|
261
258
|
conversationId?: string;
|
|
262
259
|
collectionId?: string;
|
|
260
|
+
tags?: string[];
|
|
261
|
+
/**
|
|
262
|
+
* If provided, scope chat to a specific video instead of the whole library.
|
|
263
|
+
*/
|
|
264
|
+
videoId?: string;
|
|
265
|
+
/**
|
|
266
|
+
* Current playback position in seconds. Only used when videoId is set.
|
|
267
|
+
* Helps AI understand what the viewer just watched.
|
|
268
|
+
*/
|
|
269
|
+
currentTime?: number;
|
|
263
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* @deprecated Use ChatOptions instead
|
|
273
|
+
*/
|
|
274
|
+
type AskOptions = ChatOptions;
|
|
264
275
|
/**
|
|
265
276
|
* Conversation message for AI context
|
|
266
277
|
*/
|
|
@@ -277,20 +288,9 @@ interface SearchOptions {
|
|
|
277
288
|
limit?: number;
|
|
278
289
|
collectionId?: string;
|
|
279
290
|
videoId?: string;
|
|
291
|
+
tags?: string[];
|
|
280
292
|
context?: AIContextMessage[];
|
|
281
293
|
}
|
|
282
|
-
/**
|
|
283
|
-
* Options for bold.ai.chat()
|
|
284
|
-
*
|
|
285
|
-
* conversationId: Pass to continue an existing conversation (multi-turn chat).
|
|
286
|
-
* If omitted, a new conversation is created. The id is returned in the
|
|
287
|
-
* message_start event - capture it to pass to subsequent requests.
|
|
288
|
-
*/
|
|
289
|
-
interface ChatOptions {
|
|
290
|
-
prompt: string;
|
|
291
|
-
stream?: boolean;
|
|
292
|
-
conversationId?: string;
|
|
293
|
-
}
|
|
294
294
|
/**
|
|
295
295
|
* A recommended video with relevance score
|
|
296
296
|
*/
|
|
@@ -299,64 +299,82 @@ interface RecommendationVideo {
|
|
|
299
299
|
title: string;
|
|
300
300
|
playback_id: string;
|
|
301
301
|
relevance: number;
|
|
302
|
-
|
|
302
|
+
reason: string;
|
|
303
303
|
}
|
|
304
304
|
/**
|
|
305
305
|
* A topic recommendation with its videos
|
|
306
306
|
*/
|
|
307
307
|
interface Recommendation {
|
|
308
308
|
topic: string;
|
|
309
|
-
position: number;
|
|
310
309
|
videos: RecommendationVideo[];
|
|
311
310
|
}
|
|
312
311
|
/**
|
|
313
|
-
*
|
|
314
|
-
*/
|
|
315
|
-
type TopicInput = string | {
|
|
316
|
-
q: string;
|
|
317
|
-
priority?: number;
|
|
318
|
-
};
|
|
319
|
-
/**
|
|
320
|
-
* Options for bold.ai.recommend()
|
|
312
|
+
* Options for bold.ai.recommendations()
|
|
321
313
|
*/
|
|
322
|
-
interface
|
|
323
|
-
topics:
|
|
314
|
+
interface RecommendationsOptions {
|
|
315
|
+
topics: string[];
|
|
324
316
|
stream?: boolean;
|
|
325
317
|
limit?: number;
|
|
326
318
|
collectionId?: string;
|
|
327
319
|
tags?: string[];
|
|
328
|
-
|
|
329
|
-
context?:
|
|
320
|
+
includeGuidance?: boolean;
|
|
321
|
+
context?: AIContextMessage[];
|
|
330
322
|
}
|
|
331
323
|
/**
|
|
332
|
-
*
|
|
324
|
+
* @deprecated Use RecommendationsOptions instead
|
|
325
|
+
*/
|
|
326
|
+
type RecommendOptions = RecommendationsOptions;
|
|
327
|
+
/**
|
|
328
|
+
* Non-streaming response for recommendations endpoint
|
|
333
329
|
*/
|
|
334
|
-
interface
|
|
330
|
+
interface RecommendationsResponse {
|
|
335
331
|
id: string;
|
|
336
332
|
recommendations: Recommendation[];
|
|
337
333
|
guidance: string;
|
|
338
334
|
sources: Source[];
|
|
335
|
+
context?: AIContextMessage[];
|
|
336
|
+
usage?: AIUsage;
|
|
339
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* @deprecated Use RecommendationsResponse instead
|
|
340
|
+
*/
|
|
341
|
+
type RecommendResponse = RecommendationsResponse;
|
|
340
342
|
|
|
341
343
|
/**
|
|
342
344
|
* AI client interface for type-safe method overloading
|
|
343
345
|
*/
|
|
344
346
|
interface AIClient {
|
|
345
347
|
/**
|
|
346
|
-
*
|
|
348
|
+
* Chat - Conversational AI for Q&A
|
|
349
|
+
*
|
|
350
|
+
* If `videoId` is provided, scopes to that video. Otherwise searches your entire library.
|
|
347
351
|
*
|
|
348
352
|
* @example
|
|
349
|
-
* //
|
|
350
|
-
* const stream = await bold.ai.
|
|
353
|
+
* // Library-wide Q&A
|
|
354
|
+
* const stream = await bold.ai.chat({ prompt: "How do I price my SaaS?" });
|
|
351
355
|
* for await (const event of stream) {
|
|
352
356
|
* if (event.type === "text_delta") process.stdout.write(event.delta);
|
|
353
357
|
* }
|
|
354
358
|
*
|
|
355
359
|
* @example
|
|
360
|
+
* // Video-scoped Q&A
|
|
361
|
+
* const stream = await bold.ai.chat({ videoId: "vid_xyz", prompt: "What does she mean?" });
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
356
364
|
* // Non-streaming
|
|
357
|
-
* const response = await bold.ai.
|
|
365
|
+
* const response = await bold.ai.chat({ prompt: "How do I price my SaaS?", stream: false });
|
|
358
366
|
* console.log(response.content);
|
|
359
367
|
*/
|
|
368
|
+
chat(options: ChatOptions & {
|
|
369
|
+
stream: false;
|
|
370
|
+
}): Promise<AIResponse>;
|
|
371
|
+
chat(options: ChatOptions & {
|
|
372
|
+
stream?: true;
|
|
373
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
374
|
+
chat(options: ChatOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
375
|
+
/**
|
|
376
|
+
* @deprecated Use chat() instead. Will be removed in a future version.
|
|
377
|
+
*/
|
|
360
378
|
ask(options: AskOptions & {
|
|
361
379
|
stream: false;
|
|
362
380
|
}): Promise<AIResponse>;
|
|
@@ -365,7 +383,7 @@ interface AIClient {
|
|
|
365
383
|
}): Promise<AsyncIterable<AIEvent>>;
|
|
366
384
|
ask(options: AskOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
367
385
|
/**
|
|
368
|
-
*
|
|
386
|
+
* @deprecated Use chat() instead. Will be removed in a future version.
|
|
369
387
|
*/
|
|
370
388
|
coach(options: AskOptions & {
|
|
371
389
|
stream: false;
|
|
@@ -391,36 +409,30 @@ interface AIClient {
|
|
|
391
409
|
}): Promise<AsyncIterable<AIEvent>>;
|
|
392
410
|
search(options: SearchOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
393
411
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* @example
|
|
397
|
-
* const stream = await bold.ai.chat("video-id", { prompt: "What is discussed at 5 minutes?" });
|
|
398
|
-
* for await (const event of stream) {
|
|
399
|
-
* if (event.type === "text_delta") process.stdout.write(event.delta);
|
|
400
|
-
* }
|
|
401
|
-
*/
|
|
402
|
-
chat(videoId: string, options: ChatOptions & {
|
|
403
|
-
stream: false;
|
|
404
|
-
}): Promise<AIResponse>;
|
|
405
|
-
chat(videoId: string, options: ChatOptions & {
|
|
406
|
-
stream?: true;
|
|
407
|
-
}): Promise<AsyncIterable<AIEvent>>;
|
|
408
|
-
chat(videoId: string, options: ChatOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
409
|
-
/**
|
|
410
|
-
* Recommend - AI-powered video recommendations
|
|
412
|
+
* Recommendations - AI-powered video recommendations
|
|
411
413
|
*
|
|
412
414
|
* @example
|
|
413
415
|
* // Streaming (default)
|
|
414
|
-
* const stream = await bold.ai.
|
|
416
|
+
* const stream = await bold.ai.recommendations({ topics: ["sales", "negotiation"] });
|
|
415
417
|
* for await (const event of stream) {
|
|
416
418
|
* if (event.type === "recommendations") console.log(event.recommendations);
|
|
417
419
|
* }
|
|
418
420
|
*
|
|
419
421
|
* @example
|
|
420
422
|
* // Non-streaming
|
|
421
|
-
* const response = await bold.ai.
|
|
423
|
+
* const response = await bold.ai.recommendations({ topics: ["sales"], stream: false });
|
|
422
424
|
* console.log(response.guidance);
|
|
423
425
|
*/
|
|
426
|
+
recommendations(options: RecommendationsOptions & {
|
|
427
|
+
stream: false;
|
|
428
|
+
}): Promise<RecommendationsResponse>;
|
|
429
|
+
recommendations(options: RecommendationsOptions & {
|
|
430
|
+
stream?: true;
|
|
431
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
432
|
+
recommendations(options: RecommendationsOptions): Promise<AsyncIterable<AIEvent> | RecommendationsResponse>;
|
|
433
|
+
/**
|
|
434
|
+
* @deprecated Use recommendations() instead. Will be removed in a future version.
|
|
435
|
+
*/
|
|
424
436
|
recommend(options: RecommendOptions & {
|
|
425
437
|
stream: false;
|
|
426
438
|
}): Promise<RecommendResponse>;
|
|
@@ -472,4 +484,4 @@ declare const DEFAULT_API_BASE_URL = "https://app.boldvideo.io/api/v1/";
|
|
|
472
484
|
*/
|
|
473
485
|
declare const DEFAULT_INTERNAL_API_BASE_URL = "https://app.boldvideo.io/i/v1/";
|
|
474
486
|
|
|
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,
|
|
487
|
+
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, RecommendationsOptions, RecommendationsResponse, SearchOptions, Settings, Source, ThemeColors, ThemeConfig, Video, VideoAttachment, VideoDownloadUrls, VideoMetadata, VideoSubtitles, VideoTranscript, createClient };
|
package/dist/index.js
CHANGED
|
@@ -212,7 +212,7 @@ async function* parseSSE(response) {
|
|
|
212
212
|
try {
|
|
213
213
|
const event = JSON.parse(json);
|
|
214
214
|
yield event;
|
|
215
|
-
if (event.type === "
|
|
215
|
+
if (event.type === "message_complete" || event.type === "error") {
|
|
216
216
|
await reader.cancel();
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
@@ -263,19 +263,29 @@ async function jsonRequest(path, body, config) {
|
|
|
263
263
|
return response.json();
|
|
264
264
|
}
|
|
265
265
|
function createAI(config) {
|
|
266
|
-
async function
|
|
267
|
-
const
|
|
266
|
+
async function chat(options) {
|
|
267
|
+
const isVideoScoped = !!options.videoId;
|
|
268
|
+
const basePath = isVideoScoped ? `ai/videos/${options.videoId}/chat` : "ai/chat";
|
|
269
|
+
const path = options.conversationId ? `${basePath}/${options.conversationId}` : basePath;
|
|
268
270
|
const body = { prompt: options.prompt };
|
|
269
271
|
if (options.collectionId)
|
|
270
272
|
body.collection_id = options.collectionId;
|
|
273
|
+
if (options.tags)
|
|
274
|
+
body.tags = options.tags;
|
|
275
|
+
if (isVideoScoped && options.currentTime !== void 0) {
|
|
276
|
+
body.current_time = options.currentTime;
|
|
277
|
+
}
|
|
271
278
|
if (options.stream === false) {
|
|
272
279
|
body.stream = false;
|
|
273
280
|
return jsonRequest(path, body, config);
|
|
274
281
|
}
|
|
275
282
|
return streamRequest(path, body, config);
|
|
276
283
|
}
|
|
284
|
+
async function ask(options) {
|
|
285
|
+
return chat(options);
|
|
286
|
+
}
|
|
277
287
|
async function coach(options) {
|
|
278
|
-
return
|
|
288
|
+
return chat(options);
|
|
279
289
|
}
|
|
280
290
|
async function search(options) {
|
|
281
291
|
const path = "ai/search";
|
|
@@ -286,6 +296,8 @@ function createAI(config) {
|
|
|
286
296
|
body.collection_id = options.collectionId;
|
|
287
297
|
if (options.videoId)
|
|
288
298
|
body.video_id = options.videoId;
|
|
299
|
+
if (options.tags)
|
|
300
|
+
body.tags = options.tags;
|
|
289
301
|
if (options.context)
|
|
290
302
|
body.context = options.context;
|
|
291
303
|
if (options.stream === false) {
|
|
@@ -294,17 +306,8 @@ function createAI(config) {
|
|
|
294
306
|
}
|
|
295
307
|
return streamRequest(path, body, config);
|
|
296
308
|
}
|
|
297
|
-
async function
|
|
298
|
-
const path =
|
|
299
|
-
const body = { prompt: options.prompt };
|
|
300
|
-
if (options.stream === false) {
|
|
301
|
-
body.stream = false;
|
|
302
|
-
return jsonRequest(path, body, config);
|
|
303
|
-
}
|
|
304
|
-
return streamRequest(path, body, config);
|
|
305
|
-
}
|
|
306
|
-
async function recommend(options) {
|
|
307
|
-
const path = "ai/recommend";
|
|
309
|
+
async function recommendations(options) {
|
|
310
|
+
const path = "ai/recommendations";
|
|
308
311
|
const body = { topics: options.topics };
|
|
309
312
|
if (options.limit)
|
|
310
313
|
body.limit = options.limit;
|
|
@@ -312,8 +315,8 @@ function createAI(config) {
|
|
|
312
315
|
body.collection_id = options.collectionId;
|
|
313
316
|
if (options.tags)
|
|
314
317
|
body.tags = options.tags;
|
|
315
|
-
if (options.
|
|
316
|
-
body.
|
|
318
|
+
if (options.includeGuidance !== void 0)
|
|
319
|
+
body.include_guidance = options.includeGuidance;
|
|
317
320
|
if (options.context)
|
|
318
321
|
body.context = options.context;
|
|
319
322
|
if (options.stream === false) {
|
|
@@ -322,11 +325,15 @@ function createAI(config) {
|
|
|
322
325
|
}
|
|
323
326
|
return streamRequest(path, body, config);
|
|
324
327
|
}
|
|
328
|
+
async function recommend(options) {
|
|
329
|
+
return recommendations(options);
|
|
330
|
+
}
|
|
325
331
|
return {
|
|
332
|
+
chat,
|
|
326
333
|
ask,
|
|
327
334
|
coach,
|
|
328
335
|
search,
|
|
329
|
-
|
|
336
|
+
recommendations,
|
|
330
337
|
recommend
|
|
331
338
|
};
|
|
332
339
|
}
|
package/llms.txt
CHANGED
|
@@ -14,11 +14,11 @@ const videos = await bold.videos.list();
|
|
|
14
14
|
const video = await bold.videos.get('video-id');
|
|
15
15
|
|
|
16
16
|
// AI-powered recommendations
|
|
17
|
-
const recs = await bold.ai.
|
|
17
|
+
const recs = await bold.ai.recommendations({ topics: ['sales', 'negotiation'], stream: false });
|
|
18
18
|
console.log(recs.guidance);
|
|
19
19
|
|
|
20
20
|
// AI streaming
|
|
21
|
-
const stream = await bold.ai.
|
|
21
|
+
const stream = await bold.ai.chat({ prompt: 'How do I price my SaaS?' });
|
|
22
22
|
for await (const event of stream) {
|
|
23
23
|
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
24
24
|
}
|
|
@@ -43,11 +43,14 @@ for await (const event of stream) {
|
|
|
43
43
|
|
|
44
44
|
All AI methods return `AsyncIterable<AIEvent>` (streaming) or `Promise<AIResponse>` (non-streaming).
|
|
45
45
|
|
|
46
|
-
- `bold.ai.
|
|
47
|
-
- `bold.ai.coach(options)` - Library-wide RAG assistant (alias: `ask`)
|
|
48
|
-
- `bold.ai.ask(options)` - Library-wide RAG assistant
|
|
46
|
+
- `bold.ai.chat(options)` - Conversational AI for Q&A (pass `videoId` to scope to a video)
|
|
49
47
|
- `bold.ai.search(options)` - Semantic search with synthesis
|
|
50
|
-
- `bold.ai.
|
|
48
|
+
- `bold.ai.recommendations(options)` - AI-powered video recommendations based on topics
|
|
49
|
+
|
|
50
|
+
**Deprecated aliases** (still work but will be removed):
|
|
51
|
+
- `bold.ai.ask(options)` → use `chat()`
|
|
52
|
+
- `bold.ai.coach(options)` → use `chat()`
|
|
53
|
+
- `bold.ai.recommend(options)` → use `recommendations()`
|
|
51
54
|
|
|
52
55
|
### Analytics
|
|
53
56
|
|
|
@@ -56,28 +59,17 @@ All AI methods return `AsyncIterable<AIEvent>` (streaming) or `Promise<AIRespons
|
|
|
56
59
|
|
|
57
60
|
## AI Options
|
|
58
61
|
|
|
59
|
-
###
|
|
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
|
|
62
|
+
### ChatOptions
|
|
74
63
|
|
|
75
64
|
```typescript
|
|
76
65
|
{
|
|
77
66
|
prompt: string; // Question to ask (required)
|
|
78
67
|
stream?: boolean; // Default: true
|
|
68
|
+
videoId?: string; // If set, scope to this video
|
|
69
|
+
currentTime?: number; // Current playback position (with videoId)
|
|
79
70
|
conversationId?: string; // Continue existing conversation
|
|
80
71
|
collectionId?: string; // Filter to collection
|
|
72
|
+
tags?: string[]; // Filter by tags
|
|
81
73
|
}
|
|
82
74
|
```
|
|
83
75
|
|
|
@@ -90,17 +82,22 @@ All AI methods return `AsyncIterable<AIEvent>` (streaming) or `Promise<AIRespons
|
|
|
90
82
|
limit?: number; // Max results
|
|
91
83
|
collectionId?: string; // Filter to collection
|
|
92
84
|
videoId?: string; // Search within specific video
|
|
85
|
+
tags?: string[]; // Filter by tags
|
|
93
86
|
context?: AIContextMessage[]; // Conversation context
|
|
94
87
|
}
|
|
95
88
|
```
|
|
96
89
|
|
|
97
|
-
###
|
|
90
|
+
### RecommendationsOptions
|
|
98
91
|
|
|
99
92
|
```typescript
|
|
100
93
|
{
|
|
101
|
-
|
|
94
|
+
topics: string[]; // Topics to find content for (required)
|
|
102
95
|
stream?: boolean; // Default: true
|
|
103
|
-
|
|
96
|
+
limit?: number; // Max videos per topic (default: 5, max: 20)
|
|
97
|
+
collectionId?: string; // Filter to collection
|
|
98
|
+
tags?: string[]; // Filter by tags
|
|
99
|
+
includeGuidance?: boolean; // Include AI learning path narrative (default: true)
|
|
100
|
+
context?: AIContextMessage[]; // Previous conversation turns for follow-ups
|
|
104
101
|
}
|
|
105
102
|
```
|
|
106
103
|
|
|
@@ -110,8 +107,8 @@ Key types exported:
|
|
|
110
107
|
|
|
111
108
|
- `Video`, `Playlist`, `Settings`, `Portal`
|
|
112
109
|
- `AIEvent`, `AIResponse`, `Source`, `AIUsage`
|
|
113
|
-
- `
|
|
114
|
-
- `
|
|
110
|
+
- `ChatOptions`, `SearchOptions`
|
|
111
|
+
- `RecommendationsOptions`, `RecommendationsResponse`, `Recommendation`, `RecommendationVideo`
|
|
115
112
|
|
|
116
113
|
## Links
|
|
117
114
|
|