21 Commits

Author SHA1 Message Date
Juergen Kunz
4bf7113334 feat(documentation): comprehensive documentation enhancement and test improvements
Some checks failed
Default (tags) / security (push) Failing after 25s
Default (tags) / test (push) Failing after 12s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-07-25 18:00:23 +00:00
6bdbeae144 0.5.4 2025-05-13 18:39:58 +00:00
09c27379cb fix(provider.openai): Update dependency versions, clean test imports, and adjust default OpenAI model configurations 2025-05-13 18:39:57 +00:00
2bc6f7ee5e 0.5.3 2025-04-03 21:46:40 +00:00
0ac50d647d fix(package.json): Add explicit packageManager field to package.json 2025-04-03 21:46:40 +00:00
5f9ffc7356 0.5.2 2025-04-03 21:46:15 +00:00
502b665224 fix(readme): Remove redundant conclusion section from README to streamline documentation. 2025-04-03 21:46:14 +00:00
bda0d7ed7e 0.5.1 2025-02-25 19:15:32 +00:00
de2a60d12f fix(OpenAiProvider): Corrected audio model ID in OpenAiProvider 2025-02-25 19:15:32 +00:00
5b3a93a43a 0.5.0 2025-02-25 19:04:40 +00:00
6b241f8889 feat(documentation and configuration): Enhanced package and README documentation 2025-02-25 19:04:40 +00:00
0a80ac0a8a 0.4.2 2025-02-25 18:23:28 +00:00
6ce442354e fix(core): Fix OpenAI chat streaming and PDF document processing logic. 2025-02-25 18:23:28 +00:00
9b38a3c06e 0.4.1 2025-02-25 13:01:23 +00:00
5dead05324 fix(provider): Fix provider modules for consistency 2025-02-25 13:01:23 +00:00
6916dd9e2a 0.4.0 2025-02-08 12:08:14 +01:00
f89888a542 feat(core): Added support for Exo AI provider 2025-02-08 12:08:14 +01:00
d93b198b09 0.3.3 2025-02-05 14:24:34 +01:00
9e390d0fdb fix(documentation): Update readme with detailed license and legal information. 2025-02-05 14:24:34 +01:00
8329ee861e 0.3.2 2025-02-05 14:22:41 +01:00
b8585a0afb fix(documentation): Remove redundant badges from readme 2025-02-05 14:22:41 +01:00
13 changed files with 6929 additions and 1924 deletions

View File

@@ -1,5 +1,78 @@
# 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)
Added support for Exo AI provider
- Introduced ExoProvider with chat functionalities.
- Updated SmartAi class to initialize ExoProvider.
- Extended Conversation class to support ExoProvider.
## 2025-02-05 - 0.3.3 - fix(documentation)
Update readme with detailed license and legal information.
- Added explicit section on License and Legal Information in the README.
- Clarified the use of trademarks and company information.
## 2025-02-05 - 0.3.2 - fix(documentation)
Remove redundant badges from readme
- Removed Build Status badge from the readme file.
- Removed License badge from the readme file.
## 2025-02-05 - 0.3.1 - fix(documentation)
Updated README structure and added detailed usage examples

View File

@@ -5,20 +5,33 @@
"githost": "code.foss.global",
"gitscope": "push.rocks",
"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",
"license": "MIT",
"projectDomain": "push.rocks",
"keywords": [
"AI integration",
"chatbot",
"TypeScript",
"chatbot",
"OpenAI",
"Anthropic",
"multi-model support",
"audio responses",
"multi-model",
"audio generation",
"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"
]
}
},

View File

@@ -1,37 +1,37 @@
{
"name": "@push.rocks/smartai",
"version": "0.3.1",
"version": "0.5.5",
"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",
"typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Task Venture Capital GmbH",
"license": "MIT",
"scripts": {
"test": "(tstest test/ --web)",
"test": "(tstest test/ --web --verbose)",
"build": "(tsbuild --web --allowimplicitany)",
"buildDocs": "(tsdoc)"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.1.84",
"@git.zone/tsbundle": "^2.0.5",
"@git.zone/tsrun": "^1.2.49",
"@git.zone/tstest": "^1.0.90",
"@push.rocks/qenv": "^6.0.5",
"@push.rocks/tapbundle": "^5.3.0",
"@types/node": "^22.5.5"
"@git.zone/tsbuild": "^2.6.4",
"@git.zone/tsbundle": "^2.5.1",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.2",
"@push.rocks/qenv": "^6.1.0",
"@push.rocks/tapbundle": "^6.0.3",
"@types/node": "^22.15.17"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.27.3",
"@push.rocks/smartarray": "^1.0.8",
"@push.rocks/smartfile": "^11.0.21",
"@anthropic-ai/sdk": "^0.57.0",
"@push.rocks/smartarray": "^1.1.0",
"@push.rocks/smartfile": "^11.2.5",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpdf": "^3.1.6",
"@push.rocks/smartpromise": "^4.0.4",
"@push.rocks/smartrequest": "^2.0.22",
"@push.rocks/smartpdf": "^3.2.2",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^2.1.0",
"@push.rocks/webstream": "^1.0.10",
"openai": "^4.62.1"
"openai": "^5.10.2"
},
"repository": {
"type": "git",
@@ -58,13 +58,33 @@
],
"keywords": [
"AI integration",
"chatbot",
"TypeScript",
"chatbot",
"OpenAI",
"Anthropic",
"multi-model support",
"audio responses",
"multi-model",
"audio generation",
"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

File diff suppressed because it is too large Load Diff

515
readme.md
View File

@@ -1,333 +1,408 @@
# @push.rocks/smartai
[![npm version](https://badge.fury.io/js/%40push.rocks%2Fsmartai.svg)](https://www.npmjs.com/package/@push.rocks/smartai)
[![Build Status](https://github.com/push.rocks/smartai/workflows/CI/badge.svg)](https://github.com/push.rocks/smartai/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
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
- [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:
To install SmartAi into your project, use pnpm:
```bash
npm install @push.rocks/smartai
pnpm install @push.rocks/smartai
```
This will add the package to your projects 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
- **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
}
```
## Quick Start
Initialize SmartAi with the provider configurations you plan to use:
First, initialize SmartAi with the API tokens and configuration for the providers you want to use:
```typescript
import { SmartAi } from '@push.rocks/smartai';
const smartAi = new SmartAi({
openaiToken: 'your-openai-token',
xaiToken: 'your-xai-token',
anthropicToken: 'your-anthropic-token',
perplexityToken: 'your-perplexity-token',
groqToken: 'your-groq-token',
// OpenAI - for GPT models, DALL-E, and TTS
openaiToken: 'your-openai-api-key',
// Anthropic - for Claude models
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: {
baseUrl: 'http://localhost:11434',
model: 'llama2'
model: 'llama2', // default model for chat
visionModel: 'llava' // default model for vision
},
// Exo - for distributed inference
exo: {
baseUrl: 'http://localhost:8080/v1',
apiKey: 'your-exo-api-key'
}
});
// Start the SmartAi instance
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
const response = await smartAi.openaiProvider.chat({
// OpenAI Example
const openAiResponse = await smartAi.openaiProvider.chat({
systemMessage: 'You are a helpful assistant.',
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
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
// Create a transform stream for sending and receiving data
const { writable, readable } = new TransformStream();
// Create a readable stream for input
const { readable, writable } = new TransformStream();
const writer = writable.getWriter();
const message = {
// Send a message
const encoder = new TextEncoder();
await writer.write(encoder.encode(JSON.stringify({
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'));
// Start streaming the response
const stream = await smartAi.openaiProvider.chatStream(readable);
const reader = stream.getReader();
// Get streaming response
const responseStream = await smartAi.openaiProvider.chatStream(readable);
const reader = responseStream.getReader();
const decoder = new TextDecoder();
// Read the stream
while (true) {
const { done, value } = await reader.read();
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
import * as fs from 'fs';
// Generate speech from text
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
Analyze and extract key information from documents:
```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
// Or use in your application directly
audioStream.on('data', (chunk) => {
// Process audio chunks
});
```
Other providers (e.g., Ollama and Anthropic) follow a similar pattern:
### 3. Vision Processing
Analyze images and get detailed descriptions:
```typescript
// Using Ollama for document processing
const ollamaResult = await smartAi.ollamaProvider.document({
systemMessage: 'You are a document analysis assistant',
userMessage: 'Extract key information from this document',
import * as fs from 'fs';
// Read an image file
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: [],
pdfDocuments: [pdfBuffer]
});
```
console.log('OpenAI Analysis:', openAiAnalysis.message);
```typescript
// Using Anthropic for document processing
const anthropicResult = await smartAi.anthropicProvider.document({
systemMessage: 'Analyze the document',
userMessage: 'Please extract the main points',
// Analyze with Anthropic
const anthropicAnalysis = await smartAi.anthropicProvider.document({
systemMessage: 'You are a legal expert.',
userMessage: 'Identify any legal terms or implications in this document.',
messageHistory: [],
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
// Using OpenAI GPT-4 Vision
const imageDescription = await smartAi.openaiProvider.vision({
image: imageBuffer, // Uint8Array containing image data
prompt: 'What do you see in this image?'
});
// Create a conversation with OpenAI
const conversation = smartAi.createConversation('openai');
// Using Ollama for vision tasks
const ollamaImageAnalysis = await smartAi.ollamaProvider.vision({
image: imageBuffer,
prompt: 'Analyze this image in detail'
});
// Set the system message
await conversation.setSystemMessage('You are a helpful coding assistant.');
// Using Anthropic for vision analysis
const anthropicImageAnalysis = await smartAi.anthropicProvider.vision({
image: imageBuffer,
prompt: 'Describe the contents of this image'
});
// Get input and output streams
const inputWriter = conversation.getInputStreamWriter();
const outputStream = conversation.getOutputStream();
// 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
try {
const response = await smartAi.openaiProvider.chat({
systemMessage: 'You are a helpful assistant.',
systemMessage: 'You are an assistant.',
userMessage: 'Hello!',
messageHistory: []
});
console.log(response.message);
} catch (error: any) {
console.error('AI provider error:', error.message);
} catch (error) {
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
npm run test
// Apply to streaming chat
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
npm run build
// Anthropic - Use Claude's strength in analysis
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. Create a feature branch:
```bash
git checkout -b feature/my-feature
```
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.
// 2. Use streaming for long responses
// Streaming reduces time-to-first-token and memory usage
## License
// 3. Batch operations when possible
const promises = [
smartAi.openaiProvider.chat({ /* ... */ }),
smartAi.anthropicProvider.chat({ /* ... */ })
];
const results = await Promise.all(promises);
This project is licensed under the [MIT License](LICENSE).
// 4. Clean up resources
await smartAi.stop(); // When done
```
## Legal Information
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and its related products or services are trademarks of Task Venture Capital GmbH and are not covered by the MIT License. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines.
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
Contact: hello@task.vc
Registered at District court Bremen HRB 35230 HB, Germany
By using this repository, you agree to the terms outlined in this section.
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
---
Happy coding with SmartAi!
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

View File

@@ -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 smartrequest from '@push.rocks/smartrequest';
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({
systemMessage: 'Hello',
userMessage: userMessage,
messageHistory: [
],
messageHistory: [],
});
console.log(`userMessage: ${userMessage}`);
console.log(response.message);
@@ -55,7 +54,7 @@ tap.test('should recognize companies in a pdf', async () => {
address: string;
city: string;
country: string;
EU: boolean; // wether the entity is within EU
EU: boolean; // whether the entity is within EU
};
entityReceiver: {
type: 'official state entity' | 'company' | 'person';
@@ -63,7 +62,7 @@ tap.test('should recognize companies in a pdf', async () => {
address: string;
city: 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
title: string; // a short title, suitable for a filename
@@ -75,7 +74,24 @@ tap.test('should recognize companies in a pdf', async () => {
pdfDocuments: [pdfBuffer],
});
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 () => {
await testSmartai.stop();

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartai',
version: '0.3.1',
description: 'A TypeScript library for integrating and interacting with multiple AI models, offering capabilities for chat and potentially audio responses.'
version: '0.5.4',
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.'
}

View File

@@ -48,6 +48,18 @@ export class Conversation {
return conversation;
}
public static async createWithExo(smartaiRefArg: SmartAi) {
if (!smartaiRefArg.exoProvider) {
throw new Error('Exo provider not available');
}
const conversation = new Conversation(smartaiRefArg, {
processFunction: async (input) => {
return '' // TODO implement proper streaming
}
});
return conversation;
}
public static async createWithOllama(smartaiRefArg: SmartAi) {
if (!smartaiRefArg.ollamaProvider) {
throw new Error('Ollama provider not available');
@@ -60,6 +72,30 @@ export class Conversation {
return conversation;
}
public static async createWithGroq(smartaiRefArg: SmartAi) {
if (!smartaiRefArg.groqProvider) {
throw new Error('Groq provider not available');
}
const conversation = new Conversation(smartaiRefArg, {
processFunction: async (input) => {
return '' // TODO implement proper streaming
}
});
return conversation;
}
public static async createWithXai(smartaiRefArg: SmartAi) {
if (!smartaiRefArg.xaiProvider) {
throw new Error('XAI provider not available');
}
const conversation = new Conversation(smartaiRefArg, {
processFunction: async (input) => {
return '' // TODO implement proper streaming
}
});
return conversation;
}
// INSTANCE
smartaiRef: SmartAi
private systemMessage: string;

View File

@@ -1,18 +1,32 @@
import { Conversation } from './classes.conversation.js';
import * as plugins from './plugins.js';
import { AnthropicProvider } from './provider.anthropic.js';
import type { OllamaProvider } from './provider.ollama.js';
import { OllamaProvider } from './provider.ollama.js';
import { OpenAiProvider } from './provider.openai.js';
import type { PerplexityProvider } from './provider.perplexity.js';
import { PerplexityProvider } from './provider.perplexity.js';
import { ExoProvider } from './provider.exo.js';
import { GroqProvider } from './provider.groq.js';
import { XAIProvider } from './provider.xai.js';
export interface ISmartAiOptions {
openaiToken?: string;
anthropicToken?: string;
perplexityToken?: string;
groqToken?: string;
xaiToken?: string;
exo?: {
baseUrl?: string;
apiKey?: string;
};
ollama?: {
baseUrl?: string;
model?: string;
visionModel?: string;
};
}
export type TProvider = 'openai' | 'anthropic' | 'perplexity' | 'ollama';
export type TProvider = 'openai' | 'anthropic' | 'perplexity' | 'ollama' | 'exo' | 'groq' | 'xai';
export class SmartAi {
public options: ISmartAiOptions;
@@ -21,6 +35,9 @@ export class SmartAi {
public anthropicProvider: AnthropicProvider;
public perplexityProvider: PerplexityProvider;
public ollamaProvider: OllamaProvider;
public exoProvider: ExoProvider;
public groqProvider: GroqProvider;
public xaiProvider: XAIProvider;
constructor(optionsArg: ISmartAiOptions) {
this.options = optionsArg;
@@ -37,6 +54,40 @@ export class SmartAi {
this.anthropicProvider = new AnthropicProvider({
anthropicToken: this.options.anthropicToken,
});
await this.anthropicProvider.start();
}
if (this.options.perplexityToken) {
this.perplexityProvider = new PerplexityProvider({
perplexityToken: this.options.perplexityToken,
});
await this.perplexityProvider.start();
}
if (this.options.groqToken) {
this.groqProvider = new GroqProvider({
groqToken: this.options.groqToken,
});
await this.groqProvider.start();
}
if (this.options.xaiToken) {
this.xaiProvider = new XAIProvider({
xaiToken: this.options.xaiToken,
});
await this.xaiProvider.start();
}
if (this.options.ollama) {
this.ollamaProvider = new OllamaProvider({
baseUrl: this.options.ollama.baseUrl,
model: this.options.ollama.model,
visionModel: this.options.ollama.visionModel,
});
await this.ollamaProvider.start();
}
if (this.options.exo) {
this.exoProvider = new ExoProvider({
exoBaseUrl: this.options.exo.baseUrl,
apiKey: this.options.exo.apiKey,
});
await this.exoProvider.start();
}
}
@@ -47,6 +98,8 @@ export class SmartAi {
*/
createConversation(provider: TProvider) {
switch (provider) {
case 'exo':
return Conversation.createWithExo(this);
case 'openai':
return Conversation.createWithOpenAi(this);
case 'anthropic':
@@ -55,6 +108,10 @@ export class SmartAi {
return Conversation.createWithPerplexity(this);
case 'ollama':
return Conversation.createWithOllama(this);
case 'groq':
return Conversation.createWithGroq(this);
case 'xai':
return Conversation.createWithXai(this);
default:
throw new Error('Provider not available');
}

128
ts/provider.exo.ts Normal file
View File

@@ -0,0 +1,128 @@
import * as plugins from './plugins.js';
import * as paths from './paths.js';
import { MultiModalModel } from './abstract.classes.multimodal.js';
import type { ChatOptions, ChatResponse, ChatMessage } from './abstract.classes.multimodal.js';
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
export interface IExoProviderOptions {
exoBaseUrl?: string;
apiKey?: string;
}
export class ExoProvider extends MultiModalModel {
private options: IExoProviderOptions;
public openAiApiClient: plugins.openai.default;
constructor(optionsArg: IExoProviderOptions = {}) {
super();
this.options = {
exoBaseUrl: 'http://localhost:8080/v1', // Default Exo API endpoint
...optionsArg
};
}
public async start() {
this.openAiApiClient = new plugins.openai.default({
apiKey: this.options.apiKey || 'not-needed', // Exo might not require an API key for local deployment
baseURL: this.options.exoBaseUrl,
});
}
public async stop() {}
public async chatStream(input: ReadableStream<Uint8Array>): Promise<ReadableStream<string>> {
// Create a TextDecoder to handle incoming chunks
const decoder = new TextDecoder();
let buffer = '';
let currentMessage: { role: string; content: string; } | null = null;
// Create a TransformStream to process the input
const transform = new TransformStream<Uint8Array, string>({
transform: async (chunk, controller) => {
buffer += decoder.decode(chunk, { stream: true });
// Try to parse complete JSON messages from the buffer
while (true) {
const newlineIndex = buffer.indexOf('\n');
if (newlineIndex === -1) break;
const line = buffer.slice(0, newlineIndex);
buffer = buffer.slice(newlineIndex + 1);
if (line.trim()) {
try {
const message = JSON.parse(line);
currentMessage = message;
// Process the message based on its type
if (message.type === 'message') {
const response = await this.chat({
systemMessage: '',
userMessage: message.content,
messageHistory: [{ role: message.role as 'user' | 'assistant' | 'system', content: message.content }]
});
controller.enqueue(JSON.stringify(response) + '\n');
}
} catch (error) {
console.error('Error processing message:', error);
}
}
}
},
flush(controller) {
if (buffer) {
try {
const message = JSON.parse(buffer);
currentMessage = message;
} catch (error) {
console.error('Error processing remaining buffer:', error);
}
}
}
});
return input.pipeThrough(transform);
}
public async chat(options: ChatOptions): Promise<ChatResponse> {
const messages: ChatCompletionMessageParam[] = [
{ role: 'system', content: options.systemMessage },
...options.messageHistory,
{ role: 'user', content: options.userMessage }
];
try {
const response = await this.openAiApiClient.chat.completions.create({
model: 'local-model', // Exo uses local models
messages: messages,
stream: false
});
return {
role: 'assistant',
message: response.choices[0]?.message?.content || ''
};
} catch (error) {
console.error('Error in chat completion:', error);
throw error;
}
}
public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
throw new Error('Audio generation is not supported by Exo provider');
}
public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
throw new Error('Vision processing is not supported by Exo provider');
}
public async document(optionsArg: {
systemMessage: string;
userMessage: string;
pdfDocuments: Uint8Array[];
messageHistory: ChatMessage[];
}): Promise<{ message: any }> {
throw new Error('Document processing is not supported by Exo provider');
}
}

View File

@@ -32,7 +32,7 @@ export class GroqProvider extends MultiModalModel {
// Create a TransformStream to process the input
const transform = new TransformStream<Uint8Array, string>({
async transform(chunk, controller) {
transform: async (chunk, controller) => {
buffer += decoder.decode(chunk, { stream: true });
// Try to parse complete JSON messages from the buffer

View File

@@ -45,7 +45,7 @@ export class OllamaProvider extends MultiModalModel {
// Create a TransformStream to process the input
const transform = new TransformStream<Uint8Array, string>({
async transform(chunk, controller) {
transform: async (chunk, controller) => {
buffer += decoder.decode(chunk, { stream: true });
// Try to parse complete JSON messages from the buffer

View File

@@ -1,10 +1,20 @@
import * as plugins from './plugins.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';
export interface IOpenaiProviderOptions {
openaiToken: string;
chatModel?: string;
audioModel?: string;
visionModel?: string;
// Optionally add more model options (e.g., documentModel) if needed.
}
export class OpenAiProvider extends MultiModalModel {
@@ -31,11 +41,14 @@ export class OpenAiProvider extends MultiModalModel {
// Create a TextDecoder to handle incoming chunks
const decoder = new TextDecoder();
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
const transform = new TransformStream<Uint8Array, string>({
async transform(chunk, controller) {
transform: async (chunk, controller) => {
buffer += decoder.decode(chunk, { stream: true });
// Try to parse complete JSON messages from the buffer
@@ -50,7 +63,7 @@ export class OpenAiProvider extends MultiModalModel {
try {
const message = JSON.parse(line);
currentMessage = {
role: message.role || 'user',
role: (message.role || 'user') as "function" | "user" | "system" | "assistant" | "tool" | "developer",
content: message.content || '',
};
} catch (e) {
@@ -61,20 +74,24 @@ export class OpenAiProvider extends MultiModalModel {
// If we have a complete message, send it to OpenAI
if (currentMessage) {
const stream = await this.openAiApiClient.chat.completions.create({
model: 'gpt-4',
messages: [{ role: currentMessage.role, content: currentMessage.content }],
const messageToSend = { role: "user" as const, content: currentMessage.content };
const chatModel = this.options.chatModel ?? 'o3-mini';
const requestParams: any = {
model: chatModel,
messages: [messageToSend],
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
for await (const chunk of stream) {
for await (const chunk of streamAsyncIterable) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
controller.enqueue(content);
}
}
currentMessage = null;
}
},
@@ -104,15 +121,17 @@ export class OpenAiProvider extends MultiModalModel {
content: string;
}[];
}) {
const result = await this.openAiApiClient.chat.completions.create({
model: 'gpt-4o',
const chatModel = this.options.chatModel ?? 'o3-mini';
const requestParams: any = {
model: chatModel,
messages: [
{ role: 'system', content: optionsArg.systemMessage },
...optionsArg.messageHistory,
{ role: 'user', content: optionsArg.userMessage },
],
});
};
// Temperature parameter removed to avoid unsupported error.
const result = await this.openAiApiClient.chat.completions.create(requestParams);
return {
role: result.choices[0].message.role as 'assistant',
message: result.choices[0].message.content,
@@ -122,7 +141,7 @@ export class OpenAiProvider extends MultiModalModel {
public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
const done = plugins.smartpromise.defer<NodeJS.ReadableStream>();
const result = await this.openAiApiClient.audio.speech.create({
model: 'tts-1-hd',
model: this.options.audioModel ?? 'tts-1-hd',
input: optionsArg.message,
voice: 'nova',
response_format: 'mp3',
@@ -144,27 +163,30 @@ export class OpenAiProvider extends MultiModalModel {
}) {
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) {
const documentImageArray = await this.smartpdfInstance.convertPDFToPngBytes(pdfDocument);
const documentImageArray = await smartpdfInstance.convertPDFToPngBytes(pdfDocument);
pdfDocumentImageBytesArray = pdfDocumentImageBytesArray.concat(documentImageArray);
}
await smartpdfInstance.stop();
console.log(`image smartfile array`);
console.log(pdfDocumentImageBytesArray.map((smartfile) => smartfile.length));
const smartfileArray = await plugins.smartarray.map(
pdfDocumentImageBytesArray,
async (pdfDocumentImageBytes) => {
return plugins.smartfile.SmartFile.fromBuffer(
'pdfDocumentImage.jpg',
Buffer.from(pdfDocumentImageBytes)
);
}
);
// Filter out any empty buffers to avoid sending invalid image URLs.
const validImageBytesArray = pdfDocumentImageBytesArray.filter(imageBytes => imageBytes && imageBytes.length > 0);
const imageAttachments = validImageBytesArray.map(imageBytes => ({
type: 'image_url',
image_url: {
url: 'data:image/png;base64,' + Buffer.from(imageBytes).toString('base64'),
},
}));
const result = await this.openAiApiClient.chat.completions.create({
model: 'gpt-4o',
// response_format: { type: "json_object" }, // not supported for now
const chatModel = this.options.chatModel ?? 'o4-mini';
const requestParams: any = {
model: chatModel,
messages: [
{ role: 'system', content: optionsArg.systemMessage },
...optionsArg.messageHistory,
@@ -172,30 +194,22 @@ export class OpenAiProvider extends MultiModalModel {
role: 'user',
content: [
{ type: 'text', text: optionsArg.userMessage },
...(() => {
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;
})(),
...imageAttachments,
],
},
],
});
};
// Temperature parameter removed.
const result = await this.openAiApiClient.chat.completions.create(requestParams);
return {
message: result.choices[0].message,
};
}
public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
const result = await this.openAiApiClient.chat.completions.create({
model: 'gpt-4-vision-preview',
const visionModel = this.options.visionModel ?? '04-mini';
const requestParams: any = {
model: visionModel,
messages: [
{
role: 'user',
@@ -211,8 +225,8 @@ export class OpenAiProvider extends MultiModalModel {
}
],
max_tokens: 300
});
};
const result = await this.openAiApiClient.chat.completions.create(requestParams);
return result.choices[0].message.content || '';
}
}