@push.rocks/smartai 0.13.3 → 2.0.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.
Files changed (98) hide show
  1. package/dist_ts/00_commitinfo_data.js +3 -3
  2. package/dist_ts/index.d.ts +6 -11
  3. package/dist_ts/index.js +6 -12
  4. package/dist_ts/plugins.d.ts +10 -15
  5. package/dist_ts/plugins.js +13 -19
  6. package/dist_ts/smartai.classes.smartai.d.ts +7 -0
  7. package/dist_ts/smartai.classes.smartai.js +51 -0
  8. package/dist_ts/smartai.interfaces.d.ts +41 -0
  9. package/dist_ts/smartai.interfaces.js +2 -0
  10. package/dist_ts/smartai.middleware.anthropic.d.ts +7 -0
  11. package/dist_ts/smartai.middleware.anthropic.js +36 -0
  12. package/dist_ts/smartai.provider.ollama.d.ts +8 -0
  13. package/dist_ts/smartai.provider.ollama.js +378 -0
  14. package/dist_ts_audio/index.d.ts +9 -0
  15. package/dist_ts_audio/index.js +15 -0
  16. package/dist_ts_audio/plugins.d.ts +2 -0
  17. package/dist_ts_audio/plugins.js +3 -0
  18. package/dist_ts_document/index.d.ts +11 -0
  19. package/dist_ts_document/index.js +45 -0
  20. package/dist_ts_document/plugins.d.ts +3 -0
  21. package/dist_ts_document/plugins.js +4 -0
  22. package/dist_ts_image/index.d.ts +46 -0
  23. package/dist_ts_image/index.js +110 -0
  24. package/dist_ts_image/plugins.d.ts +3 -0
  25. package/dist_ts_image/plugins.js +4 -0
  26. package/dist_ts_research/index.d.ts +19 -0
  27. package/dist_ts_research/index.js +98 -0
  28. package/dist_ts_research/plugins.d.ts +2 -0
  29. package/dist_ts_research/plugins.js +3 -0
  30. package/dist_ts_vision/index.d.ts +8 -0
  31. package/dist_ts_vision/index.js +21 -0
  32. package/dist_ts_vision/plugins.d.ts +2 -0
  33. package/dist_ts_vision/plugins.js +3 -0
  34. package/package.json +50 -22
  35. package/readme.hints.md +34 -88
  36. package/readme.md +284 -547
  37. package/ts/00_commitinfo_data.ts +2 -2
  38. package/ts/index.ts +8 -11
  39. package/ts/plugins.ts +19 -35
  40. package/ts/smartai.classes.smartai.ts +51 -0
  41. package/ts/smartai.interfaces.ts +53 -0
  42. package/ts/smartai.middleware.anthropic.ts +38 -0
  43. package/ts/smartai.provider.ollama.ts +426 -0
  44. package/ts_audio/index.ts +24 -0
  45. package/ts_audio/plugins.ts +2 -0
  46. package/ts_document/index.ts +61 -0
  47. package/ts_document/plugins.ts +3 -0
  48. package/ts_image/index.ts +147 -0
  49. package/ts_image/plugins.ts +3 -0
  50. package/ts_research/index.ts +120 -0
  51. package/ts_research/plugins.ts +2 -0
  52. package/ts_vision/index.ts +29 -0
  53. package/ts_vision/plugins.ts +2 -0
  54. package/dist_ts/abstract.classes.multimodal.d.ts +0 -212
  55. package/dist_ts/abstract.classes.multimodal.js +0 -43
  56. package/dist_ts/classes.conversation.d.ts +0 -31
  57. package/dist_ts/classes.conversation.js +0 -150
  58. package/dist_ts/classes.smartai.d.ts +0 -59
  59. package/dist_ts/classes.smartai.js +0 -139
  60. package/dist_ts/classes.tts.d.ts +0 -6
  61. package/dist_ts/classes.tts.js +0 -10
  62. package/dist_ts/interfaces.d.ts +0 -1
  63. package/dist_ts/interfaces.js +0 -2
  64. package/dist_ts/paths.d.ts +0 -2
  65. package/dist_ts/paths.js +0 -4
  66. package/dist_ts/provider.anthropic.d.ts +0 -48
  67. package/dist_ts/provider.anthropic.js +0 -369
  68. package/dist_ts/provider.elevenlabs.d.ts +0 -43
  69. package/dist_ts/provider.elevenlabs.js +0 -64
  70. package/dist_ts/provider.exo.d.ts +0 -40
  71. package/dist_ts/provider.exo.js +0 -116
  72. package/dist_ts/provider.groq.d.ts +0 -39
  73. package/dist_ts/provider.groq.js +0 -178
  74. package/dist_ts/provider.mistral.d.ts +0 -61
  75. package/dist_ts/provider.mistral.js +0 -288
  76. package/dist_ts/provider.ollama.d.ts +0 -141
  77. package/dist_ts/provider.ollama.js +0 -529
  78. package/dist_ts/provider.openai.d.ts +0 -62
  79. package/dist_ts/provider.openai.js +0 -403
  80. package/dist_ts/provider.perplexity.d.ts +0 -37
  81. package/dist_ts/provider.perplexity.js +0 -215
  82. package/dist_ts/provider.xai.d.ts +0 -52
  83. package/dist_ts/provider.xai.js +0 -160
  84. package/ts/abstract.classes.multimodal.ts +0 -240
  85. package/ts/classes.conversation.ts +0 -176
  86. package/ts/classes.smartai.ts +0 -187
  87. package/ts/classes.tts.ts +0 -15
  88. package/ts/interfaces.ts +0 -0
  89. package/ts/paths.ts +0 -4
  90. package/ts/provider.anthropic.ts +0 -446
  91. package/ts/provider.elevenlabs.ts +0 -116
  92. package/ts/provider.exo.ts +0 -155
  93. package/ts/provider.groq.ts +0 -219
  94. package/ts/provider.mistral.ts +0 -352
  95. package/ts/provider.ollama.ts +0 -705
  96. package/ts/provider.openai.ts +0 -462
  97. package/ts/provider.perplexity.ts +0 -259
  98. package/ts/provider.xai.ts +0 -214
@@ -1,462 +0,0 @@
1
- import * as plugins from './plugins.js';
2
- import * as paths from './paths.js';
3
- import { Readable } from 'stream';
4
- import { toFile } from 'openai';
5
-
6
- // Custom type definition for chat completion messages
7
- export type TChatCompletionRequestMessage = {
8
- role: "system" | "user" | "assistant";
9
- content: string;
10
- };
11
-
12
- import { MultiModalModel } from './abstract.classes.multimodal.js';
13
- import type {
14
- ResearchOptions,
15
- ResearchResponse,
16
- ImageGenerateOptions,
17
- ImageEditOptions,
18
- ImageResponse
19
- } from './abstract.classes.multimodal.js';
20
-
21
- export interface IOpenaiProviderOptions {
22
- openaiToken: string;
23
- chatModel?: string;
24
- audioModel?: string;
25
- visionModel?: string;
26
- researchModel?: string;
27
- imageModel?: string;
28
- enableWebSearch?: boolean;
29
- }
30
-
31
- export class OpenAiProvider extends MultiModalModel {
32
- private options: IOpenaiProviderOptions;
33
- public openAiApiClient: plugins.openai.default;
34
-
35
- constructor(optionsArg: IOpenaiProviderOptions) {
36
- super();
37
- this.options = optionsArg;
38
- }
39
-
40
- public async start() {
41
- await super.start();
42
- this.openAiApiClient = new plugins.openai.default({
43
- apiKey: this.options.openaiToken,
44
- dangerouslyAllowBrowser: true,
45
- });
46
- }
47
-
48
- public async stop() {
49
- await super.stop();
50
- }
51
-
52
- public async chatStream(input: ReadableStream<Uint8Array>): Promise<ReadableStream<string>> {
53
- // Create a TextDecoder to handle incoming chunks
54
- const decoder = new TextDecoder();
55
- let buffer = '';
56
- let currentMessage: {
57
- role: "function" | "user" | "system" | "assistant" | "tool" | "developer";
58
- content: string;
59
- } | null = null;
60
-
61
- // Create a TransformStream to process the input
62
- const transform = new TransformStream<Uint8Array, string>({
63
- transform: async (chunk, controller) => {
64
- buffer += decoder.decode(chunk, { stream: true });
65
-
66
- // Try to parse complete JSON messages from the buffer
67
- while (true) {
68
- const newlineIndex = buffer.indexOf('\n');
69
- if (newlineIndex === -1) break;
70
-
71
- const line = buffer.slice(0, newlineIndex);
72
- buffer = buffer.slice(newlineIndex + 1);
73
-
74
- if (line.trim()) {
75
- try {
76
- const message = JSON.parse(line);
77
- currentMessage = {
78
- role: (message.role || 'user') as "function" | "user" | "system" | "assistant" | "tool" | "developer",
79
- content: message.content || '',
80
- };
81
- } catch (e) {
82
- console.error('Failed to parse message:', e);
83
- }
84
- }
85
- }
86
-
87
- // If we have a complete message, send it to OpenAI
88
- if (currentMessage) {
89
- const messageToSend = { role: "user" as const, content: currentMessage.content };
90
- const chatModel = this.options.chatModel ?? 'gpt-5-mini';
91
- const requestParams: any = {
92
- model: chatModel,
93
- messages: [messageToSend],
94
- stream: true,
95
- };
96
- // Temperature is omitted since the model does not support it.
97
- const stream = await this.openAiApiClient.chat.completions.create(requestParams);
98
- // Explicitly cast the stream as an async iterable to satisfy TypeScript.
99
- const streamAsyncIterable = stream as unknown as AsyncIterableIterator<any>;
100
- // Process each chunk from OpenAI
101
- for await (const chunk of streamAsyncIterable) {
102
- const content = chunk.choices[0]?.delta?.content;
103
- if (content) {
104
- controller.enqueue(content);
105
- }
106
- }
107
- currentMessage = null;
108
- }
109
- },
110
-
111
- flush(controller) {
112
- if (buffer) {
113
- try {
114
- const message = JSON.parse(buffer);
115
- controller.enqueue(message.content || '');
116
- } catch (e) {
117
- console.error('Failed to parse remaining buffer:', e);
118
- }
119
- }
120
- }
121
- });
122
-
123
- // Connect the input to our transform stream
124
- return input.pipeThrough(transform);
125
- }
126
-
127
- // Implementing the synchronous chat interaction
128
- public async chat(optionsArg: {
129
- systemMessage: string;
130
- userMessage: string;
131
- messageHistory: {
132
- role: 'assistant' | 'user';
133
- content: string;
134
- }[];
135
- }) {
136
- const chatModel = this.options.chatModel ?? 'gpt-5-mini';
137
- const requestParams: any = {
138
- model: chatModel,
139
- messages: [
140
- { role: 'system', content: optionsArg.systemMessage },
141
- ...optionsArg.messageHistory,
142
- { role: 'user', content: optionsArg.userMessage },
143
- ],
144
- };
145
- // Temperature parameter removed to avoid unsupported error.
146
- const result = await this.openAiApiClient.chat.completions.create(requestParams);
147
- return {
148
- role: result.choices[0].message.role as 'assistant',
149
- message: result.choices[0].message.content,
150
- };
151
- }
152
-
153
- public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
154
- const done = plugins.smartpromise.defer<NodeJS.ReadableStream>();
155
- const result = await this.openAiApiClient.audio.speech.create({
156
- model: this.options.audioModel ?? 'tts-1-hd',
157
- input: optionsArg.message,
158
- voice: 'nova',
159
- response_format: 'mp3',
160
- speed: 1,
161
- });
162
- const stream = result.body;
163
- const nodeStream = Readable.fromWeb(stream as any);
164
- done.resolve(nodeStream);
165
- return done.promise;
166
- }
167
-
168
- public async document(optionsArg: {
169
- systemMessage: string;
170
- userMessage: string;
171
- pdfDocuments: Uint8Array[];
172
- messageHistory: {
173
- role: 'assistant' | 'user';
174
- content: any;
175
- }[];
176
- }) {
177
- // Ensure SmartPdf is initialized before processing documents
178
- await this.ensureSmartpdfReady();
179
-
180
- let pdfDocumentImageBytesArray: Uint8Array[] = [];
181
-
182
- // Convert each PDF into one or more image byte arrays.
183
- for (const pdfDocument of optionsArg.pdfDocuments) {
184
- const documentImageArray = await this.smartpdfInstance!.convertPDFToPngBytes(pdfDocument);
185
- pdfDocumentImageBytesArray = pdfDocumentImageBytesArray.concat(documentImageArray);
186
- }
187
-
188
- console.log(`image smartfile array`);
189
- console.log(pdfDocumentImageBytesArray.map((smartfile) => smartfile.length));
190
-
191
- // Filter out any empty buffers to avoid sending invalid image URLs.
192
- const validImageBytesArray = pdfDocumentImageBytesArray.filter(imageBytes => imageBytes && imageBytes.length > 0);
193
- const imageAttachments = validImageBytesArray.map(imageBytes => ({
194
- type: 'image_url',
195
- image_url: {
196
- url: 'data:image/png;base64,' + Buffer.from(imageBytes).toString('base64'),
197
- },
198
- }));
199
-
200
- const chatModel = this.options.chatModel ?? 'gpt-5-mini';
201
- const requestParams: any = {
202
- model: chatModel,
203
- messages: [
204
- { role: 'system', content: optionsArg.systemMessage },
205
- ...optionsArg.messageHistory,
206
- {
207
- role: 'user',
208
- content: [
209
- { type: 'text', text: optionsArg.userMessage },
210
- ...imageAttachments,
211
- ],
212
- },
213
- ],
214
- };
215
- // Temperature parameter removed.
216
- const result = await this.openAiApiClient.chat.completions.create(requestParams);
217
- return {
218
- message: result.choices[0].message,
219
- };
220
- }
221
-
222
- public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
223
- const visionModel = this.options.visionModel ?? '04-mini';
224
- const requestParams: any = {
225
- model: visionModel,
226
- messages: [
227
- {
228
- role: 'user',
229
- content: [
230
- { type: 'text', text: optionsArg.prompt },
231
- {
232
- type: 'image_url',
233
- image_url: {
234
- url: `data:image/jpeg;base64,${optionsArg.image.toString('base64')}`
235
- }
236
- }
237
- ]
238
- }
239
- ],
240
- max_tokens: 300
241
- };
242
- const result = await this.openAiApiClient.chat.completions.create(requestParams);
243
- return result.choices[0].message.content || '';
244
- }
245
-
246
- public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
247
- // Determine which model to use - Deep Research API requires specific models
248
- let model: string;
249
- if (optionsArg.searchDepth === 'deep') {
250
- model = this.options.researchModel || 'o4-mini-deep-research-2025-06-26';
251
- } else {
252
- // For basic/advanced, still use deep research models if web search is needed
253
- if (optionsArg.includeWebSearch) {
254
- model = this.options.researchModel || 'o4-mini-deep-research-2025-06-26';
255
- } else {
256
- model = this.options.chatModel || 'gpt-5-mini';
257
- }
258
- }
259
-
260
- const systemMessage = 'You are a research assistant. Provide comprehensive answers with citations and sources when available.';
261
-
262
- // Prepare request parameters using Deep Research API format
263
- const requestParams: any = {
264
- model,
265
- instructions: systemMessage,
266
- input: optionsArg.query
267
- };
268
-
269
- // Add web search tool if requested
270
- if (optionsArg.includeWebSearch || optionsArg.searchDepth === 'deep') {
271
- requestParams.tools = [
272
- {
273
- type: 'web_search_preview',
274
- search_context_size: optionsArg.searchDepth === 'deep' ? 'high' :
275
- optionsArg.searchDepth === 'advanced' ? 'medium' : 'low'
276
- }
277
- ];
278
- }
279
-
280
- // Add background flag for deep research
281
- if (optionsArg.background && optionsArg.searchDepth === 'deep') {
282
- requestParams.background = true;
283
- }
284
-
285
- try {
286
- // Execute the research request using Deep Research API
287
- const result = await this.openAiApiClient.responses.create(requestParams);
288
-
289
- // Extract the answer from output items
290
- let answer = '';
291
- const sources: Array<{ url: string; title: string; snippet: string }> = [];
292
- const searchQueries: string[] = [];
293
-
294
- // Process output items
295
- for (const item of result.output || []) {
296
- // Extract message content
297
- if (item.type === 'message' && 'content' in item) {
298
- const messageItem = item as any;
299
- for (const contentItem of messageItem.content || []) {
300
- if (contentItem.type === 'output_text' && 'text' in contentItem) {
301
- answer += contentItem.text;
302
- }
303
- }
304
- }
305
-
306
- // Extract web search queries
307
- if (item.type === 'web_search_call' && 'action' in item) {
308
- const searchItem = item as any;
309
- if (searchItem.action && searchItem.action.type === 'search' && 'query' in searchItem.action) {
310
- searchQueries.push(searchItem.action.query);
311
- }
312
- }
313
- }
314
-
315
- // Parse sources from markdown links in the answer
316
- const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
317
- let match: RegExpExecArray | null;
318
-
319
- while ((match = urlRegex.exec(answer)) !== null) {
320
- sources.push({
321
- title: match[1],
322
- url: match[2],
323
- snippet: ''
324
- });
325
- }
326
-
327
- return {
328
- answer,
329
- sources,
330
- searchQueries: searchQueries.length > 0 ? searchQueries : undefined,
331
- metadata: {
332
- model,
333
- searchDepth: optionsArg.searchDepth || 'basic',
334
- tokensUsed: result.usage?.total_tokens
335
- }
336
- };
337
- } catch (error) {
338
- console.error('Research API error:', error);
339
- throw new Error(`Failed to perform research: ${error.message}`);
340
- }
341
- }
342
-
343
- /**
344
- * Image generation using OpenAI's gpt-image-1 or DALL-E models
345
- */
346
- public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
347
- const model = optionsArg.model || this.options.imageModel || 'gpt-image-1';
348
-
349
- try {
350
- const requestParams: any = {
351
- model,
352
- prompt: optionsArg.prompt,
353
- n: optionsArg.n || 1,
354
- };
355
-
356
- // Add gpt-image-1 specific parameters
357
- if (model === 'gpt-image-1') {
358
- if (optionsArg.quality) requestParams.quality = optionsArg.quality;
359
- if (optionsArg.size) requestParams.size = optionsArg.size;
360
- if (optionsArg.background) requestParams.background = optionsArg.background;
361
- if (optionsArg.outputFormat) requestParams.output_format = optionsArg.outputFormat;
362
- if (optionsArg.outputCompression !== undefined) requestParams.output_compression = optionsArg.outputCompression;
363
- if (optionsArg.moderation) requestParams.moderation = optionsArg.moderation;
364
- if (optionsArg.stream !== undefined) requestParams.stream = optionsArg.stream;
365
- if (optionsArg.partialImages !== undefined) requestParams.partial_images = optionsArg.partialImages;
366
- } else if (model === 'dall-e-3') {
367
- // DALL-E 3 specific parameters
368
- if (optionsArg.quality) requestParams.quality = optionsArg.quality;
369
- if (optionsArg.size) requestParams.size = optionsArg.size;
370
- if (optionsArg.style) requestParams.style = optionsArg.style;
371
- requestParams.response_format = 'b64_json'; // Always use base64 for consistency
372
- } else if (model === 'dall-e-2') {
373
- // DALL-E 2 specific parameters
374
- if (optionsArg.size) requestParams.size = optionsArg.size;
375
- requestParams.response_format = 'b64_json';
376
- }
377
-
378
- const result = await this.openAiApiClient.images.generate(requestParams);
379
-
380
- const images = (result.data || []).map(img => ({
381
- b64_json: img.b64_json,
382
- url: img.url,
383
- revisedPrompt: img.revised_prompt
384
- }));
385
-
386
- return {
387
- images,
388
- metadata: {
389
- model,
390
- quality: result.quality,
391
- size: result.size,
392
- outputFormat: result.output_format,
393
- tokensUsed: result.usage?.total_tokens
394
- }
395
- };
396
- } catch (error) {
397
- console.error('Image generation error:', error);
398
- throw new Error(`Failed to generate image: ${error.message}`);
399
- }
400
- }
401
-
402
- /**
403
- * Image editing using OpenAI's gpt-image-1 or DALL-E 2 models
404
- */
405
- public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
406
- const model = optionsArg.model || this.options.imageModel || 'gpt-image-1';
407
-
408
- try {
409
- // Convert Buffer to uploadable file format for OpenAI API
410
- const imageFile = await toFile(optionsArg.image, 'image.png', { type: 'image/png' });
411
-
412
- const requestParams: any = {
413
- model,
414
- image: imageFile,
415
- prompt: optionsArg.prompt,
416
- n: optionsArg.n || 1,
417
- };
418
-
419
- // Add mask if provided (also convert to file format)
420
- if (optionsArg.mask) {
421
- requestParams.mask = await toFile(optionsArg.mask, 'mask.png', { type: 'image/png' });
422
- }
423
-
424
- // Add gpt-image-1 specific parameters
425
- if (model === 'gpt-image-1') {
426
- if (optionsArg.quality) requestParams.quality = optionsArg.quality;
427
- if (optionsArg.size) requestParams.size = optionsArg.size;
428
- if (optionsArg.background) requestParams.background = optionsArg.background;
429
- if (optionsArg.outputFormat) requestParams.output_format = optionsArg.outputFormat;
430
- if (optionsArg.outputCompression !== undefined) requestParams.output_compression = optionsArg.outputCompression;
431
- if (optionsArg.stream !== undefined) requestParams.stream = optionsArg.stream;
432
- if (optionsArg.partialImages !== undefined) requestParams.partial_images = optionsArg.partialImages;
433
- } else if (model === 'dall-e-2') {
434
- // DALL-E 2 specific parameters
435
- if (optionsArg.size) requestParams.size = optionsArg.size;
436
- requestParams.response_format = 'b64_json';
437
- }
438
-
439
- const result = await this.openAiApiClient.images.edit(requestParams);
440
-
441
- const images = (result.data || []).map(img => ({
442
- b64_json: img.b64_json,
443
- url: img.url,
444
- revisedPrompt: img.revised_prompt
445
- }));
446
-
447
- return {
448
- images,
449
- metadata: {
450
- model,
451
- quality: result.quality,
452
- size: result.size,
453
- outputFormat: result.output_format,
454
- tokensUsed: result.usage?.total_tokens
455
- }
456
- };
457
- } catch (error) {
458
- console.error('Image edit error:', error);
459
- throw new Error(`Failed to edit image: ${error.message}`);
460
- }
461
- }
462
- }