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