apick-api 2.4.0 → 3.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.2.0 — 2026-09-14
4
+
5
+ - Seedance 참조 영상 작업에 `referenceAudios`(MP3·WAV) 입력을 추가했습니다.
6
+ - Add video generation version selection documentation and compatibility tests.
7
+ - 영상 생성 버전 선택, 버전별 옵션·요금 안내와 호환 검증을 추가했습니다.
8
+ - Add createVideoJob, getVideoJob, downloadVideoResult and public TypeScript types.
9
+ - Document and verify Seedance 2.0 Fast and Mini tier pass-through.
10
+
11
+ ## 3.1.0 - 2026-09-08
12
+
13
+ - TTS 발화별 검수 이력, 후보 WAV 조회, 멱등 키를 사용하는 같은 작업 재개 메서드를 추가했습니다.
14
+ - Added TTS quality history, candidate WAV downloads, and idempotent job recovery methods.
15
+
16
+ ## 3.0.0 - 2026-09-05
17
+
18
+ - 이미지 프롬프트 허용 길이를 최대 28,000자로 확대했습니다.
19
+ - 작업 접수 시 전체 포인트를 먼저 차감하고 실패한 이미지의 포인트를 즉시 환급하는 계약을 반영했습니다.
20
+ - 접수된 이미지 작업은 취소할 수 없도록 `cancelImageJob` 메서드와 `cancelled` 상태를 제거했습니다.
21
+
3
22
  ## 2.4.0 - 2026-09-05
4
23
 
5
24
  - 이미지 장수 옵션을 의미가 분명한 `imageCount`로 바꾸고 압축 조정 옵션을 제거했습니다.
package/README.md CHANGED
@@ -72,6 +72,9 @@ Leave the allowed-IP list blank for unrestricted access. To restrict access, reg
72
72
  | `cancelTtsJob(jobId)` | 대기·생성 중 TTS 작업 취소 / Cancel waiting or processing TTS job | JSON |
73
73
  | `downloadTtsResult(jobId)` | TTS 결과 1회 다운로드 / One-time TTS result | MP3 |
74
74
  | `downloadTtsSubtitles(jobId)` | TTS 자막 1회 다운로드 / One-time TTS subtitles | ASS |
75
+ | `getTtsQuality(jobId)` | 발화별 검수·후보 이력 / Utterance quality and candidates | JSON |
76
+ | `retryTtsJob(jobId, utteranceIds, idempotencyKey)` | 같은 작업의 국소 복구 / Idempotent local recovery | JSON |
77
+ | `downloadTtsCandidate(jobId, candidateId)` | 검수 후보 청취 / Candidate audio | WAV |
75
78
  | `htmlToPdf(html, options)` | HTML→PDF | Binary |
76
79
  | `jsonToExcel(data, options)` | JSON→Excel | Binary |
77
80
  | `summarize(text)` | 텍스트 요약 / Text summarization | JSON |
@@ -80,7 +83,7 @@ Leave the allowed-IP list blank for unrestricted access. To restrict access, reg
80
83
  | `editImages(image, prompt, options)` | 이미지 편집 / Image editing | JSON |
81
84
  | `createImageGenerationJob(prompt, options)` | 대량 이미지 생성 작업 / Batch generation job | JSON |
82
85
  | `createImageEditJob(image, prompt, options)` | 대량 이미지 편집 작업 / Batch edit job | JSON |
83
- | `getImageJob(jobId)` · `cancelImageJob(jobId)` | 이미지 작업 조회·취소 / Job status and cancellation | JSON |
86
+ | `getImageJob(jobId)` | 이미지 작업 상태 조회 / Job status | JSON |
84
87
  | `downloadImageJobImage(jobId, index)` | 개별 결과 / Individual result | Binary |
85
88
  | `downloadImageJobArchive(jobId)` | ZIP 결과 / ZIP archive | Binary |
86
89
 
@@ -101,9 +104,9 @@ console.log(result.meta);
101
104
 
102
105
  ## 이미지 생성·편집 / Image generation and editing
103
106
 
104
- 이미지는 장당 25포인트이며 동기는 1~4장, 작업형 API는 최대 50장까지 지원합니다. 성공적으로 저장된 이미지에 대해서만 과금되며 결과는 완료 후 24시간 동안 반복 다운로드할 수 있습니다.
107
+ 이미지는 장당 25포인트이며 동기는 1~4장, 작업형 API는 최대 50장까지 지원합니다. 요청이 접수되면 전체 금액을 먼저 차감하고, 생성에 실패한 이미지가 있으면 해당 장수만큼 즉시 환급합니다. 접수된 작업은 취소할 수 없으며 결과는 완료 후 24시간 동안 반복 다운로드할 수 있습니다.
105
108
 
106
- Images cost 25 points each. Synchronous calls support 1–4 images and job calls support up to 50. Only stored successful results are charged, and completed job results remain downloadable for 24 hours.
109
+ Images cost 25 points each. Synchronous calls support 1–4 images and job calls support up to 50. The full amount is deducted when a request is accepted, and failed images are refunded immediately. Accepted jobs cannot be cancelled. Completed results remain downloadable for 24 hours.
107
110
 
108
111
  ```js
109
112
  const made = await apick.generateImages("따뜻한 조명의 미니멀 제품 사진", {
@@ -127,9 +130,9 @@ const image = await apick.downloadImageJobImage(job.data.job_id, 0);
127
130
  await image.save("./result.png");
128
131
  ```
129
132
 
130
- PNG·JPEG·WebP 출력, 투명 배경 미리보기(PNG/WebP), 5개 표준 크기(`1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, `864x1152`)를 지원합니다. 입력 프롬프트는 최대 6,000자입니다. `idempotencyKey`는 네트워크 재전송 때 중복 생성과 중복 과금을 막는 8~128자의 요청 식별자이며, 같은 작업을 다시 보낼 때 같은 값을 사용합니다. 자동 재시도는 하지 않습니다.
133
+ PNG·JPEG·WebP 출력, 투명 배경 미리보기(PNG/WebP), 5개 표준 크기(`1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, `864x1152`)를 지원합니다. 입력 프롬프트는 최대 28,000자입니다. `idempotencyKey`는 네트워크 재전송 때 중복 생성과 중복 과금을 막는 8~128자의 요청 식별자이며, 같은 작업을 다시 보낼 때 같은 값을 사용합니다. 자동 재시도는 하지 않습니다.
131
134
 
132
- PNG, JPEG, and WebP outputs, transparent-background previews for PNG/WebP, and five standard sizes are supported. Prompts are limited to 6,000 characters. `idempotencyKey` identifies the same request during network retransmission to prevent duplicate generation and billing. Requests are never retried automatically.
135
+ PNG, JPEG, and WebP outputs, transparent-background previews for PNG/WebP, and five standard sizes are supported. Prompts are limited to 28,000 characters. `idempotencyKey` identifies the same request during network retransmission to prevent duplicate generation and billing. Requests are never retried automatically.
133
136
 
134
137
  OCR은 PNG/JPEG 파일 경로, `Blob`, `ArrayBuffer`, `Uint8Array`를 받습니다. 최대 크기는 50MB입니다.
135
138
  OCR accepts a PNG/JPEG file path, `Blob`, `ArrayBuffer`, or `Uint8Array`, up to 50MB.
@@ -261,3 +264,36 @@ Error codes are one of `APICK_AUTH_ERROR`, `APICK_TIMEOUT`, `APICK_NETWORK_ERROR
261
264
  ## License
262
265
 
263
266
  MIT — see [LICENSE](LICENSE). Use of the APICK service is governed by the [APICK terms](https://apick.app/terms).
267
+
268
+ ## Video model versions
269
+
270
+ Omitting `version` preserves Seedance 2.5, Veo 3.1 and Kling 3.0. Set `version` and `tier` explicitly to select a generation; jobs are never silently switched to another version. Submission and status responses include `version`.
271
+
272
+ Available generations: Seedance 1.0/1.5/2.0/2.5, including Seedance 2.0 Standard/Fast/Mini; Veo 3.1 (Standard/Fast/Lite); Kling 1.6/2.0/2.1/2.5/2.6/3.0/O1/O3. Veo 3.0 is unavailable. Modes, tiers, resolutions, durations, audio, file limits and prices vary by combination. See the [Seedance](https://apick.app/dev_guide/seedancejobs), [Veo](https://apick.app/dev_guide/veojobs) and [Kling](https://apick.app/dev_guide/klingjobs) version tables. Unsupported combinations are rejected before submission.
273
+
274
+ Seedance reference mode accepts `referenceImages`, `referenceVideos`, and `referenceAudios` (MP3/WAV) when supported by the selected version.
275
+
276
+ ## 영상 모델 버전 선택
277
+
278
+ `version`을 생략하면 Seedance 2.5, Veo 3.1, Kling 3.0을 사용합니다. 버전과 등급을 명시하면 해당 조합으로 생성하며 다른 모델로 자동 대체하지 않습니다. 생성과 상태 응답의 `version`으로 확인할 수 있습니다.
279
+
280
+ | 제품 | 제공 버전 | 제약과 요금 |
281
+ |---|---|---|
282
+ | Seedance | 2.5, 2.0(Standard·Fast·Mini), 1.5, 1.0 | [버전별 지원표](https://apick.app/dev_guide/seedancejobs) |
283
+ | Veo | 3.1 (Standard, Fast, Lite) | [버전별 지원표](https://apick.app/dev_guide/veojobs) |
284
+ | Kling | 3.0, O3, O1, 2.6, 2.5, 2.1, 2.0, 1.6 | [버전별 지원표](https://apick.app/dev_guide/klingjobs) |
285
+
286
+ 등급·해상도·길이·오디오·파일 개수와 초당 포인트는 선택 조합별로 다릅니다. Seedance 2.0은 Standard·Fast·Mini를 제공하며 Mini는 480p·720p와 4~15초를 지원합니다. 무음 전용 모델은 `audio=false`, 오디오 필수 모델은 `audio=true`만 허용합니다. Veo 3.0은 현재 제공하지 않습니다. 지원하지 않는 조합은 접수 전에 거절됩니다.
287
+
288
+ Seedance 참조 소재 모드는 지원 버전에서 `referenceImages`, `referenceVideos`, `referenceAudios`(MP3·WAV)를 함께 사용할 수 있습니다.
289
+
290
+ ```js
291
+ const job = await client.createVideoJob("kling", "A boat crossing the sea", {
292
+ version: "1.6", tier: "std", mode: "text", duration: 5, audio: false,
293
+ idempotencyKey: "boat-video-0001"
294
+ });
295
+ const status = await client.getVideoJob("kling", job.data.job_id);
296
+ if (status.data.status === "completed") {
297
+ await (await client.downloadVideoResult("kling", job.data.job_id)).save("boat.mp4");
298
+ }
299
+ ```
package/docs/guide.en.md CHANGED
@@ -141,11 +141,11 @@ const job = await client.createImageGenerationJob('Landscape article cover conce
141
141
  const status = await client.getImageJob(job.data.job_id);
142
142
  ```
143
143
 
144
- `imageCount` is the number of images to make and defaults to one. Synchronous generation and editing support 1–4 images; job methods support 1–50. Add `referenceImage` to generation when the prompt should build from an existing composition, palette, or product shape. Editing accepts one PNG, JPEG, or WebP source up to 50 MB plus a prompt; mask files are not supported. Choose one of five sizes: `1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, or `864x1152`. Each stored successful image costs 25 points, while reservations for failed or cancelled items are released. Results remain available for 24 hours.
144
+ `imageCount` is the number of images to make and defaults to one. Synchronous generation and editing support 1–4 images; job methods support 1–50. Add `referenceImage` to generation when the prompt should build from an existing composition, palette, or product shape. Editing accepts one PNG, JPEG, or WebP source up to 50 MB plus a prompt; mask files are not supported. Choose one of five sizes: `1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, or `864x1152`; prompts may contain up to 28,000 characters. The full image count × 25 points is deducted when accepted, and 25 points are refunded immediately for every failed image. Accepted jobs cannot be cancelled. Results remain available for 24 hours.
145
145
 
146
146
  `idempotencyKey` is a safety identifier that prevents duplicate generation and billing if a network problem sends the same request twice. Use 8–128 letters, numbers, underscores, or hyphens. Reuse it only for the exact same request and create a new value when the prompt or options change.
147
147
 
148
- Methods: `generateImages`, `editImages`, `createImageGenerationJob`, `createImageEditJob`, `getImageJob`, `cancelImageJob`, `downloadImageJobImage`, and `downloadImageJobArchive`.
148
+ Methods: `generateImages`, `editImages`, `createImageGenerationJob`, `createImageEditJob`, `getImageJob`, `downloadImageJobImage`, and `downloadImageJobArchive`.
149
149
 
150
150
  ## Response shape
151
151
 
@@ -180,3 +180,27 @@ The document-specific methods are `maskResidenceCard`, `maskPassport`, `maskIdCa
180
180
  ## Errors and retries
181
181
 
182
182
  `ApickApiError` includes public error information: `code`, optional `serviceCode`, `status`, and `message`. The SDK does not retry automatically because a retry could duplicate an API call and its charge. If your application needs retries, decide explicitly after checking the error code and whether the operation is safe to repeat.
183
+ # TTS quality and recovery
184
+
185
+ Use `getTtsQuality(jobId)` to inspect utterance speed, rejection reasons, and candidate history. Candidates remain available for 72 hours after the job terminates. `downloadTtsCandidate(jobId, candidateId)` does not consume the final MP3 or ASS download.
186
+
187
+ `retryTtsJob(jobId, ['u002'], idempotencyKey)` requests technical recovery within the same job without an additional charge. Reuse the same key and utterance list after a lost response. Check `resume_revision` to identify the current revision. Required quality checks must pass before a job completes.
188
+
189
+ ## Video model versions
190
+
191
+ Omitting `version` preserves Seedance 2.5, Veo 3.1 and Kling 3.0. Set `version` and `tier` explicitly to select a generation; jobs are never silently switched to another version. Submission and status responses include `version`.
192
+
193
+ Available generations: Seedance 1.0/1.5/2.0/2.5, including Seedance 2.0 Standard/Fast/Mini; Veo 3.1 (Standard/Fast/Lite); Kling 1.6/2.0/2.1/2.5/2.6/3.0/O1/O3. Veo 3.0 is unavailable. Seedance 2.0 Mini supports 480p/720p and 4–15 seconds. Modes, tiers, resolutions, durations, audio, file limits and prices vary by combination. See the [Seedance](https://apick.app/dev_guide/seedancejobs), [Veo](https://apick.app/dev_guide/veojobs) and [Kling](https://apick.app/dev_guide/klingjobs) version tables. Unsupported combinations are rejected before submission.
194
+
195
+ Seedance reference mode accepts `referenceImages`, `referenceVideos`, and `referenceAudios` (MP3/WAV) when supported by the selected version.
196
+
197
+ ```js
198
+ const job = await client.createVideoJob("kling", "A boat crossing the sea", {
199
+ version: "1.6", tier: "std", mode: "text", duration: 5, audio: false,
200
+ idempotencyKey: "boat-video-0001"
201
+ });
202
+ const status = await client.getVideoJob("kling", job.data.job_id);
203
+ if (status.data.status === "completed") {
204
+ await (await client.downloadVideoResult("kling", job.data.job_id)).save("boat.mp4");
205
+ }
206
+ ```
package/docs/guide.ko.md CHANGED
@@ -143,11 +143,11 @@ const job = await client.createImageGenerationJob('가로형 커버 시안', { i
143
143
  const status = await client.getImageJob(job.data.job_id);
144
144
  ```
145
145
 
146
- `imageCount`는 만들 이미지 장수이며 생략하면 1장입니다. 동기 생성·편집은 1~4장, 작업형 생성·편집은 1~50장입니다. 생성에 `referenceImage`를 함께 전달하면 참고 이미지의 구도·색감·제품 형태 등을 프롬프트와 조합할 수 있습니다. 편집은 50MB 이하의 PNG/JPEG/WebP 원본 이미지 한 장과 프롬프트를 받으며 마스크 파일은 지원하지 않습니다. 크기는 `1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, `864x1152` 중에서 선택합니다. 성공 이미지 한 장당 25포인트가 확정되며 실패·취소 수량의 예약 포인트는 해제됩니다. 결과 보관 기간은 완료 후 24시간입니다.
146
+ `imageCount`는 만들 이미지 장수이며 생략하면 1장입니다. 동기 생성·편집은 1~4장, 작업형 생성·편집은 1~50장입니다. 생성에 `referenceImage`를 함께 전달하면 참고 이미지의 구도·색감·제품 형태 등을 프롬프트와 조합할 수 있습니다. 편집은 50MB 이하의 PNG/JPEG/WebP 원본 이미지 한 장과 프롬프트를 받으며 마스크 파일은 지원하지 않습니다. 크기는 `1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, `864x1152` 중에서 선택하고 프롬프트는 최대 28,000자까지 입력할 수 있습니다. 접수 시 이미지 장수×25포인트를 먼저 차감하며 실패한 이미지의 25포인트는 즉시 환급합니다. 접수된 작업은 취소할 수 없습니다. 결과 보관 기간은 완료 후 24시간입니다.
147
147
 
148
148
  `idempotencyKey`는 같은 요청이 통신 오류로 두 번 전송됐을 때 중복 생성과 중복 과금을 막는 안전번호입니다. 영문·숫자·밑줄·하이픈으로 8~128자를 만들고, 같은 작업을 다시 보낼 때는 같은 값을 사용하세요. 프롬프트나 옵션이 달라진 새 작업에는 새 값을 사용해야 합니다.
149
149
 
150
- 지원 메서드: `generateImages`, `editImages`, `createImageGenerationJob`, `createImageEditJob`, `getImageJob`, `cancelImageJob`, `downloadImageJobImage`, `downloadImageJobArchive`.
150
+ 지원 메서드: `generateImages`, `editImages`, `createImageGenerationJob`, `createImageEditJob`, `getImageJob`, `downloadImageJobImage`, `downloadImageJobArchive`.
151
151
 
152
152
  ## 응답 구조
153
153
 
@@ -182,3 +182,33 @@ console.log(result.data.result.fields);
182
182
  ## 오류와 재시도
183
183
 
184
184
  `ApickApiError`에는 공개 오류 정보인 `code`, `serviceCode`, `status`, `message`가 포함됩니다. SDK는 중복 호출과 중복 과금을 방지하기 위해 자동 재시도를 하지 않습니다. 재시도가 필요하면 작업의 멱등성과 오류 코드를 확인한 뒤 애플리케이션에서 명시적으로 결정하세요.
185
+ # TTS 검수와 재개
186
+
187
+ `getTtsQuality(jobId)`로 발화별 속도·실패 이유와 후보 목록을 조회합니다. 후보는 작업 종료 후 72시간 보존되며 `downloadTtsCandidate(jobId, candidateId)` 호출은 최종 MP3·ASS의 1회 다운로드를 소비하지 않습니다.
188
+
189
+ `retryTtsJob(jobId, ['u002'], idempotencyKey)`는 해당 발화의 기술적 복구를 같은 작업에서 요청합니다. 응답이 끊겨도 같은 키와 발화 목록을 사용하세요. 기술적 복구는 추가 과금하지 않으며, 재개 회차는 `resume_revision`으로 확인합니다. 필수 검수를 통과하지 못한 작업은 완료되지 않습니다.
190
+
191
+ ## 영상 모델 버전 선택
192
+
193
+ `version`을 생략하면 Seedance 2.5, Veo 3.1, Kling 3.0을 사용합니다. 버전과 등급을 명시하면 해당 조합으로 생성하며 다른 모델로 자동 대체하지 않습니다. 생성과 상태 응답의 `version`으로 확인할 수 있습니다.
194
+
195
+ | 제품 | 제공 버전 | 제약과 요금 |
196
+ |---|---|---|
197
+ | Seedance | 2.5, 2.0(Standard·Fast·Mini), 1.5, 1.0 | [버전별 지원표](https://apick.app/dev_guide/seedancejobs) |
198
+ | Veo | 3.1 (Standard, Fast, Lite) | [버전별 지원표](https://apick.app/dev_guide/veojobs) |
199
+ | Kling | 3.0, O3, O1, 2.6, 2.5, 2.1, 2.0, 1.6 | [버전별 지원표](https://apick.app/dev_guide/klingjobs) |
200
+
201
+ 등급·해상도·길이·오디오·파일 개수와 초당 포인트는 선택 조합별로 다릅니다. Seedance 2.0은 Standard·Fast·Mini를 제공하며 Mini는 480p·720p와 4~15초를 지원합니다. 무음 전용 모델은 `audio=false`, 오디오 필수 모델은 `audio=true`만 허용합니다. Veo 3.0은 현재 제공하지 않습니다. 지원하지 않는 조합은 접수 전에 거절됩니다.
202
+
203
+ Seedance 참조 소재 모드는 지원 버전에서 `referenceImages`, `referenceVideos`, `referenceAudios`(MP3·WAV)를 함께 사용할 수 있습니다.
204
+
205
+ ```js
206
+ const job = await client.createVideoJob("kling", "A boat crossing the sea", {
207
+ version: "1.6", tier: "std", mode: "text", duration: 5, audio: false,
208
+ idempotencyKey: "boat-video-0001"
209
+ });
210
+ const status = await client.getVideoJob("kling", job.data.job_id);
211
+ if (status.data.status === "completed") {
212
+ await (await client.downloadVideoResult("kling", job.data.job_id)).save("boat.mp4");
213
+ }
214
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apick-api",
3
- "version": "2.4.0",
3
+ "version": "3.2.0",
4
4
  "description": "Official zero-dependency Node.js client for APICK data, AI, and image APIs. 에이픽 데이터·AI·이미지 API 공식 Node.js SDK.",
5
5
  "type": "module",
6
6
  "main": "./src/index.cjs",
package/src/index.cjs CHANGED
@@ -37,6 +37,7 @@ const SERVICE_DEFINITIONS = Object.freeze({
37
37
  googleImageSearch: { endpoint: '/rest/google_image_search', timeoutMs: 35_000, output: 'json' },
38
38
  screenshot: { endpoint: '/rest/url_screenshot', timeoutMs: 75_000, output: 'binary', filename: 'screenshot.jpeg' },
39
39
  createTtsJob: { endpoint: '/rest/tts/jobs', timeoutMs: 35_000, output: 'json' },
40
+ createVideoJob: { endpoint: '/rest/seedance/jobs', timeoutMs: 60_000, output: 'json' },
40
41
  htmlToPdf: { endpoint: '/rest/html_to_pdf', timeoutMs: 25_000, output: 'binary', filename: 'document.pdf' },
41
42
  jsonToExcel: { endpoint: '/rest/json_to_excel', timeoutMs: 45_000, output: 'binary', filename: 'data.xlsx' },
42
43
  summarize: { endpoint: '/rest/llm/text_summary', timeoutMs: 75_000, output: 'json' },
@@ -467,6 +468,52 @@ class ApickClient {
467
468
  return this._call('screenshot', { url: normalizeUrl(url) });
468
469
  }
469
470
 
471
+ async createVideoJob(model, prompt, options) {
472
+ if (!['seedance', 'veo', 'kling'].includes(model)) throw new RangeError('model must be seedance, veo or kling.');
473
+ const config = options || {};
474
+ const payload = { prompt: config.mode === 'reference' && prompt === '' ? '' : requiredString('prompt', prompt, 2000) };
475
+ for (const [key, field] of Object.entries({ version:'version', tier:'tier', mode:'mode', duration:'duration', aspectRatio:'aspect_ratio', resolution:'resolution', audio:'audio', negativePrompt:'negative_prompt', seed:'seed', cfgScale:'cfg_scale', idempotencyKey:'idempotency_key' })) {
476
+ if (config[key] !== undefined) payload[field] = config[key];
477
+ }
478
+ const files = [['image', config.image], ['last_image', config.lastImage]];
479
+ for (const input of config.referenceImages || []) files.push(['reference_image', input]);
480
+ for (const input of config.referenceVideos || []) files.push(['reference_video', input]);
481
+ for (const input of config.referenceAudios || []) files.push(['reference_audio', input]);
482
+ const present = files.filter(([, input]) => input !== undefined);
483
+ const request = { endpoint: '/rest/' + model + '/jobs' };
484
+ if (!present.length) return this._call('createVideoJob', payload, null, request);
485
+ const form = new FormData();
486
+ for (const [key, value] of Object.entries(payload)) form.append(key, String(value));
487
+ for (const [field, input] of present) {
488
+ if (field !== 'reference_video' && field !== 'reference_audio') {
489
+ const upload = await normalizeImage(input);
490
+ form.append(field, upload.blob, upload.filename);
491
+ } else {
492
+ let bytes, filename, contentType;
493
+ if (typeof input === 'string') {
494
+ bytes = await require('node:fs/promises').readFile(input);
495
+ filename = require('node:path').basename(input);
496
+ contentType = field === 'reference_audio' ? (/\.wav$/i.test(filename) ? 'audio/wav' : 'audio/mpeg') : /\.webm$/i.test(filename) ? 'video/webm' : /\.mov$/i.test(filename) ? 'video/quicktime' : 'video/mp4';
497
+ } else { bytes = await input.arrayBuffer(); filename = input.name || (field === 'reference_audio' ? 'reference.mp3' : 'reference.mp4'); contentType = input.type || (field === 'reference_audio' ? 'audio/mpeg' : 'video/mp4'); }
498
+ const allowed = field === 'reference_audio' ? ['audio/mpeg', 'audio/wav', 'audio/x-wav'] : ['video/mp4', 'video/quicktime', 'video/webm'];
499
+ const maxBytes = field === 'reference_audio' ? 15 * 1024 * 1024 : 100 * 1024 * 1024;
500
+ if (!allowed.includes(contentType) || bytes.byteLength < 1 || bytes.byteLength > maxBytes) throw new RangeError(field === 'reference_audio' ? 'Invalid reference audio.' : 'Invalid reference video.');
501
+ form.append(field, new Blob([bytes], { type: contentType }), filename);
502
+ }
503
+ }
504
+ return this._call('createVideoJob', null, form, request);
505
+ }
506
+
507
+ getVideoJob(model, jobId) {
508
+ if (!['seedance', 'veo', 'kling'].includes(model) || !/^[a-f0-9]{32}$/.test(jobId)) throw new RangeError('Invalid video model or job ID.');
509
+ return this._call('createVideoJob', null, null, { endpoint:'/rest/'+model+'/jobs/'+jobId, method:'GET', timeoutMs:30_000 });
510
+ }
511
+
512
+ downloadVideoResult(model, jobId) {
513
+ if (!['seedance', 'veo', 'kling'].includes(model) || !/^[a-f0-9]{32}$/.test(jobId)) throw new RangeError('Invalid video model or job ID.');
514
+ return this._call('createVideoJob', null, null, { endpoint:'/rest/'+model+'/jobs/'+jobId+'/result', method:'GET', output:'binary', filename:jobId+'.mp4', timeoutMs:60_000 });
515
+ }
516
+
470
517
  createTtsJob(text, options) {
471
518
  const config = options || {};
472
519
  return this._call('createTtsJob', {
@@ -485,6 +532,30 @@ class ApickClient {
485
532
  return this._call('createTtsJob', null, null, { endpoint: '/rest/tts/jobs/' + id + '/cancel' });
486
533
  }
487
534
 
535
+ getTtsQuality(jobId) {
536
+ const id = normalizeTtsJobId(jobId);
537
+ return this._call('createTtsJob', null, null, { endpoint: '/rest/tts/jobs/' + id + '/quality', method: 'GET' });
538
+ }
539
+
540
+ retryTtsJob(jobId, utteranceIds, idempotencyKey) {
541
+ const id = normalizeTtsJobId(jobId);
542
+ if (!Array.isArray(utteranceIds) || utteranceIds.length > 100 || utteranceIds.some(value => typeof value !== 'string' || !/^u\d{3}$/.test(value))) {
543
+ throw new TypeError('utteranceIds must contain up to 100 uNNN identifiers.');
544
+ }
545
+ if (typeof idempotencyKey !== 'string' || !/^[A-Za-z0-9_-]{8,128}$/.test(idempotencyKey)) {
546
+ throw new TypeError('idempotencyKey must contain 8 to 128 letters, digits, underscores or hyphens.');
547
+ }
548
+ return this._call('createTtsJob', { utterance_ids: [...new Set(utteranceIds)].sort(), idempotency_key: idempotencyKey }, null,
549
+ { endpoint: '/rest/tts/jobs/' + id + '/retry' });
550
+ }
551
+
552
+ downloadTtsCandidate(jobId, candidateId) {
553
+ const id = normalizeTtsJobId(jobId);
554
+ if (typeof candidateId !== 'string' || !/^[a-f0-9]{32}$/.test(candidateId)) throw new TypeError('candidateId must be a 32-character hexadecimal identifier.');
555
+ return this._call('createTtsJob', null, null, { endpoint: '/rest/tts/jobs/' + id + '/candidates/' + candidateId + '/audio',
556
+ method: 'GET', output: 'binary', filename: candidateId + '.wav' });
557
+ }
558
+
488
559
  downloadTtsResult(jobId) {
489
560
  const id = normalizeTtsJobId(jobId);
490
561
  return this._call('createTtsJob', null, null, {
@@ -539,7 +610,7 @@ class ApickClient {
539
610
  const size = config.size || '1024x1024';
540
611
  if (!IMAGE_AI_SIZE_SET.has(size)) throw new TypeError(`size must be one of: ${IMAGE_AI_SIZES.join(', ')}.`);
541
612
  const payload = {
542
- prompt: requiredString('prompt', prompt, 6_000), image_count: imageCount,
613
+ prompt: requiredString('prompt', prompt, 28_000), image_count: imageCount,
543
614
  size, output_format: config.outputFormat || 'png',
544
615
  background: config.background || 'auto'
545
616
  };
@@ -601,11 +672,6 @@ class ApickClient {
601
672
  return this._call('generateImages', null, null, { endpoint:'/rest/image-generation/jobs/'+id, method:'GET', timeoutMs:30_000 });
602
673
  }
603
674
 
604
- cancelImageJob(jobId) {
605
- const id = normalizeTtsJobId(jobId);
606
- return this._call('generateImages', null, null, { endpoint:'/rest/image-generation/jobs/'+id+'/cancel', timeoutMs:30_000 });
607
- }
608
-
609
675
  downloadImageJobImage(jobId, index) {
610
676
  const id=normalizeTtsJobId(jobId), value=Number(index);
611
677
  if(!Number.isInteger(value)||value<0||value>49) throw new RangeError('index must be an integer from 0 through 49.');
package/src/index.d.ts CHANGED
@@ -30,14 +30,14 @@ export interface OcrOptions {
30
30
  export type ImageAiFormat = 'png' | 'jpeg' | 'webp';
31
31
  export type ImageAiBackground = 'auto' | 'opaque' | 'transparent';
32
32
  export type ImageAiSize = '1024x1024' | '1536x1024' | '1024x1536' | '1152x864' | '864x1152';
33
- export type ImageAiStatus = 'waiting' | 'processing' | 'completed' | 'completed_partial' | 'cancelled' | 'failed';
33
+ export type ImageAiStatus = 'waiting' | 'processing' | 'completed' | 'completed_partial' | 'failed';
34
34
  export type ApickImageErrorCode = `APICK_IMAGE_${string}`;
35
35
  export interface ImageAiOptions { imageCount?: number; size?: ImageAiSize; outputFormat?: ImageAiFormat; background?: ImageAiBackground; idempotencyKey?: string; }
36
36
  export interface ImageAiGenerateOptions extends ImageAiOptions { referenceImage?: string|BinaryInput|ArrayBuffer|ArrayBufferView; referenceFilename?: string; referenceContentType?: 'image/png'|'image/jpeg'|'image/webp'; }
37
37
  export interface ImageAiEditOptions extends ImageAiOptions { filename?: string; contentType?: 'image/png'|'image/jpeg'|'image/webp'; }
38
38
  export interface ImageAiResultImage { index:number; b64_json:string; mime_type:'image/png'|'image/jpeg'|'image/webp'; width:number; height:number; }
39
39
  export interface ImageAiResultData { request_id:string; image_count:number; images:ImageAiResultImage[]; idempotent_replay?:boolean; }
40
- export interface ImageAiJobData { job_id:string; status:ImageAiStatus; requested_count:number; completed_count?:number; failed_count?:number; charged_point?:number; result_available?:boolean; expires_at?:string|null; error_code?:ApickImageErrorCode|null; }
40
+ export interface ImageAiJobData { job_id:string; status:ImageAiStatus; requested_count:number; completed_count?:number; failed_count?:number; prepaid_point?:number; charged_point?:number; refunded_point?:number; result_available?:boolean; expires_at?:string|null; error_code?:ApickImageErrorCode|null; }
41
41
 
42
42
  export interface MaskResidentNumberOptions extends OcrOptions {
43
43
  type: 1 | 2 | 3;
@@ -59,6 +59,21 @@ export interface TtsJobData {
59
59
  character_count?: number;
60
60
  result_available?: boolean;
61
61
  subtitles_available?: boolean;
62
+ resume_revision?: number;
63
+ operation_revision?: number;
64
+ quality?: TtsQualityData | null;
65
+ }
66
+
67
+ export interface TtsQualityData {
68
+ job_id?: string;
69
+ resume_revision?: number;
70
+ phase?: string;
71
+ accepted_utterances?: number;
72
+ failed_utterances?: number;
73
+ total_utterances?: number;
74
+ utterances?: Array<{ id: string; status: string; attempt?: number; reasons?: string[];
75
+ speech_rate?: { chars: number; duration_sec: number; cps: number; expected_sec: number; duration_ratio: number | null; status: string } }>;
76
+ candidates?: Array<{ candidate_id: string; utterance_id: string; status: string; attempt: number; audio_available?: boolean }>;
62
77
  }
63
78
 
64
79
  export class ApickApiError extends Error {
@@ -93,6 +108,9 @@ export const SERVICES: Readonly<Record<string, Readonly<{
93
108
  }>>>;
94
109
 
95
110
  export class ApickClient {
111
+ createVideoJob(model: VideoModel, prompt: string, options?: VideoJobOptions): Promise<ApickResult<VideoJobData>>;
112
+ getVideoJob(model: VideoModel, jobId: string): Promise<ApickResult<VideoJobData>>;
113
+ downloadVideoResult(model: VideoModel, jobId: string): Promise<ApickBinaryResult>;
96
114
  constructor(apiKeyOrOptions: string | ApickClientOptions);
97
115
  businessDetails(businessNumber: string): Promise<ApickResult>;
98
116
  ventureBusiness(businessNumber: string): Promise<ApickResult>;
@@ -119,6 +137,9 @@ export class ApickClient {
119
137
  cancelTtsJob(jobId: string): Promise<ApickResult<TtsJobData>>;
120
138
  downloadTtsResult(jobId: string): Promise<ApickBinaryResult>;
121
139
  downloadTtsSubtitles(jobId: string): Promise<ApickBinaryResult>;
140
+ getTtsQuality(jobId: string): Promise<ApickResult<TtsQualityData>>;
141
+ retryTtsJob(jobId: string, utteranceIds: string[], idempotencyKey: string): Promise<ApickResult<TtsJobData>>;
142
+ downloadTtsCandidate(jobId: string, candidateId: string): Promise<ApickBinaryResult>;
122
143
  htmlToPdf(html: string, options?: { pagination?: boolean }): Promise<ApickBinaryResult>;
123
144
  jsonToExcel(data: unknown[], options?: { sheetName?: string }): Promise<ApickBinaryResult>;
124
145
  summarize(text: string): Promise<ApickResult>;
@@ -128,9 +149,28 @@ export class ApickClient {
128
149
  createImageGenerationJob(prompt:string, options?:ImageAiGenerateOptions): Promise<ApickResult<ImageAiJobData>>;
129
150
  createImageEditJob(image:string|BinaryInput|ArrayBuffer|ArrayBufferView, prompt:string, options?:ImageAiEditOptions): Promise<ApickResult<ImageAiJobData>>;
130
151
  getImageJob(jobId:string): Promise<ApickResult<ImageAiJobData>>;
131
- cancelImageJob(jobId:string): Promise<ApickResult<ImageAiJobData>>;
132
152
  downloadImageJobImage(jobId:string,index:number): Promise<ApickBinaryResult>;
133
153
  downloadImageJobArchive(jobId:string): Promise<ApickBinaryResult>;
134
154
  }
135
155
 
136
156
  export default ApickClient;
157
+
158
+ export type VideoModel = 'seedance' | 'veo' | 'kling';
159
+ export interface VideoJobOptions {
160
+ version?: string; tier?: string; mode?: 'text' | 'image' | 'reference'; duration?: number;
161
+ aspectRatio?: string; resolution?: string; audio?: boolean; negativePrompt?: string;
162
+ seed?: number; cfgScale?: number; idempotencyKey?: string;
163
+ image?: string | BinaryInput | ArrayBuffer | ArrayBufferView;
164
+ lastImage?: string | BinaryInput | ArrayBuffer | ArrayBufferView;
165
+ referenceImages?: Array<string | BinaryInput | ArrayBuffer | ArrayBufferView>;
166
+ referenceVideos?: Array<string | BinaryInput>;
167
+ referenceAudios?: Array<string | BinaryInput>;
168
+ }
169
+ export interface VideoJobData {
170
+ job_id: string; model: VideoModel; version: string; mode: string; tier: string;
171
+ status: 'waiting' | 'processing' | 'completed' | 'failed' | 'cancelled';
172
+ duration: number; resolution?: string; audio?: boolean; point_per_second?: number;
173
+ charged_point?: number; result_available?: boolean; result_url?: string;
174
+ result_expires_at?: string | null; idempotent_replay?: boolean;
175
+ error?: { code: string; message: string };
176
+ }