@bernierllc/openai-client 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +291 -0
- package/dist/OpenAIClient.d.ts +17 -0
- package/dist/OpenAIClient.d.ts.map +1 -0
- package/dist/OpenAIClient.js +294 -0
- package/dist/OpenAIClient.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# @bernierllc/openai-client
|
|
2
|
+
|
|
3
|
+
Type-safe OpenAI API client with automatic rate limiting, retry logic, streaming support, and cost tracking.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bernierllc/openai-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Type-safe API**: Full TypeScript support with strict typing
|
|
14
|
+
- **Automatic Retries**: Built-in retry logic with exponential backoff
|
|
15
|
+
- **Rate Limiting**: Configurable request rate limiting
|
|
16
|
+
- **Cost Tracking**: Automatic tracking of API usage and costs
|
|
17
|
+
- **Streaming Support**: Stream completions with real-time chunks
|
|
18
|
+
- **Multiple Models**: Support for GPT-4, GPT-4 Turbo, GPT-4o, GPT-3.5 Turbo
|
|
19
|
+
- **Usage Statistics**: Track tokens, costs, and requests by model
|
|
20
|
+
- **Logger Integration**: Uses @bernierllc/logger for structured logging
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Basic Completion
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { OpenAIClient, OpenAIModel } from '@bernierllc/openai-client';
|
|
28
|
+
|
|
29
|
+
const client = new OpenAIClient({
|
|
30
|
+
apiKey: process.env.OPENAI_API_KEY
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const result = await client.complete('Explain quantum computing in simple terms', {
|
|
34
|
+
model: OpenAIModel.GPT_4O,
|
|
35
|
+
maxTokens: 500
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (result.success) {
|
|
39
|
+
console.log(result.content);
|
|
40
|
+
console.log('Cost:', result.cost?.totalCost);
|
|
41
|
+
console.log('Tokens:', result.usage?.totalTokens);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Streaming Response
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const result = await client.stream(
|
|
49
|
+
'Write a short story about a robot',
|
|
50
|
+
(chunk) => {
|
|
51
|
+
process.stdout.write(chunk);
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
model: OpenAIModel.GPT_4O_MINI,
|
|
55
|
+
maxTokens: 1000
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
console.log('\nStreaming complete!');
|
|
60
|
+
console.log('Total cost:', result.cost?.totalCost);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### With System Prompt
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const result = await client.complete(
|
|
67
|
+
'What is the capital of France?',
|
|
68
|
+
{
|
|
69
|
+
systemPrompt: 'You are a helpful geography teacher. Keep answers brief.',
|
|
70
|
+
model: OpenAIModel.GPT_35_TURBO,
|
|
71
|
+
temperature: 0.7
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Advanced Configuration
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const client = new OpenAIClient({
|
|
80
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
81
|
+
organization: 'org-123',
|
|
82
|
+
defaultModel: OpenAIModel.GPT_4O,
|
|
83
|
+
maxRetries: 5,
|
|
84
|
+
rateLimit: {
|
|
85
|
+
requestsPerMinute: 60,
|
|
86
|
+
tokensPerMinute: 90000
|
|
87
|
+
},
|
|
88
|
+
enableLogging: true
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Cost Tracking
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Make several requests
|
|
96
|
+
await client.complete('Question 1');
|
|
97
|
+
await client.complete('Question 2');
|
|
98
|
+
await client.complete('Question 3');
|
|
99
|
+
|
|
100
|
+
// Get usage statistics
|
|
101
|
+
const stats = client.getUsage();
|
|
102
|
+
|
|
103
|
+
console.log('Total Requests:', stats.totalRequests);
|
|
104
|
+
console.log('Total Tokens:', stats.totalTokens);
|
|
105
|
+
console.log('Total Cost: $', stats.totalCost.toFixed(4));
|
|
106
|
+
console.log('Requests by Model:', stats.requestsByModel);
|
|
107
|
+
|
|
108
|
+
// Reset statistics
|
|
109
|
+
client.resetUsage();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Rate Limiting
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const client = new OpenAIClient({
|
|
116
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
117
|
+
rateLimit: {
|
|
118
|
+
requestsPerMinute: 10,
|
|
119
|
+
tokensPerMinute: 10000
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Check rate limit status
|
|
124
|
+
const status = client.getRateLimitStatus();
|
|
125
|
+
console.log('Requests remaining:', status?.requestsRemaining);
|
|
126
|
+
console.log('Reset time:', status?.resetTime);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Disable Rate Limiting
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const client = new OpenAIClient({
|
|
133
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
134
|
+
rateLimit: null // Disable rate limiting
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## API Reference
|
|
139
|
+
|
|
140
|
+
### OpenAIClient
|
|
141
|
+
|
|
142
|
+
#### Constructor
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
new OpenAIClient(config: OpenAIClientConfig)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Config Options:**
|
|
149
|
+
|
|
150
|
+
- `apiKey` (required): OpenAI API key
|
|
151
|
+
- `organization` (optional): OpenAI organization ID
|
|
152
|
+
- `defaultModel` (optional): Default model to use (default: GPT_4O_MINI)
|
|
153
|
+
- `maxRetries` (optional): Maximum retry attempts (default: 3)
|
|
154
|
+
- `rateLimit` (optional): Rate limiting configuration or null to disable
|
|
155
|
+
- `enableLogging` (optional): Enable logging (default: true)
|
|
156
|
+
|
|
157
|
+
#### Methods
|
|
158
|
+
|
|
159
|
+
##### `complete(prompt: string, options?: CompletionOptions): Promise<CompletionResult>`
|
|
160
|
+
|
|
161
|
+
Send a completion request to OpenAI.
|
|
162
|
+
|
|
163
|
+
**Options:**
|
|
164
|
+
|
|
165
|
+
- `model`: OpenAI model to use
|
|
166
|
+
- `maxTokens`: Maximum tokens to generate (default: 1024)
|
|
167
|
+
- `temperature`: Sampling temperature (0-2)
|
|
168
|
+
- `topP`: Nucleus sampling parameter
|
|
169
|
+
- `frequencyPenalty`: Frequency penalty (-2 to 2)
|
|
170
|
+
- `presencePenalty`: Presence penalty (-2 to 2)
|
|
171
|
+
- `stopSequences`: Array of stop sequences
|
|
172
|
+
- `systemPrompt`: System message for conversation
|
|
173
|
+
- `user`: Unique user identifier for abuse monitoring
|
|
174
|
+
|
|
175
|
+
**Returns:**
|
|
176
|
+
|
|
177
|
+
- `success`: Whether the request succeeded
|
|
178
|
+
- `content`: Generated text content
|
|
179
|
+
- `usage`: Token usage statistics
|
|
180
|
+
- `cost`: Cost breakdown (input, output, total)
|
|
181
|
+
- `model`: Model used
|
|
182
|
+
- `finishReason`: Why generation stopped
|
|
183
|
+
- `error`: Error message if failed
|
|
184
|
+
|
|
185
|
+
##### `stream(prompt: string, onChunk: StreamChunkCallback, options?: CompletionOptions): Promise<CompletionResult>`
|
|
186
|
+
|
|
187
|
+
Stream a completion response with real-time chunks.
|
|
188
|
+
|
|
189
|
+
**Parameters:**
|
|
190
|
+
|
|
191
|
+
- `prompt`: The prompt text
|
|
192
|
+
- `onChunk`: Callback function called for each chunk
|
|
193
|
+
- `options`: Same as `complete()` options
|
|
194
|
+
|
|
195
|
+
##### `getUsage(): UsageStats`
|
|
196
|
+
|
|
197
|
+
Get current usage statistics.
|
|
198
|
+
|
|
199
|
+
**Returns:**
|
|
200
|
+
|
|
201
|
+
- `totalRequests`: Total number of requests
|
|
202
|
+
- `totalInputTokens`: Total input tokens used
|
|
203
|
+
- `totalOutputTokens`: Total output tokens used
|
|
204
|
+
- `totalTokens`: Total tokens (input + output)
|
|
205
|
+
- `totalCost`: Total cost in USD
|
|
206
|
+
- `requestsByModel`: Request count per model
|
|
207
|
+
|
|
208
|
+
##### `getRateLimitStatus(): RateLimitStatus | null`
|
|
209
|
+
|
|
210
|
+
Get current rate limit status. Returns `null` if rate limiting is disabled.
|
|
211
|
+
|
|
212
|
+
**Returns:**
|
|
213
|
+
|
|
214
|
+
- `requestsRemaining`: Requests remaining in current window
|
|
215
|
+
- `tokensRemaining`: Tokens remaining (currently not tracked)
|
|
216
|
+
- `resetTime`: When the rate limit resets
|
|
217
|
+
|
|
218
|
+
##### `resetUsage(): void`
|
|
219
|
+
|
|
220
|
+
Reset all usage statistics.
|
|
221
|
+
|
|
222
|
+
### Models
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
enum OpenAIModel {
|
|
226
|
+
GPT_4 = 'gpt-4',
|
|
227
|
+
GPT_4_TURBO = 'gpt-4-turbo-preview',
|
|
228
|
+
GPT_4O = 'gpt-4o',
|
|
229
|
+
GPT_4O_MINI = 'gpt-4o-mini',
|
|
230
|
+
GPT_35_TURBO = 'gpt-3.5-turbo',
|
|
231
|
+
GPT_35_TURBO_16K = 'gpt-3.5-turbo-16k'
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Pricing (per 1M tokens)
|
|
236
|
+
|
|
237
|
+
| Model | Input | Output |
|
|
238
|
+
|-------|-------|--------|
|
|
239
|
+
| GPT-4 | $30.00 | $60.00 |
|
|
240
|
+
| GPT-4 Turbo | $10.00 | $30.00 |
|
|
241
|
+
| GPT-4o | $2.50 | $10.00 |
|
|
242
|
+
| GPT-4o Mini | $0.15 | $0.60 |
|
|
243
|
+
| GPT-3.5 Turbo | $0.50 | $1.50 |
|
|
244
|
+
| GPT-3.5 Turbo 16K | $3.00 | $4.00 |
|
|
245
|
+
|
|
246
|
+
*Pricing as of January 2025. Check OpenAI's pricing page for current rates.*
|
|
247
|
+
|
|
248
|
+
## Error Handling
|
|
249
|
+
|
|
250
|
+
The client automatically retries failed requests with exponential backoff. All methods return a `CompletionResult` with a `success` flag:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const result = await client.complete('Test prompt');
|
|
254
|
+
|
|
255
|
+
if (result.success) {
|
|
256
|
+
console.log('Success:', result.content);
|
|
257
|
+
} else {
|
|
258
|
+
console.error('Error:', result.error);
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Integration
|
|
263
|
+
|
|
264
|
+
### Logger Integration
|
|
265
|
+
|
|
266
|
+
This package uses [@bernierllc/logger](../logger) for structured logging. Logs include:
|
|
267
|
+
|
|
268
|
+
- Request start/completion
|
|
269
|
+
- Retry attempts
|
|
270
|
+
- Rate limiting events
|
|
271
|
+
- Cost and token usage
|
|
272
|
+
- Error details
|
|
273
|
+
|
|
274
|
+
### Retry Policy Integration
|
|
275
|
+
|
|
276
|
+
Uses [@bernierllc/retry-policy](../retry-policy) for intelligent retry logic with:
|
|
277
|
+
|
|
278
|
+
- Exponential backoff
|
|
279
|
+
- Jitter to prevent thundering herd
|
|
280
|
+
- Configurable retry attempts
|
|
281
|
+
- Automatic error classification
|
|
282
|
+
|
|
283
|
+
## See Also
|
|
284
|
+
|
|
285
|
+
- [@bernierllc/anthropic-client](../anthropic-client) - Anthropic Claude API client
|
|
286
|
+
- [@bernierllc/logger](../logger) - Structured logging
|
|
287
|
+
- [@bernierllc/retry-policy](../retry-policy) - Retry logic utilities
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
Copyright (c) 2025 Bernier LLC. All rights reserved.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpenAIClientConfig, CompletionOptions, CompletionResult, StreamChunkCallback, UsageStats, RateLimitStatus } from './types';
|
|
2
|
+
export declare class OpenAIClient {
|
|
3
|
+
private client;
|
|
4
|
+
private logger;
|
|
5
|
+
private rateLimiter;
|
|
6
|
+
private config;
|
|
7
|
+
private stats;
|
|
8
|
+
constructor(config: OpenAIClientConfig);
|
|
9
|
+
complete(prompt: string, options?: CompletionOptions): Promise<CompletionResult>;
|
|
10
|
+
stream(prompt: string, onChunk: StreamChunkCallback, options?: CompletionOptions): Promise<CompletionResult>;
|
|
11
|
+
getUsage(): UsageStats;
|
|
12
|
+
getRateLimitStatus(): RateLimitStatus | null;
|
|
13
|
+
resetUsage(): void;
|
|
14
|
+
private updateStats;
|
|
15
|
+
private sleep;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=OpenAIClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAIClient.d.ts","sourceRoot":"","sources":["../src/OpenAIClient.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,EACV,eAAe,EAGhB,MAAM,SAAS,CAAC;AA2CjB,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,MAAM,CAAiF;IAC/F,OAAO,CAAC,KAAK,CAOX;gBAEU,MAAM,EAAE,kBAAkB;IA+ChC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuHpF,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;IAmG5B,QAAQ,IAAI,UAAU;IAOtB,kBAAkB,IAAI,eAAe,GAAG,IAAI;IAkB5C,UAAU,IAAI,IAAI;IAYlB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OpenAIClient = void 0;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
const logger_1 = require("@bernierllc/logger");
|
|
9
|
+
const retry_policy_1 = require("@bernierllc/retry-policy");
|
|
10
|
+
const types_1 = require("./types");
|
|
11
|
+
class SimpleRateLimiter {
|
|
12
|
+
constructor(maxRequests, windowMs) {
|
|
13
|
+
this.maxRequests = maxRequests;
|
|
14
|
+
this.windowMs = windowMs;
|
|
15
|
+
this.requests = [];
|
|
16
|
+
}
|
|
17
|
+
tryAcquire() {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
this.requests = this.requests.filter(time => now - time < this.windowMs);
|
|
20
|
+
if (this.requests.length < this.maxRequests) {
|
|
21
|
+
this.requests.push(now);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
getWaitTime() {
|
|
27
|
+
if (this.requests.length === 0)
|
|
28
|
+
return 0;
|
|
29
|
+
const oldestRequest = Math.min(...this.requests);
|
|
30
|
+
const waitTime = this.windowMs - (Date.now() - oldestRequest);
|
|
31
|
+
return Math.max(0, waitTime);
|
|
32
|
+
}
|
|
33
|
+
getRemainingRequests() {
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
this.requests = this.requests.filter(time => now - time < this.windowMs);
|
|
36
|
+
return Math.max(0, this.maxRequests - this.requests.length);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
class OpenAIClient {
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.rateLimiter = null;
|
|
42
|
+
this.stats = {
|
|
43
|
+
totalRequests: 0,
|
|
44
|
+
totalInputTokens: 0,
|
|
45
|
+
totalOutputTokens: 0,
|
|
46
|
+
totalTokens: 0,
|
|
47
|
+
totalCost: 0,
|
|
48
|
+
requestsByModel: {}
|
|
49
|
+
};
|
|
50
|
+
if (!config.apiKey) {
|
|
51
|
+
throw new Error('API key is required');
|
|
52
|
+
}
|
|
53
|
+
this.config = {
|
|
54
|
+
apiKey: config.apiKey,
|
|
55
|
+
maxRetries: config.maxRetries ?? 3,
|
|
56
|
+
rateLimit: config.rateLimit === null ? null : (config.rateLimit ?? {
|
|
57
|
+
requestsPerMinute: 60,
|
|
58
|
+
tokensPerMinute: 90000
|
|
59
|
+
}),
|
|
60
|
+
defaultModel: config.defaultModel ?? types_1.OpenAIModel.GPT_4O_MINI,
|
|
61
|
+
enableLogging: config.enableLogging ?? true,
|
|
62
|
+
organization: config.organization
|
|
63
|
+
};
|
|
64
|
+
this.client = new openai_1.default({
|
|
65
|
+
apiKey: this.config.apiKey,
|
|
66
|
+
organization: this.config.organization
|
|
67
|
+
});
|
|
68
|
+
this.logger = new logger_1.Logger({
|
|
69
|
+
level: this.config.enableLogging ? logger_1.LogLevel.INFO : logger_1.LogLevel.ERROR,
|
|
70
|
+
transports: [
|
|
71
|
+
new logger_1.ConsoleTransport({
|
|
72
|
+
level: this.config.enableLogging ? logger_1.LogLevel.INFO : logger_1.LogLevel.ERROR
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
if (this.config.rateLimit) {
|
|
77
|
+
this.rateLimiter = new SimpleRateLimiter(this.config.rateLimit.requestsPerMinute, 60000);
|
|
78
|
+
}
|
|
79
|
+
this.logger.info('OpenAIClient initialized', {
|
|
80
|
+
model: this.config.defaultModel,
|
|
81
|
+
rateLimit: this.config.rateLimit
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async complete(prompt, options = {}) {
|
|
85
|
+
const model = options.model ?? this.config.defaultModel;
|
|
86
|
+
const maxTokens = options.maxTokens ?? 1024;
|
|
87
|
+
this.logger.debug('Starting completion request', { model, promptLength: prompt.length });
|
|
88
|
+
let attempt = 0;
|
|
89
|
+
let lastError = null;
|
|
90
|
+
while (attempt < this.config.maxRetries) {
|
|
91
|
+
try {
|
|
92
|
+
if (this.rateLimiter && !this.rateLimiter.tryAcquire()) {
|
|
93
|
+
const waitTime = this.rateLimiter.getWaitTime();
|
|
94
|
+
this.logger.warn('Rate limit reached, waiting', { waitTime });
|
|
95
|
+
await this.sleep(waitTime);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const messages = [];
|
|
99
|
+
if (options.systemPrompt) {
|
|
100
|
+
messages.push({ role: 'system', content: options.systemPrompt });
|
|
101
|
+
}
|
|
102
|
+
messages.push({ role: 'user', content: prompt });
|
|
103
|
+
const response = await this.client.chat.completions.create({
|
|
104
|
+
model,
|
|
105
|
+
messages,
|
|
106
|
+
max_tokens: maxTokens,
|
|
107
|
+
temperature: options.temperature,
|
|
108
|
+
top_p: options.topP,
|
|
109
|
+
frequency_penalty: options.frequencyPenalty,
|
|
110
|
+
presence_penalty: options.presencePenalty,
|
|
111
|
+
stop: options.stopSequences,
|
|
112
|
+
user: options.user
|
|
113
|
+
});
|
|
114
|
+
const content = response.choices[0]?.message?.content || '';
|
|
115
|
+
const inputTokens = response.usage?.prompt_tokens || 0;
|
|
116
|
+
const outputTokens = response.usage?.completion_tokens || 0;
|
|
117
|
+
const totalTokens = inputTokens + outputTokens;
|
|
118
|
+
const pricing = types_1.MODEL_PRICING[model];
|
|
119
|
+
const inputCost = (inputTokens / 1000000) * pricing.input;
|
|
120
|
+
const outputCost = (outputTokens / 1000000) * pricing.output;
|
|
121
|
+
const totalCost = inputCost + outputCost;
|
|
122
|
+
this.updateStats(model, inputTokens, outputTokens, totalCost);
|
|
123
|
+
this.logger.info('Completion successful', {
|
|
124
|
+
model,
|
|
125
|
+
inputTokens,
|
|
126
|
+
outputTokens,
|
|
127
|
+
totalCost: totalCost.toFixed(6)
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
content,
|
|
132
|
+
usage: {
|
|
133
|
+
inputTokens,
|
|
134
|
+
outputTokens,
|
|
135
|
+
totalTokens
|
|
136
|
+
},
|
|
137
|
+
cost: {
|
|
138
|
+
inputCost,
|
|
139
|
+
outputCost,
|
|
140
|
+
totalCost
|
|
141
|
+
},
|
|
142
|
+
model,
|
|
143
|
+
finishReason: response.choices[0]?.finish_reason || undefined
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
lastError = error;
|
|
148
|
+
attempt++;
|
|
149
|
+
if (attempt < this.config.maxRetries && (0, retry_policy_1.shouldRetry)(attempt, error)) {
|
|
150
|
+
const delay = (0, retry_policy_1.calculateRetryDelay)(attempt, {
|
|
151
|
+
initialDelayMs: 1000,
|
|
152
|
+
maxDelayMs: 30000,
|
|
153
|
+
jitter: true
|
|
154
|
+
});
|
|
155
|
+
this.logger.warn('Request failed, retrying', {
|
|
156
|
+
attempt,
|
|
157
|
+
delay,
|
|
158
|
+
error: error.message
|
|
159
|
+
});
|
|
160
|
+
await this.sleep(delay);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (lastError) {
|
|
168
|
+
this.logger.error('Completion failed after retries', lastError, {
|
|
169
|
+
attempts: attempt
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
error: lastError?.message ?? 'Unknown error'
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
async stream(prompt, onChunk, options = {}) {
|
|
178
|
+
const model = options.model ?? this.config.defaultModel;
|
|
179
|
+
const maxTokens = options.maxTokens ?? 1024;
|
|
180
|
+
this.logger.debug('Starting streaming request', { model, promptLength: prompt.length });
|
|
181
|
+
try {
|
|
182
|
+
if (this.rateLimiter && !this.rateLimiter.tryAcquire()) {
|
|
183
|
+
const waitTime = this.rateLimiter.getWaitTime();
|
|
184
|
+
this.logger.warn('Rate limit reached, waiting', { waitTime });
|
|
185
|
+
await this.sleep(waitTime);
|
|
186
|
+
}
|
|
187
|
+
const messages = [];
|
|
188
|
+
if (options.systemPrompt) {
|
|
189
|
+
messages.push({ role: 'system', content: options.systemPrompt });
|
|
190
|
+
}
|
|
191
|
+
messages.push({ role: 'user', content: prompt });
|
|
192
|
+
const stream = await this.client.chat.completions.create({
|
|
193
|
+
model,
|
|
194
|
+
messages,
|
|
195
|
+
max_tokens: maxTokens,
|
|
196
|
+
temperature: options.temperature,
|
|
197
|
+
top_p: options.topP,
|
|
198
|
+
frequency_penalty: options.frequencyPenalty,
|
|
199
|
+
presence_penalty: options.presencePenalty,
|
|
200
|
+
stop: options.stopSequences,
|
|
201
|
+
user: options.user,
|
|
202
|
+
stream: true
|
|
203
|
+
});
|
|
204
|
+
let fullContent = '';
|
|
205
|
+
let finishReason = '';
|
|
206
|
+
for await (const chunk of stream) {
|
|
207
|
+
const delta = chunk.choices[0]?.delta?.content;
|
|
208
|
+
if (delta) {
|
|
209
|
+
fullContent += delta;
|
|
210
|
+
await onChunk(delta);
|
|
211
|
+
}
|
|
212
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
213
|
+
finishReason = chunk.choices[0].finish_reason;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const estimatedInputTokens = Math.ceil((prompt.length + (options.systemPrompt?.length || 0)) / 4);
|
|
217
|
+
const estimatedOutputTokens = Math.ceil(fullContent.length / 4);
|
|
218
|
+
const totalTokens = estimatedInputTokens + estimatedOutputTokens;
|
|
219
|
+
const pricing = types_1.MODEL_PRICING[model];
|
|
220
|
+
const inputCost = (estimatedInputTokens / 1000000) * pricing.input;
|
|
221
|
+
const outputCost = (estimatedOutputTokens / 1000000) * pricing.output;
|
|
222
|
+
const totalCost = inputCost + outputCost;
|
|
223
|
+
this.updateStats(model, estimatedInputTokens, estimatedOutputTokens, totalCost);
|
|
224
|
+
this.logger.info('Streaming completed', {
|
|
225
|
+
model,
|
|
226
|
+
estimatedInputTokens,
|
|
227
|
+
estimatedOutputTokens,
|
|
228
|
+
totalCost: totalCost.toFixed(6)
|
|
229
|
+
});
|
|
230
|
+
return {
|
|
231
|
+
success: true,
|
|
232
|
+
content: fullContent,
|
|
233
|
+
usage: {
|
|
234
|
+
inputTokens: estimatedInputTokens,
|
|
235
|
+
outputTokens: estimatedOutputTokens,
|
|
236
|
+
totalTokens
|
|
237
|
+
},
|
|
238
|
+
cost: {
|
|
239
|
+
inputCost,
|
|
240
|
+
outputCost,
|
|
241
|
+
totalCost
|
|
242
|
+
},
|
|
243
|
+
model,
|
|
244
|
+
finishReason
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
this.logger.error('Streaming failed', error);
|
|
249
|
+
return {
|
|
250
|
+
success: false,
|
|
251
|
+
error: error.message
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
getUsage() {
|
|
256
|
+
return { ...this.stats };
|
|
257
|
+
}
|
|
258
|
+
getRateLimitStatus() {
|
|
259
|
+
if (!this.rateLimiter) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
const requestsRemaining = this.rateLimiter.getRemainingRequests();
|
|
263
|
+
const resetTime = new Date(Date.now() + this.rateLimiter.getWaitTime());
|
|
264
|
+
return {
|
|
265
|
+
requestsRemaining,
|
|
266
|
+
tokensRemaining: 0,
|
|
267
|
+
resetTime
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
resetUsage() {
|
|
271
|
+
this.stats = {
|
|
272
|
+
totalRequests: 0,
|
|
273
|
+
totalInputTokens: 0,
|
|
274
|
+
totalOutputTokens: 0,
|
|
275
|
+
totalTokens: 0,
|
|
276
|
+
totalCost: 0,
|
|
277
|
+
requestsByModel: {}
|
|
278
|
+
};
|
|
279
|
+
this.logger.info('Usage statistics reset');
|
|
280
|
+
}
|
|
281
|
+
updateStats(model, inputTokens, outputTokens, cost) {
|
|
282
|
+
this.stats.totalRequests++;
|
|
283
|
+
this.stats.totalInputTokens += inputTokens;
|
|
284
|
+
this.stats.totalOutputTokens += outputTokens;
|
|
285
|
+
this.stats.totalTokens += inputTokens + outputTokens;
|
|
286
|
+
this.stats.totalCost += cost;
|
|
287
|
+
this.stats.requestsByModel[model] = (this.stats.requestsByModel[model] || 0) + 1;
|
|
288
|
+
}
|
|
289
|
+
sleep(ms) {
|
|
290
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
exports.OpenAIClient = OpenAIClient;
|
|
294
|
+
//# sourceMappingURL=OpenAIClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAIClient.js","sourceRoot":"","sources":["../src/OpenAIClient.ts"],"names":[],"mappings":";;;;;;AAQA,oDAA4B;AAC5B,+CAAwE;AACxE,2DAA4E;AAC5E,mCASiB;AAKjB,MAAM,iBAAiB;IAGrB,YACU,WAAmB,EACnB,QAAgB;QADhB,gBAAW,GAAX,WAAW,CAAQ;QACnB,aAAQ,GAAR,QAAQ,CAAQ;QAJlB,aAAQ,GAAa,EAAE,CAAC;IAK7B,CAAC;IAEJ,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEzE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,oBAAoB;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;CACF;AAMD,MAAa,YAAY;IAcvB,YAAY,MAA0B;QAX9B,gBAAW,GAA6B,IAAI,CAAC;QAE7C,UAAK,GAAe;YAC1B,aAAa,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,iBAAiB,EAAE,CAAC;YACpB,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,CAAC;YACZ,eAAe,EAAE,EAAE;SACpB,CAAC;QAGA,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,CAAC,MAAM,GAAG;YACZ,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;YAClC,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI;gBACjE,iBAAiB,EAAE,EAAE;gBACrB,eAAe,EAAE,KAAK;aACvB,CAAC;YACF,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,mBAAW,CAAC,WAAW;YAC5D,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;YAC3C,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC,CAAC;QAEF,IAAI,CAAC,MAAM,GAAG,IAAI,gBAAM,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;SACvC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CAAC;YACvB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAQ,CAAC,KAAK;YACjE,UAAU,EAAE;gBACV,IAAI,yBAAgB,CAAC;oBACnB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAQ,CAAC,KAAK;iBAClE,CAAC;aACH;SACF,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,iBAAiB,CACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,EACvC,KAAK,CACN,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;YAC3C,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YAC/B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;SACjC,CAAC,CAAC;IACL,CAAC;IAKD,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,UAA6B,EAAE;QAC5D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QACxD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;QAE5C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAEzF,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,SAAS,GAAiB,IAAI,CAAC;QAEnC,OAAO,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC;gBAEH,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,CAAC;oBACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;oBAChD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC9D,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC3B,SAAS;gBACX,CAAC;gBAGD,MAAM,QAAQ,GAA6C,EAAE,CAAC;gBAE9D,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;oBACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;gBACnE,CAAC;gBAED,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAGjD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;oBACzD,KAAK;oBACL,QAAQ;oBACR,UAAU,EAAE,SAAS;oBACrB,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,KAAK,EAAE,OAAO,CAAC,IAAI;oBACnB,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;oBAC3C,gBAAgB,EAAE,OAAO,CAAC,eAAe;oBACzC,IAAI,EAAE,OAAO,CAAC,aAAa;oBAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;iBACnB,CAAC,CAAC;gBAGH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;gBAG5D,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;gBACvD,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,CAAC,CAAC;gBAC5D,MAAM,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;gBAE/C,MAAM,OAAO,GAAG,qBAAa,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,OAAS,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5D,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,OAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;gBAC/D,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;gBAGzC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;gBAE9D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE;oBACxC,KAAK;oBACL,WAAW;oBACX,YAAY;oBACZ,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;iBAChC,CAAC,CAAC;gBAEH,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO;oBACP,KAAK,EAAE;wBACL,WAAW;wBACX,YAAY;wBACZ,WAAW;qBACZ;oBACD,IAAI,EAAE;wBACJ,SAAS;wBACT,UAAU;wBACV,SAAS;qBACV;oBACD,KAAK;oBACL,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,SAAS;iBAC9D,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,KAAc,CAAC;gBAC3B,OAAO,EAAE,CAAC;gBAEV,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,IAAA,0BAAW,EAAC,OAAO,EAAE,KAAc,CAAC,EAAE,CAAC;oBAC7E,MAAM,KAAK,GAAG,IAAA,kCAAmB,EAAC,OAAO,EAAE;wBACzC,cAAc,EAAE,IAAI;wBACpB,UAAU,EAAE,KAAK;wBACjB,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC;oBAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;wBAC3C,OAAO;wBACP,KAAK;wBACL,KAAK,EAAG,KAAe,CAAC,OAAO;qBAChC,CAAC,CAAC;oBAEH,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,SAAS,EAAE;gBAC9D,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI,eAAe;SAC7C,CAAC;IACJ,CAAC;IAKD,KAAK,CAAC,MAAM,CACV,MAAc,EACd,OAA4B,EAC5B,UAA6B,EAAE;QAE/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QACxD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;QAE5C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAExF,IAAI,CAAC;YAEH,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,CAAC;gBACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;gBAChD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC9D,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC;YAGD,MAAM,QAAQ,GAA6C,EAAE,CAAC;YAE9D,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;YACnE,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAEjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACvD,KAAK;gBACL,QAAQ;gBACR,UAAU,EAAE,SAAS;gBACrB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,KAAK,EAAE,OAAO,CAAC,IAAI;gBACnB,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;gBAC3C,gBAAgB,EAAE,OAAO,CAAC,eAAe;gBACzC,IAAI,EAAE,OAAO,CAAC,aAAa;gBAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YAEH,IAAI,WAAW,GAAG,EAAE,CAAC;YACrB,IAAI,YAAY,GAAG,EAAE,CAAC;YAEtB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBACjC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC;gBAC/C,IAAI,KAAK,EAAE,CAAC;oBACV,WAAW,IAAI,KAAK,CAAC;oBACrB,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC;gBAED,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC;oBACpC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;gBAChD,CAAC;YACH,CAAC;YAGD,MAAM,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAClG,MAAM,qBAAqB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAChE,MAAM,WAAW,GAAG,oBAAoB,GAAG,qBAAqB,CAAC;YAEjE,MAAM,OAAO,GAAG,qBAAa,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,SAAS,GAAG,CAAC,oBAAoB,GAAG,OAAS,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;YACrE,MAAM,UAAU,GAAG,CAAC,qBAAqB,GAAG,OAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;YACxE,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;YAEzC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,SAAS,CAAC,CAAC;YAEhF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE;gBACtC,KAAK;gBACL,oBAAoB;gBACpB,qBAAqB;gBACrB,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;aAChC,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAE;oBACL,WAAW,EAAE,oBAAoB;oBACjC,YAAY,EAAE,qBAAqB;oBACnC,WAAW;iBACZ;gBACD,IAAI,EAAE;oBACJ,SAAS;oBACT,UAAU;oBACV,SAAS;iBACV;gBACD,KAAK;gBACL,YAAY;aACb,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAc,CAAC,CAAC;YAEtD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAG,KAAe,CAAC,OAAO;aAChC,CAAC;QACJ,CAAC;IACH,CAAC;IAKD,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAKD,kBAAkB;QAChB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC;QAExE,OAAO;YACL,iBAAiB;YACjB,eAAe,EAAE,CAAC;YAClB,SAAS;SACV,CAAC;IACJ,CAAC;IAKD,UAAU;QACR,IAAI,CAAC,KAAK,GAAG;YACX,aAAa,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,iBAAiB,EAAE,CAAC;YACpB,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,CAAC;YACZ,eAAe,EAAE,EAAE;SACpB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC7C,CAAC;IAEO,WAAW,CACjB,KAAa,EACb,WAAmB,EACnB,YAAoB,EACpB,IAAY;QAEZ,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,WAAW,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,YAAY,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,WAAW,GAAG,YAAY,CAAC;QACrD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACnF,CAAC;IAEO,KAAK,CAAC,EAAU;QACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;CACF;AAjVD,oCAiVC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,cAAc,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.OpenAIClient = void 0;
|
|
18
|
+
var OpenAIClient_1 = require("./OpenAIClient");
|
|
19
|
+
Object.defineProperty(exports, "OpenAIClient", { enumerable: true, get: function () { return OpenAIClient_1.OpenAIClient; } });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAQA,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,0CAAwB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare enum OpenAIModel {
|
|
2
|
+
GPT_4 = "gpt-4",
|
|
3
|
+
GPT_4_TURBO = "gpt-4-turbo-preview",
|
|
4
|
+
GPT_4O = "gpt-4o",
|
|
5
|
+
GPT_4O_MINI = "gpt-4o-mini",
|
|
6
|
+
GPT_35_TURBO = "gpt-3.5-turbo",
|
|
7
|
+
GPT_35_TURBO_16K = "gpt-3.5-turbo-16k"
|
|
8
|
+
}
|
|
9
|
+
export interface ModelPricing {
|
|
10
|
+
input: number;
|
|
11
|
+
output: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const MODEL_PRICING: Record<OpenAIModel, ModelPricing>;
|
|
14
|
+
export interface OpenAIClientConfig {
|
|
15
|
+
apiKey: string;
|
|
16
|
+
maxRetries?: number;
|
|
17
|
+
rateLimit?: {
|
|
18
|
+
requestsPerMinute: number;
|
|
19
|
+
tokensPerMinute: number;
|
|
20
|
+
} | null;
|
|
21
|
+
defaultModel?: OpenAIModel;
|
|
22
|
+
enableLogging?: boolean;
|
|
23
|
+
organization?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CompletionOptions {
|
|
26
|
+
model?: OpenAIModel;
|
|
27
|
+
maxTokens?: number;
|
|
28
|
+
temperature?: number;
|
|
29
|
+
topP?: number;
|
|
30
|
+
frequencyPenalty?: number;
|
|
31
|
+
presencePenalty?: number;
|
|
32
|
+
stopSequences?: string[];
|
|
33
|
+
systemPrompt?: string;
|
|
34
|
+
user?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface CompletionResult {
|
|
37
|
+
success: boolean;
|
|
38
|
+
content?: string;
|
|
39
|
+
usage?: {
|
|
40
|
+
inputTokens: number;
|
|
41
|
+
outputTokens: number;
|
|
42
|
+
totalTokens: number;
|
|
43
|
+
};
|
|
44
|
+
cost?: {
|
|
45
|
+
inputCost: number;
|
|
46
|
+
outputCost: number;
|
|
47
|
+
totalCost: number;
|
|
48
|
+
};
|
|
49
|
+
model?: string;
|
|
50
|
+
finishReason?: string;
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
export type StreamChunkCallback = (chunk: string) => void | Promise<void>;
|
|
54
|
+
export interface UsageStats {
|
|
55
|
+
totalRequests: number;
|
|
56
|
+
totalInputTokens: number;
|
|
57
|
+
totalOutputTokens: number;
|
|
58
|
+
totalTokens: number;
|
|
59
|
+
totalCost: number;
|
|
60
|
+
requestsByModel: Record<string, number>;
|
|
61
|
+
}
|
|
62
|
+
export interface RateLimitStatus {
|
|
63
|
+
requestsRemaining: number;
|
|
64
|
+
tokensRemaining: number;
|
|
65
|
+
resetTime: Date;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAWA,oBAAY,WAAW;IACrB,KAAK,UAAU;IACf,WAAW,wBAAwB;IACnC,MAAM,WAAW;IACjB,WAAW,gBAAgB;IAC3B,YAAY,kBAAkB;IAC9B,gBAAgB,sBAAsB;CACvC;AAKD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,WAAW,EAAE,YAAY,CAO3D,CAAC;AAKF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE;QACV,iBAAiB,EAAE,MAAM,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;KACzB,GAAG,IAAI,CAAC;IACT,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAK1E,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAKD,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MODEL_PRICING = exports.OpenAIModel = void 0;
|
|
4
|
+
var OpenAIModel;
|
|
5
|
+
(function (OpenAIModel) {
|
|
6
|
+
OpenAIModel["GPT_4"] = "gpt-4";
|
|
7
|
+
OpenAIModel["GPT_4_TURBO"] = "gpt-4-turbo-preview";
|
|
8
|
+
OpenAIModel["GPT_4O"] = "gpt-4o";
|
|
9
|
+
OpenAIModel["GPT_4O_MINI"] = "gpt-4o-mini";
|
|
10
|
+
OpenAIModel["GPT_35_TURBO"] = "gpt-3.5-turbo";
|
|
11
|
+
OpenAIModel["GPT_35_TURBO_16K"] = "gpt-3.5-turbo-16k";
|
|
12
|
+
})(OpenAIModel || (exports.OpenAIModel = OpenAIModel = {}));
|
|
13
|
+
exports.MODEL_PRICING = {
|
|
14
|
+
[OpenAIModel.GPT_4]: { input: 30.0, output: 60.0 },
|
|
15
|
+
[OpenAIModel.GPT_4_TURBO]: { input: 10.0, output: 30.0 },
|
|
16
|
+
[OpenAIModel.GPT_4O]: { input: 2.5, output: 10.0 },
|
|
17
|
+
[OpenAIModel.GPT_4O_MINI]: { input: 0.15, output: 0.6 },
|
|
18
|
+
[OpenAIModel.GPT_35_TURBO]: { input: 0.5, output: 1.5 },
|
|
19
|
+
[OpenAIModel.GPT_35_TURBO_16K]: { input: 3.0, output: 4.0 }
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAWA,IAAY,WAOX;AAPD,WAAY,WAAW;IACrB,8BAAe,CAAA;IACf,kDAAmC,CAAA;IACnC,gCAAiB,CAAA;IACjB,0CAA2B,CAAA;IAC3B,6CAA8B,CAAA;IAC9B,qDAAsC,CAAA;AACxC,CAAC,EAPW,WAAW,2BAAX,WAAW,QAOtB;AAaY,QAAA,aAAa,GAAsC;IAC9D,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAClD,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IACxD,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAClD,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACvD,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACvD,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CAC5D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bernierllc/openai-client",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Type-safe OpenAI API client with automatic rate limiting, retry logic, streaming support, and cost tracking",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"openai",
|
|
14
|
+
"gpt",
|
|
15
|
+
"gpt-4",
|
|
16
|
+
"ai",
|
|
17
|
+
"api",
|
|
18
|
+
"rate-limiting",
|
|
19
|
+
"retry",
|
|
20
|
+
"streaming",
|
|
21
|
+
"cost-tracking",
|
|
22
|
+
"bernierllc"
|
|
23
|
+
],
|
|
24
|
+
"author": "Bernier LLC",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/bernier-llc/tools"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"openai": "^4.73.0",
|
|
32
|
+
"@bernierllc/logger": "^1.0.1",
|
|
33
|
+
"@bernierllc/retry-policy": "^0.1.3"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/jest": "^29.5.14",
|
|
37
|
+
"@types/node": "^20.0.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
39
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
40
|
+
"eslint": "^8.0.0",
|
|
41
|
+
"jest": "^29.5.0",
|
|
42
|
+
"rimraf": "^5.0.0",
|
|
43
|
+
"ts-jest": "^29.4.0",
|
|
44
|
+
"typescript": "^5.0.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc",
|
|
51
|
+
"dev": "tsc --watch",
|
|
52
|
+
"test": "jest",
|
|
53
|
+
"test:watch": "jest --watch",
|
|
54
|
+
"test:coverage": "jest --coverage",
|
|
55
|
+
"test:run": "jest --passWithNoTests",
|
|
56
|
+
"lint": "eslint src/**/*.ts",
|
|
57
|
+
"clean": "rimraf dist"
|
|
58
|
+
}
|
|
59
|
+
}
|