@omelhorsite/sdk 0.1.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 +321 -0
- package/dist/index.js +11589 -0
- package/dist/types/auth/device.d.ts +156 -0
- package/dist/types/auth/index.d.ts +127 -0
- package/dist/types/auth/tokens.d.ts +356 -0
- package/dist/types/client.d.ts +133 -0
- package/dist/types/errors.d.ts +202 -0
- package/dist/types/http.d.ts +204 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/local/index.d.ts +42 -0
- package/dist/types/local/password.d.ts +169 -0
- package/dist/types/local/qr.d.ts +127 -0
- package/dist/types/local/wordlist.d.ts +26 -0
- package/dist/types/resources/account.d.ts +296 -0
- package/dist/types/resources/chests.d.ts +194 -0
- package/dist/types/resources/dynamicQrs.d.ts +172 -0
- package/dist/types/resources/forms.d.ts +331 -0
- package/dist/types/resources/index.d.ts +30 -0
- package/dist/types/resources/ipLookup.d.ts +63 -0
- package/dist/types/resources/jobs.d.ts +233 -0
- package/dist/types/resources/linkTrees.d.ts +249 -0
- package/dist/types/resources/notepads.d.ts +96 -0
- package/dist/types/resources/shortLinks.d.ts +248 -0
- package/dist/types/resources/storage/upload.d.ts +459 -0
- package/dist/types/resources/storage.d.ts +527 -0
- package/dist/types/resources/tickets.d.ts +236 -0
- package/dist/types/resources/tools/backgroundRemoval.d.ts +99 -0
- package/dist/types/resources/tools/captions.d.ts +318 -0
- package/dist/types/resources/tools/downloader.d.ts +397 -0
- package/dist/types/resources/tools/index.d.ts +215 -0
- package/dist/types/resources/tools/jumpstyle.d.ts +194 -0
- package/dist/types/resources/tools/transcription.d.ts +178 -0
- package/dist/types/resources/tools/upscale.d.ts +94 -0
- package/dist/types/resources/tools/vocalSeparation.d.ts +183 -0
- package/dist/types/types.d.ts +245 -0
- package/package.json +37 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jumpstyle edits: a track plus a pile of clips, cut to the beat.
|
|
3
|
+
*
|
|
4
|
+
* The odd one out of the tool family in three ways. Its quota is metered in
|
|
5
|
+
* finished EDITS, not seconds, so it uses {@link EditsQuota}. Its create call
|
|
6
|
+
* is a multi-file form: one `track` plus a `clips[]` array. And its row has no
|
|
7
|
+
* `"pending"` state at all - the controller forwards the files to the sidecar
|
|
8
|
+
* inside the request and saves the row already `"processing"`, so a create that
|
|
9
|
+
* returns at all has work under way.
|
|
10
|
+
*
|
|
11
|
+
* Limits, all enforced by the backend:
|
|
12
|
+
*
|
|
13
|
+
* | | |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | track | 30 MiB, and the MIME type must be `audio/*` |
|
|
16
|
+
* | each clip | 120 MiB, and the MIME type must be `video/*` or `image/*` |
|
|
17
|
+
* | whole upload | 400 MiB |
|
|
18
|
+
* | clips | 20 |
|
|
19
|
+
* | output length | clamped to `[10, 60]` seconds |
|
|
20
|
+
* | daily quota, anonymous | 3 edits |
|
|
21
|
+
* | daily quota, signed in | 15 edits |
|
|
22
|
+
* | `POST /jumpstyle_jobs` | 20 a minute, shared with every other expensive tool |
|
|
23
|
+
*
|
|
24
|
+
* The MIME checks read the `contentType` on each {@link FileInput}, which the
|
|
25
|
+
* SDK sends as the part's `Content-Type`. A file handed over with the wrong one
|
|
26
|
+
* - or with none, which some hosts do for an unknown extension - is a 400 that
|
|
27
|
+
* has nothing to do with the bytes.
|
|
28
|
+
*
|
|
29
|
+
* Read {@link JumpstyleNamespace.quota} before uploading. It is the cheapest
|
|
30
|
+
* preflight in the family, because one invocation is exactly one edit: if
|
|
31
|
+
* `remaining_edits` is `0`, the upload cannot succeed.
|
|
32
|
+
*/
|
|
33
|
+
import { Resource } from "../../http";
|
|
34
|
+
import type { FileInput, Id, RequestOptions } from "../../types";
|
|
35
|
+
import { type EditsQuota, type ToolCaptcha, type ToolRecord, type ToolRunOptions } from "./index";
|
|
36
|
+
/**
|
|
37
|
+
* How busy the cut is, in the sidecar's own words.
|
|
38
|
+
*
|
|
39
|
+
* `chill` cuts once a phrase, `normal` is the default, `hyper` cuts on
|
|
40
|
+
* subdivisions and is what the tool did before the setting existed.
|
|
41
|
+
*
|
|
42
|
+
* Get this wrong and nothing tells you: the controller replaces an
|
|
43
|
+
* unrecognised value with `"normal"` rather than refusing it, so a plausible
|
|
44
|
+
* synonym is a silent no-op that costs a whole edit to discover.
|
|
45
|
+
*/
|
|
46
|
+
export type JumpstyleDensity = "chill" | "normal" | "hyper";
|
|
47
|
+
/** The three the backend accepts. Anything else is silently read as `"normal"`. */
|
|
48
|
+
export declare const JUMPSTYLE_DENSITIES: readonly JumpstyleDensity[];
|
|
49
|
+
/** A jumpstyle edit. */
|
|
50
|
+
export interface JumpstyleJob extends ToolRecord {
|
|
51
|
+
readonly track_filename?: string | null;
|
|
52
|
+
readonly n_clips?: number | null;
|
|
53
|
+
/** Seconds of output. */
|
|
54
|
+
readonly duration?: number | null;
|
|
55
|
+
/** The seed that produced this cut. Reuse it to reproduce the edit. */
|
|
56
|
+
readonly seed?: number | null;
|
|
57
|
+
readonly density?: string | null;
|
|
58
|
+
readonly rapid_fire?: boolean | null;
|
|
59
|
+
/** BPM that was forced, when one was. */
|
|
60
|
+
readonly bpm?: number | null;
|
|
61
|
+
/** BPM the sidecar detected, or the forced one once the run settles. */
|
|
62
|
+
readonly detected_bpm?: number | null;
|
|
63
|
+
/** What the sidecar is doing right now. `null` unless processing. */
|
|
64
|
+
readonly stage?: string | null;
|
|
65
|
+
/** The finished video, once the status is `"complete"`. */
|
|
66
|
+
readonly output_url?: string | null;
|
|
67
|
+
}
|
|
68
|
+
/** Arguments for starting an edit. */
|
|
69
|
+
export interface CreateJumpstyleInput extends ToolCaptcha {
|
|
70
|
+
/** The music. Must be `audio/*`. Backend cap: 30 MiB. */
|
|
71
|
+
readonly track: FileInput;
|
|
72
|
+
/** Footage to cut. Must be `video/*` or `image/*`. At most 20, 120 MiB each. */
|
|
73
|
+
readonly clips: FileInput[];
|
|
74
|
+
/**
|
|
75
|
+
* Seconds of output. Clamped by the server to `[10, 60]`.
|
|
76
|
+
*
|
|
77
|
+
* Omitting it is NOT the same as leaving it to a server default: the
|
|
78
|
+
* controller reads a missing value as `0` and then clamps, so an omitted
|
|
79
|
+
* duration produces a 10-second edit. Pass one.
|
|
80
|
+
*/
|
|
81
|
+
readonly duration?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Reproducibility seed. Omit and the server rolls one; read it back off the
|
|
84
|
+
* finished row to make the same cut again. Taken modulo 100000.
|
|
85
|
+
*/
|
|
86
|
+
readonly seed?: number;
|
|
87
|
+
/** Defaults to `"normal"`. An unknown value is silently replaced by it. */
|
|
88
|
+
readonly density?: JumpstyleDensity;
|
|
89
|
+
/** Cuts on every beat rather than every phrase. */
|
|
90
|
+
readonly rapidFire?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Forces the tempo. Pass it ONLY when detection has already failed; the
|
|
93
|
+
* server clamps it to `[100, 220]`.
|
|
94
|
+
*/
|
|
95
|
+
readonly bpm?: number;
|
|
96
|
+
}
|
|
97
|
+
/** The `jumpstyle` tool, reachable as `oms.tools.jumpstyle`. */
|
|
98
|
+
export declare class JumpstyleNamespace extends Resource {
|
|
99
|
+
/**
|
|
100
|
+
* `GET /jumpstyle_jobs/quota` - edits spent and left today.
|
|
101
|
+
*
|
|
102
|
+
* Cheap and anonymous-safe. The only quota in the family counted in whole
|
|
103
|
+
* units, which makes the preflight exact: one call to {@link create} spends
|
|
104
|
+
* exactly one edit, so `remaining_edits === 0` means the next upload fails.
|
|
105
|
+
*
|
|
106
|
+
* `limit_edits` and `remaining_edits` are `null` exactly when `unlimited` is
|
|
107
|
+
* `true`. A failed edit does not count against the day.
|
|
108
|
+
*/
|
|
109
|
+
quota(options?: RequestOptions): Promise<EditsQuota>;
|
|
110
|
+
/**
|
|
111
|
+
* `POST /jumpstyle_jobs` - uploads the track and the clips, enqueues the cut.
|
|
112
|
+
*
|
|
113
|
+
* The clips go up as a `clips[]` array, which is how Rails reads a list; the
|
|
114
|
+
* transport appends the suffix itself, so pass a plain array.
|
|
115
|
+
*
|
|
116
|
+
* The files are forwarded to the sidecar INSIDE this request, which is why it
|
|
117
|
+
* is the slowest create in the family - up to 400 MiB moves twice before it
|
|
118
|
+
* answers - and why the row comes back already `"processing"` rather than
|
|
119
|
+
* `"pending"`. If the sidecar refuses, the row is destroyed rather than left
|
|
120
|
+
* dangling, so a failure here leaves nothing to clean up.
|
|
121
|
+
*
|
|
122
|
+
* NOT retried by default: replaying this `POST` after a 502 re-uploads the
|
|
123
|
+
* whole pile and spends a second edit. Pass `retry: {}` to opt back in.
|
|
124
|
+
*
|
|
125
|
+
* @throws {OmsQuotaError} 429 when the daily edits are spent. The message is
|
|
126
|
+
* a bare string with no `Retry-After`, so `retryAfterMs` is `undefined` -
|
|
127
|
+
* the wait is until midnight. The expensive-tools throttle, also a 429,
|
|
128
|
+
* DOES set it.
|
|
129
|
+
* @throws {OmsApiError} 413 when a file or the total is over a cap, 400 for a
|
|
130
|
+
* wrong MIME type, no clips, or more than 20 of them, 503 when the edit
|
|
131
|
+
* sidecar is down.
|
|
132
|
+
* @throws {OmsAuthError} 401 when anonymous and the captcha is missing or bad.
|
|
133
|
+
*/
|
|
134
|
+
create(input: CreateJumpstyleInput, options?: RequestOptions): Promise<JumpstyleJob>;
|
|
135
|
+
/**
|
|
136
|
+
* `GET /jumpstyle_jobs/:id` - one poll, carrying `stage` and
|
|
137
|
+
* `progress_percent` while the sidecar works.
|
|
138
|
+
*
|
|
139
|
+
* Both are read live off the sidecar and are `null` the moment the row
|
|
140
|
+
* settles - at which point `detected_bpm` stops being the sidecar's guess
|
|
141
|
+
* and becomes whatever was saved on the row.
|
|
142
|
+
*
|
|
143
|
+
* @throws {OmsApiError} 404 once the 24-hour retention sweep has taken it.
|
|
144
|
+
* @throws {OmsAuthError} 401 when the job belongs to someone else, which
|
|
145
|
+
* includes an anonymous job being read from a different address.
|
|
146
|
+
*/
|
|
147
|
+
get(id: Id, options?: RequestOptions): Promise<JumpstyleJob>;
|
|
148
|
+
/**
|
|
149
|
+
* Uploads, waits, and returns the finished row.
|
|
150
|
+
*
|
|
151
|
+
* The wait is {@link get} on a loop, driven by `pollUntilTerminal` from the
|
|
152
|
+
* jobs module - the same loop every other tool uses.
|
|
153
|
+
*
|
|
154
|
+
* Resolves with a `"failed"` row rather than throwing when the work failed.
|
|
155
|
+
* Pass `waitTimeoutMs` (or a `signal`) to bound the wait; there is no default
|
|
156
|
+
* deadline.
|
|
157
|
+
*
|
|
158
|
+
* Read {@link JumpstyleJob.seed} off the row that comes back: it is the only
|
|
159
|
+
* way to reproduce a cut you liked, and the server rolls a fresh one every
|
|
160
|
+
* time it is not given one.
|
|
161
|
+
*
|
|
162
|
+
* @throws {OmsTimeoutError} `code: "timeout"` when `waitTimeoutMs` elapses,
|
|
163
|
+
* `code: "aborted"` when the signal fires. Neither cancels the run: pick it
|
|
164
|
+
* up later with {@link get}.
|
|
165
|
+
*/
|
|
166
|
+
run(input: CreateJumpstyleInput, options?: ToolRunOptions): Promise<JumpstyleJob>;
|
|
167
|
+
/**
|
|
168
|
+
* `DELETE /jumpstyle_jobs/:id`.
|
|
169
|
+
*
|
|
170
|
+
* @throws {OmsApiError} 404 when it is already gone.
|
|
171
|
+
* @throws {OmsAuthError} 401 when the job belongs to someone else.
|
|
172
|
+
*/
|
|
173
|
+
delete(id: Id, options?: RequestOptions): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* Downloads the finished video.
|
|
176
|
+
*
|
|
177
|
+
* Two calls: one to read the row for its `output_url`, one to fetch the
|
|
178
|
+
* signed URL itself with NO credential attached. Hand a row you already hold
|
|
179
|
+
* to {@link outputUrl} plus `fetchToolArtifact` if you would rather not pay
|
|
180
|
+
* for the first.
|
|
181
|
+
*
|
|
182
|
+
* @throws {OmsError} `conflict` when the edit has not finished,
|
|
183
|
+
* `invalid_request` when it failed, `not_found` when the artefact is gone.
|
|
184
|
+
*/
|
|
185
|
+
download(id: Id, options?: RequestOptions): Promise<Blob>;
|
|
186
|
+
/**
|
|
187
|
+
* The signed URL of the finished video, from a row you already hold.
|
|
188
|
+
*
|
|
189
|
+
* It is a credential: anyone holding it can watch the video.
|
|
190
|
+
*
|
|
191
|
+
* @throws {OmsError} explaining which of the three reasons there is no URL.
|
|
192
|
+
*/
|
|
193
|
+
outputUrl(record: JumpstyleJob): string;
|
|
194
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcription: speech to text, with SRT and VTT subtitle output.
|
|
3
|
+
*
|
|
4
|
+
* Runs on the `transcriber` service, which is the ONLY place whisper lives in
|
|
5
|
+
* this project. No other sidecar embeds it, and no client should call whisper
|
|
6
|
+
* directly; that rule is deliberate and predates this SDK.
|
|
7
|
+
*
|
|
8
|
+
* The quota is metered in seconds of audio, so it is charged on the file's
|
|
9
|
+
* duration at create time, not on how long the run takes. A file whose
|
|
10
|
+
* duration alone exceeds the daily ceiling is a 400, not a 429: it can never
|
|
11
|
+
* fit, no matter how long you wait.
|
|
12
|
+
*
|
|
13
|
+
* Limits, all enforced by the backend:
|
|
14
|
+
*
|
|
15
|
+
* | | |
|
|
16
|
+
* |---|---|
|
|
17
|
+
* | file size | 250 MiB (`413`) |
|
|
18
|
+
* | daily quota, anonymous | 15 minutes of audio |
|
|
19
|
+
* | daily quota, signed in | 60 minutes of audio |
|
|
20
|
+
* | `POST /transcriptions` | 20 a minute, shared with every other expensive tool |
|
|
21
|
+
*
|
|
22
|
+
* The daily quota is per user when signed in and per IP when not, and an
|
|
23
|
+
* account can be given a bigger one - or none at all, in which case
|
|
24
|
+
* {@link SecondsQuota.unlimited} is `true` and the numbers mean nothing. Read
|
|
25
|
+
* {@link TranscriptionNamespace.quota} before uploading; it is cheap, it works
|
|
26
|
+
* anonymously, and it is the difference between a refusal and 250 MiB spent on
|
|
27
|
+
* a 429.
|
|
28
|
+
*
|
|
29
|
+
* The 20-a-minute throttle is shared across background removal, upscale,
|
|
30
|
+
* transcription, vocal separation, captions, jumpstyle and the downloader, and
|
|
31
|
+
* it is keyed on the credential when there is one and on the IP when there is
|
|
32
|
+
* not. It answers 429 with a `Retry-After`, which the transport honours, so a
|
|
33
|
+
* caller that hits it waits rather than failing - unless it passed
|
|
34
|
+
* `retry: false`, which {@link TranscriptionNamespace.create} does by default.
|
|
35
|
+
*/
|
|
36
|
+
import { Resource } from "../../http";
|
|
37
|
+
import type { FileInput, Id, RequestOptions } from "../../types";
|
|
38
|
+
import { type SecondsQuota, type ToolCaptcha, type ToolModel, type ToolRecord, type ToolRunOptions } from "./index";
|
|
39
|
+
/** A transcription run. */
|
|
40
|
+
export interface Transcription extends ToolRecord {
|
|
41
|
+
readonly model_id: string;
|
|
42
|
+
/** Audio duration charged against the quota. */
|
|
43
|
+
readonly duration_seconds: number;
|
|
44
|
+
/** Language that was requested, or `null` when it was auto-detected. */
|
|
45
|
+
readonly language?: string | null;
|
|
46
|
+
/** Language the model actually detected. */
|
|
47
|
+
readonly detected_language?: string | null;
|
|
48
|
+
readonly has_original?: boolean;
|
|
49
|
+
/** The transcript. Only shipped once the status is `"complete"`. */
|
|
50
|
+
readonly text?: string | null;
|
|
51
|
+
/** SubRip subtitles, once complete. */
|
|
52
|
+
readonly srt_url?: string | null;
|
|
53
|
+
/** WebVTT subtitles, once complete. */
|
|
54
|
+
readonly vtt_url?: string | null;
|
|
55
|
+
}
|
|
56
|
+
/** Arguments for starting a transcription. */
|
|
57
|
+
export interface CreateTranscriptionInput extends ToolCaptcha {
|
|
58
|
+
/** The audio. Sent as the `audio` form field. Backend cap: 250 MiB. */
|
|
59
|
+
readonly audio: FileInput;
|
|
60
|
+
/** Model to use. Omit for the one flagged `default` in {@link TranscriptionNamespace.models}. */
|
|
61
|
+
readonly modelId?: string;
|
|
62
|
+
/** ISO language hint. Omit to let the model detect it. */
|
|
63
|
+
readonly language?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Which subtitle format {@link TranscriptionNamespace.subtitles} should fetch. */
|
|
66
|
+
export type SubtitleFormat = "srt" | "vtt";
|
|
67
|
+
/** The `transcription` tool, reachable as `oms.tools.transcription`. */
|
|
68
|
+
export declare class TranscriptionNamespace extends Resource {
|
|
69
|
+
/**
|
|
70
|
+
* `GET /transcriptions/models` - the selectable models.
|
|
71
|
+
*
|
|
72
|
+
* The controller answers `{ models: [...] }`; this unwraps it, because a
|
|
73
|
+
* one-key envelope is not information a caller should have to know about.
|
|
74
|
+
* Exactly one entry carries `default: true`, and that is the model the
|
|
75
|
+
* server picks when {@link CreateTranscriptionInput.modelId} is omitted.
|
|
76
|
+
*
|
|
77
|
+
* `translation_key` is an i18n key, not a display name. The SDK does not
|
|
78
|
+
* translate; render the id if you have no catalogue.
|
|
79
|
+
*/
|
|
80
|
+
models(options?: RequestOptions): Promise<ToolModel[]>;
|
|
81
|
+
/**
|
|
82
|
+
* `GET /transcriptions/quota` - seconds spent and left today.
|
|
83
|
+
*
|
|
84
|
+
* Cheap and anonymous-safe. Call it before a long file rather than
|
|
85
|
+
* discovering the ceiling through a 429 after the upload.
|
|
86
|
+
*
|
|
87
|
+
* `limit_seconds` and `remaining_seconds` are `null` exactly when
|
|
88
|
+
* `unlimited` is `true`; `used_seconds` is always a real number. The window
|
|
89
|
+
* is a calendar day, so "remaining" is not a rate - it does not tick back up
|
|
90
|
+
* until midnight.
|
|
91
|
+
*/
|
|
92
|
+
quota(options?: RequestOptions): Promise<SecondsQuota>;
|
|
93
|
+
/**
|
|
94
|
+
* `POST /transcriptions` - uploads the audio and enqueues the run.
|
|
95
|
+
*
|
|
96
|
+
* Answers with the row in `"pending"`. There is no `job_id` here: this tool
|
|
97
|
+
* is polled by re-reading its own row with {@link get}, which is what
|
|
98
|
+
* {@link run} does.
|
|
99
|
+
*
|
|
100
|
+
* NOT retried by default, unlike most of the SDK. The transport's policy
|
|
101
|
+
* replays a `POST` that died with a 502, and here that would re-upload up to
|
|
102
|
+
* 250 MiB and start a second run - charged twice against the daily quota.
|
|
103
|
+
* Pass `retry: {}` to opt back in.
|
|
104
|
+
*
|
|
105
|
+
* `modelId` and `language` are omitted from the form when absent rather than
|
|
106
|
+
* sent empty, so the server applies its own defaults.
|
|
107
|
+
*
|
|
108
|
+
* @throws {OmsQuotaError} 429 when the daily seconds are spent, or when the
|
|
109
|
+
* 20-a-minute expensive-tools throttle fires. Only the throttle sets
|
|
110
|
+
* `Retry-After`, so `retryAfterMs` being `undefined` means the wait is
|
|
111
|
+
* until midnight, not seconds.
|
|
112
|
+
* @throws {OmsApiError} 413 when the file is over 250 MiB. 400 when the file
|
|
113
|
+
* is missing, undecodable, names an unknown model, or is longer on its own
|
|
114
|
+
* than the whole daily quota.
|
|
115
|
+
* @throws {OmsAuthError} 401 when anonymous and the captcha is missing or bad.
|
|
116
|
+
*/
|
|
117
|
+
create(input: CreateTranscriptionInput, options?: RequestOptions): Promise<Transcription>;
|
|
118
|
+
/**
|
|
119
|
+
* `GET /transcriptions/:id` - one poll. Carries `progress_percent` while
|
|
120
|
+
* processing and the text once complete.
|
|
121
|
+
*
|
|
122
|
+
* `text`, `srt_url` and `vtt_url` are `null` until the status is
|
|
123
|
+
* `"complete"` - deliberately, so that polling a long run does not drag the
|
|
124
|
+
* whole transcript across the wire every few seconds.
|
|
125
|
+
*
|
|
126
|
+
* Ownership is the caller's session, or - for an anonymous run - the IP the
|
|
127
|
+
* run was started from.
|
|
128
|
+
*
|
|
129
|
+
* @throws {OmsApiError} 404 once the 24-hour retention sweep has taken it.
|
|
130
|
+
* @throws {OmsAuthError} 401 when the run belongs to someone else, which
|
|
131
|
+
* includes an anonymous run being read from a different address.
|
|
132
|
+
*/
|
|
133
|
+
get(id: Id, options?: RequestOptions): Promise<Transcription>;
|
|
134
|
+
/**
|
|
135
|
+
* Uploads, waits, and returns the finished row with its text.
|
|
136
|
+
*
|
|
137
|
+
* There is no `job_id` for this tool, so the wait is {@link get} on a loop -
|
|
138
|
+
* but the loop itself is `pollUntilTerminal` from the jobs module, the same
|
|
139
|
+
* one every other tool uses. Nothing here opens a second one.
|
|
140
|
+
*
|
|
141
|
+
* Resolves with a `"failed"` row rather than throwing when the work failed:
|
|
142
|
+
* the request cycle worked, the work did not, and only the caller knows
|
|
143
|
+
* whether that is an exception. Check `status` before reading `text`.
|
|
144
|
+
*
|
|
145
|
+
* Pass `waitTimeoutMs` (or a `signal`) to bound the wait; there is no default
|
|
146
|
+
* deadline, because a two-hour file is a legitimate run.
|
|
147
|
+
*
|
|
148
|
+
* @throws {OmsTimeoutError} `code: "timeout"` when `waitTimeoutMs` elapses,
|
|
149
|
+
* `code: "aborted"` when the signal fires. Neither cancels the run: pick it
|
|
150
|
+
* up later with {@link get}.
|
|
151
|
+
*/
|
|
152
|
+
run(input: CreateTranscriptionInput, options?: ToolRunOptions): Promise<Transcription>;
|
|
153
|
+
/**
|
|
154
|
+
* Downloads the subtitles of a finished run.
|
|
155
|
+
*
|
|
156
|
+
* Two calls: one to read the row for the format's URL, one to fetch the
|
|
157
|
+
* signed URL itself with NO credential attached. Hand a row you already hold
|
|
158
|
+
* to {@link subtitleUrl} plus `fetchToolArtifact` if you would rather not pay
|
|
159
|
+
* for the first.
|
|
160
|
+
*
|
|
161
|
+
* For the plain transcript there is nothing to download: it rides on the row
|
|
162
|
+
* as {@link Transcription.text} once the run completes.
|
|
163
|
+
*
|
|
164
|
+
* @throws {OmsError} `conflict` when the run has not finished,
|
|
165
|
+
* `invalid_request` when it failed, `not_found` when the artefact is gone -
|
|
166
|
+
* which after 24 hours means the retention sweep took it.
|
|
167
|
+
*/
|
|
168
|
+
subtitles(id: Id, format: SubtitleFormat, options?: RequestOptions): Promise<Blob>;
|
|
169
|
+
/**
|
|
170
|
+
* The signed URL of one subtitle format, from a row you already hold.
|
|
171
|
+
*
|
|
172
|
+
* Good for handing to a player or a browser instead of moving the bytes. It
|
|
173
|
+
* is a credential: anyone holding it can read the subtitles.
|
|
174
|
+
*
|
|
175
|
+
* @throws {OmsError} explaining which of the three reasons there is no URL.
|
|
176
|
+
*/
|
|
177
|
+
subtitleUrl(record: Transcription, format: SubtitleFormat): string;
|
|
178
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upscaling: enlarges an image without turning it to mush.
|
|
3
|
+
*
|
|
4
|
+
* Same shape as background removal: `POST /upscales` enqueues a proxy job and
|
|
5
|
+
* answers with a row plus a `job_id` and, when anonymous, a `watch_token`.
|
|
6
|
+
*
|
|
7
|
+
* Backend limits: 20 MiB, and the scale must be one the upscaler advertises.
|
|
8
|
+
*
|
|
9
|
+
* Like background removal, this tool is not metered by the `Quotas` catalogue,
|
|
10
|
+
* so there is no `quota()` to call first.
|
|
11
|
+
*/
|
|
12
|
+
import { Resource } from "../../http";
|
|
13
|
+
import type { FileInput, Id, RequestOptions } from "../../types";
|
|
14
|
+
import { type ToolCaptcha, type ToolJobHandle, type ToolRecord, type ToolRunOptions } from "./index";
|
|
15
|
+
/**
|
|
16
|
+
* Enlargement factor, as the string the API expects.
|
|
17
|
+
*
|
|
18
|
+
* A string and not a number because the backend compares it against an
|
|
19
|
+
* allow-list of strings; `4` and `"4"` are not the same request.
|
|
20
|
+
*/
|
|
21
|
+
export type UpscaleScale = "2" | "3" | "4";
|
|
22
|
+
/** An upscale run. */
|
|
23
|
+
export interface Upscale extends ToolRecord {
|
|
24
|
+
readonly scale: string;
|
|
25
|
+
/** URL of the enlarged image, once the status is `"complete"`. */
|
|
26
|
+
readonly result_url?: string | null;
|
|
27
|
+
}
|
|
28
|
+
/** What `POST /upscales` answers with. */
|
|
29
|
+
export type UpscaleCreated = Upscale & ToolJobHandle;
|
|
30
|
+
/** Arguments for starting a run. */
|
|
31
|
+
export interface CreateUpscaleInput extends ToolCaptcha {
|
|
32
|
+
/** The image. Backend cap: 20 MiB. */
|
|
33
|
+
readonly file: FileInput;
|
|
34
|
+
/** Defaults to `"4"`, which is what the backend picks when none is sent. */
|
|
35
|
+
readonly scale?: UpscaleScale;
|
|
36
|
+
}
|
|
37
|
+
/** The `upscale` tool, reachable as `oms.tools.upscale`. */
|
|
38
|
+
export declare class UpscaleNamespace extends Resource {
|
|
39
|
+
/**
|
|
40
|
+
* The one polling loop, reached through the jobs namespace. Built here for
|
|
41
|
+
* the same reason as in every other tool: the constructor stays
|
|
42
|
+
* one-argument, and the wrapper is stateless.
|
|
43
|
+
*/
|
|
44
|
+
private readonly jobs;
|
|
45
|
+
/**
|
|
46
|
+
* `POST /upscales` - enqueues a run and returns straight away.
|
|
47
|
+
*
|
|
48
|
+
* `scale` is omitted from the form when the caller did not pick one, so the
|
|
49
|
+
* server applies its own default rather than the SDK guessing at it.
|
|
50
|
+
*
|
|
51
|
+
* NOT retried by default: replaying this `POST` after a 502 re-uploads the
|
|
52
|
+
* image and starts a second run. Pass `retry: {}` to opt back in.
|
|
53
|
+
*
|
|
54
|
+
* @throws {OmsApiError} 400 for an oversized image, an image bomb, or a
|
|
55
|
+
* scale outside the allow-list.
|
|
56
|
+
* @throws {OmsAuthError} 401 when anonymous and the captcha is missing or bad.
|
|
57
|
+
*/
|
|
58
|
+
create(input: CreateUpscaleInput, options?: RequestOptions): Promise<UpscaleCreated>;
|
|
59
|
+
/**
|
|
60
|
+
* `GET /upscales/:id` - one poll.
|
|
61
|
+
*
|
|
62
|
+
* @throws {OmsApiError} 404 once the 24-hour retention sweep has taken it.
|
|
63
|
+
* @throws {OmsAuthError} 401 when the run belongs to someone else, which
|
|
64
|
+
* includes an anonymous run being read from a different address.
|
|
65
|
+
*/
|
|
66
|
+
get(id: Id, options?: RequestOptions): Promise<Upscale>;
|
|
67
|
+
/**
|
|
68
|
+
* Creates a run and waits for it, through `oms.jobs.wait`.
|
|
69
|
+
*
|
|
70
|
+
* Resolves with a `"failed"` row rather than throwing when the work failed.
|
|
71
|
+
* Pass `waitTimeoutMs` (or a `signal`) to bound the wait; there is no default
|
|
72
|
+
* deadline.
|
|
73
|
+
*
|
|
74
|
+
* @throws {OmsTimeoutError} `code: "timeout"` when `waitTimeoutMs` elapses,
|
|
75
|
+
* `code: "aborted"` when the signal fires. Neither cancels the run: pick it
|
|
76
|
+
* up later with {@link get}.
|
|
77
|
+
*/
|
|
78
|
+
run(input: CreateUpscaleInput, options?: ToolRunOptions): Promise<Upscale>;
|
|
79
|
+
/**
|
|
80
|
+
* Downloads the enlarged image of a finished run.
|
|
81
|
+
*
|
|
82
|
+
* @throws {OmsError} `conflict` when the run has not finished,
|
|
83
|
+
* `invalid_request` when it failed, `not_found` when the artefact is gone.
|
|
84
|
+
*/
|
|
85
|
+
download(id: Id, options?: RequestOptions): Promise<Blob>;
|
|
86
|
+
/**
|
|
87
|
+
* The signed URL of a finished run's image, from a row you already hold.
|
|
88
|
+
*
|
|
89
|
+
* It is a credential: anyone holding it can read the image.
|
|
90
|
+
*
|
|
91
|
+
* @throws {OmsError} explaining which of the three reasons there is no URL.
|
|
92
|
+
*/
|
|
93
|
+
resultUrl(record: Upscale): string;
|
|
94
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vocal separation: splits a track into a vocals stem and an instrumental.
|
|
3
|
+
*
|
|
4
|
+
* Runs are serialised against a single sidecar, so a pending row reports
|
|
5
|
+
* {@link VocalSeparation.queue_position} - how many live runs entered the queue
|
|
6
|
+
* ahead of it, `0` meaning next up. Surface it: on a busy day the wait is the
|
|
7
|
+
* queue, not the model. {@link vocalSeparationProgress} folds it into the
|
|
8
|
+
* progress line for exactly that reason.
|
|
9
|
+
*
|
|
10
|
+
* There is a second door onto the same machinery, `POST /songs/:id/separate`,
|
|
11
|
+
* which separates a track already in the music library and leaves the stems on
|
|
12
|
+
* the song rather than as attachments. Both doors share one daily ceiling, and
|
|
13
|
+
* both are behind the same expensive-tools throttle - the twin was added to
|
|
14
|
+
* that throttle only after a load generator drove it on its own and pushed the
|
|
15
|
+
* box into swap.
|
|
16
|
+
*
|
|
17
|
+
* Limits, all enforced by the backend:
|
|
18
|
+
*
|
|
19
|
+
* | | |
|
|
20
|
+
* |---|---|
|
|
21
|
+
* | file size | 100 MiB (`413`) |
|
|
22
|
+
* | daily quota, anonymous | 12 minutes of audio |
|
|
23
|
+
* | daily quota, signed in | 30 minutes of audio |
|
|
24
|
+
* | `POST /vocal_separations` | 20 a minute, shared with every other expensive tool |
|
|
25
|
+
*
|
|
26
|
+
* The quota is metered in seconds of audio and charged on the file's duration
|
|
27
|
+
* at create time, not on how long the run takes - which matters here more than
|
|
28
|
+
* anywhere else, because this is the slowest tool in the family. Read
|
|
29
|
+
* {@link VocalSeparationNamespace.quota} before uploading; it is cheap, it
|
|
30
|
+
* works anonymously, and a track longer than the whole daily ceiling is a 400
|
|
31
|
+
* that no amount of waiting fixes.
|
|
32
|
+
*/
|
|
33
|
+
import { Resource } from "../../http";
|
|
34
|
+
import type { FileInput, Id, Progress, RequestOptions } from "../../types";
|
|
35
|
+
import { type SecondsQuota, type ToolCaptcha, type ToolModel, type ToolRecord, type ToolRunOptions } from "./index";
|
|
36
|
+
/** Which stem to fetch. */
|
|
37
|
+
export type VocalStem = "vocals" | "instrumental";
|
|
38
|
+
/** A vocal separation run. */
|
|
39
|
+
export interface VocalSeparation extends ToolRecord {
|
|
40
|
+
readonly model_id: string;
|
|
41
|
+
/** Audio duration charged against the quota. */
|
|
42
|
+
readonly duration_seconds: number;
|
|
43
|
+
/** Set when the run came from the music library rather than an upload. */
|
|
44
|
+
readonly song_id?: Id | null;
|
|
45
|
+
readonly song_title?: string | null;
|
|
46
|
+
readonly has_original?: boolean;
|
|
47
|
+
readonly has_vocals?: boolean;
|
|
48
|
+
readonly has_instrumental?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Live runs queued ahead of this one; `0` means next up. `null` once the run
|
|
51
|
+
* is processing or terminal.
|
|
52
|
+
*/
|
|
53
|
+
readonly queue_position?: number | null;
|
|
54
|
+
/**
|
|
55
|
+
* Stem URLs, once complete. Both stay `null` for a song-owned separation,
|
|
56
|
+
* whose stems live on the song as filesystem nodes instead.
|
|
57
|
+
*/
|
|
58
|
+
readonly vocals_url?: string | null;
|
|
59
|
+
readonly instrumental_url?: string | null;
|
|
60
|
+
}
|
|
61
|
+
/** Arguments for starting a separation. */
|
|
62
|
+
export interface CreateVocalSeparationInput extends ToolCaptcha {
|
|
63
|
+
/** The audio. Sent as the `audio` form field. Backend cap: 100 MiB. */
|
|
64
|
+
readonly audio: FileInput;
|
|
65
|
+
/** Model to use. Omit for the one flagged `default` in {@link VocalSeparationNamespace.models}. */
|
|
66
|
+
readonly modelId?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Renders a separation as a {@link Progress}, queue position included.
|
|
70
|
+
*
|
|
71
|
+
* Identical to the shared `toolProgress` except while the run is queued, where
|
|
72
|
+
* the position is folded into `status` - `"pending (2 ahead in the queue)"`.
|
|
73
|
+
* That is a deliberate liberty with a field documented as the server's own
|
|
74
|
+
* status string: `status` is the only part of a {@link Progress} a host
|
|
75
|
+
* renders as text, and "pending" for forty minutes with no explanation is the
|
|
76
|
+
* single worst thing this tool does to a person watching it.
|
|
77
|
+
*/
|
|
78
|
+
export declare function vocalSeparationProgress(record: VocalSeparation): Progress;
|
|
79
|
+
/** The `vocalSeparation` tool, reachable as `oms.tools.vocalSeparation`. */
|
|
80
|
+
export declare class VocalSeparationNamespace extends Resource {
|
|
81
|
+
/**
|
|
82
|
+
* `GET /vocal_separations/models` - the selectable models.
|
|
83
|
+
*
|
|
84
|
+
* The controller answers `{ models: [...] }`; this unwraps it. Exactly one
|
|
85
|
+
* entry carries `default: true`, and that is what the server picks when
|
|
86
|
+
* {@link CreateVocalSeparationInput.modelId} is omitted.
|
|
87
|
+
*
|
|
88
|
+
* The models differ in cost as well as quality - the default is the heaviest
|
|
89
|
+
* of them - but the API exposes no such ranking, so there is nothing here to
|
|
90
|
+
* choose on but the id.
|
|
91
|
+
*/
|
|
92
|
+
models(options?: RequestOptions): Promise<ToolModel[]>;
|
|
93
|
+
/**
|
|
94
|
+
* `GET /vocal_separations/quota` - seconds spent and left today.
|
|
95
|
+
*
|
|
96
|
+
* Cheap and anonymous-safe. `limit_seconds` and `remaining_seconds` are
|
|
97
|
+
* `null` exactly when `unlimited` is `true`. The window is a calendar day, so
|
|
98
|
+
* "remaining" is not a rate: it does not tick back up until midnight.
|
|
99
|
+
*
|
|
100
|
+
* This ceiling is shared with `POST /songs/:id/separate`, so a separation
|
|
101
|
+
* started from the music library spends the same budget.
|
|
102
|
+
*/
|
|
103
|
+
quota(options?: RequestOptions): Promise<SecondsQuota>;
|
|
104
|
+
/**
|
|
105
|
+
* `POST /vocal_separations` - uploads the audio and enqueues the run.
|
|
106
|
+
*
|
|
107
|
+
* Answers with the row in `"pending"`, already carrying its
|
|
108
|
+
* {@link VocalSeparation.queue_position}. There is no `job_id` here: this
|
|
109
|
+
* tool is polled by re-reading its own row with {@link get}.
|
|
110
|
+
*
|
|
111
|
+
* NOT retried by default: replaying this `POST` after a 502 re-uploads up to
|
|
112
|
+
* 100 MiB, charges the quota twice, and puts a second run behind the first in
|
|
113
|
+
* a queue that is already the slowest thing in the API. Pass `retry: {}` to
|
|
114
|
+
* opt back in.
|
|
115
|
+
*
|
|
116
|
+
* @throws {OmsQuotaError} 429 for the daily ceiling or the expensive-tools
|
|
117
|
+
* throttle. Read `retryAfterMs`; the throttle sets it, the daily ceiling
|
|
118
|
+
* does not, so `undefined` means the wait is until midnight.
|
|
119
|
+
* @throws {OmsApiError} 413 when the file is over 100 MiB. 400 when it is
|
|
120
|
+
* missing, undecodable, names an unknown model, or is longer on its own
|
|
121
|
+
* than the whole daily quota.
|
|
122
|
+
* @throws {OmsAuthError} 401 when anonymous and the captcha is missing or bad.
|
|
123
|
+
*/
|
|
124
|
+
create(input: CreateVocalSeparationInput, options?: RequestOptions): Promise<VocalSeparation>;
|
|
125
|
+
/**
|
|
126
|
+
* `GET /vocal_separations/:id` - one poll, carrying `queue_position` while
|
|
127
|
+
* pending and `progress_percent` while processing.
|
|
128
|
+
*
|
|
129
|
+
* Never both: the position is `null` from the moment the sidecar picks the
|
|
130
|
+
* run up, and the percentage is `null` before that and after it finishes.
|
|
131
|
+
*
|
|
132
|
+
* @throws {OmsApiError} 404 once the 24-hour retention sweep has taken it.
|
|
133
|
+
* @throws {OmsAuthError} 401 when the run belongs to someone else, which
|
|
134
|
+
* includes an anonymous run being read from a different address.
|
|
135
|
+
*/
|
|
136
|
+
get(id: Id, options?: RequestOptions): Promise<VocalSeparation>;
|
|
137
|
+
/**
|
|
138
|
+
* Uploads, waits, and returns the finished row.
|
|
139
|
+
*
|
|
140
|
+
* The wait is {@link get} on a loop, driven by `pollUntilTerminal` from the
|
|
141
|
+
* jobs module - the same loop every other tool uses. Progress reports carry
|
|
142
|
+
* the queue position while the run is still waiting its turn; see
|
|
143
|
+
* {@link vocalSeparationProgress}.
|
|
144
|
+
*
|
|
145
|
+
* Resolves with a `"failed"` row rather than throwing when the work failed.
|
|
146
|
+
* Pass `waitTimeoutMs` (or a `signal`) to bound the wait; there is no default
|
|
147
|
+
* deadline, and this is the tool where that matters most - a busy queue plus
|
|
148
|
+
* a long track is comfortably an hour.
|
|
149
|
+
*
|
|
150
|
+
* @throws {OmsTimeoutError} `code: "timeout"` when `waitTimeoutMs` elapses,
|
|
151
|
+
* `code: "aborted"` when the signal fires. Neither cancels the run: pick it
|
|
152
|
+
* up later with {@link get}.
|
|
153
|
+
*/
|
|
154
|
+
run(input: CreateVocalSeparationInput, options?: ToolRunOptions): Promise<VocalSeparation>;
|
|
155
|
+
/**
|
|
156
|
+
* Downloads one stem of a finished run.
|
|
157
|
+
*
|
|
158
|
+
* Two calls: one to read the row for the stem's URL, one to fetch the signed
|
|
159
|
+
* URL itself with NO credential attached. Hand a row you already hold to
|
|
160
|
+
* {@link stemUrl} plus `fetchToolArtifact` if you would rather not pay for
|
|
161
|
+
* the first.
|
|
162
|
+
*
|
|
163
|
+
* @throws {OmsError} `not_found` for a song-owned separation, whose stems are
|
|
164
|
+
* not attachments at all; read them through the music library instead.
|
|
165
|
+
* `conflict` when the run has not finished, `invalid_request` when it
|
|
166
|
+
* failed, `not_found` again once the 24-hour sweep has taken the stems.
|
|
167
|
+
*/
|
|
168
|
+
download(id: Id, stem: VocalStem, options?: RequestOptions): Promise<Blob>;
|
|
169
|
+
/**
|
|
170
|
+
* The signed URL of one stem, from a row you already hold.
|
|
171
|
+
*
|
|
172
|
+
* Good for handing to a player instead of moving the bytes. It is a
|
|
173
|
+
* credential: anyone holding it can read the stem.
|
|
174
|
+
*
|
|
175
|
+
* A song-owned separation is answered separately and first, because
|
|
176
|
+
* otherwise it looks exactly like a swept artefact - complete, no URL - and
|
|
177
|
+
* the caller would be told to blame a retention sweep for a run whose stems
|
|
178
|
+
* were never attachments in the first place.
|
|
179
|
+
*
|
|
180
|
+
* @throws {OmsError} explaining which of the four reasons there is no URL.
|
|
181
|
+
*/
|
|
182
|
+
stemUrl(record: VocalSeparation, stem: VocalStem): string;
|
|
183
|
+
}
|