Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4bf7113334 | ||
6bdbeae144 | |||
09c27379cb | |||
2bc6f7ee5e | |||
0ac50d647d | |||
5f9ffc7356 | |||
502b665224 | |||
bda0d7ed7e | |||
de2a60d12f | |||
5b3a93a43a | |||
6b241f8889 | |||
0a80ac0a8a | |||
6ce442354e | |||
9b38a3c06e | |||
5dead05324 |
54
changelog.md
54
changelog.md
@@ -1,5 +1,59 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-07-25 - 0.5.5 - feat(documentation)
|
||||||
|
Comprehensive documentation enhancement and test improvements
|
||||||
|
|
||||||
|
- Completely rewrote readme.md with detailed provider comparisons, advanced usage examples, and performance tips
|
||||||
|
- Added comprehensive examples for all supported providers (OpenAI, Anthropic, Perplexity, Groq, XAI, Ollama, Exo)
|
||||||
|
- Included detailed sections on chat interactions, streaming, TTS, vision processing, and document analysis
|
||||||
|
- Added verbose flag to test script for better debugging
|
||||||
|
|
||||||
|
## 2025-05-13 - 0.5.4 - fix(provider.openai)
|
||||||
|
Update dependency versions, clean test imports, and adjust default OpenAI model configurations
|
||||||
|
|
||||||
|
- Bump dependency versions in package.json (@git.zone/tsbuild, @push.rocks/tapbundle, openai, etc.)
|
||||||
|
- Change default chatModel from 'gpt-4o' to 'o4-mini' and visionModel from 'gpt-4o' to '04-mini' in provider.openai.ts
|
||||||
|
- Remove unused 'expectAsync' import from test file
|
||||||
|
|
||||||
|
## 2025-04-03 - 0.5.3 - fix(package.json)
|
||||||
|
Add explicit packageManager field to package.json
|
||||||
|
|
||||||
|
- Include the packageManager property to specify the pnpm version and checksum.
|
||||||
|
- Align package metadata with current standards.
|
||||||
|
|
||||||
|
## 2025-04-03 - 0.5.2 - fix(readme)
|
||||||
|
Remove redundant conclusion section from README to streamline documentation.
|
||||||
|
|
||||||
|
- Eliminated the conclusion block describing SmartAi's capabilities and documentation pointers.
|
||||||
|
|
||||||
|
## 2025-02-25 - 0.5.1 - fix(OpenAiProvider)
|
||||||
|
Corrected audio model ID in OpenAiProvider
|
||||||
|
|
||||||
|
- Fixed audio model identifier from 'o3-mini' to 'tts-1-hd' in the OpenAiProvider's audio method.
|
||||||
|
- Addressed minor code formatting issues in test suite for better readability.
|
||||||
|
- Corrected spelling errors in test documentation and comments.
|
||||||
|
|
||||||
|
## 2025-02-25 - 0.5.0 - feat(documentation and configuration)
|
||||||
|
Enhanced package and README documentation
|
||||||
|
|
||||||
|
- Expanded the package description to better reflect the library's capabilities.
|
||||||
|
- Improved README with detailed usage examples for initialization, chat interactions, streaming chat, audio generation, document analysis, and vision processing.
|
||||||
|
- Provided error handling strategies and advanced streaming customization examples.
|
||||||
|
|
||||||
|
## 2025-02-25 - 0.4.2 - fix(core)
|
||||||
|
Fix OpenAI chat streaming and PDF document processing logic.
|
||||||
|
|
||||||
|
- Updated OpenAI chat streaming to handle new async iterable format.
|
||||||
|
- Improved PDF document processing by filtering out empty image buffers.
|
||||||
|
- Removed unsupported temperature options from OpenAI requests.
|
||||||
|
|
||||||
|
## 2025-02-25 - 0.4.1 - fix(provider)
|
||||||
|
Fix provider modules for consistency
|
||||||
|
|
||||||
|
- Updated TypeScript interfaces and options in provider modules for better type safety.
|
||||||
|
- Modified transform stream handlers in Exo, Groq, and Ollama providers for consistency.
|
||||||
|
- Added optional model options to OpenAI provider for custom model usage.
|
||||||
|
|
||||||
## 2025-02-08 - 0.4.0 - feat(core)
|
## 2025-02-08 - 0.4.0 - feat(core)
|
||||||
Added support for Exo AI provider
|
Added support for Exo AI provider
|
||||||
|
|
||||||
|
@@ -5,20 +5,33 @@
|
|||||||
"githost": "code.foss.global",
|
"githost": "code.foss.global",
|
||||||
"gitscope": "push.rocks",
|
"gitscope": "push.rocks",
|
||||||
"gitrepo": "smartai",
|
"gitrepo": "smartai",
|
||||||
"description": "A TypeScript library for integrating and interacting with multiple AI models, offering capabilities for chat and potentially audio responses.",
|
"description": "SmartAi is a versatile TypeScript library designed to facilitate integration and interaction with various AI models, offering functionalities for chat, audio generation, document processing, and vision tasks.",
|
||||||
"npmPackagename": "@push.rocks/smartai",
|
"npmPackagename": "@push.rocks/smartai",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"projectDomain": "push.rocks",
|
"projectDomain": "push.rocks",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"AI integration",
|
"AI integration",
|
||||||
"chatbot",
|
|
||||||
"TypeScript",
|
"TypeScript",
|
||||||
|
"chatbot",
|
||||||
"OpenAI",
|
"OpenAI",
|
||||||
"Anthropic",
|
"Anthropic",
|
||||||
"multi-model support",
|
"multi-model",
|
||||||
"audio responses",
|
"audio generation",
|
||||||
"text-to-speech",
|
"text-to-speech",
|
||||||
"streaming chat"
|
"document processing",
|
||||||
|
"vision processing",
|
||||||
|
"streaming chat",
|
||||||
|
"API",
|
||||||
|
"multiple providers",
|
||||||
|
"AI models",
|
||||||
|
"synchronous chat",
|
||||||
|
"asynchronous chat",
|
||||||
|
"real-time interaction",
|
||||||
|
"content analysis",
|
||||||
|
"image description",
|
||||||
|
"document classification",
|
||||||
|
"AI toolkit",
|
||||||
|
"provider switching"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
62
package.json
62
package.json
@@ -1,37 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartai",
|
"name": "@push.rocks/smartai",
|
||||||
"version": "0.4.0",
|
"version": "0.5.5",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A TypeScript library for integrating and interacting with multiple AI models, offering capabilities for chat and potentially audio responses.",
|
"description": "SmartAi is a versatile TypeScript library designed to facilitate integration and interaction with various AI models, offering functionalities for chat, audio generation, document processing, and vision tasks.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "Task Venture Capital GmbH",
|
"author": "Task Venture Capital GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/ --web)",
|
"test": "(tstest test/ --web --verbose)",
|
||||||
"build": "(tsbuild --web --allowimplicitany)",
|
"build": "(tsbuild --web --allowimplicitany)",
|
||||||
"buildDocs": "(tsdoc)"
|
"buildDocs": "(tsdoc)"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsbuild": "^2.1.84",
|
"@git.zone/tsbuild": "^2.6.4",
|
||||||
"@git.zone/tsbundle": "^2.0.5",
|
"@git.zone/tsbundle": "^2.5.1",
|
||||||
"@git.zone/tsrun": "^1.2.49",
|
"@git.zone/tsrun": "^1.3.3",
|
||||||
"@git.zone/tstest": "^1.0.90",
|
"@git.zone/tstest": "^2.3.2",
|
||||||
"@push.rocks/qenv": "^6.0.5",
|
"@push.rocks/qenv": "^6.1.0",
|
||||||
"@push.rocks/tapbundle": "^5.3.0",
|
"@push.rocks/tapbundle": "^6.0.3",
|
||||||
"@types/node": "^22.5.5"
|
"@types/node": "^22.15.17"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/sdk": "^0.27.3",
|
"@anthropic-ai/sdk": "^0.57.0",
|
||||||
"@push.rocks/smartarray": "^1.0.8",
|
"@push.rocks/smartarray": "^1.1.0",
|
||||||
"@push.rocks/smartfile": "^11.0.21",
|
"@push.rocks/smartfile": "^11.2.5",
|
||||||
"@push.rocks/smartpath": "^5.0.18",
|
"@push.rocks/smartpath": "^5.0.18",
|
||||||
"@push.rocks/smartpdf": "^3.1.6",
|
"@push.rocks/smartpdf": "^3.2.2",
|
||||||
"@push.rocks/smartpromise": "^4.0.4",
|
"@push.rocks/smartpromise": "^4.2.3",
|
||||||
"@push.rocks/smartrequest": "^2.0.22",
|
"@push.rocks/smartrequest": "^2.1.0",
|
||||||
"@push.rocks/webstream": "^1.0.10",
|
"@push.rocks/webstream": "^1.0.10",
|
||||||
"openai": "^4.62.1"
|
"openai": "^5.10.2"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -58,13 +58,33 @@
|
|||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"AI integration",
|
"AI integration",
|
||||||
"chatbot",
|
|
||||||
"TypeScript",
|
"TypeScript",
|
||||||
|
"chatbot",
|
||||||
"OpenAI",
|
"OpenAI",
|
||||||
"Anthropic",
|
"Anthropic",
|
||||||
"multi-model support",
|
"multi-model",
|
||||||
"audio responses",
|
"audio generation",
|
||||||
"text-to-speech",
|
"text-to-speech",
|
||||||
"streaming chat"
|
"document processing",
|
||||||
|
"vision processing",
|
||||||
|
"streaming chat",
|
||||||
|
"API",
|
||||||
|
"multiple providers",
|
||||||
|
"AI models",
|
||||||
|
"synchronous chat",
|
||||||
|
"asynchronous chat",
|
||||||
|
"real-time interaction",
|
||||||
|
"content analysis",
|
||||||
|
"image description",
|
||||||
|
"document classification",
|
||||||
|
"AI toolkit",
|
||||||
|
"provider switching"
|
||||||
|
],
|
||||||
|
"pnpm": {
|
||||||
|
"onlyBuiltDependencies": [
|
||||||
|
"esbuild",
|
||||||
|
"puppeteer"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||||
}
|
}
|
||||||
|
7807
pnpm-lock.yaml
generated
7807
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
505
readme.md
505
readme.md
@@ -1,329 +1,392 @@
|
|||||||
# @push.rocks/smartai
|
# @push.rocks/smartai
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/@push.rocks/smartai)
|
SmartAi is a powerful TypeScript library that provides a unified interface for integrating with multiple AI providers including OpenAI, Anthropic, Perplexity, Ollama, Groq, XAI, and Exo. It offers comprehensive support for chat interactions, streaming conversations, text-to-speech, document analysis, and vision processing.
|
||||||
|
|
||||||
SmartAi is a comprehensive TypeScript library that provides a standardized interface for integrating and interacting with multiple AI models. It supports a range of operations from synchronous and streaming chat to audio generation, document processing, and vision tasks.
|
## Install
|
||||||
|
|
||||||
## Table of Contents
|
To install SmartAi into your project, use pnpm:
|
||||||
|
|
||||||
- [Features](#features)
|
|
||||||
- [Installation](#installation)
|
|
||||||
- [Supported AI Providers](#supported-ai-providers)
|
|
||||||
- [Quick Start](#quick-start)
|
|
||||||
- [Usage Examples](#usage-examples)
|
|
||||||
- [Chat Interactions](#chat-interactions)
|
|
||||||
- [Streaming Chat](#streaming-chat)
|
|
||||||
- [Audio Generation](#audio-generation)
|
|
||||||
- [Document Processing](#document-processing)
|
|
||||||
- [Vision Processing](#vision-processing)
|
|
||||||
- [Error Handling](#error-handling)
|
|
||||||
- [Development](#development)
|
|
||||||
- [Running Tests](#running-tests)
|
|
||||||
- [Building the Project](#building-the-project)
|
|
||||||
- [Contributing](#contributing)
|
|
||||||
- [License](#license)
|
|
||||||
- [Legal Information](#legal-information)
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **Unified API:** Seamlessly integrate multiple AI providers with a consistent interface.
|
|
||||||
- **Chat & Streaming:** Support for both synchronous and real-time streaming chat interactions.
|
|
||||||
- **Audio & Vision:** Generate audio responses and perform detailed image analysis.
|
|
||||||
- **Document Processing:** Analyze PDFs and other documents using vision models.
|
|
||||||
- **Extensible:** Easily extend the library to support additional AI providers.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
To install SmartAi, run the following command:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install @push.rocks/smartai
|
pnpm install @push.rocks/smartai
|
||||||
```
|
```
|
||||||
|
|
||||||
This will add the package to your project’s dependencies.
|
## Usage
|
||||||
|
|
||||||
## Supported AI Providers
|
SmartAi provides a clean, consistent API across all supported AI providers. This documentation covers all features with practical examples for each provider and capability.
|
||||||
|
|
||||||
SmartAi supports multiple AI providers. Configure each provider with its corresponding token or settings:
|
### Initialization
|
||||||
|
|
||||||
### OpenAI
|
First, initialize SmartAi with the API tokens and configuration for the providers you want to use:
|
||||||
|
|
||||||
- **Models:** GPT-4, GPT-3.5-turbo, GPT-4-vision-preview
|
|
||||||
- **Features:** Chat, Streaming, Audio Generation, Vision, Document Processing
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
openaiToken: 'your-openai-token'
|
|
||||||
```
|
|
||||||
|
|
||||||
### X.AI
|
|
||||||
|
|
||||||
- **Models:** Grok-2-latest
|
|
||||||
- **Features:** Chat, Streaming, Document Processing
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
xaiToken: 'your-xai-token'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Anthropic
|
|
||||||
|
|
||||||
- **Models:** Claude-3-opus-20240229
|
|
||||||
- **Features:** Chat, Streaming, Vision, Document Processing
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
anthropicToken: 'your-anthropic-token'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Perplexity
|
|
||||||
|
|
||||||
- **Models:** Mixtral-8x7b-instruct
|
|
||||||
- **Features:** Chat, Streaming
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
perplexityToken: 'your-perplexity-token'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Groq
|
|
||||||
|
|
||||||
- **Models:** Llama-3.3-70b-versatile
|
|
||||||
- **Features:** Chat, Streaming
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
groqToken: 'your-groq-token'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ollama
|
|
||||||
|
|
||||||
- **Models:** Configurable (default: llama2; use llava for vision/document tasks)
|
|
||||||
- **Features:** Chat, Streaming, Vision, Document Processing
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
ollama: {
|
|
||||||
baseUrl: 'http://localhost:11434', // Optional
|
|
||||||
model: 'llama2', // Optional
|
|
||||||
visionModel: 'llava' // Optional for vision and document tasks
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Exo
|
|
||||||
|
|
||||||
- **Models:** Configurable (supports LLaMA, Mistral, LlaVA, Qwen, and Deepseek)
|
|
||||||
- **Features:** Chat, Streaming
|
|
||||||
- **Configuration Example:**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
exo: {
|
|
||||||
baseUrl: 'http://localhost:8080/v1', // Optional
|
|
||||||
apiKey: 'your-api-key' // Optional for local deployments
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
Initialize SmartAi with the provider configurations you plan to use:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { SmartAi } from '@push.rocks/smartai';
|
import { SmartAi } from '@push.rocks/smartai';
|
||||||
|
|
||||||
const smartAi = new SmartAi({
|
const smartAi = new SmartAi({
|
||||||
openaiToken: 'your-openai-token',
|
// OpenAI - for GPT models, DALL-E, and TTS
|
||||||
xaiToken: 'your-xai-token',
|
openaiToken: 'your-openai-api-key',
|
||||||
anthropicToken: 'your-anthropic-token',
|
|
||||||
perplexityToken: 'your-perplexity-token',
|
// Anthropic - for Claude models
|
||||||
groqToken: 'your-groq-token',
|
anthropicToken: 'your-anthropic-api-key',
|
||||||
|
|
||||||
|
// Perplexity - for research-focused AI
|
||||||
|
perplexityToken: 'your-perplexity-api-key',
|
||||||
|
|
||||||
|
// Groq - for fast inference
|
||||||
|
groqToken: 'your-groq-api-key',
|
||||||
|
|
||||||
|
// XAI - for Grok models
|
||||||
|
xaiToken: 'your-xai-api-key',
|
||||||
|
|
||||||
|
// Ollama - for local models
|
||||||
ollama: {
|
ollama: {
|
||||||
baseUrl: 'http://localhost:11434',
|
baseUrl: 'http://localhost:11434',
|
||||||
model: 'llama2'
|
model: 'llama2', // default model for chat
|
||||||
|
visionModel: 'llava' // default model for vision
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Exo - for distributed inference
|
||||||
exo: {
|
exo: {
|
||||||
baseUrl: 'http://localhost:8080/v1',
|
baseUrl: 'http://localhost:8080/v1',
|
||||||
apiKey: 'your-api-key'
|
apiKey: 'your-exo-api-key'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Start the SmartAi instance
|
||||||
await smartAi.start();
|
await smartAi.start();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Supported Providers
|
||||||
|
|
||||||
### Chat Interactions
|
SmartAi supports the following AI providers:
|
||||||
|
|
||||||
**Synchronous Chat:**
|
| Provider | Use Case | Key Features |
|
||||||
|
|----------|----------|--------------|
|
||||||
|
| **OpenAI** | General purpose, GPT models | Chat, streaming, TTS, vision, documents |
|
||||||
|
| **Anthropic** | Claude models, safety-focused | Chat, streaming, vision, documents |
|
||||||
|
| **Perplexity** | Research and factual queries | Chat, streaming, documents |
|
||||||
|
| **Groq** | Fast inference | Chat, streaming |
|
||||||
|
| **XAI** | Grok models | Chat, streaming |
|
||||||
|
| **Ollama** | Local models | Chat, streaming, vision |
|
||||||
|
| **Exo** | Distributed inference | Chat, streaming |
|
||||||
|
|
||||||
|
## Core Features
|
||||||
|
|
||||||
|
### 1. Chat Interactions
|
||||||
|
|
||||||
|
SmartAi provides both synchronous and streaming chat capabilities across all supported providers.
|
||||||
|
|
||||||
|
#### Synchronous Chat
|
||||||
|
|
||||||
|
Simple request-response interactions with any provider:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const response = await smartAi.openaiProvider.chat({
|
// OpenAI Example
|
||||||
|
const openAiResponse = await smartAi.openaiProvider.chat({
|
||||||
systemMessage: 'You are a helpful assistant.',
|
systemMessage: 'You are a helpful assistant.',
|
||||||
userMessage: 'What is the capital of France?',
|
userMessage: 'What is the capital of France?',
|
||||||
messageHistory: [] // Include previous conversation messages if applicable
|
messageHistory: []
|
||||||
});
|
});
|
||||||
|
console.log(openAiResponse.message); // "The capital of France is Paris."
|
||||||
|
|
||||||
console.log(response.message);
|
// Anthropic Example
|
||||||
|
const anthropicResponse = await smartAi.anthropicProvider.chat({
|
||||||
|
systemMessage: 'You are a knowledgeable historian.',
|
||||||
|
userMessage: 'Tell me about the French Revolution',
|
||||||
|
messageHistory: []
|
||||||
|
});
|
||||||
|
console.log(anthropicResponse.message);
|
||||||
|
|
||||||
|
// Using message history for context
|
||||||
|
const contextualResponse = await smartAi.openaiProvider.chat({
|
||||||
|
systemMessage: 'You are a math tutor.',
|
||||||
|
userMessage: 'What about multiplication?',
|
||||||
|
messageHistory: [
|
||||||
|
{ role: 'user', content: 'Can you teach me math?' },
|
||||||
|
{ role: 'assistant', content: 'Of course! What would you like to learn?' }
|
||||||
|
]
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Streaming Chat
|
#### Streaming Chat
|
||||||
|
|
||||||
**Real-Time Streaming:**
|
For real-time, token-by-token responses:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const textEncoder = new TextEncoder();
|
// Create a readable stream for input
|
||||||
const textDecoder = new TextDecoder();
|
const { readable, writable } = new TransformStream();
|
||||||
|
|
||||||
// Create a transform stream for sending and receiving data
|
|
||||||
const { writable, readable } = new TransformStream();
|
|
||||||
const writer = writable.getWriter();
|
const writer = writable.getWriter();
|
||||||
|
|
||||||
const message = {
|
// Send a message
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
await writer.write(encoder.encode(JSON.stringify({
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: 'Tell me a story about a brave knight'
|
content: 'Write a haiku about programming'
|
||||||
};
|
})));
|
||||||
|
await writer.close();
|
||||||
|
|
||||||
writer.write(textEncoder.encode(JSON.stringify(message) + '\n'));
|
// Get streaming response
|
||||||
|
const responseStream = await smartAi.openaiProvider.chatStream(readable);
|
||||||
// Start streaming the response
|
const reader = responseStream.getReader();
|
||||||
const stream = await smartAi.openaiProvider.chatStream(readable);
|
const decoder = new TextDecoder();
|
||||||
const reader = stream.getReader();
|
|
||||||
|
|
||||||
|
// Read the stream
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
if (done) break;
|
if (done) break;
|
||||||
console.log('AI:', value);
|
process.stdout.write(value); // Print each chunk as it arrives
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Audio Generation
|
### 2. Text-to-Speech (Audio Generation)
|
||||||
|
|
||||||
Generate audio (supported by providers like OpenAI):
|
Convert text to natural-sounding speech (currently supported by OpenAI):
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
// Generate speech from text
|
||||||
const audioStream = await smartAi.openaiProvider.audio({
|
const audioStream = await smartAi.openaiProvider.audio({
|
||||||
message: 'Hello, this is a test of text-to-speech'
|
message: 'Hello world! This is a test of the text-to-speech system.'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process the audio stream, for example, play it or save to a file.
|
// Save to file
|
||||||
```
|
const writeStream = fs.createWriteStream('output.mp3');
|
||||||
|
audioStream.pipe(writeStream);
|
||||||
|
|
||||||
### Document Processing
|
// Or use in your application directly
|
||||||
|
audioStream.on('data', (chunk) => {
|
||||||
Analyze and extract key information from documents:
|
// Process audio chunks
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Example using OpenAI
|
|
||||||
const documentResult = await smartAi.openaiProvider.document({
|
|
||||||
systemMessage: 'Classify the document type',
|
|
||||||
userMessage: 'What type of document is this?',
|
|
||||||
messageHistory: [],
|
|
||||||
pdfDocuments: [pdfBuffer] // Uint8Array containing the PDF content
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Other providers (e.g., Ollama and Anthropic) follow a similar pattern:
|
### 3. Vision Processing
|
||||||
|
|
||||||
|
Analyze images and get detailed descriptions:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Using Ollama for document processing
|
import * as fs from 'fs';
|
||||||
const ollamaResult = await smartAi.ollamaProvider.document({
|
|
||||||
systemMessage: 'You are a document analysis assistant',
|
// Read an image file
|
||||||
userMessage: 'Extract key information from this document',
|
const imageBuffer = fs.readFileSync('image.jpg');
|
||||||
|
|
||||||
|
// OpenAI Vision
|
||||||
|
const openAiVision = await smartAi.openaiProvider.vision({
|
||||||
|
image: imageBuffer,
|
||||||
|
prompt: 'What is in this image? Describe in detail.'
|
||||||
|
});
|
||||||
|
console.log('OpenAI:', openAiVision);
|
||||||
|
|
||||||
|
// Anthropic Vision
|
||||||
|
const anthropicVision = await smartAi.anthropicProvider.vision({
|
||||||
|
image: imageBuffer,
|
||||||
|
prompt: 'Analyze this image and identify any text or objects.'
|
||||||
|
});
|
||||||
|
console.log('Anthropic:', anthropicVision);
|
||||||
|
|
||||||
|
// Ollama Vision (using local model)
|
||||||
|
const ollamaVision = await smartAi.ollamaProvider.vision({
|
||||||
|
image: imageBuffer,
|
||||||
|
prompt: 'Describe the colors and composition of this image.'
|
||||||
|
});
|
||||||
|
console.log('Ollama:', ollamaVision);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Document Analysis
|
||||||
|
|
||||||
|
Process and analyze PDF documents with AI:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
// Read PDF documents
|
||||||
|
const pdfBuffer = fs.readFileSync('document.pdf');
|
||||||
|
|
||||||
|
// Analyze with OpenAI
|
||||||
|
const openAiAnalysis = await smartAi.openaiProvider.document({
|
||||||
|
systemMessage: 'You are a document analyst. Extract key information.',
|
||||||
|
userMessage: 'Summarize this document and list the main points.',
|
||||||
messageHistory: [],
|
messageHistory: [],
|
||||||
pdfDocuments: [pdfBuffer]
|
pdfDocuments: [pdfBuffer]
|
||||||
});
|
});
|
||||||
```
|
console.log('OpenAI Analysis:', openAiAnalysis.message);
|
||||||
|
|
||||||
```typescript
|
// Analyze with Anthropic
|
||||||
// Using Anthropic for document processing
|
const anthropicAnalysis = await smartAi.anthropicProvider.document({
|
||||||
const anthropicResult = await smartAi.anthropicProvider.document({
|
systemMessage: 'You are a legal expert.',
|
||||||
systemMessage: 'Analyze the document',
|
userMessage: 'Identify any legal terms or implications in this document.',
|
||||||
userMessage: 'Please extract the main points',
|
|
||||||
messageHistory: [],
|
messageHistory: [],
|
||||||
pdfDocuments: [pdfBuffer]
|
pdfDocuments: [pdfBuffer]
|
||||||
});
|
});
|
||||||
|
console.log('Anthropic Analysis:', anthropicAnalysis.message);
|
||||||
|
|
||||||
|
// Process multiple documents
|
||||||
|
const doc1 = fs.readFileSync('contract1.pdf');
|
||||||
|
const doc2 = fs.readFileSync('contract2.pdf');
|
||||||
|
|
||||||
|
const comparison = await smartAi.openaiProvider.document({
|
||||||
|
systemMessage: 'You are a contract analyst.',
|
||||||
|
userMessage: 'Compare these two contracts and highlight the differences.',
|
||||||
|
messageHistory: [],
|
||||||
|
pdfDocuments: [doc1, doc2]
|
||||||
|
});
|
||||||
|
console.log('Comparison:', comparison.message);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Vision Processing
|
### 5. Conversation Management
|
||||||
|
|
||||||
Analyze images with vision capabilities:
|
Create persistent conversation sessions with any provider:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Using OpenAI GPT-4 Vision
|
// Create a conversation with OpenAI
|
||||||
const imageDescription = await smartAi.openaiProvider.vision({
|
const conversation = smartAi.createConversation('openai');
|
||||||
image: imageBuffer, // Uint8Array containing image data
|
|
||||||
prompt: 'What do you see in this image?'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Using Ollama for vision tasks
|
// Set the system message
|
||||||
const ollamaImageAnalysis = await smartAi.ollamaProvider.vision({
|
await conversation.setSystemMessage('You are a helpful coding assistant.');
|
||||||
image: imageBuffer,
|
|
||||||
prompt: 'Analyze this image in detail'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Using Anthropic for vision analysis
|
// Get input and output streams
|
||||||
const anthropicImageAnalysis = await smartAi.anthropicProvider.vision({
|
const inputWriter = conversation.getInputStreamWriter();
|
||||||
image: imageBuffer,
|
const outputStream = conversation.getOutputStream();
|
||||||
prompt: 'Describe the contents of this image'
|
|
||||||
});
|
// Set up output reader
|
||||||
|
const reader = outputStream.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
// Send messages
|
||||||
|
await inputWriter.write('How do I create a REST API in Node.js?');
|
||||||
|
|
||||||
|
// Read responses
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
console.log('Assistant:', decoder.decode(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue the conversation
|
||||||
|
await inputWriter.write('Can you show me an example with Express?');
|
||||||
|
|
||||||
|
// Create conversations with different providers
|
||||||
|
const anthropicConversation = smartAi.createConversation('anthropic');
|
||||||
|
const groqConversation = smartAi.createConversation('groq');
|
||||||
```
|
```
|
||||||
|
|
||||||
## Error Handling
|
## Advanced Usage
|
||||||
|
|
||||||
Always wrap API calls in try-catch blocks to manage errors effectively:
|
### Error Handling
|
||||||
|
|
||||||
|
Always wrap AI operations in try-catch blocks for robust error handling:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
try {
|
try {
|
||||||
const response = await smartAi.openaiProvider.chat({
|
const response = await smartAi.openaiProvider.chat({
|
||||||
systemMessage: 'You are a helpful assistant.',
|
systemMessage: 'You are an assistant.',
|
||||||
userMessage: 'Hello!',
|
userMessage: 'Hello!',
|
||||||
messageHistory: []
|
messageHistory: []
|
||||||
});
|
});
|
||||||
console.log(response.message);
|
console.log(response.message);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('AI provider error:', error.message);
|
if (error.code === 'rate_limit_exceeded') {
|
||||||
|
console.error('Rate limit hit, please retry later');
|
||||||
|
} else if (error.code === 'invalid_api_key') {
|
||||||
|
console.error('Invalid API key provided');
|
||||||
|
} else {
|
||||||
|
console.error('Unexpected error:', error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development
|
### Streaming with Custom Processing
|
||||||
|
|
||||||
### Running Tests
|
Implement custom transformations on streaming responses:
|
||||||
|
|
||||||
To run the test suite, use the following command:
|
```typescript
|
||||||
|
// Create a custom transform stream
|
||||||
|
const customTransform = new TransformStream({
|
||||||
|
transform(chunk, controller) {
|
||||||
|
// Example: Add timestamps to each chunk
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
controller.enqueue(`[${timestamp}] ${chunk}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
```bash
|
// Apply to streaming chat
|
||||||
npm run test
|
const inputStream = new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
controller.enqueue(new TextEncoder().encode(JSON.stringify({
|
||||||
|
role: 'user',
|
||||||
|
content: 'Tell me a story'
|
||||||
|
})));
|
||||||
|
controller.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseStream = await smartAi.openaiProvider.chatStream(inputStream);
|
||||||
|
const processedStream = responseStream.pipeThrough(customTransform);
|
||||||
|
|
||||||
|
// Read processed stream
|
||||||
|
const reader = processedStream.getReader();
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure your environment is configured with the appropriate tokens and settings for the providers you are testing.
|
### Provider-Specific Features
|
||||||
|
|
||||||
### Building the Project
|
Each provider may have unique capabilities. Here's how to leverage them:
|
||||||
|
|
||||||
Compile the TypeScript code and build the package using:
|
```typescript
|
||||||
|
// OpenAI - Use specific models
|
||||||
|
const gpt4Response = await smartAi.openaiProvider.chat({
|
||||||
|
systemMessage: 'You are a helpful assistant.',
|
||||||
|
userMessage: 'Explain quantum computing',
|
||||||
|
messageHistory: []
|
||||||
|
});
|
||||||
|
|
||||||
```bash
|
// Anthropic - Use Claude's strength in analysis
|
||||||
npm run build
|
const codeReview = await smartAi.anthropicProvider.chat({
|
||||||
|
systemMessage: 'You are a code reviewer.',
|
||||||
|
userMessage: 'Review this code for security issues: ...',
|
||||||
|
messageHistory: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Perplexity - Best for research and current events
|
||||||
|
const research = await smartAi.perplexityProvider.chat({
|
||||||
|
systemMessage: 'You are a research assistant.',
|
||||||
|
userMessage: 'What are the latest developments in renewable energy?',
|
||||||
|
messageHistory: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Groq - Optimized for speed
|
||||||
|
const quickResponse = await smartAi.groqProvider.chat({
|
||||||
|
systemMessage: 'You are a quick helper.',
|
||||||
|
userMessage: 'Give me a one-line summary of photosynthesis',
|
||||||
|
messageHistory: []
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
This command prepares the library for distribution.
|
### Performance Optimization
|
||||||
|
|
||||||
## Contributing
|
Tips for optimal performance:
|
||||||
|
|
||||||
Contributions are welcome! Please follow these steps:
|
```typescript
|
||||||
|
// 1. Reuse providers instead of creating new instances
|
||||||
|
const smartAi = new SmartAi({ /* config */ });
|
||||||
|
await smartAi.start(); // Initialize once
|
||||||
|
|
||||||
1. Fork the repository.
|
// 2. Use streaming for long responses
|
||||||
2. Create a feature branch:
|
// Streaming reduces time-to-first-token and memory usage
|
||||||
```bash
|
|
||||||
git checkout -b feature/my-feature
|
// 3. Batch operations when possible
|
||||||
|
const promises = [
|
||||||
|
smartAi.openaiProvider.chat({ /* ... */ }),
|
||||||
|
smartAi.anthropicProvider.chat({ /* ... */ })
|
||||||
|
];
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
|
||||||
|
// 4. Clean up resources
|
||||||
|
await smartAi.stop(); // When done
|
||||||
```
|
```
|
||||||
3. Commit your changes with clear messages:
|
|
||||||
```bash
|
|
||||||
git commit -m 'Add new feature'
|
|
||||||
```
|
|
||||||
4. Push your branch to your fork:
|
|
||||||
```bash
|
|
||||||
git push origin feature/my-feature
|
|
||||||
```
|
|
||||||
5. Open a Pull Request with a detailed description of your changes.
|
|
||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
|
28
test/test.ts
28
test/test.ts
@@ -1,4 +1,4 @@
|
|||||||
import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
|
import { expect, tap } from '@push.rocks/tapbundle';
|
||||||
import * as qenv from '@push.rocks/qenv';
|
import * as qenv from '@push.rocks/qenv';
|
||||||
import * as smartrequest from '@push.rocks/smartrequest';
|
import * as smartrequest from '@push.rocks/smartrequest';
|
||||||
import * as smartfile from '@push.rocks/smartfile';
|
import * as smartfile from '@push.rocks/smartfile';
|
||||||
@@ -21,8 +21,7 @@ tap.test('should create chat response with openai', async () => {
|
|||||||
const response = await testSmartai.openaiProvider.chat({
|
const response = await testSmartai.openaiProvider.chat({
|
||||||
systemMessage: 'Hello',
|
systemMessage: 'Hello',
|
||||||
userMessage: userMessage,
|
userMessage: userMessage,
|
||||||
messageHistory: [
|
messageHistory: [],
|
||||||
],
|
|
||||||
});
|
});
|
||||||
console.log(`userMessage: ${userMessage}`);
|
console.log(`userMessage: ${userMessage}`);
|
||||||
console.log(response.message);
|
console.log(response.message);
|
||||||
@@ -55,7 +54,7 @@ tap.test('should recognize companies in a pdf', async () => {
|
|||||||
address: string;
|
address: string;
|
||||||
city: string;
|
city: string;
|
||||||
country: string;
|
country: string;
|
||||||
EU: boolean; // wether the entity is within EU
|
EU: boolean; // whether the entity is within EU
|
||||||
};
|
};
|
||||||
entityReceiver: {
|
entityReceiver: {
|
||||||
type: 'official state entity' | 'company' | 'person';
|
type: 'official state entity' | 'company' | 'person';
|
||||||
@@ -63,7 +62,7 @@ tap.test('should recognize companies in a pdf', async () => {
|
|||||||
address: string;
|
address: string;
|
||||||
city: string;
|
city: string;
|
||||||
country: string;
|
country: string;
|
||||||
EU: boolean; // wether the entity is within EU
|
EU: boolean; // whether the entity is within EU
|
||||||
};
|
};
|
||||||
date: string; // the date of the document as YYYY-MM-DD
|
date: string; // the date of the document as YYYY-MM-DD
|
||||||
title: string; // a short title, suitable for a filename
|
title: string; // a short title, suitable for a filename
|
||||||
@@ -75,7 +74,24 @@ tap.test('should recognize companies in a pdf', async () => {
|
|||||||
pdfDocuments: [pdfBuffer],
|
pdfDocuments: [pdfBuffer],
|
||||||
});
|
});
|
||||||
console.log(result);
|
console.log(result);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
tap.test('should create audio response with openai', async () => {
|
||||||
|
// Call the audio method with a sample message.
|
||||||
|
const audioStream = await testSmartai.openaiProvider.audio({
|
||||||
|
message: 'This is a test of audio generation.',
|
||||||
|
});
|
||||||
|
// Read all chunks from the stream.
|
||||||
|
const chunks: Uint8Array[] = [];
|
||||||
|
for await (const chunk of audioStream) {
|
||||||
|
chunks.push(chunk as Uint8Array);
|
||||||
|
}
|
||||||
|
const audioBuffer = Buffer.concat(chunks);
|
||||||
|
await smartfile.fs.toFs(audioBuffer, './.nogit/testoutput.mp3');
|
||||||
|
console.log(`Audio Buffer length: ${audioBuffer.length}`);
|
||||||
|
// Assert that the resulting buffer is not empty.
|
||||||
|
expect(audioBuffer.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
tap.test('should stop the smartai instance', async () => {
|
tap.test('should stop the smartai instance', async () => {
|
||||||
await testSmartai.stop();
|
await testSmartai.stop();
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartai',
|
name: '@push.rocks/smartai',
|
||||||
version: '0.4.0',
|
version: '0.5.4',
|
||||||
description: 'A TypeScript library for integrating and interacting with multiple AI models, offering capabilities for chat and potentially audio responses.'
|
description: 'SmartAi is a versatile TypeScript library designed to facilitate integration and interaction with various AI models, offering functionalities for chat, audio generation, document processing, and vision tasks.'
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ export class ExoProvider extends MultiModalModel {
|
|||||||
|
|
||||||
// Create a TransformStream to process the input
|
// Create a TransformStream to process the input
|
||||||
const transform = new TransformStream<Uint8Array, string>({
|
const transform = new TransformStream<Uint8Array, string>({
|
||||||
async transform(chunk, controller) {
|
transform: async (chunk, controller) => {
|
||||||
buffer += decoder.decode(chunk, { stream: true });
|
buffer += decoder.decode(chunk, { stream: true });
|
||||||
|
|
||||||
// Try to parse complete JSON messages from the buffer
|
// Try to parse complete JSON messages from the buffer
|
||||||
|
@@ -32,7 +32,7 @@ export class GroqProvider extends MultiModalModel {
|
|||||||
|
|
||||||
// Create a TransformStream to process the input
|
// Create a TransformStream to process the input
|
||||||
const transform = new TransformStream<Uint8Array, string>({
|
const transform = new TransformStream<Uint8Array, string>({
|
||||||
async transform(chunk, controller) {
|
transform: async (chunk, controller) => {
|
||||||
buffer += decoder.decode(chunk, { stream: true });
|
buffer += decoder.decode(chunk, { stream: true });
|
||||||
|
|
||||||
// Try to parse complete JSON messages from the buffer
|
// Try to parse complete JSON messages from the buffer
|
||||||
|
@@ -45,7 +45,7 @@ export class OllamaProvider extends MultiModalModel {
|
|||||||
|
|
||||||
// Create a TransformStream to process the input
|
// Create a TransformStream to process the input
|
||||||
const transform = new TransformStream<Uint8Array, string>({
|
const transform = new TransformStream<Uint8Array, string>({
|
||||||
async transform(chunk, controller) {
|
transform: async (chunk, controller) => {
|
||||||
buffer += decoder.decode(chunk, { stream: true });
|
buffer += decoder.decode(chunk, { stream: true });
|
||||||
|
|
||||||
// Try to parse complete JSON messages from the buffer
|
// Try to parse complete JSON messages from the buffer
|
||||||
|
@@ -1,10 +1,20 @@
|
|||||||
import * as plugins from './plugins.js';
|
import * as plugins from './plugins.js';
|
||||||
import * as paths from './paths.js';
|
import * as paths from './paths.js';
|
||||||
|
|
||||||
|
// Custom type definition for chat completion messages
|
||||||
|
export type TChatCompletionRequestMessage = {
|
||||||
|
role: "system" | "user" | "assistant";
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
import { MultiModalModel } from './abstract.classes.multimodal.js';
|
import { MultiModalModel } from './abstract.classes.multimodal.js';
|
||||||
|
|
||||||
export interface IOpenaiProviderOptions {
|
export interface IOpenaiProviderOptions {
|
||||||
openaiToken: string;
|
openaiToken: string;
|
||||||
|
chatModel?: string;
|
||||||
|
audioModel?: string;
|
||||||
|
visionModel?: string;
|
||||||
|
// Optionally add more model options (e.g., documentModel) if needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OpenAiProvider extends MultiModalModel {
|
export class OpenAiProvider extends MultiModalModel {
|
||||||
@@ -31,11 +41,14 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
// Create a TextDecoder to handle incoming chunks
|
// Create a TextDecoder to handle incoming chunks
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
let buffer = '';
|
let buffer = '';
|
||||||
let currentMessage: { role: string; content: string; } | null = null;
|
let currentMessage: {
|
||||||
|
role: "function" | "user" | "system" | "assistant" | "tool" | "developer";
|
||||||
|
content: string;
|
||||||
|
} | null = null;
|
||||||
|
|
||||||
// Create a TransformStream to process the input
|
// Create a TransformStream to process the input
|
||||||
const transform = new TransformStream<Uint8Array, string>({
|
const transform = new TransformStream<Uint8Array, string>({
|
||||||
async transform(chunk, controller) {
|
transform: async (chunk, controller) => {
|
||||||
buffer += decoder.decode(chunk, { stream: true });
|
buffer += decoder.decode(chunk, { stream: true });
|
||||||
|
|
||||||
// Try to parse complete JSON messages from the buffer
|
// Try to parse complete JSON messages from the buffer
|
||||||
@@ -50,7 +63,7 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
try {
|
try {
|
||||||
const message = JSON.parse(line);
|
const message = JSON.parse(line);
|
||||||
currentMessage = {
|
currentMessage = {
|
||||||
role: message.role || 'user',
|
role: (message.role || 'user') as "function" | "user" | "system" | "assistant" | "tool" | "developer",
|
||||||
content: message.content || '',
|
content: message.content || '',
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -61,20 +74,24 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
|
|
||||||
// If we have a complete message, send it to OpenAI
|
// If we have a complete message, send it to OpenAI
|
||||||
if (currentMessage) {
|
if (currentMessage) {
|
||||||
const stream = await this.openAiApiClient.chat.completions.create({
|
const messageToSend = { role: "user" as const, content: currentMessage.content };
|
||||||
model: 'gpt-4',
|
const chatModel = this.options.chatModel ?? 'o3-mini';
|
||||||
messages: [{ role: currentMessage.role, content: currentMessage.content }],
|
const requestParams: any = {
|
||||||
|
model: chatModel,
|
||||||
|
messages: [messageToSend],
|
||||||
stream: true,
|
stream: true,
|
||||||
});
|
};
|
||||||
|
// Temperature is omitted since the model does not support it.
|
||||||
|
const stream = await this.openAiApiClient.chat.completions.create(requestParams);
|
||||||
|
// Explicitly cast the stream as an async iterable to satisfy TypeScript.
|
||||||
|
const streamAsyncIterable = stream as unknown as AsyncIterableIterator<any>;
|
||||||
// Process each chunk from OpenAI
|
// Process each chunk from OpenAI
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of streamAsyncIterable) {
|
||||||
const content = chunk.choices[0]?.delta?.content;
|
const content = chunk.choices[0]?.delta?.content;
|
||||||
if (content) {
|
if (content) {
|
||||||
controller.enqueue(content);
|
controller.enqueue(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMessage = null;
|
currentMessage = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -104,15 +121,17 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
content: string;
|
content: string;
|
||||||
}[];
|
}[];
|
||||||
}) {
|
}) {
|
||||||
const result = await this.openAiApiClient.chat.completions.create({
|
const chatModel = this.options.chatModel ?? 'o3-mini';
|
||||||
model: 'gpt-4o',
|
const requestParams: any = {
|
||||||
|
model: chatModel,
|
||||||
messages: [
|
messages: [
|
||||||
{ role: 'system', content: optionsArg.systemMessage },
|
{ role: 'system', content: optionsArg.systemMessage },
|
||||||
...optionsArg.messageHistory,
|
...optionsArg.messageHistory,
|
||||||
{ role: 'user', content: optionsArg.userMessage },
|
{ role: 'user', content: optionsArg.userMessage },
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
// Temperature parameter removed to avoid unsupported error.
|
||||||
|
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
||||||
return {
|
return {
|
||||||
role: result.choices[0].message.role as 'assistant',
|
role: result.choices[0].message.role as 'assistant',
|
||||||
message: result.choices[0].message.content,
|
message: result.choices[0].message.content,
|
||||||
@@ -122,7 +141,7 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
|
public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
|
||||||
const done = plugins.smartpromise.defer<NodeJS.ReadableStream>();
|
const done = plugins.smartpromise.defer<NodeJS.ReadableStream>();
|
||||||
const result = await this.openAiApiClient.audio.speech.create({
|
const result = await this.openAiApiClient.audio.speech.create({
|
||||||
model: 'tts-1-hd',
|
model: this.options.audioModel ?? 'tts-1-hd',
|
||||||
input: optionsArg.message,
|
input: optionsArg.message,
|
||||||
voice: 'nova',
|
voice: 'nova',
|
||||||
response_format: 'mp3',
|
response_format: 'mp3',
|
||||||
@@ -144,27 +163,30 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
}) {
|
}) {
|
||||||
let pdfDocumentImageBytesArray: Uint8Array[] = [];
|
let pdfDocumentImageBytesArray: Uint8Array[] = [];
|
||||||
|
|
||||||
|
// Convert each PDF into one or more image byte arrays.
|
||||||
|
const smartpdfInstance = new plugins.smartpdf.SmartPdf();
|
||||||
|
await smartpdfInstance.start();
|
||||||
for (const pdfDocument of optionsArg.pdfDocuments) {
|
for (const pdfDocument of optionsArg.pdfDocuments) {
|
||||||
const documentImageArray = await this.smartpdfInstance.convertPDFToPngBytes(pdfDocument);
|
const documentImageArray = await smartpdfInstance.convertPDFToPngBytes(pdfDocument);
|
||||||
pdfDocumentImageBytesArray = pdfDocumentImageBytesArray.concat(documentImageArray);
|
pdfDocumentImageBytesArray = pdfDocumentImageBytesArray.concat(documentImageArray);
|
||||||
}
|
}
|
||||||
|
await smartpdfInstance.stop();
|
||||||
|
|
||||||
console.log(`image smartfile array`);
|
console.log(`image smartfile array`);
|
||||||
console.log(pdfDocumentImageBytesArray.map((smartfile) => smartfile.length));
|
console.log(pdfDocumentImageBytesArray.map((smartfile) => smartfile.length));
|
||||||
|
|
||||||
const smartfileArray = await plugins.smartarray.map(
|
// Filter out any empty buffers to avoid sending invalid image URLs.
|
||||||
pdfDocumentImageBytesArray,
|
const validImageBytesArray = pdfDocumentImageBytesArray.filter(imageBytes => imageBytes && imageBytes.length > 0);
|
||||||
async (pdfDocumentImageBytes) => {
|
const imageAttachments = validImageBytesArray.map(imageBytes => ({
|
||||||
return plugins.smartfile.SmartFile.fromBuffer(
|
type: 'image_url',
|
||||||
'pdfDocumentImage.jpg',
|
image_url: {
|
||||||
Buffer.from(pdfDocumentImageBytes)
|
url: 'data:image/png;base64,' + Buffer.from(imageBytes).toString('base64'),
|
||||||
);
|
},
|
||||||
}
|
}));
|
||||||
);
|
|
||||||
|
|
||||||
const result = await this.openAiApiClient.chat.completions.create({
|
const chatModel = this.options.chatModel ?? 'o4-mini';
|
||||||
model: 'gpt-4o',
|
const requestParams: any = {
|
||||||
// response_format: { type: "json_object" }, // not supported for now
|
model: chatModel,
|
||||||
messages: [
|
messages: [
|
||||||
{ role: 'system', content: optionsArg.systemMessage },
|
{ role: 'system', content: optionsArg.systemMessage },
|
||||||
...optionsArg.messageHistory,
|
...optionsArg.messageHistory,
|
||||||
@@ -172,30 +194,22 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
role: 'user',
|
role: 'user',
|
||||||
content: [
|
content: [
|
||||||
{ type: 'text', text: optionsArg.userMessage },
|
{ type: 'text', text: optionsArg.userMessage },
|
||||||
...(() => {
|
...imageAttachments,
|
||||||
const returnArray = [];
|
|
||||||
for (const imageBytes of pdfDocumentImageBytesArray) {
|
|
||||||
returnArray.push({
|
|
||||||
type: 'image_url',
|
|
||||||
image_url: {
|
|
||||||
url: 'data:image/png;base64,' + Buffer.from(imageBytes).toString('base64'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return returnArray;
|
|
||||||
})(),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
// Temperature parameter removed.
|
||||||
|
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
||||||
return {
|
return {
|
||||||
message: result.choices[0].message,
|
message: result.choices[0].message,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
|
public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
|
||||||
const result = await this.openAiApiClient.chat.completions.create({
|
const visionModel = this.options.visionModel ?? '04-mini';
|
||||||
model: 'gpt-4-vision-preview',
|
const requestParams: any = {
|
||||||
|
model: visionModel,
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
@@ -211,8 +225,8 @@ export class OpenAiProvider extends MultiModalModel {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
max_tokens: 300
|
max_tokens: 300
|
||||||
});
|
};
|
||||||
|
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
||||||
return result.choices[0].message.content || '';
|
return result.choices[0].message.content || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user