@boldvideo/bold-js 0.9.0 → 1.0.1
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 +24 -0
- package/dist/index.cjs +64 -36
- package/dist/index.d.ts +159 -32
- package/dist/index.js +64 -36
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @boldvideo/bold-js
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 844d6f1: Add persona and ai_search types to Account settings
|
|
8
|
+
|
|
9
|
+
- Added `Persona` type (discriminated union based on `enabled` flag)
|
|
10
|
+
- Added `AccountAISearch` type with `enabled` boolean
|
|
11
|
+
- Updated `Account` type to include `ai_search` and `persona` fields
|
|
12
|
+
|
|
13
|
+
## 1.0.0
|
|
14
|
+
|
|
15
|
+
### Major Changes
|
|
16
|
+
|
|
17
|
+
- 8afb7b3: Breaking: Unified AI API
|
|
18
|
+
|
|
19
|
+
- New methods: `bold.ai.ask()`, `bold.ai.search()`, `bold.ai.chat(videoId, opts)`
|
|
20
|
+
- `bold.ai.coach()` is now an alias for `bold.ai.ask()`
|
|
21
|
+
- New parameter: `prompt` replaces `message`
|
|
22
|
+
- New parameter: `stream` (boolean, default: true) for non-streaming responses
|
|
23
|
+
- New event types: `message_start`, `text_delta`, `sources`, `message_complete`
|
|
24
|
+
- New types: `AIEvent`, `AIResponse`, `Source`, `AIUsage`, `SearchOptions`, `ChatOptions`
|
|
25
|
+
- Removed: `CoachEvent`, `Citation`, `Usage`, `CoachOptions` (old `AskOptions`)
|
|
26
|
+
|
|
3
27
|
## 0.9.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -247,7 +247,7 @@ async function* parseSSE(response) {
|
|
|
247
247
|
try {
|
|
248
248
|
const event = JSON.parse(json);
|
|
249
249
|
yield event;
|
|
250
|
-
if (event.type === "
|
|
250
|
+
if (event.type === "message_complete" || event.type === "error") {
|
|
251
251
|
await reader.cancel();
|
|
252
252
|
return;
|
|
253
253
|
}
|
|
@@ -259,9 +259,12 @@ async function* parseSSE(response) {
|
|
|
259
259
|
reader.releaseLock();
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
|
+
function buildURL(baseURL, path) {
|
|
263
|
+
const base = baseURL.endsWith("/") ? baseURL : `${baseURL}/`;
|
|
264
|
+
return new URL(path, base);
|
|
265
|
+
}
|
|
262
266
|
async function streamRequest(path, body, config) {
|
|
263
|
-
const
|
|
264
|
-
const url = new URL(path, baseURL);
|
|
267
|
+
const url = buildURL(config.baseURL, path);
|
|
265
268
|
const response = await fetch(url, {
|
|
266
269
|
method: "POST",
|
|
267
270
|
headers: {
|
|
@@ -276,41 +279,66 @@ async function streamRequest(path, body, config) {
|
|
|
276
279
|
}
|
|
277
280
|
return parseSSE(response);
|
|
278
281
|
}
|
|
279
|
-
function
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* const stream = await bold.ai.coach({ message: "How do I price my SaaS?" });
|
|
288
|
-
* for await (const event of stream) {
|
|
289
|
-
* if (event.type === "token") console.log(event.content);
|
|
290
|
-
* }
|
|
291
|
-
*/
|
|
292
|
-
async coach(options) {
|
|
293
|
-
const path = options.conversationId ? `coach/${options.conversationId}` : "coach";
|
|
294
|
-
const body = { message: options.message };
|
|
295
|
-
if (options.collectionId)
|
|
296
|
-
body.collection_id = options.collectionId;
|
|
297
|
-
return streamRequest(path, body, config);
|
|
282
|
+
async function jsonRequest(path, body, config) {
|
|
283
|
+
const url = buildURL(config.baseURL, path);
|
|
284
|
+
const response = await fetch(url, {
|
|
285
|
+
method: "POST",
|
|
286
|
+
headers: {
|
|
287
|
+
"Content-Type": "application/json",
|
|
288
|
+
"Accept": "application/json",
|
|
289
|
+
...config.headers
|
|
298
290
|
},
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
291
|
+
body: JSON.stringify(body)
|
|
292
|
+
});
|
|
293
|
+
if (!response.ok) {
|
|
294
|
+
throw new Error(`AI request failed: ${response.status} ${response.statusText}`);
|
|
295
|
+
}
|
|
296
|
+
return response.json();
|
|
297
|
+
}
|
|
298
|
+
function createAI(config) {
|
|
299
|
+
async function ask(options) {
|
|
300
|
+
const path = options.conversationId ? `ai/ask/${options.conversationId}` : "ai/ask";
|
|
301
|
+
const body = { prompt: options.prompt };
|
|
302
|
+
if (options.collectionId)
|
|
303
|
+
body.collection_id = options.collectionId;
|
|
304
|
+
if (options.stream === false) {
|
|
305
|
+
body.stream = false;
|
|
306
|
+
return jsonRequest(path, body, config);
|
|
313
307
|
}
|
|
308
|
+
return streamRequest(path, body, config);
|
|
309
|
+
}
|
|
310
|
+
async function coach(options) {
|
|
311
|
+
return ask(options);
|
|
312
|
+
}
|
|
313
|
+
async function search(options) {
|
|
314
|
+
const path = "ai/search";
|
|
315
|
+
const body = { prompt: options.prompt };
|
|
316
|
+
if (options.limit)
|
|
317
|
+
body.limit = options.limit;
|
|
318
|
+
if (options.collectionId)
|
|
319
|
+
body.collection_id = options.collectionId;
|
|
320
|
+
if (options.videoId)
|
|
321
|
+
body.video_id = options.videoId;
|
|
322
|
+
if (options.stream === false) {
|
|
323
|
+
body.stream = false;
|
|
324
|
+
return jsonRequest(path, body, config);
|
|
325
|
+
}
|
|
326
|
+
return streamRequest(path, body, config);
|
|
327
|
+
}
|
|
328
|
+
async function chat(videoId, options) {
|
|
329
|
+
const path = options.conversationId ? `ai/videos/${videoId}/chat/${options.conversationId}` : `ai/videos/${videoId}/chat`;
|
|
330
|
+
const body = { prompt: options.prompt };
|
|
331
|
+
if (options.stream === false) {
|
|
332
|
+
body.stream = false;
|
|
333
|
+
return jsonRequest(path, body, config);
|
|
334
|
+
}
|
|
335
|
+
return streamRequest(path, body, config);
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
ask,
|
|
339
|
+
coach,
|
|
340
|
+
search,
|
|
341
|
+
chat
|
|
314
342
|
};
|
|
315
343
|
}
|
|
316
344
|
|
package/dist/index.d.ts
CHANGED
|
@@ -133,9 +133,24 @@ type AccountAI = {
|
|
|
133
133
|
greeting: string;
|
|
134
134
|
name: string;
|
|
135
135
|
};
|
|
136
|
+
type AccountAISearch = {
|
|
137
|
+
enabled: boolean;
|
|
138
|
+
};
|
|
139
|
+
type PersonaEnabled = {
|
|
140
|
+
enabled: true;
|
|
141
|
+
name: string;
|
|
142
|
+
greeting: string;
|
|
143
|
+
conversation_starters: string[];
|
|
144
|
+
};
|
|
145
|
+
type PersonaDisabled = {
|
|
146
|
+
enabled: false;
|
|
147
|
+
};
|
|
148
|
+
type Persona = PersonaEnabled | PersonaDisabled;
|
|
136
149
|
type Account = {
|
|
137
150
|
ai: AccountAI;
|
|
151
|
+
ai_search: AccountAISearch;
|
|
138
152
|
name: string;
|
|
153
|
+
persona: Persona;
|
|
139
154
|
slug: string;
|
|
140
155
|
};
|
|
141
156
|
type Settings = {
|
|
@@ -162,49 +177,164 @@ type Settings = {
|
|
|
162
177
|
theme_config: ThemeConfig;
|
|
163
178
|
version: string;
|
|
164
179
|
};
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Source citation from AI responses
|
|
182
|
+
*/
|
|
183
|
+
interface Source {
|
|
184
|
+
video_id: string;
|
|
185
|
+
title: string;
|
|
186
|
+
timestamp: number;
|
|
187
|
+
timestamp_end?: number;
|
|
169
188
|
text: string;
|
|
189
|
+
playback_id?: string;
|
|
190
|
+
speaker?: string;
|
|
170
191
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Token usage statistics
|
|
194
|
+
*/
|
|
195
|
+
interface AIUsage {
|
|
196
|
+
prompt_tokens: number;
|
|
197
|
+
completion_tokens: number;
|
|
198
|
+
total_tokens: number;
|
|
174
199
|
}
|
|
175
|
-
|
|
176
|
-
|
|
200
|
+
/**
|
|
201
|
+
* SSE event types for AI streaming responses
|
|
202
|
+
*/
|
|
203
|
+
type AIEvent = {
|
|
204
|
+
type: "message_start";
|
|
177
205
|
id: string;
|
|
178
|
-
|
|
206
|
+
model?: string;
|
|
207
|
+
} | {
|
|
208
|
+
type: "sources";
|
|
209
|
+
sources: Source[];
|
|
210
|
+
} | {
|
|
211
|
+
type: "text_delta";
|
|
212
|
+
delta: string;
|
|
179
213
|
} | {
|
|
180
214
|
type: "clarification";
|
|
181
215
|
questions: string[];
|
|
182
|
-
mode: "clarification";
|
|
183
|
-
needs_clarification: true;
|
|
184
|
-
} | {
|
|
185
|
-
type: "token";
|
|
186
|
-
content: string;
|
|
187
216
|
} | {
|
|
188
|
-
type: "
|
|
217
|
+
type: "message_complete";
|
|
189
218
|
content: string;
|
|
190
|
-
|
|
191
|
-
usage:
|
|
219
|
+
sources: Source[];
|
|
220
|
+
usage: AIUsage;
|
|
192
221
|
} | {
|
|
193
222
|
type: "error";
|
|
223
|
+
code: string;
|
|
194
224
|
message: string;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
timestamp: string;
|
|
198
|
-
} | {
|
|
199
|
-
type: "complete";
|
|
225
|
+
retryable: boolean;
|
|
226
|
+
details?: Record<string, unknown>;
|
|
200
227
|
};
|
|
201
|
-
|
|
202
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Non-streaming AI response
|
|
230
|
+
*/
|
|
231
|
+
interface AIResponse {
|
|
232
|
+
id: string;
|
|
233
|
+
content: string;
|
|
234
|
+
sources: Source[];
|
|
235
|
+
usage: AIUsage;
|
|
236
|
+
model?: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Options for bold.ai.ask() and bold.ai.coach()
|
|
240
|
+
*/
|
|
241
|
+
interface AskOptions {
|
|
242
|
+
prompt: string;
|
|
243
|
+
stream?: boolean;
|
|
203
244
|
conversationId?: string;
|
|
204
245
|
collectionId?: string;
|
|
205
246
|
}
|
|
206
|
-
|
|
207
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Options for bold.ai.search()
|
|
249
|
+
*/
|
|
250
|
+
interface SearchOptions {
|
|
251
|
+
prompt: string;
|
|
252
|
+
stream?: boolean;
|
|
253
|
+
limit?: number;
|
|
254
|
+
collectionId?: string;
|
|
255
|
+
videoId?: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Options for bold.ai.chat()
|
|
259
|
+
*
|
|
260
|
+
* conversationId: Pass to continue an existing conversation (multi-turn chat).
|
|
261
|
+
* If omitted, a new conversation is created. The id is returned in the
|
|
262
|
+
* message_start event - capture it to pass to subsequent requests.
|
|
263
|
+
*/
|
|
264
|
+
interface ChatOptions {
|
|
265
|
+
prompt: string;
|
|
266
|
+
stream?: boolean;
|
|
267
|
+
conversationId?: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* AI client interface for type-safe method overloading
|
|
272
|
+
*/
|
|
273
|
+
interface AIClient {
|
|
274
|
+
/**
|
|
275
|
+
* Ask - Library-wide RAG assistant
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* // Streaming (default)
|
|
279
|
+
* const stream = await bold.ai.ask({ prompt: "How do I price my SaaS?" });
|
|
280
|
+
* for await (const event of stream) {
|
|
281
|
+
* if (event.type === "text_delta") process.stdout.write(event.delta);
|
|
282
|
+
* }
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* // Non-streaming
|
|
286
|
+
* const response = await bold.ai.ask({ prompt: "How do I price my SaaS?", stream: false });
|
|
287
|
+
* console.log(response.content);
|
|
288
|
+
*/
|
|
289
|
+
ask(options: AskOptions & {
|
|
290
|
+
stream: false;
|
|
291
|
+
}): Promise<AIResponse>;
|
|
292
|
+
ask(options: AskOptions & {
|
|
293
|
+
stream?: true;
|
|
294
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
295
|
+
ask(options: AskOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
296
|
+
/**
|
|
297
|
+
* Coach - Alias for ask() (Library-wide RAG assistant)
|
|
298
|
+
*/
|
|
299
|
+
coach(options: AskOptions & {
|
|
300
|
+
stream: false;
|
|
301
|
+
}): Promise<AIResponse>;
|
|
302
|
+
coach(options: AskOptions & {
|
|
303
|
+
stream?: true;
|
|
304
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
305
|
+
coach(options: AskOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
306
|
+
/**
|
|
307
|
+
* Search - Semantic search with light synthesis
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* const stream = await bold.ai.search({ prompt: "pricing strategies", limit: 10 });
|
|
311
|
+
* for await (const event of stream) {
|
|
312
|
+
* if (event.type === "sources") console.log("Found:", event.sources.length, "results");
|
|
313
|
+
* }
|
|
314
|
+
*/
|
|
315
|
+
search(options: SearchOptions & {
|
|
316
|
+
stream: false;
|
|
317
|
+
}): Promise<AIResponse>;
|
|
318
|
+
search(options: SearchOptions & {
|
|
319
|
+
stream?: true;
|
|
320
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
321
|
+
search(options: SearchOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
322
|
+
/**
|
|
323
|
+
* Chat - Video-scoped conversation
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* const stream = await bold.ai.chat("video-id", { prompt: "What is discussed at 5 minutes?" });
|
|
327
|
+
* for await (const event of stream) {
|
|
328
|
+
* if (event.type === "text_delta") process.stdout.write(event.delta);
|
|
329
|
+
* }
|
|
330
|
+
*/
|
|
331
|
+
chat(videoId: string, options: ChatOptions & {
|
|
332
|
+
stream: false;
|
|
333
|
+
}): Promise<AIResponse>;
|
|
334
|
+
chat(videoId: string, options: ChatOptions & {
|
|
335
|
+
stream?: true;
|
|
336
|
+
}): Promise<AsyncIterable<AIEvent>>;
|
|
337
|
+
chat(videoId: string, options: ChatOptions): Promise<AsyncIterable<AIEvent> | AIResponse>;
|
|
208
338
|
}
|
|
209
339
|
|
|
210
340
|
type ClientOptions = {
|
|
@@ -235,10 +365,7 @@ declare function createClient(apiKey: string, options?: ClientOptions): {
|
|
|
235
365
|
data: Playlist;
|
|
236
366
|
}>;
|
|
237
367
|
};
|
|
238
|
-
ai:
|
|
239
|
-
coach(options: CoachOptions): Promise<AsyncIterable<CoachEvent>>;
|
|
240
|
-
ask(videoId: string, options: AskOptions): Promise<AsyncIterable<CoachEvent>>;
|
|
241
|
-
};
|
|
368
|
+
ai: AIClient;
|
|
242
369
|
trackEvent: (video: any, event: Event) => void;
|
|
243
370
|
trackPageView: (title: string) => void;
|
|
244
371
|
};
|
|
@@ -252,4 +379,4 @@ declare const DEFAULT_API_BASE_URL = "https://app.boldvideo.io/api/v1/";
|
|
|
252
379
|
*/
|
|
253
380
|
declare const DEFAULT_INTERNAL_API_BASE_URL = "https://app.boldvideo.io/i/v1/";
|
|
254
381
|
|
|
255
|
-
export { Account, AccountAI, AskOptions, AssistantConfig,
|
|
382
|
+
export { 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 };
|
package/dist/index.js
CHANGED
|
@@ -209,7 +209,7 @@ async function* parseSSE(response) {
|
|
|
209
209
|
try {
|
|
210
210
|
const event = JSON.parse(json);
|
|
211
211
|
yield event;
|
|
212
|
-
if (event.type === "
|
|
212
|
+
if (event.type === "message_complete" || event.type === "error") {
|
|
213
213
|
await reader.cancel();
|
|
214
214
|
return;
|
|
215
215
|
}
|
|
@@ -221,9 +221,12 @@ async function* parseSSE(response) {
|
|
|
221
221
|
reader.releaseLock();
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
+
function buildURL(baseURL, path) {
|
|
225
|
+
const base = baseURL.endsWith("/") ? baseURL : `${baseURL}/`;
|
|
226
|
+
return new URL(path, base);
|
|
227
|
+
}
|
|
224
228
|
async function streamRequest(path, body, config) {
|
|
225
|
-
const
|
|
226
|
-
const url = new URL(path, baseURL);
|
|
229
|
+
const url = buildURL(config.baseURL, path);
|
|
227
230
|
const response = await fetch(url, {
|
|
228
231
|
method: "POST",
|
|
229
232
|
headers: {
|
|
@@ -238,41 +241,66 @@ async function streamRequest(path, body, config) {
|
|
|
238
241
|
}
|
|
239
242
|
return parseSSE(response);
|
|
240
243
|
}
|
|
241
|
-
function
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
* const stream = await bold.ai.coach({ message: "How do I price my SaaS?" });
|
|
250
|
-
* for await (const event of stream) {
|
|
251
|
-
* if (event.type === "token") console.log(event.content);
|
|
252
|
-
* }
|
|
253
|
-
*/
|
|
254
|
-
async coach(options) {
|
|
255
|
-
const path = options.conversationId ? `coach/${options.conversationId}` : "coach";
|
|
256
|
-
const body = { message: options.message };
|
|
257
|
-
if (options.collectionId)
|
|
258
|
-
body.collection_id = options.collectionId;
|
|
259
|
-
return streamRequest(path, body, config);
|
|
244
|
+
async function jsonRequest(path, body, config) {
|
|
245
|
+
const url = buildURL(config.baseURL, path);
|
|
246
|
+
const response = await fetch(url, {
|
|
247
|
+
method: "POST",
|
|
248
|
+
headers: {
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
"Accept": "application/json",
|
|
251
|
+
...config.headers
|
|
260
252
|
},
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
253
|
+
body: JSON.stringify(body)
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
throw new Error(`AI request failed: ${response.status} ${response.statusText}`);
|
|
257
|
+
}
|
|
258
|
+
return response.json();
|
|
259
|
+
}
|
|
260
|
+
function createAI(config) {
|
|
261
|
+
async function ask(options) {
|
|
262
|
+
const path = options.conversationId ? `ai/ask/${options.conversationId}` : "ai/ask";
|
|
263
|
+
const body = { prompt: options.prompt };
|
|
264
|
+
if (options.collectionId)
|
|
265
|
+
body.collection_id = options.collectionId;
|
|
266
|
+
if (options.stream === false) {
|
|
267
|
+
body.stream = false;
|
|
268
|
+
return jsonRequest(path, body, config);
|
|
275
269
|
}
|
|
270
|
+
return streamRequest(path, body, config);
|
|
271
|
+
}
|
|
272
|
+
async function coach(options) {
|
|
273
|
+
return ask(options);
|
|
274
|
+
}
|
|
275
|
+
async function search(options) {
|
|
276
|
+
const path = "ai/search";
|
|
277
|
+
const body = { prompt: options.prompt };
|
|
278
|
+
if (options.limit)
|
|
279
|
+
body.limit = options.limit;
|
|
280
|
+
if (options.collectionId)
|
|
281
|
+
body.collection_id = options.collectionId;
|
|
282
|
+
if (options.videoId)
|
|
283
|
+
body.video_id = options.videoId;
|
|
284
|
+
if (options.stream === false) {
|
|
285
|
+
body.stream = false;
|
|
286
|
+
return jsonRequest(path, body, config);
|
|
287
|
+
}
|
|
288
|
+
return streamRequest(path, body, config);
|
|
289
|
+
}
|
|
290
|
+
async function chat(videoId, options) {
|
|
291
|
+
const path = options.conversationId ? `ai/videos/${videoId}/chat/${options.conversationId}` : `ai/videos/${videoId}/chat`;
|
|
292
|
+
const body = { prompt: options.prompt };
|
|
293
|
+
if (options.stream === false) {
|
|
294
|
+
body.stream = false;
|
|
295
|
+
return jsonRequest(path, body, config);
|
|
296
|
+
}
|
|
297
|
+
return streamRequest(path, body, config);
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
ask,
|
|
301
|
+
coach,
|
|
302
|
+
search,
|
|
303
|
+
chat
|
|
276
304
|
};
|
|
277
305
|
}
|
|
278
306
|
|