2dai-sdk 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1287 -0
- package/dist/client.d.ts +222 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +643 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +175 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +260 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +438 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,1287 @@
|
|
|
1
|
+
# 2dai-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for 2DAI AI Generation API
|
|
4
|
+
|
|
5
|
+
Generate images, videos, and text using state-of-the-art AI models through a simple and intuitive API.
|
|
6
|
+
|
|
7
|
+
[](.)
|
|
8
|
+
[](.)
|
|
9
|
+
[](.)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
- [Features](#features)
|
|
16
|
+
- [What's New](#whats-new)
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Getting an API Key](#getting-an-api-key)
|
|
19
|
+
- [Quick Start](#quick-start)
|
|
20
|
+
- [Documentation](#documentation)
|
|
21
|
+
- [Initialization](#initialization)
|
|
22
|
+
- [Image Generation](#image-generation)
|
|
23
|
+
- [Image Editing](#image-editing)
|
|
24
|
+
- [Image Upscaling](#image-upscaling)
|
|
25
|
+
- [Video Generation](#video-generation)
|
|
26
|
+
- [Text Generation (LLM)](#text-generation-llm)
|
|
27
|
+
- [CDN Operations](#cdn-operations)
|
|
28
|
+
- [Watermarking](#watermarking)
|
|
29
|
+
- [Settings & Usage Tracking](#settings--usage-tracking)
|
|
30
|
+
- [Advanced Usage](#advanced-usage)
|
|
31
|
+
- [Complete Examples](#complete-examples)
|
|
32
|
+
- [API Reference](#api-reference)
|
|
33
|
+
- [Best Practices](#best-practices)
|
|
34
|
+
- [Troubleshooting](#troubleshooting)
|
|
35
|
+
- [Migration Guide](#migration-guide)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **Text-to-Image**: Generate stunning images from text prompts
|
|
42
|
+
- **Image-to-Image**: Edit and transform existing images
|
|
43
|
+
- **AI Image Upscale**: Upscale images 2-4x using AI
|
|
44
|
+
- **Image-to-Video**: Create videos from static images
|
|
45
|
+
- **LLM Text Generation**: Generate text with context, memory, and JSON support
|
|
46
|
+
- **Image Description (Vision)**: Analyze images with LLM for structured data extraction
|
|
47
|
+
- **12 Style Presets**: Realistic, anime, manga, cinematic, and more
|
|
48
|
+
- **7 Format Presets**: Portrait, landscape, profile, story, post, smartphone, banner
|
|
49
|
+
- **Type-Safe**: Full TypeScript support with comprehensive type definitions
|
|
50
|
+
- **Built-in Watermarking**: Apply custom watermarks to generated content
|
|
51
|
+
- **WebSocket Support**: Real-time generation with progress updates
|
|
52
|
+
- **Usage Tracking**: Real-time usage monitoring with remaining quota and reset times
|
|
53
|
+
- **Rate Limiting**: Built-in rate limit tracking for requests and tokens (LLM)
|
|
54
|
+
- **CDN Format Conversion**: Convert between image formats (JPG, PNG, GIF) and extract frames from videos
|
|
55
|
+
- **Comprehensive Tests**: Full test coverage for all API endpoints and WebSocket operations
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## What's New
|
|
60
|
+
|
|
61
|
+
### v1.4.0 (Latest)
|
|
62
|
+
|
|
63
|
+
- **AI Image Upscale** - New upscale methods for AI-powered image upscaling
|
|
64
|
+
- `upscaleImage()` - REST API upscaling with factor 2-4x
|
|
65
|
+
- `wsUpscaleImage()` - WebSocket upscaling for real-time operations
|
|
66
|
+
- **Image Description (Vision)** - Analyze images with LLM
|
|
67
|
+
- Pass `imageId` to `generateText()` or `wsGenerateLlm()` for image analysis
|
|
68
|
+
- Extract structured JSON data from images
|
|
69
|
+
- **New Types** - `UpscaleOptions`, `UpscaleResult`, `WsUpscaleRequest`, `WsUpscaleResponse`
|
|
70
|
+
- **New Constants** - `UPSCALE_FACTOR` (MIN: 2, MAX: 4, DEFAULT: 2)
|
|
71
|
+
|
|
72
|
+
### v1.3.0
|
|
73
|
+
|
|
74
|
+
- **Full WebSocket Client** - Complete WebSocket implementation
|
|
75
|
+
- `wsConnect()`, `wsGenerateImage()`, `wsGenerateVideo()`, `wsGenerateLlm()`
|
|
76
|
+
- Auto-reconnect with exponential backoff
|
|
77
|
+
- Ping/pong keepalive to prevent timeouts
|
|
78
|
+
- Request tracking with `requestId`
|
|
79
|
+
- **Image Resize for img2img** - New `width` and `height` parameters for `editImage()`
|
|
80
|
+
- Resize output to custom dimensions (320-1344) during image editing
|
|
81
|
+
- **JSON Output Enhancement** - `TextGenerationResult.json` field for parsed JSON output
|
|
82
|
+
- **WebSocket Types** - New exported types for WebSocket requests/responses
|
|
83
|
+
|
|
84
|
+
### v1.2.0
|
|
85
|
+
|
|
86
|
+
- **Video Frame Extraction** - Extract frames from videos with `?seek=<ms>` CDN parameter
|
|
87
|
+
- **Video Metadata** - `duration` and `fps` in video generation responses
|
|
88
|
+
- **WatermarkPosition Constants** - Type-safe watermark positioning
|
|
89
|
+
|
|
90
|
+
### v1.1.0
|
|
91
|
+
|
|
92
|
+
- **Style Update** - Replaced `legacy` style with new `text` style
|
|
93
|
+
- Updated style presets to match Gen6 improvements
|
|
94
|
+
|
|
95
|
+
### v1.0.3
|
|
96
|
+
|
|
97
|
+
- **Markdown Formatting** - New `useMarkdown` option for LLM text generation
|
|
98
|
+
- When enabled, responses include markdown formatting (headers, bullet points, code blocks)
|
|
99
|
+
- Works with both REST API and WebSocket connections
|
|
100
|
+
|
|
101
|
+
### v1.0.2
|
|
102
|
+
|
|
103
|
+
- **JSON Format Fix** - Fixed `jsonFormat: true` responses returning empty strings
|
|
104
|
+
- LLM text generation now correctly returns JSON responses when using `jsonFormat` and `jsonTemplate` options
|
|
105
|
+
|
|
106
|
+
### v1.0.1
|
|
107
|
+
|
|
108
|
+
- **GIF File Format Support** - Full GIF upload, download, and processing via CDN
|
|
109
|
+
- **Format Conversion** - Convert between image formats (PNG, JPG, GIF) and extract video frames as GIF
|
|
110
|
+
- **GIF Watermarking** - Apply watermarks to GIF files with position control
|
|
111
|
+
- **Enhanced Debug Logging** - Improved watermark operation debugging
|
|
112
|
+
|
|
113
|
+
### v1.0.0
|
|
114
|
+
|
|
115
|
+
- Initial public release
|
|
116
|
+
- Text-to-image generation with 12 style presets
|
|
117
|
+
- Image-to-image editing with strength control
|
|
118
|
+
- Image-to-video generation
|
|
119
|
+
- LLM text generation with memory and JSON format support
|
|
120
|
+
- 7 format presets for different aspect ratios
|
|
121
|
+
- WebSocket and REST API support
|
|
122
|
+
- Built-in rate limiting and watermarking support
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Installation
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm install 2dai-sdk
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
or
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
yarn add 2dai-sdk
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Getting an API Key
|
|
141
|
+
|
|
142
|
+
To use this SDK, you need an API key.
|
|
143
|
+
|
|
144
|
+
**Request Access:**
|
|
145
|
+
1. Fill out the [API Access Request Form](https://YOUR_2DAI_FORM_LINK)
|
|
146
|
+
2. We'll review your request within 24-48 hours
|
|
147
|
+
3. Once approved, you'll receive your API key via email
|
|
148
|
+
|
|
149
|
+
**Contact:**
|
|
150
|
+
- Twitter/X: [@2DAICommunity](https://x.com/2DAICommunity)
|
|
151
|
+
- Telegram: [Token2dAI](https://t.me/Token2dAI)
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Quick Start
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { createClient, STYLES, FORMATS } from '2dai-sdk';
|
|
159
|
+
|
|
160
|
+
// Initialize the client
|
|
161
|
+
const client = createClient('2dai_pk_your_api_key_here');
|
|
162
|
+
|
|
163
|
+
// Generate an image (REST API)
|
|
164
|
+
const image = await client.generateImage({
|
|
165
|
+
prompt: 'a majestic lion in the savanna at sunset',
|
|
166
|
+
style: STYLES.cine.id,
|
|
167
|
+
format: FORMATS.landscape.id
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Construct CDN URL from image ID
|
|
171
|
+
const imageUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${image.imageId}.jpg`;
|
|
172
|
+
console.log(`Image URL: ${imageUrl}`);
|
|
173
|
+
|
|
174
|
+
// Or use WebSocket for real-time generation
|
|
175
|
+
await client.wsConnect();
|
|
176
|
+
const wsImage = await client.wsGenerateImage({
|
|
177
|
+
prompt: 'a futuristic city at night',
|
|
178
|
+
style: STYLES.cine.id,
|
|
179
|
+
format: FORMATS.landscape.id
|
|
180
|
+
});
|
|
181
|
+
console.log(`WebSocket Image ID: ${wsImage.result.imageId}`);
|
|
182
|
+
await client.close();
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Documentation
|
|
188
|
+
|
|
189
|
+
### Initialization
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { createClient } from '2dai-sdk';
|
|
193
|
+
|
|
194
|
+
const client = createClient('2dai_pk_your_api_key_here', {
|
|
195
|
+
baseUrl: 'https://apiv2.2dai.io:800', // Optional, defaults to production
|
|
196
|
+
timeout: 300000, // Optional, 5 minutes default
|
|
197
|
+
debug: false // Optional, enable debug logging
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Image Generation
|
|
202
|
+
|
|
203
|
+
#### Generate from Text Prompt
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { STYLES, FORMATS } from '2dai-sdk';
|
|
207
|
+
|
|
208
|
+
const result = await client.generateImage({
|
|
209
|
+
prompt: 'a cyberpunk cityscape at night with neon lights',
|
|
210
|
+
negativePrompt: 'blurry, low quality, distorted',
|
|
211
|
+
style: STYLES.cine.id,
|
|
212
|
+
format: FORMATS.landscape.id,
|
|
213
|
+
seed: 12345 // Optional, for reproducibility
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
console.log(result);
|
|
217
|
+
// {
|
|
218
|
+
// success: true,
|
|
219
|
+
// imageId: '550e8400-e29b-41d4-a716-446655440000',
|
|
220
|
+
// width: 1344,
|
|
221
|
+
// height: 768,
|
|
222
|
+
// seed: 12345
|
|
223
|
+
// }
|
|
224
|
+
|
|
225
|
+
// Construct CDN URL from imageId
|
|
226
|
+
const imageUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${result.imageId}.jpg`;
|
|
227
|
+
console.log(`Access image at: ${imageUrl}`);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### Available Styles
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import { STYLES } from '2dai-sdk';
|
|
234
|
+
|
|
235
|
+
STYLES.raw // Raw Gen6 defaults
|
|
236
|
+
STYLES.realistic // Realistic 2DAI generation
|
|
237
|
+
STYLES.text // Text & Clarity
|
|
238
|
+
STYLES.ciniji // Niji anime style with vibrant colors
|
|
239
|
+
STYLES.portrait // Gen6 Portrait
|
|
240
|
+
STYLES.cine // Gen6 Cinematic
|
|
241
|
+
STYLES.sport // Gen6 Sport
|
|
242
|
+
STYLES.fashion // Gen6 Fashion
|
|
243
|
+
STYLES.niji // Gen6 Anime Niji
|
|
244
|
+
STYLES.anime // Gen6 Anime
|
|
245
|
+
STYLES.manga // Gen6 Manga
|
|
246
|
+
STYLES.paint // Gen6 Paint
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### Available Formats
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { FORMATS } from '2dai-sdk';
|
|
253
|
+
|
|
254
|
+
FORMATS.portrait // 9:16 vertical (768x1344)
|
|
255
|
+
FORMATS.landscape // 16:9 horizontal (1344x768)
|
|
256
|
+
FORMATS.profile // 1:1 profile picture (1024x1024)
|
|
257
|
+
FORMATS.story // 9:16 story format (720x1280)
|
|
258
|
+
FORMATS.post // 9:7 wide square (1152x896)
|
|
259
|
+
FORMATS.smartphone // Phone screen (640x1344)
|
|
260
|
+
FORMATS.banner // 3:1 wide screen (1472x448)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Image Editing
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Edit using image ID
|
|
267
|
+
const edited = await client.editImage('550e8400-e29b-41d4-a716-446655440000', {
|
|
268
|
+
prompt: 'make the sky more dramatic with storm clouds'
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Edit with resize - output to custom dimensions
|
|
272
|
+
const resized = await client.editImage('550e8400-e29b-41d4-a716-446655440000', {
|
|
273
|
+
prompt: 'Seamlessly extend the image, remove the black background',
|
|
274
|
+
width: 768, // Custom output width (320-1344)
|
|
275
|
+
height: 1344 // Custom output height (320-1344)
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
console.log(resized);
|
|
279
|
+
// {
|
|
280
|
+
// success: true,
|
|
281
|
+
// imageId: 'new-image-id',
|
|
282
|
+
// width: 768,
|
|
283
|
+
// height: 1344,
|
|
284
|
+
// seed: 12345
|
|
285
|
+
// }
|
|
286
|
+
|
|
287
|
+
// Edit with resizePad - fit original in frame with black padding
|
|
288
|
+
const padded = await client.editImage('550e8400-e29b-41d4-a716-446655440000', {
|
|
289
|
+
prompt: 'Seamlessly extend the image',
|
|
290
|
+
width: 768,
|
|
291
|
+
height: 1344,
|
|
292
|
+
resizePad: true // Fits original image in resized frame, fills extra space with black
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Edit via WebSocket
|
|
296
|
+
await client.wsConnect();
|
|
297
|
+
const wsEdited = await client.wsGenerateImage({
|
|
298
|
+
imageId: '550e8400-e29b-41d4-a716-446655440000',
|
|
299
|
+
prompt: 'make the image black and white',
|
|
300
|
+
width: 1344,
|
|
301
|
+
height: 768
|
|
302
|
+
});
|
|
303
|
+
console.log(wsEdited.result.imageId);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Resize Padding (`resizePad`)
|
|
307
|
+
|
|
308
|
+
When resizing images to different dimensions, the `resizePad` option controls how the original image is fitted:
|
|
309
|
+
|
|
310
|
+
| resizePad | Behavior |
|
|
311
|
+
|-----------|----------|
|
|
312
|
+
| `false` (default) | Image is cropped/stretched to fill the target dimensions |
|
|
313
|
+
| `true` | Original image fits entirely within the frame, extra space is filled with black |
|
|
314
|
+
|
|
315
|
+
### Image Upscaling
|
|
316
|
+
|
|
317
|
+
AI-powered image upscaling. No user prompt needed.
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { UPSCALE_FACTOR } from '2dai-sdk';
|
|
321
|
+
|
|
322
|
+
// Upscale an image (REST API)
|
|
323
|
+
const upscaled = await client.upscaleImage('550e8400-e29b-41d4-a716-446655440000', {
|
|
324
|
+
factor: 2 // 2x, 3x, or 4x (default: 2)
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
console.log(upscaled);
|
|
328
|
+
// {
|
|
329
|
+
// success: true,
|
|
330
|
+
// imageId: 'upscaled-image-id',
|
|
331
|
+
// width: 2048,
|
|
332
|
+
// height: 2048,
|
|
333
|
+
// seed: 12345
|
|
334
|
+
// }
|
|
335
|
+
|
|
336
|
+
// Upscale via WebSocket
|
|
337
|
+
await client.wsConnect();
|
|
338
|
+
const wsUpscaled = await client.wsUpscaleImage({
|
|
339
|
+
imageId: '550e8400-e29b-41d4-a716-446655440000',
|
|
340
|
+
factor: 2
|
|
341
|
+
});
|
|
342
|
+
console.log(wsUpscaled.result.imageId);
|
|
343
|
+
await client.close();
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### Upscale Factor Limits
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { UPSCALE_FACTOR } from '2dai-sdk';
|
|
350
|
+
|
|
351
|
+
UPSCALE_FACTOR.MIN // 2
|
|
352
|
+
UPSCALE_FACTOR.MAX // 4
|
|
353
|
+
UPSCALE_FACTOR.DEFAULT // 2
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Video Generation
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// Generate video from image ID
|
|
360
|
+
const video = await client.generateVideo({
|
|
361
|
+
imageId: '550e8400-e29b-41d4-a716-446655440000',
|
|
362
|
+
duration: 5, // 1-10 seconds
|
|
363
|
+
fps: 16 // 8-32 fps
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Generate video from buffer
|
|
367
|
+
const video = await client.generateVideo({
|
|
368
|
+
imageBuffer,
|
|
369
|
+
duration: 5
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
console.log(video);
|
|
373
|
+
// {
|
|
374
|
+
// success: true,
|
|
375
|
+
// videoId: '660e8400-e29b-41d4-a716-446655440000',
|
|
376
|
+
// duration: 5,
|
|
377
|
+
// fps: 16
|
|
378
|
+
// }
|
|
379
|
+
|
|
380
|
+
// Construct CDN URL from videoId
|
|
381
|
+
const videoUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${video.videoId}.mp4`;
|
|
382
|
+
console.log(`Access video at: ${videoUrl}`);
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Text Generation (LLM)
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
// Simple text generation
|
|
389
|
+
const result = await client.generateText({
|
|
390
|
+
prompt: 'Write a short poem about AI and creativity'
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
console.log(result.response);
|
|
394
|
+
|
|
395
|
+
// With markdown formatting
|
|
396
|
+
const formatted = await client.generateText({
|
|
397
|
+
prompt: 'Explain what TypeScript is. Use headers and code examples.',
|
|
398
|
+
useMarkdown: true // Response includes markdown formatting
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
console.log(formatted.response); // Contains # headers, ```code blocks```, bullet points, etc.
|
|
402
|
+
|
|
403
|
+
// With system message and memory
|
|
404
|
+
const result = await client.generateText({
|
|
405
|
+
prompt: 'What were we discussing?',
|
|
406
|
+
system: 'You are a helpful assistant',
|
|
407
|
+
memory: [
|
|
408
|
+
'User asked about AI capabilities',
|
|
409
|
+
'Discussed image generation features'
|
|
410
|
+
]
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// JSON format response
|
|
414
|
+
const result = await client.generateText({
|
|
415
|
+
prompt: 'Analyze this product review',
|
|
416
|
+
jsonFormat: true,
|
|
417
|
+
jsonTemplate: {
|
|
418
|
+
sentiment: 'positive/negative/neutral',
|
|
419
|
+
score: '1-10',
|
|
420
|
+
summary: 'brief summary'
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
console.log(result.response); // Returns structured JSON
|
|
425
|
+
|
|
426
|
+
// With knowledge base
|
|
427
|
+
const result = await client.generateText({
|
|
428
|
+
prompt: 'What is our refund policy?',
|
|
429
|
+
askKnowledge: {
|
|
430
|
+
sources: ['docs', 'policies'],
|
|
431
|
+
query: 'refund policy'
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Image description (Vision)
|
|
436
|
+
const imageResult = await client.generateImage({
|
|
437
|
+
prompt: 'a futuristic city at night'
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
const description = await client.generateText({
|
|
441
|
+
prompt: 'Analyze this image and extract structured data',
|
|
442
|
+
system: 'Extract information from images into structured JSON format.',
|
|
443
|
+
imageId: imageResult.imageId, // Pass image for analysis
|
|
444
|
+
jsonFormat: true,
|
|
445
|
+
jsonTemplate: {
|
|
446
|
+
main_subject: 'string - primary subject of the image',
|
|
447
|
+
objects: 'array of strings - objects visible in the image',
|
|
448
|
+
colors: 'array of strings - dominant colors',
|
|
449
|
+
mood: 'string - overall mood/atmosphere'
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
console.log(description.json);
|
|
454
|
+
// Output: { main_subject: "futuristic cityscape", objects: ["buildings", "lights", ...], ... }
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### CDN Operations
|
|
458
|
+
|
|
459
|
+
The CDN supports multiple file formats and operations including format conversion, resizing, and watermarking.
|
|
460
|
+
|
|
461
|
+
#### Supported File Formats
|
|
462
|
+
|
|
463
|
+
| Format | Extension | Description |
|
|
464
|
+
|--------|-----------|-------------|
|
|
465
|
+
| JPEG | `.jpg`, `.jpeg` | Standard image format |
|
|
466
|
+
| PNG | `.png` | Lossless image format with transparency |
|
|
467
|
+
| GIF | `.gif` | Static or animated image format |
|
|
468
|
+
| MP4 | `.mp4` | Video format |
|
|
469
|
+
|
|
470
|
+
#### CDN URL Construction
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// Basic image URL
|
|
474
|
+
const imageUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.jpg`;
|
|
475
|
+
|
|
476
|
+
// Image with resize
|
|
477
|
+
const resizedUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.jpg?w=512&h=512`;
|
|
478
|
+
|
|
479
|
+
// Image with watermark
|
|
480
|
+
const watermarkedUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.jpg?watermark=${watermarkId}&position=southeast`;
|
|
481
|
+
|
|
482
|
+
// Video URL
|
|
483
|
+
const videoUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${videoId}.mp4`;
|
|
484
|
+
|
|
485
|
+
// Extract first frame from video as GIF
|
|
486
|
+
const gifFromVideo = `https://apiv2.2dai.io:800/api/v1/cdn/${videoId}.gif`;
|
|
487
|
+
|
|
488
|
+
// GIF with resize
|
|
489
|
+
const resizedGif = `https://apiv2.2dai.io:800/api/v1/cdn/${videoId}.gif?w=256&h=256`;
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
#### Format Conversion Matrix
|
|
493
|
+
|
|
494
|
+
| From \ To | PNG | JPG | JPEG | GIF |
|
|
495
|
+
|-----------|-----|-----|------|-----|
|
|
496
|
+
| PNG | - | Yes | Yes | Yes |
|
|
497
|
+
| JPG | Yes | - | Yes | Yes |
|
|
498
|
+
| JPEG | Yes | Yes | - | Yes |
|
|
499
|
+
| GIF | Yes | Yes | Yes | - |
|
|
500
|
+
| MP4 | Yes | Yes | Yes | Yes |
|
|
501
|
+
|
|
502
|
+
**Notes:**
|
|
503
|
+
- Converting animated GIF to other formats extracts the first frame
|
|
504
|
+
- MP4 to image formats extracts a single frame as still image
|
|
505
|
+
- Watermarking supported on all image formats including GIF
|
|
506
|
+
|
|
507
|
+
#### CDN Query Parameters
|
|
508
|
+
|
|
509
|
+
| Parameter | Description | Example |
|
|
510
|
+
|-----------|-------------|---------|
|
|
511
|
+
| `w` | Target width in pixels | `?w=1024` |
|
|
512
|
+
| `h` | Target height in pixels | `?h=768` |
|
|
513
|
+
| `watermark` | Watermark file ID | `?watermark=abc123` |
|
|
514
|
+
| `position` | Watermark position | `?position=southeast` |
|
|
515
|
+
|
|
516
|
+
**Watermark Positions:**
|
|
517
|
+
- Sharp gravity: `northwest`, `north`, `northeast`, `west`, `center`, `east`, `southwest`, `south`, `southeast`
|
|
518
|
+
- Human-readable: `top-left`, `top-center`, `top-right`, `middle-left`, `middle-center`, `middle-right`, `bottom-left`, `bottom-center`, `bottom-right`
|
|
519
|
+
|
|
520
|
+
#### Downloading Files
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
import axios from 'axios';
|
|
524
|
+
import fs from 'fs';
|
|
525
|
+
|
|
526
|
+
// Download image
|
|
527
|
+
const imageResponse = await axios.get(
|
|
528
|
+
`https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.jpg`,
|
|
529
|
+
{
|
|
530
|
+
responseType: 'arraybuffer',
|
|
531
|
+
headers: { 'Authorization': `Bearer ${apiKey}` }
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
fs.writeFileSync('output.jpg', imageResponse.data);
|
|
535
|
+
|
|
536
|
+
// Download video
|
|
537
|
+
const videoResponse = await axios.get(
|
|
538
|
+
`https://apiv2.2dai.io:800/api/v1/cdn/${videoId}.mp4`,
|
|
539
|
+
{
|
|
540
|
+
responseType: 'arraybuffer',
|
|
541
|
+
headers: { 'Authorization': `Bearer ${apiKey}` }
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
fs.writeFileSync('output.mp4', videoResponse.data);
|
|
545
|
+
|
|
546
|
+
// Extract video frame as GIF
|
|
547
|
+
const gifResponse = await axios.get(
|
|
548
|
+
`https://apiv2.2dai.io:800/api/v1/cdn/${videoId}.gif`,
|
|
549
|
+
{
|
|
550
|
+
responseType: 'arraybuffer',
|
|
551
|
+
headers: { 'Authorization': `Bearer ${apiKey}` }
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
fs.writeFileSync('frame.gif', gifResponse.data);
|
|
555
|
+
|
|
556
|
+
// Download with resize
|
|
557
|
+
const resizedResponse = await axios.get(
|
|
558
|
+
`https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.png?w=256&h=256`,
|
|
559
|
+
{
|
|
560
|
+
responseType: 'arraybuffer',
|
|
561
|
+
headers: { 'Authorization': `Bearer ${apiKey}` }
|
|
562
|
+
}
|
|
563
|
+
);
|
|
564
|
+
fs.writeFileSync('thumbnail.png', resizedResponse.data);
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Watermarking
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
// Upload watermark and set as default
|
|
571
|
+
const settings = await client.getSettings();
|
|
572
|
+
await client.updateWatermark('watermark-cdn-id');
|
|
573
|
+
|
|
574
|
+
// Apply watermark to generation
|
|
575
|
+
const image = await client.generateImage({
|
|
576
|
+
prompt: 'a beautiful landscape',
|
|
577
|
+
watermark: 'watermark-cdn-id',
|
|
578
|
+
watermarkPosition: 'southeast', // bottom-right
|
|
579
|
+
copyright: '2024 My Company'
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Tiled watermark (images only)
|
|
583
|
+
const image = await client.generateImage({
|
|
584
|
+
prompt: 'product photography',
|
|
585
|
+
watermark: 'watermark-cdn-id',
|
|
586
|
+
watermarkAsTiles: true
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// Apply watermark via CDN URL
|
|
590
|
+
const watermarkedUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${imageId}.jpg?watermark=${watermarkId}&position=center`;
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Settings & Usage Tracking
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
// Get API key settings with current usage
|
|
597
|
+
const settings = await client.getSettings();
|
|
598
|
+
|
|
599
|
+
console.log('API Key:', settings.name);
|
|
600
|
+
console.log('Status:', settings.status);
|
|
601
|
+
console.log('\nRate Limits:');
|
|
602
|
+
console.log('Image:', settings.rateLimits.image);
|
|
603
|
+
console.log('Video:', settings.rateLimits.video);
|
|
604
|
+
console.log('LLM:', settings.rateLimits.llm);
|
|
605
|
+
console.log('CDN:', settings.rateLimits.cdn);
|
|
606
|
+
|
|
607
|
+
// Current usage with remaining quota and reset times
|
|
608
|
+
console.log('\nCurrent Usage:');
|
|
609
|
+
console.log('Image:', {
|
|
610
|
+
used15min: settings.currentUsage.image.current.requestsPer15Min,
|
|
611
|
+
usedDaily: settings.currentUsage.image.current.requestsPerDay,
|
|
612
|
+
remaining15min: settings.currentUsage.image.remaining.requestsPer15Min,
|
|
613
|
+
remainingDaily: settings.currentUsage.image.remaining.requestsPerDay,
|
|
614
|
+
resetAt: settings.currentUsage.image.resetAt
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// LLM usage includes token tracking
|
|
618
|
+
console.log('LLM:', {
|
|
619
|
+
requests15min: settings.currentUsage.llm.current.requestsPer15Min,
|
|
620
|
+
requestsDaily: settings.currentUsage.llm.current.requestsPerDay,
|
|
621
|
+
tokens15min: settings.currentUsage.llm.current.tokensPer15Min,
|
|
622
|
+
tokensDaily: settings.currentUsage.llm.current.tokensPerDay,
|
|
623
|
+
resetAt: settings.currentUsage.llm.resetAt
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Rate Limit Checking
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
// Check current rate limits for all operations
|
|
631
|
+
const limits = await client.checkLimits();
|
|
632
|
+
|
|
633
|
+
limits.forEach(limit => {
|
|
634
|
+
console.log(`${limit.operation}:`);
|
|
635
|
+
console.log(` Requests: ${limit.current.requestsPer15Min}/${limit.limit.requestsPer15Min} (15min)`);
|
|
636
|
+
console.log(` Requests: ${limit.current.requestsPerDay}/${limit.limit.requestsPerDay} (daily)`);
|
|
637
|
+
|
|
638
|
+
if (limit.operation === 'llm') {
|
|
639
|
+
console.log(` Tokens: ${limit.current.tokensPer15Min}/${limit.limit.tokensPer15Min} (15min)`);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Health Check
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
const health = await client.health();
|
|
648
|
+
console.log(health);
|
|
649
|
+
// {
|
|
650
|
+
// status: 'ok',
|
|
651
|
+
// timestamp: '2024-01-15T10:30:00.000Z'
|
|
652
|
+
// }
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Advanced Usage
|
|
658
|
+
|
|
659
|
+
### Custom Dimensions
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
const image = await client.generateImage({
|
|
663
|
+
prompt: 'a mountain landscape',
|
|
664
|
+
width: 1280,
|
|
665
|
+
height: 720
|
|
666
|
+
// Note: width/height must be between 320-1344
|
|
667
|
+
});
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Debug Mode
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
const client = createClient('2dai_pk_your_api_key_here', {
|
|
674
|
+
debug: true // Enable detailed logging
|
|
675
|
+
});
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## Complete Examples
|
|
681
|
+
|
|
682
|
+
### Example 1: Generate Image with Watermark and Download
|
|
683
|
+
|
|
684
|
+
```typescript
|
|
685
|
+
import { createClient, STYLES, FORMATS } from '2dai-sdk';
|
|
686
|
+
import axios from 'axios';
|
|
687
|
+
import fs from 'fs';
|
|
688
|
+
|
|
689
|
+
const client = createClient('2dai_pk_your_api_key_here');
|
|
690
|
+
|
|
691
|
+
async function generateAndDownload() {
|
|
692
|
+
try {
|
|
693
|
+
// Generate image
|
|
694
|
+
const result = await client.generateImage({
|
|
695
|
+
prompt: 'a futuristic city at sunset with flying cars',
|
|
696
|
+
style: STYLES.cine.id,
|
|
697
|
+
format: FORMATS.landscape.id,
|
|
698
|
+
watermark: 'your-watermark-id',
|
|
699
|
+
watermarkPosition: 'southeast'
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
console.log('Image generated:', result.imageId);
|
|
703
|
+
|
|
704
|
+
// Download the image
|
|
705
|
+
const imageUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${result.imageId}.jpg`;
|
|
706
|
+
const response = await axios.get(imageUrl, {
|
|
707
|
+
responseType: 'arraybuffer',
|
|
708
|
+
headers: { 'Authorization': `Bearer 2dai_pk_your_api_key_here` }
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
fs.writeFileSync('generated-image.jpg', response.data);
|
|
712
|
+
console.log('Image saved to generated-image.jpg');
|
|
713
|
+
|
|
714
|
+
} catch (error) {
|
|
715
|
+
console.error('Error:', error.message);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
generateAndDownload();
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### Example 2: Generate Video and Extract GIF Frame
|
|
723
|
+
|
|
724
|
+
```typescript
|
|
725
|
+
import { createClient, STYLES, FORMATS } from '2dai-sdk';
|
|
726
|
+
import axios from 'axios';
|
|
727
|
+
import fs from 'fs';
|
|
728
|
+
|
|
729
|
+
const client = createClient('2dai_pk_your_api_key_here');
|
|
730
|
+
|
|
731
|
+
async function generateVideoAndExtractFrame() {
|
|
732
|
+
try {
|
|
733
|
+
// First generate an image
|
|
734
|
+
const image = await client.generateImage({
|
|
735
|
+
prompt: 'a dancing robot in a disco',
|
|
736
|
+
style: STYLES.anime.id,
|
|
737
|
+
format: FORMATS.profile.id
|
|
738
|
+
});
|
|
739
|
+
console.log('Image generated:', image.imageId);
|
|
740
|
+
|
|
741
|
+
// Generate video from image
|
|
742
|
+
const video = await client.generateVideo({
|
|
743
|
+
imageId: image.imageId,
|
|
744
|
+
duration: 3,
|
|
745
|
+
fps: 16
|
|
746
|
+
});
|
|
747
|
+
console.log('Video generated:', video.videoId);
|
|
748
|
+
|
|
749
|
+
// Download video as MP4
|
|
750
|
+
const mp4Url = `https://apiv2.2dai.io:800/api/v1/cdn/${video.videoId}.mp4`;
|
|
751
|
+
const mp4Response = await axios.get(mp4Url, {
|
|
752
|
+
responseType: 'arraybuffer',
|
|
753
|
+
headers: { 'Authorization': `Bearer 2dai_pk_your_api_key_here` }
|
|
754
|
+
});
|
|
755
|
+
fs.writeFileSync('video.mp4', mp4Response.data);
|
|
756
|
+
console.log('Video saved to video.mp4');
|
|
757
|
+
|
|
758
|
+
// Extract first frame as GIF
|
|
759
|
+
const gifUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${video.videoId}.gif`;
|
|
760
|
+
const gifResponse = await axios.get(gifUrl, {
|
|
761
|
+
responseType: 'arraybuffer',
|
|
762
|
+
headers: { 'Authorization': `Bearer 2dai_pk_your_api_key_here` }
|
|
763
|
+
});
|
|
764
|
+
fs.writeFileSync('thumbnail.gif', gifResponse.data);
|
|
765
|
+
console.log('GIF thumbnail saved to thumbnail.gif');
|
|
766
|
+
|
|
767
|
+
} catch (error) {
|
|
768
|
+
console.error('Error:', error.message);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
generateVideoAndExtractFrame();
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Example 3: LLM with Memory and JSON Output
|
|
776
|
+
|
|
777
|
+
```typescript
|
|
778
|
+
import { createClient } from '2dai-sdk';
|
|
779
|
+
|
|
780
|
+
const client = createClient('2dai_pk_your_api_key_here');
|
|
781
|
+
|
|
782
|
+
async function chatWithMemory() {
|
|
783
|
+
const memory: string[] = [];
|
|
784
|
+
|
|
785
|
+
// First message
|
|
786
|
+
const response1 = await client.generateText({
|
|
787
|
+
prompt: 'My name is Alice and I love painting',
|
|
788
|
+
system: 'You are a friendly art assistant'
|
|
789
|
+
});
|
|
790
|
+
console.log('Response 1:', response1.response);
|
|
791
|
+
memory.push('User: My name is Alice and I love painting');
|
|
792
|
+
memory.push(`Assistant: ${response1.response}`);
|
|
793
|
+
|
|
794
|
+
// Second message with memory
|
|
795
|
+
const response2 = await client.generateText({
|
|
796
|
+
prompt: 'What art supplies would you recommend for me?',
|
|
797
|
+
system: 'You are a friendly art assistant',
|
|
798
|
+
memory
|
|
799
|
+
});
|
|
800
|
+
console.log('Response 2:', response2.response);
|
|
801
|
+
|
|
802
|
+
// Get structured JSON output
|
|
803
|
+
const analysis = await client.generateText({
|
|
804
|
+
prompt: 'Analyze the conversation we just had',
|
|
805
|
+
system: 'Analyze conversations and return structured data',
|
|
806
|
+
memory,
|
|
807
|
+
jsonFormat: true,
|
|
808
|
+
jsonTemplate: {
|
|
809
|
+
userName: 'the user name mentioned',
|
|
810
|
+
interests: 'array of user interests',
|
|
811
|
+
recommendationsGiven: 'number of recommendations',
|
|
812
|
+
sentiment: 'positive/neutral/negative'
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
console.log('Analysis:', JSON.parse(analysis.response));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
chatWithMemory();
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Example 4: Batch Image Generation with Rate Limit Checking
|
|
822
|
+
|
|
823
|
+
```typescript
|
|
824
|
+
import { createClient, STYLES } from '2dai-sdk';
|
|
825
|
+
|
|
826
|
+
const client = createClient('2dai_pk_your_api_key_here');
|
|
827
|
+
|
|
828
|
+
async function batchGenerate(prompts: string[]) {
|
|
829
|
+
const results = [];
|
|
830
|
+
|
|
831
|
+
for (const prompt of prompts) {
|
|
832
|
+
// Check rate limits before each request
|
|
833
|
+
const limits = await client.checkLimits();
|
|
834
|
+
const imageLimit = limits.find(l => l.operation === 'image');
|
|
835
|
+
|
|
836
|
+
if (imageLimit && imageLimit.remaining.requestsPer15Min <= 0) {
|
|
837
|
+
console.log('Rate limit reached, waiting for reset...');
|
|
838
|
+
const resetTime = new Date(imageLimit.resetAt.window15Min);
|
|
839
|
+
const waitMs = resetTime.getTime() - Date.now();
|
|
840
|
+
await new Promise(resolve => setTimeout(resolve, waitMs + 1000));
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
try {
|
|
844
|
+
const result = await client.generateImage({
|
|
845
|
+
prompt,
|
|
846
|
+
style: STYLES.realistic.id
|
|
847
|
+
});
|
|
848
|
+
results.push({ prompt, imageId: result.imageId, success: true });
|
|
849
|
+
console.log(`Generated: ${prompt.substring(0, 30)}... -> ${result.imageId}`);
|
|
850
|
+
} catch (error: any) {
|
|
851
|
+
results.push({ prompt, error: error.message, success: false });
|
|
852
|
+
console.error(`Failed: ${prompt.substring(0, 30)}... -> ${error.message}`);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return results;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Usage
|
|
860
|
+
const prompts = [
|
|
861
|
+
'a red apple on a wooden table',
|
|
862
|
+
'a blue ocean with waves',
|
|
863
|
+
'a green forest with sunlight'
|
|
864
|
+
];
|
|
865
|
+
|
|
866
|
+
batchGenerate(prompts).then(results => {
|
|
867
|
+
console.log('Batch complete:', results);
|
|
868
|
+
});
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
## API Reference
|
|
874
|
+
|
|
875
|
+
### Types
|
|
876
|
+
|
|
877
|
+
```typescript
|
|
878
|
+
interface ImageGenerationOptions {
|
|
879
|
+
prompt: string;
|
|
880
|
+
style?: StylePreset | string;
|
|
881
|
+
format?: FormatPreset | string;
|
|
882
|
+
negativePrompt?: string;
|
|
883
|
+
seed?: number;
|
|
884
|
+
width?: number;
|
|
885
|
+
height?: number;
|
|
886
|
+
watermark?: string;
|
|
887
|
+
watermarkPosition?: WatermarkPosition;
|
|
888
|
+
watermarkAsTiles?: boolean;
|
|
889
|
+
copyright?: string;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
interface VideoGenerationOptions {
|
|
893
|
+
imageId?: string;
|
|
894
|
+
imageBuffer?: Buffer;
|
|
895
|
+
duration?: number; // 1-10 seconds
|
|
896
|
+
fps?: number; // 8-32 fps
|
|
897
|
+
watermark?: string;
|
|
898
|
+
watermarkPosition?: WatermarkPosition;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
interface TextGenerationOptions {
|
|
902
|
+
prompt: string;
|
|
903
|
+
system?: string;
|
|
904
|
+
memory?: string[];
|
|
905
|
+
jsonFormat?: boolean;
|
|
906
|
+
jsonTemplate?: { [key: string]: string };
|
|
907
|
+
useRandomSeed?: boolean;
|
|
908
|
+
askKnowledge?: {
|
|
909
|
+
sources?: string[];
|
|
910
|
+
query?: string;
|
|
911
|
+
};
|
|
912
|
+
useMarkdown?: boolean; // Enable markdown formatting in response (default: false)
|
|
913
|
+
imageId?: string; // Image ID from CDN for vision/image analysis
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
interface UpscaleOptions {
|
|
917
|
+
factor?: number; // 2, 3, or 4 (default: 2)
|
|
918
|
+
seed?: number; // Optional seed for reproducibility
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
interface UpscaleResult {
|
|
922
|
+
success: boolean;
|
|
923
|
+
imageId: string;
|
|
924
|
+
width: number;
|
|
925
|
+
height: number;
|
|
926
|
+
seed?: number;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
interface OperationUsage {
|
|
930
|
+
current: {
|
|
931
|
+
requestsPer15Min: number;
|
|
932
|
+
requestsPerDay: number;
|
|
933
|
+
tokensPer15Min?: number; // Only for LLM operations
|
|
934
|
+
tokensPerDay?: number; // Only for LLM operations
|
|
935
|
+
};
|
|
936
|
+
remaining: {
|
|
937
|
+
requestsPer15Min: number;
|
|
938
|
+
requestsPerDay: number;
|
|
939
|
+
};
|
|
940
|
+
resetAt: {
|
|
941
|
+
window15Min: string; // ISO timestamp
|
|
942
|
+
daily: string; // ISO timestamp
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
interface APIKeySettings {
|
|
947
|
+
key: string;
|
|
948
|
+
name: string;
|
|
949
|
+
status: 'active' | 'suspended';
|
|
950
|
+
rateLimits: {
|
|
951
|
+
image: RateLimitConfig;
|
|
952
|
+
video: RateLimitConfig;
|
|
953
|
+
llm: LLMRateLimitConfig;
|
|
954
|
+
cdn: RateLimitConfig;
|
|
955
|
+
};
|
|
956
|
+
currentUsage?: {
|
|
957
|
+
image: OperationUsage;
|
|
958
|
+
video: OperationUsage;
|
|
959
|
+
llm: OperationUsage;
|
|
960
|
+
cdn: OperationUsage;
|
|
961
|
+
};
|
|
962
|
+
llmSettings?: any;
|
|
963
|
+
createdAt?: string;
|
|
964
|
+
lastUsedAt?: string;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
type WatermarkPosition =
|
|
968
|
+
// Sharp gravity constants (recommended)
|
|
969
|
+
| 'center'
|
|
970
|
+
| 'northwest' | 'north' | 'northeast'
|
|
971
|
+
| 'west' | 'east'
|
|
972
|
+
| 'southwest' | 'south' | 'southeast'
|
|
973
|
+
// Human-readable alternatives
|
|
974
|
+
| 'top-left' | 'top-center' | 'top-right'
|
|
975
|
+
| 'middle-left' | 'middle-center' | 'middle-right'
|
|
976
|
+
| 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
---
|
|
980
|
+
|
|
981
|
+
## Rate Limits
|
|
982
|
+
|
|
983
|
+
Default rate limits per API key:
|
|
984
|
+
|
|
985
|
+
| Operation | 15-Min Window | Daily Limit |
|
|
986
|
+
|-----------|--------------|-------------|
|
|
987
|
+
| Image Generation | 150 requests | 1,000 requests |
|
|
988
|
+
| Video Generation | 30 requests | 200 requests |
|
|
989
|
+
| LLM | 300 requests | 1,000 requests |
|
|
990
|
+
| LLM Tokens | 1,500,000 tokens | 5,000,000 tokens |
|
|
991
|
+
| CDN | 1,500 requests | 10,000 requests |
|
|
992
|
+
|
|
993
|
+
Custom rate limits can be configured per API key.
|
|
994
|
+
|
|
995
|
+
---
|
|
996
|
+
|
|
997
|
+
## Best Practices
|
|
998
|
+
|
|
999
|
+
### 1. Check Rate Limits Before Batch Operations
|
|
1000
|
+
|
|
1001
|
+
```typescript
|
|
1002
|
+
const limits = await client.checkLimits();
|
|
1003
|
+
const remaining = limits.find(l => l.operation === 'image')?.remaining.requestsPer15Min;
|
|
1004
|
+
|
|
1005
|
+
if (remaining && remaining < batchSize) {
|
|
1006
|
+
console.log(`Only ${remaining} requests available, reducing batch size`);
|
|
1007
|
+
}
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### 2. Use Appropriate Styles for Your Use Case
|
|
1011
|
+
|
|
1012
|
+
```typescript
|
|
1013
|
+
import { STYLES } from '2dai-sdk';
|
|
1014
|
+
|
|
1015
|
+
// For realistic photos
|
|
1016
|
+
STYLES.realistic.id
|
|
1017
|
+
|
|
1018
|
+
// For artistic/creative content
|
|
1019
|
+
STYLES.paint.id
|
|
1020
|
+
|
|
1021
|
+
// For anime/manga content
|
|
1022
|
+
STYLES.anime.id
|
|
1023
|
+
STYLES.manga.id
|
|
1024
|
+
|
|
1025
|
+
// For cinematic shots
|
|
1026
|
+
STYLES.cine.id
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
### 3. Handle Errors Gracefully
|
|
1030
|
+
|
|
1031
|
+
```typescript
|
|
1032
|
+
try {
|
|
1033
|
+
const result = await client.generateImage({ prompt: 'test' });
|
|
1034
|
+
} catch (error: any) {
|
|
1035
|
+
if (error.message.includes('RATE_LIMIT_EXCEEDED')) {
|
|
1036
|
+
// Wait and retry
|
|
1037
|
+
await new Promise(r => setTimeout(r, 60000));
|
|
1038
|
+
} else if (error.message.includes('INVALID_API_KEY')) {
|
|
1039
|
+
// Check API key configuration
|
|
1040
|
+
} else {
|
|
1041
|
+
// Log and handle other errors
|
|
1042
|
+
console.error('Generation failed:', error.message);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
### 4. Use Negative Prompts for Better Results (not fully supported yet)
|
|
1048
|
+
|
|
1049
|
+
```typescript
|
|
1050
|
+
const result = await client.generateImage({
|
|
1051
|
+
prompt: 'a beautiful portrait of a woman',
|
|
1052
|
+
negativePrompt: 'blurry, distorted, low quality, bad anatomy, extra limbs'
|
|
1053
|
+
});
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
### 5. Cache Generated Content
|
|
1057
|
+
|
|
1058
|
+
```typescript
|
|
1059
|
+
// Store image IDs for reuse
|
|
1060
|
+
const cache = new Map<string, string>();
|
|
1061
|
+
|
|
1062
|
+
async function getOrGenerate(prompt: string): Promise<string> {
|
|
1063
|
+
if (cache.has(prompt)) {
|
|
1064
|
+
return cache.get(prompt)!;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
const result = await client.generateImage({ prompt });
|
|
1068
|
+
cache.set(prompt, result.imageId);
|
|
1069
|
+
return result.imageId;
|
|
1070
|
+
}
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
### 6. Use Seeds for Reproducibility
|
|
1074
|
+
|
|
1075
|
+
```typescript
|
|
1076
|
+
// Same seed = same result (with same prompt and settings)
|
|
1077
|
+
const result1 = await client.generateImage({
|
|
1078
|
+
prompt: 'a red car',
|
|
1079
|
+
seed: 12345
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
const result2 = await client.generateImage({
|
|
1083
|
+
prompt: 'a red car',
|
|
1084
|
+
seed: 12345
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
// result1.imageId content will be identical to result2.imageId
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
---
|
|
1091
|
+
|
|
1092
|
+
## Troubleshooting
|
|
1093
|
+
|
|
1094
|
+
### Common Issues
|
|
1095
|
+
|
|
1096
|
+
#### "RATE_LIMIT_EXCEEDED" Error
|
|
1097
|
+
|
|
1098
|
+
**Problem:** You've exceeded your rate limit for the current time window.
|
|
1099
|
+
|
|
1100
|
+
**Solution:**
|
|
1101
|
+
```typescript
|
|
1102
|
+
const settings = await client.getSettings();
|
|
1103
|
+
const resetTime = settings.currentUsage?.image.resetAt.window15Min;
|
|
1104
|
+
console.log(`Rate limit resets at: ${resetTime}`);
|
|
1105
|
+
|
|
1106
|
+
// Wait for reset
|
|
1107
|
+
const waitMs = new Date(resetTime).getTime() - Date.now();
|
|
1108
|
+
await new Promise(r => setTimeout(r, waitMs + 1000));
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
#### "INVALID_API_KEY" Error
|
|
1112
|
+
|
|
1113
|
+
**Problem:** Your API key is invalid or expired.
|
|
1114
|
+
|
|
1115
|
+
**Solution:**
|
|
1116
|
+
- Verify your API key starts with `2dai_pk_`
|
|
1117
|
+
- Check that the key hasn't been revoked
|
|
1118
|
+
- Ensure you're using the correct environment (production vs staging)
|
|
1119
|
+
|
|
1120
|
+
#### Timeout Errors
|
|
1121
|
+
|
|
1122
|
+
**Problem:** Requests are timing out.
|
|
1123
|
+
|
|
1124
|
+
**Solution:**
|
|
1125
|
+
```typescript
|
|
1126
|
+
const client = createClient('2dai_pk_...', {
|
|
1127
|
+
timeout: 600000 // Increase to 10 minutes for long operations
|
|
1128
|
+
});
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
#### Image Quality Issues
|
|
1132
|
+
|
|
1133
|
+
**Problem:** Generated images don't match expectations.
|
|
1134
|
+
|
|
1135
|
+
**Solution:**
|
|
1136
|
+
- Use more detailed, descriptive prompts (include lighting, style, mood, composition)
|
|
1137
|
+
- Add negative prompts to exclude unwanted elements (requires style support)
|
|
1138
|
+
- Try different styles for your use case (see [Available Styles](#available-styles))
|
|
1139
|
+
- Use specific dimensions with the `format` parameter
|
|
1140
|
+
- Experiment with different seeds for variations
|
|
1141
|
+
|
|
1142
|
+
**Need custom models or advanced features?** Contact us at [support@2dai.io](mailto:support@2dai.io) for:
|
|
1143
|
+
- Custom fine-tuned models for your brand/style
|
|
1144
|
+
- Higher rate limits and enterprise plans
|
|
1145
|
+
- Priority support and dedicated infrastructure
|
|
1146
|
+
|
|
1147
|
+
#### CDN Download Failures
|
|
1148
|
+
|
|
1149
|
+
**Problem:** Cannot download files from CDN.
|
|
1150
|
+
|
|
1151
|
+
**Solution:**
|
|
1152
|
+
```typescript
|
|
1153
|
+
// Ensure Authorization header is included
|
|
1154
|
+
const response = await axios.get(cdnUrl, {
|
|
1155
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
1156
|
+
responseType: 'arraybuffer',
|
|
1157
|
+
timeout: 30000
|
|
1158
|
+
});
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
### Debug Mode
|
|
1162
|
+
|
|
1163
|
+
Enable debug mode to see detailed request/response logs:
|
|
1164
|
+
|
|
1165
|
+
```typescript
|
|
1166
|
+
const client = createClient('2dai_pk_...', {
|
|
1167
|
+
debug: true
|
|
1168
|
+
});
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
---
|
|
1172
|
+
|
|
1173
|
+
## Migration Guide
|
|
1174
|
+
|
|
1175
|
+
### Breaking Changes in v1.0.0
|
|
1176
|
+
|
|
1177
|
+
**`imageUrl` and `videoUrl` have been removed from generation responses.**
|
|
1178
|
+
|
|
1179
|
+
Previously, the API returned full CDN URLs directly in the response. For security and architectural reasons, these have been removed. You now receive only file IDs and must construct CDN URLs yourself.
|
|
1180
|
+
|
|
1181
|
+
#### Before (Old Version)
|
|
1182
|
+
```typescript
|
|
1183
|
+
const result = await client.generateImage({ prompt: "..." });
|
|
1184
|
+
console.log(result.imageUrl); // Full URL was provided
|
|
1185
|
+
// "https://cdn.2dai.com/file/xyz.jpg?watermark=..."
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
#### After (Current Version)
|
|
1189
|
+
```typescript
|
|
1190
|
+
const result = await client.generateImage({ prompt: "..." });
|
|
1191
|
+
// Result now contains only imageId (no imageUrl property)
|
|
1192
|
+
|
|
1193
|
+
// Construct the CDN URL from the imageId
|
|
1194
|
+
const imageUrl = `https://apiv2.2dai.io:800/api/v1/cdn/${result.imageId}.jpg`;
|
|
1195
|
+
console.log(imageUrl);
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
**Why this change?**
|
|
1199
|
+
- **Security**: Prevents exposure of internal CDN structure and watermark IDs
|
|
1200
|
+
- **Flexibility**: Allows you to customize CDN parameters (size, watermark position, etc.)
|
|
1201
|
+
- **Future-proof**: CDN infrastructure can be updated without breaking client code
|
|
1202
|
+
|
|
1203
|
+
---
|
|
1204
|
+
|
|
1205
|
+
## Testing
|
|
1206
|
+
|
|
1207
|
+
This SDK includes comprehensive test suites covering all API functionality:
|
|
1208
|
+
|
|
1209
|
+
```bash
|
|
1210
|
+
# Run all tests (REST + WebSocket)
|
|
1211
|
+
npm test
|
|
1212
|
+
|
|
1213
|
+
# Run REST API tests only
|
|
1214
|
+
npm run test:rest
|
|
1215
|
+
|
|
1216
|
+
# Run WebSocket tests only
|
|
1217
|
+
npm run test:ws
|
|
1218
|
+
|
|
1219
|
+
# Run tests with coverage report
|
|
1220
|
+
npm run test:coverage
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### Test Performance
|
|
1224
|
+
|
|
1225
|
+
| Test Suite | Tests | Expected Time | Notes |
|
|
1226
|
+
|------------|-------|---------------|-------|
|
|
1227
|
+
| REST API (`test:rest`) | 20 | ~6-7 min | Image/video generation dominates |
|
|
1228
|
+
| WebSocket (`test:ws`) | 26 | ~6 min | Similar generation overhead |
|
|
1229
|
+
| Full Suite (`test`) | 46 | ~12-13 min | Both suites combined |
|
|
1230
|
+
|
|
1231
|
+
**Time breakdown by operation type:**
|
|
1232
|
+
- Image Generation: ~25-65s per test (AI processing)
|
|
1233
|
+
- Video Generation: ~90s per test (longest operation)
|
|
1234
|
+
- Image Upscale: ~70-80s per test
|
|
1235
|
+
- LLM Text Generation: ~1-10s per test (fast)
|
|
1236
|
+
- CDN Operations: <1s per test (instant)
|
|
1237
|
+
- Error Handling: <1s per test (validation only)
|
|
1238
|
+
|
|
1239
|
+
### Test Coverage
|
|
1240
|
+
|
|
1241
|
+
**REST API Tests (20 tests):**
|
|
1242
|
+
- Image Generation (2): Default settings, style + format
|
|
1243
|
+
- Image Editing (2): Basic edit, resize with dimensions
|
|
1244
|
+
- Image Upscale (1): AI upscale 2x
|
|
1245
|
+
- Video + CDN (4): Generation, MP4-to-GIF, resize
|
|
1246
|
+
- LLM Text (5): Simple prompt, system + memory, JSON, vision, markdown
|
|
1247
|
+
- Error Handling (3): Invalid API key, params, IDs
|
|
1248
|
+
- Settings (1): API key settings with usage
|
|
1249
|
+
- Frame Extraction (2): Multiple formats, resize + watermark
|
|
1250
|
+
- Watermarks (1): Position constants
|
|
1251
|
+
|
|
1252
|
+
**WebSocket Tests (26 tests):**
|
|
1253
|
+
- Connection & Auth (4): Connect, authenticate, reject invalid, ping/pong
|
|
1254
|
+
- Image Generation (2): Default, style + format
|
|
1255
|
+
- Image Editing (2): Basic edit, resize
|
|
1256
|
+
- Image Upscale (1): AI upscale via WS
|
|
1257
|
+
- Video Generation (1): 5-second video
|
|
1258
|
+
- GIF/CDN (3): MP4-to-GIF, resize, position
|
|
1259
|
+
- LLM Generation (4): Simple, system + memory + JSON, vision, markdown
|
|
1260
|
+
- Error Handling (3): Missing prompt, invalid ID, invalid dimensions
|
|
1261
|
+
- Connection Resilience (2): Graceful close, reconnection
|
|
1262
|
+
- Client SDK Options (4): Connection state, WS options, timeout, REST integration
|
|
1263
|
+
|
|
1264
|
+
### Test Output
|
|
1265
|
+
|
|
1266
|
+
All tests display timestamps for performance monitoring:
|
|
1267
|
+
```
|
|
1268
|
+
================================================================================
|
|
1269
|
+
🧪 TEST: Generate Image - Default Settings
|
|
1270
|
+
⏱️ [20:23:05] Total: 0.0s | Since last: 0.0s
|
|
1271
|
+
================================================================================
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
Generated files are saved to `tests/tmp/` for manual verification.
|
|
1275
|
+
|
|
1276
|
+
---
|
|
1277
|
+
|
|
1278
|
+
## Requirements
|
|
1279
|
+
|
|
1280
|
+
- Node.js 18 or higher
|
|
1281
|
+
- TypeScript 5.0+ (for TypeScript projects)
|
|
1282
|
+
|
|
1283
|
+
---
|
|
1284
|
+
|
|
1285
|
+
## License
|
|
1286
|
+
|
|
1287
|
+
MIT
|