@sogni-ai/sogni-client 3.0.0-alpha.2 → 3.0.0-alpha.20
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 +138 -0
- package/README.md +3 -1
- package/dist/Account/CurrentAccount.d.ts +3 -3
- package/dist/Account/CurrentAccount.js +14 -4
- package/dist/Account/CurrentAccount.js.map +1 -1
- package/dist/Account/index.d.ts +6 -4
- package/dist/Account/index.js +8 -5
- package/dist/Account/index.js.map +1 -1
- package/dist/Account/types.d.ts +5 -0
- package/dist/ApiClient/WebSocketClient/events.d.ts +21 -7
- package/dist/ApiClient/WebSocketClient/index.js +13 -3
- package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
- package/dist/Projects/Job.d.ts +41 -0
- package/dist/Projects/Job.js +77 -1
- package/dist/Projects/Job.js.map +1 -1
- package/dist/Projects/Project.d.ts +1 -1
- package/dist/Projects/Project.js +22 -19
- package/dist/Projects/Project.js.map +1 -1
- package/dist/Projects/createJobRequestMessage.js +1 -1
- package/dist/Projects/createJobRequestMessage.js.map +1 -1
- package/dist/Projects/index.d.ts +5 -1
- package/dist/Projects/index.js +44 -8
- package/dist/Projects/index.js.map +1 -1
- package/dist/Projects/types/ControlNetParams.d.ts +1 -1
- package/dist/Projects/types/events.d.ts +6 -0
- package/dist/Projects/types/index.d.ts +7 -0
- package/dist/Projects/utils.d.ts +2 -0
- package/dist/Projects/utils.js +14 -0
- package/dist/Projects/utils.js.map +1 -0
- package/dist/Stats/types.d.ts +1 -1
- package/dist/types/token.d.ts +1 -0
- package/dist/types/token.js +3 -0
- package/dist/types/token.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/Account/CurrentAccount.ts +16 -6
- package/src/Account/index.ts +15 -13
- package/src/Account/types.ts +7 -0
- package/src/ApiClient/WebSocketClient/events.ts +25 -8
- package/src/ApiClient/WebSocketClient/index.ts +13 -3
- package/src/Projects/Job.ts +97 -1
- package/src/Projects/Project.ts +24 -20
- package/src/Projects/createJobRequestMessage.ts +2 -1
- package/src/Projects/index.ts +44 -8
- package/src/Projects/types/ControlNetParams.ts +2 -1
- package/src/Projects/types/events.ts +6 -0
- package/src/Projects/types/index.ts +8 -0
- package/src/Projects/utils.ts +12 -0
- package/src/Stats/types.ts +2 -0
- package/src/types/token.ts +1 -0
- package/src/version.ts +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import DataEntity from '../lib/DataEntity';
|
|
2
|
-
import {
|
|
2
|
+
import { Balances } from './types';
|
|
3
3
|
import { SupernetType } from '../ApiClient/WebSocketClient/types';
|
|
4
4
|
/**
|
|
5
5
|
* @inline
|
|
@@ -16,7 +16,7 @@ export interface AccountData {
|
|
|
16
16
|
*/
|
|
17
17
|
networkStatus: 'connected' | 'disconnected' | 'connecting' | 'switching';
|
|
18
18
|
network: SupernetType | null;
|
|
19
|
-
balance:
|
|
19
|
+
balance: Balances;
|
|
20
20
|
walletAddress?: string;
|
|
21
21
|
username?: string;
|
|
22
22
|
token?: string;
|
|
@@ -28,10 +28,20 @@ function getDefaults(): AccountData {
|
|
|
28
28
|
networkStatus: 'disconnected',
|
|
29
29
|
network: null,
|
|
30
30
|
balance: {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
sogni: {
|
|
32
|
+
credit: '0',
|
|
33
|
+
debit: '0',
|
|
34
|
+
net: '0',
|
|
35
|
+
settled: '0',
|
|
36
|
+
unclaimed: '0'
|
|
37
|
+
},
|
|
38
|
+
spark: {
|
|
39
|
+
credit: '0',
|
|
40
|
+
debit: '0',
|
|
41
|
+
net: '0',
|
|
42
|
+
settled: '0',
|
|
43
|
+
unclaimed: '0'
|
|
44
|
+
}
|
|
35
45
|
},
|
|
36
46
|
walletAddress: undefined,
|
|
37
47
|
username: undefined,
|
package/src/Account/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AccountCreateData,
|
|
3
3
|
AccountCreateParams,
|
|
4
|
-
|
|
4
|
+
Balances,
|
|
5
5
|
LoginData,
|
|
6
6
|
Nonce,
|
|
7
7
|
Reward,
|
|
@@ -39,7 +39,7 @@ class AccountApi extends ApiGroup {
|
|
|
39
39
|
this.client.auth.on('updated', this.handleAuthUpdated.bind(this));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
private handleBalanceUpdate(data:
|
|
42
|
+
private handleBalanceUpdate(data: Balances) {
|
|
43
43
|
this.currentAccount._update({ balance: data });
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -214,8 +214,8 @@ class AccountApi extends ApiGroup {
|
|
|
214
214
|
* // { net: '100.000000', settled: '100.000000', credit: '0.000000', debit: '0.000000' }
|
|
215
215
|
* ```
|
|
216
216
|
*/
|
|
217
|
-
async refreshBalance(): Promise<
|
|
218
|
-
const res = await this.client.rest.get<ApiReponse<
|
|
217
|
+
async refreshBalance(): Promise<Balances> {
|
|
218
|
+
const res = await this.client.rest.get<ApiReponse<Balances>>('/v3/account/balance');
|
|
219
219
|
this.currentAccount._update({ balance: res.data });
|
|
220
220
|
return res.data;
|
|
221
221
|
}
|
|
@@ -236,12 +236,11 @@ class AccountApi extends ApiGroup {
|
|
|
236
236
|
* @param walletAddress
|
|
237
237
|
*/
|
|
238
238
|
async walletBalance(walletAddress: string) {
|
|
239
|
-
const res = await this.client.rest.get<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
);
|
|
239
|
+
const res = await this.client.rest.get<
|
|
240
|
+
ApiReponse<{ sogni: string; spark: string; ether: string }>
|
|
241
|
+
>('/v2/wallet/balance', {
|
|
242
|
+
walletAddress
|
|
243
|
+
});
|
|
245
244
|
return res.data;
|
|
246
245
|
}
|
|
247
246
|
|
|
@@ -345,7 +344,7 @@ class AccountApi extends ApiGroup {
|
|
|
345
344
|
*/
|
|
346
345
|
async rewards(): Promise<Reward[]> {
|
|
347
346
|
const r =
|
|
348
|
-
await this.client.rest.get<ApiReponse<{ rewards: RewardRaw[] }>>('/
|
|
347
|
+
await this.client.rest.get<ApiReponse<{ rewards: RewardRaw[] }>>('/v3/account/rewards');
|
|
349
348
|
|
|
350
349
|
return r.data.rewards.map(
|
|
351
350
|
(raw: RewardRaw): Reward => ({
|
|
@@ -354,6 +353,7 @@ class AccountApi extends ApiGroup {
|
|
|
354
353
|
title: raw.title,
|
|
355
354
|
description: raw.description,
|
|
356
355
|
amount: raw.amount,
|
|
356
|
+
tokenType: raw.tokenType,
|
|
357
357
|
claimed: !!raw.claimed,
|
|
358
358
|
canClaim: !!raw.canClaim,
|
|
359
359
|
lastClaim: new Date(raw.lastClaimTimestamp * 1000),
|
|
@@ -369,10 +369,12 @@ class AccountApi extends ApiGroup {
|
|
|
369
369
|
* Claim rewards by reward IDs.
|
|
370
370
|
* @internal
|
|
371
371
|
* @param rewardIds
|
|
372
|
+
* @param turnstileToken - Turnstile token, required to claim rewards
|
|
372
373
|
*/
|
|
373
|
-
async claimRewards(rewardIds: string[]): Promise<void> {
|
|
374
|
+
async claimRewards(rewardIds: string[], turnstileToken?: string): Promise<void> {
|
|
374
375
|
await this.client.rest.post('/v2/account/reward/claim', {
|
|
375
|
-
claims: rewardIds
|
|
376
|
+
claims: rewardIds,
|
|
377
|
+
turnstileToken
|
|
376
378
|
});
|
|
377
379
|
}
|
|
378
380
|
|
package/src/Account/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TokenType } from '../types/token';
|
|
2
|
+
|
|
1
3
|
export interface Nonce {
|
|
2
4
|
nonce: string;
|
|
3
5
|
}
|
|
@@ -27,8 +29,11 @@ export interface BalanceData {
|
|
|
27
29
|
credit: string;
|
|
28
30
|
debit: string;
|
|
29
31
|
net: string;
|
|
32
|
+
unclaimed: string;
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
export type Balances = Record<TokenType, BalanceData>;
|
|
36
|
+
|
|
32
37
|
export interface TxHistoryParams {
|
|
33
38
|
status: 'completed';
|
|
34
39
|
address: string;
|
|
@@ -82,6 +87,7 @@ export interface RewardRaw {
|
|
|
82
87
|
title: string;
|
|
83
88
|
description: string;
|
|
84
89
|
amount: string;
|
|
90
|
+
tokenType: TokenType;
|
|
85
91
|
claimed: number;
|
|
86
92
|
canClaim: number;
|
|
87
93
|
lastClaimTimestamp: number;
|
|
@@ -94,6 +100,7 @@ export interface Reward {
|
|
|
94
100
|
title: string;
|
|
95
101
|
description: string;
|
|
96
102
|
amount: string;
|
|
103
|
+
tokenType: TokenType;
|
|
97
104
|
claimed: boolean;
|
|
98
105
|
canClaim: boolean;
|
|
99
106
|
lastClaim: Date;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { SupernetType } from './types';
|
|
2
|
-
|
|
3
|
-
export type BalanceData = {
|
|
4
|
-
settled: string;
|
|
5
|
-
credit: string;
|
|
6
|
-
debit: string;
|
|
7
|
-
net: string;
|
|
8
|
-
};
|
|
2
|
+
import { Balances } from '../../Account/types';
|
|
9
3
|
|
|
10
4
|
export type JobErrorData = {
|
|
11
5
|
jobID: string;
|
|
@@ -38,6 +32,9 @@ export type JobStateData =
|
|
|
38
32
|
jobID: string;
|
|
39
33
|
imgID: string;
|
|
40
34
|
workerName: string;
|
|
35
|
+
positivePrompt?: string;
|
|
36
|
+
negativePrompt?: string;
|
|
37
|
+
jobIndex?: number;
|
|
41
38
|
}
|
|
42
39
|
| {
|
|
43
40
|
jobID: string;
|
|
@@ -58,11 +55,25 @@ export type ServerDisconnectData = {
|
|
|
58
55
|
reason: string;
|
|
59
56
|
};
|
|
60
57
|
|
|
58
|
+
export type ToastMessage = {
|
|
59
|
+
type: 'info' | 'success' | 'warning' | 'error';
|
|
60
|
+
message: string;
|
|
61
|
+
// Number of milliseconds to show the toast
|
|
62
|
+
autoClose: number;
|
|
63
|
+
stickyID: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type ArtistCancelConfirmation = {
|
|
67
|
+
didCancel: boolean;
|
|
68
|
+
error_message: string;
|
|
69
|
+
jobID: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
61
72
|
export type SocketEventMap = {
|
|
62
73
|
/**
|
|
63
74
|
* @event WebSocketClient#balanceUpdate - Received balance update
|
|
64
75
|
*/
|
|
65
|
-
balanceUpdate:
|
|
76
|
+
balanceUpdate: Balances;
|
|
66
77
|
/**
|
|
67
78
|
* @event WebSocketClient#changeNetwork - Default network changed
|
|
68
79
|
*/
|
|
@@ -95,4 +106,10 @@ export type SocketEventMap = {
|
|
|
95
106
|
* @event WebSocketClient#disconnected - WebSocket connection was closed
|
|
96
107
|
*/
|
|
97
108
|
disconnected: ServerDisconnectData;
|
|
109
|
+
/**
|
|
110
|
+
* @event WebSocketClient#toastMessage - Toast message received
|
|
111
|
+
*/
|
|
112
|
+
toastMessage: ToastMessage;
|
|
113
|
+
|
|
114
|
+
artistCancelConfirmation: ArtistCancelConfirmation;
|
|
98
115
|
};
|
|
@@ -28,8 +28,17 @@ class WebSocketClient extends RestClient<SocketEventMap> {
|
|
|
28
28
|
logger: Logger
|
|
29
29
|
) {
|
|
30
30
|
const _baseUrl = new URL(baseUrl);
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
switch (_baseUrl.protocol) {
|
|
32
|
+
case 'http:':
|
|
33
|
+
case 'ws:':
|
|
34
|
+
_baseUrl.protocol = 'http:';
|
|
35
|
+
break;
|
|
36
|
+
case 'https:':
|
|
37
|
+
case 'wss:':
|
|
38
|
+
_baseUrl.protocol = 'https:';
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
_baseUrl.protocol = 'https:';
|
|
33
42
|
}
|
|
34
43
|
super(_baseUrl.toString(), auth, logger);
|
|
35
44
|
this.appId = appId;
|
|
@@ -51,7 +60,8 @@ class WebSocketClient extends RestClient<SocketEventMap> {
|
|
|
51
60
|
}
|
|
52
61
|
const userAgent = `Sogni/${PROTOCOL_VERSION} (sogni-client) ${LIB_VERSION}`;
|
|
53
62
|
const url = new URL(this.baseUrl);
|
|
54
|
-
url.protocol
|
|
63
|
+
const isNotSecure = url.protocol === 'http:' || url.protocol === 'ws:';
|
|
64
|
+
url.protocol = isNotSecure ? 'ws:' : 'wss:';
|
|
55
65
|
url.searchParams.set('appId', this.appId);
|
|
56
66
|
url.searchParams.set('clientName', userAgent);
|
|
57
67
|
url.searchParams.set('clientType', 'artist');
|
package/src/Projects/Job.ts
CHANGED
|
@@ -4,6 +4,23 @@ import { RawJob, RawProject } from './types/RawProject';
|
|
|
4
4
|
import ProjectsApi from './index';
|
|
5
5
|
import { Logger } from '../lib/DefaultLogger';
|
|
6
6
|
import getUUID from '../lib/getUUID';
|
|
7
|
+
import { EnhancementStrength } from './types';
|
|
8
|
+
import Project from './Project';
|
|
9
|
+
import { SupernetType } from '../ApiClient/WebSocketClient/types';
|
|
10
|
+
import { getEnhacementStrength } from './utils';
|
|
11
|
+
|
|
12
|
+
export const enhancementDefaults = {
|
|
13
|
+
network: 'fast' as SupernetType,
|
|
14
|
+
modelId: 'flux1-schnell-fp8',
|
|
15
|
+
positivePrompt: '',
|
|
16
|
+
negativePrompt: '',
|
|
17
|
+
stylePrompt: '',
|
|
18
|
+
startingImageStrength: 0.5,
|
|
19
|
+
steps: 5,
|
|
20
|
+
guidance: 1,
|
|
21
|
+
numberOfImages: 1,
|
|
22
|
+
numberOfPreviews: 0
|
|
23
|
+
};
|
|
7
24
|
|
|
8
25
|
export type JobStatus =
|
|
9
26
|
| 'pending'
|
|
@@ -40,6 +57,9 @@ export interface JobData {
|
|
|
40
57
|
previewUrl?: string;
|
|
41
58
|
resultUrl?: string | null;
|
|
42
59
|
error?: ErrorData;
|
|
60
|
+
positivePrompt?: string;
|
|
61
|
+
negativePrompt?: string;
|
|
62
|
+
jobIndex?: number;
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
export interface JobEventMap extends EntityEvents {
|
|
@@ -51,6 +71,7 @@ export interface JobEventMap extends EntityEvents {
|
|
|
51
71
|
export interface JobOptions {
|
|
52
72
|
api: ProjectsApi;
|
|
53
73
|
logger: Logger;
|
|
74
|
+
project: Project;
|
|
54
75
|
}
|
|
55
76
|
|
|
56
77
|
class Job extends DataEntity<JobData, JobEventMap> {
|
|
@@ -72,14 +93,18 @@ class Job extends DataEntity<JobData, JobEventMap> {
|
|
|
72
93
|
|
|
73
94
|
private readonly _api: ProjectsApi;
|
|
74
95
|
private readonly _logger: Logger;
|
|
96
|
+
private readonly _project: Project;
|
|
97
|
+
private _enhancementProject: Project | null = null;
|
|
75
98
|
|
|
76
99
|
constructor(data: JobData, options: JobOptions) {
|
|
77
100
|
super(data);
|
|
78
101
|
|
|
79
102
|
this._api = options.api;
|
|
80
103
|
this._logger = options.logger;
|
|
104
|
+
this._project = options.project;
|
|
81
105
|
|
|
82
106
|
this.on('updated', this.handleUpdated.bind(this));
|
|
107
|
+
this.handleEnhancementUpdate = this.handleEnhancementUpdate.bind(this);
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
get id() {
|
|
@@ -152,12 +177,31 @@ class Job extends DataEntity<JobData, JobEventMap> {
|
|
|
152
177
|
return this.data.error;
|
|
153
178
|
}
|
|
154
179
|
|
|
180
|
+
get hasResultImage() {
|
|
181
|
+
return this.status === 'completed' && !this.isNSFW;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
get enhancedImage() {
|
|
185
|
+
if (!this._enhancementProject) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const project = this._enhancementProject;
|
|
189
|
+
const job = project.jobs[0];
|
|
190
|
+
return {
|
|
191
|
+
status: project.status,
|
|
192
|
+
progress: project.progress,
|
|
193
|
+
result: job?.resultUrl || null,
|
|
194
|
+
error: project.error,
|
|
195
|
+
getResultUrl: () => job?.getResultUrl()
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
155
199
|
/**
|
|
156
200
|
* Get the result URL of the job. This method will make a request to the API to get signed URL.
|
|
157
201
|
* IMPORTANT: URL expires after 30 minutes, so make sure to download the image as soon as possible.
|
|
158
202
|
*/
|
|
159
203
|
async getResultUrl(): Promise<string> {
|
|
160
|
-
if (this.data.status
|
|
204
|
+
if (this.data.status !== 'completed') {
|
|
161
205
|
throw new Error('Job is not completed yet');
|
|
162
206
|
}
|
|
163
207
|
const url = await this._api.downloadUrl({
|
|
@@ -225,6 +269,58 @@ class Job extends DataEntity<JobData, JobEventMap> {
|
|
|
225
269
|
this.emit('failed', this.data.error!);
|
|
226
270
|
}
|
|
227
271
|
}
|
|
272
|
+
|
|
273
|
+
private handleEnhancementUpdate() {
|
|
274
|
+
this.emit('updated', ['enhancedImage']);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async getResultData() {
|
|
278
|
+
if (!this.hasResultImage) {
|
|
279
|
+
throw new Error('No result image available');
|
|
280
|
+
}
|
|
281
|
+
const url = await this.getResultUrl();
|
|
282
|
+
const response = await fetch(url);
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
285
|
+
}
|
|
286
|
+
return response.blob();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Enhance the image using the Flux model. This method will create a new project with the
|
|
291
|
+
* enhancement parameters and use the result image of the current job as the starting image.
|
|
292
|
+
* @param strength - how much freedom the model has to change the image.
|
|
293
|
+
* @param overrides - optional parameters to override original prompt or style.
|
|
294
|
+
*/
|
|
295
|
+
async enhance(
|
|
296
|
+
strength: EnhancementStrength,
|
|
297
|
+
overrides: { positivePrompt?: string; stylePrompt?: string } = {}
|
|
298
|
+
) {
|
|
299
|
+
if (this.status !== 'completed') {
|
|
300
|
+
throw new Error('Job is not completed yet');
|
|
301
|
+
}
|
|
302
|
+
if (this.isNSFW) {
|
|
303
|
+
throw new Error('Job did not pass NSFW filter');
|
|
304
|
+
}
|
|
305
|
+
if (this._enhancementProject) {
|
|
306
|
+
this._enhancementProject.off('updated', this.handleEnhancementUpdate);
|
|
307
|
+
this._enhancementProject = null;
|
|
308
|
+
}
|
|
309
|
+
const imageData = await this.getResultData();
|
|
310
|
+
const project = await this._api.create({
|
|
311
|
+
...enhancementDefaults,
|
|
312
|
+
positivePrompt: overrides.positivePrompt || this._project.params.positivePrompt,
|
|
313
|
+
stylePrompt: overrides.stylePrompt || this._project.params.stylePrompt,
|
|
314
|
+
seed: this.seed || this._project.params.seed,
|
|
315
|
+
startingImage: imageData,
|
|
316
|
+
startingImageStrength: 1 - getEnhacementStrength(strength),
|
|
317
|
+
sizePreset: this._project.params.sizePreset
|
|
318
|
+
});
|
|
319
|
+
this._enhancementProject = project;
|
|
320
|
+
this._enhancementProject.on('updated', this.handleEnhancementUpdate);
|
|
321
|
+
const images = await project.waitForCompletion();
|
|
322
|
+
return images[0];
|
|
323
|
+
}
|
|
228
324
|
}
|
|
229
325
|
|
|
230
326
|
export default Job;
|
package/src/Projects/Project.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Job, { JobData
|
|
1
|
+
import Job, { JobData } from './Job';
|
|
2
2
|
import DataEntity, { EntityEvents } from '../lib/DataEntity';
|
|
3
3
|
import { ProjectParams } from './types';
|
|
4
4
|
import cloneDeep from 'lodash/cloneDeep';
|
|
@@ -50,6 +50,7 @@ export interface ProjectEventMap extends EntityEvents {
|
|
|
50
50
|
progress: number;
|
|
51
51
|
completed: string[];
|
|
52
52
|
failed: ErrorData;
|
|
53
|
+
jobStarted: Job;
|
|
53
54
|
jobCompleted: Job;
|
|
54
55
|
jobFailed: Job;
|
|
55
56
|
}
|
|
@@ -209,48 +210,47 @@ class Project extends DataEntity<ProjectData, ProjectEventMap> {
|
|
|
209
210
|
*/
|
|
210
211
|
_addJob(data: JobData | Job) {
|
|
211
212
|
const job =
|
|
212
|
-
data instanceof Job
|
|
213
|
+
data instanceof Job
|
|
214
|
+
? data
|
|
215
|
+
: new Job(data, { api: this._api, logger: this._logger, project: this });
|
|
213
216
|
this._jobs.push(job);
|
|
214
217
|
job.on('updated', () => {
|
|
215
218
|
this.lastUpdated = new Date();
|
|
216
219
|
this.emit('updated', ['jobs']);
|
|
217
220
|
});
|
|
221
|
+
this.emit('jobStarted', job);
|
|
218
222
|
job.on('completed', () => {
|
|
219
223
|
this.emit('jobCompleted', job);
|
|
220
|
-
this._handleJobFinished(job);
|
|
221
224
|
});
|
|
222
225
|
job.on('failed', () => {
|
|
223
226
|
this.emit('jobFailed', job);
|
|
224
|
-
this._handleJobFinished(job);
|
|
225
227
|
});
|
|
226
228
|
return job;
|
|
227
229
|
}
|
|
228
230
|
|
|
229
|
-
private _handleJobFinished(job: Job) {
|
|
230
|
-
const finalStatus: JobStatus[] = ['completed', 'failed', 'canceled'];
|
|
231
|
-
const allJobsDone = this.jobs.every((job) => finalStatus.includes(job.status));
|
|
232
|
-
// If all jobs are done and project is not already failed or completed, update the project status
|
|
233
|
-
if (allJobsDone && this.status !== 'failed' && this.status !== 'completed') {
|
|
234
|
-
const allJobsFailed = this.jobs.every((job) => job.status === 'failed');
|
|
235
|
-
if (allJobsFailed) {
|
|
236
|
-
this._update({ status: 'failed' });
|
|
237
|
-
} else {
|
|
238
|
-
this._update({ status: 'completed' });
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
231
|
private _checkForTimeout() {
|
|
244
232
|
if (this.lastUpdated.getTime() + PROJECT_TIMEOUT < Date.now()) {
|
|
245
233
|
this._syncToServer().catch((error) => {
|
|
246
234
|
this._logger.error(error);
|
|
247
235
|
this._failedSyncAttempts++;
|
|
248
|
-
if (this._failedSyncAttempts
|
|
236
|
+
if (this._failedSyncAttempts >= MAX_FAILED_SYNC_ATTEMPTS) {
|
|
249
237
|
this._logger.error(
|
|
250
238
|
`Failed to sync project data after ${MAX_FAILED_SYNC_ATTEMPTS} attempts. Stopping further attempts.`
|
|
251
239
|
);
|
|
252
240
|
clearInterval(this._timeout!);
|
|
253
241
|
this._timeout = null;
|
|
242
|
+
this.jobs.forEach((job) => {
|
|
243
|
+
if (!job.finished) {
|
|
244
|
+
job._update({
|
|
245
|
+
status: 'failed',
|
|
246
|
+
error: { code: 0, message: 'Job timed out' }
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
this._update({
|
|
251
|
+
status: 'failed',
|
|
252
|
+
error: { code: 0, message: 'Project timed out. Please try again or contact support.' }
|
|
253
|
+
});
|
|
254
254
|
}
|
|
255
255
|
});
|
|
256
256
|
}
|
|
@@ -286,7 +286,11 @@ class Project extends DataEntity<ProjectData, ProjectEventMap> {
|
|
|
286
286
|
// If there are any jobs left in jobData, it means they are new jobs that are not in the project yet
|
|
287
287
|
if (Object.keys(jobData).length) {
|
|
288
288
|
for (const job of Object.values(jobData)) {
|
|
289
|
-
const jobInstance = Job.fromRaw(data, job, {
|
|
289
|
+
const jobInstance = Job.fromRaw(data, job, {
|
|
290
|
+
api: this._api,
|
|
291
|
+
logger: this._logger,
|
|
292
|
+
project: this
|
|
293
|
+
});
|
|
290
294
|
this._addJob(jobInstance);
|
|
291
295
|
}
|
|
292
296
|
}
|
|
@@ -119,7 +119,8 @@ function createJobRequestMessage(id: string, params: ProjectParams) {
|
|
|
119
119
|
keyFrames: [
|
|
120
120
|
{
|
|
121
121
|
...template.keyFrames[0],
|
|
122
|
-
scheduler: params.scheduler,
|
|
122
|
+
scheduler: params.scheduler || null,
|
|
123
|
+
timeStepSpacing: params.timeStepSpacing || null,
|
|
123
124
|
steps: params.steps,
|
|
124
125
|
guidanceScale: params.guidance,
|
|
125
126
|
modelID: params.modelId,
|
package/src/Projects/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ApiGroup, { ApiConfig } from '../ApiGroup';
|
|
2
2
|
import {
|
|
3
3
|
AvailableModel,
|
|
4
|
+
EnhancementStrength,
|
|
4
5
|
EstimateRequest,
|
|
5
6
|
ImageUrlParams,
|
|
6
7
|
ProjectParams,
|
|
@@ -24,9 +25,11 @@ import { RawProject } from './types/RawProject';
|
|
|
24
25
|
import ErrorData from '../types/ErrorData';
|
|
25
26
|
import { SupernetType } from '../ApiClient/WebSocketClient/types';
|
|
26
27
|
import Cache from '../lib/Cache';
|
|
28
|
+
import { enhancementDefaults } from './Job';
|
|
29
|
+
import { getEnhacementStrength } from './utils';
|
|
27
30
|
|
|
28
31
|
const sizePresetCache = new Cache<SizePreset[]>(10 * 60 * 1000);
|
|
29
|
-
const GARBAGE_COLLECT_TIMEOUT =
|
|
32
|
+
const GARBAGE_COLLECT_TIMEOUT = 30000;
|
|
30
33
|
const MODELS_REFRESH_INTERVAL = 1000 * 60 * 60 * 24; // 24 hours
|
|
31
34
|
|
|
32
35
|
function mapErrorCodes(code: string): number {
|
|
@@ -67,7 +70,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
67
70
|
this.client.socket.on('jobProgress', this.handleJobProgress.bind(this));
|
|
68
71
|
this.client.socket.on('jobError', this.handleJobError.bind(this));
|
|
69
72
|
this.client.socket.on('jobResult', this.handleJobResult.bind(this));
|
|
70
|
-
// Listen to server disconnect event
|
|
73
|
+
// Listen to the server disconnect event
|
|
71
74
|
this.client.on('disconnected', this.handleServerDisconnected.bind(this));
|
|
72
75
|
// Listen to project and job events and update project and job instances
|
|
73
76
|
this.on('project', this.handleProjectEvent.bind(this));
|
|
@@ -115,7 +118,10 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
115
118
|
type: 'initiating',
|
|
116
119
|
projectId: data.jobID,
|
|
117
120
|
jobId: data.imgID,
|
|
118
|
-
workerName: data.workerName
|
|
121
|
+
workerName: data.workerName,
|
|
122
|
+
positivePrompt: data.positivePrompt,
|
|
123
|
+
negativePrompt: data.negativePrompt,
|
|
124
|
+
jobIndex: data.jobIndex
|
|
119
125
|
});
|
|
120
126
|
return;
|
|
121
127
|
case 'jobStarted': {
|
|
@@ -123,7 +129,10 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
123
129
|
type: 'started',
|
|
124
130
|
projectId: data.jobID,
|
|
125
131
|
jobId: data.imgID,
|
|
126
|
-
workerName: data.workerName
|
|
132
|
+
workerName: data.workerName,
|
|
133
|
+
positivePrompt: data.positivePrompt,
|
|
134
|
+
negativePrompt: data.negativePrompt,
|
|
135
|
+
jobIndex: data.jobIndex
|
|
127
136
|
});
|
|
128
137
|
return;
|
|
129
138
|
}
|
|
@@ -241,7 +250,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
241
250
|
this.client.logger.error(e);
|
|
242
251
|
});
|
|
243
252
|
setTimeout(() => {
|
|
244
|
-
this.projects = this.projects.filter((p) => p.
|
|
253
|
+
this.projects = this.projects.filter((p) => !p.finished);
|
|
245
254
|
}, GARBAGE_COLLECT_TIMEOUT);
|
|
246
255
|
}
|
|
247
256
|
}
|
|
@@ -263,15 +272,30 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
263
272
|
}
|
|
264
273
|
switch (event.type) {
|
|
265
274
|
case 'initiating':
|
|
266
|
-
|
|
275
|
+
// positivePrompt and negativePrompt are only received if a Dynamic Prompt was used for the project creating a different prompt for each job
|
|
276
|
+
job._update({
|
|
277
|
+
status: 'initiating',
|
|
278
|
+
workerName: event.workerName,
|
|
279
|
+
positivePrompt: event.positivePrompt,
|
|
280
|
+
negativePrompt: event.negativePrompt,
|
|
281
|
+
jobIndex: event.jobIndex
|
|
282
|
+
});
|
|
267
283
|
break;
|
|
268
284
|
case 'started':
|
|
269
|
-
|
|
285
|
+
// positivePrompt and negativePrompt are only received if a Dynamic Prompt was used for the project creating a different prompt for each job
|
|
286
|
+
job._update({
|
|
287
|
+
status: 'processing',
|
|
288
|
+
workerName: event.workerName,
|
|
289
|
+
positivePrompt: event.positivePrompt,
|
|
290
|
+
negativePrompt: event.negativePrompt,
|
|
291
|
+
jobIndex: event.jobIndex
|
|
292
|
+
});
|
|
270
293
|
break;
|
|
271
294
|
case 'progress':
|
|
272
295
|
job._update({
|
|
273
296
|
status: 'processing',
|
|
274
|
-
|
|
297
|
+
// Jus in case event comes out of order
|
|
298
|
+
step: Math.max(event.step, job.step),
|
|
275
299
|
stepCount: event.stepCount
|
|
276
300
|
});
|
|
277
301
|
if (project.status !== 'processing') {
|
|
@@ -479,6 +503,18 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
479
503
|
};
|
|
480
504
|
}
|
|
481
505
|
|
|
506
|
+
async estimateEnhancementCost(strength: EnhancementStrength) {
|
|
507
|
+
return this.estimateCost({
|
|
508
|
+
network: enhancementDefaults.network,
|
|
509
|
+
model: enhancementDefaults.modelId,
|
|
510
|
+
imageCount: 1,
|
|
511
|
+
stepCount: enhancementDefaults.steps,
|
|
512
|
+
previewCount: 0,
|
|
513
|
+
cnEnabled: false,
|
|
514
|
+
startingImageStrength: getEnhacementStrength(strength)
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
482
518
|
/**
|
|
483
519
|
* Get upload URL for image
|
|
484
520
|
* @internal
|
|
@@ -29,11 +29,17 @@ export interface JobEventBase {
|
|
|
29
29
|
export interface JobInitiating extends JobEventBase {
|
|
30
30
|
type: 'initiating';
|
|
31
31
|
workerName: string;
|
|
32
|
+
positivePrompt?: string;
|
|
33
|
+
negativePrompt?: string;
|
|
34
|
+
jobIndex?: number;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
export interface JobStarted extends JobEventBase {
|
|
35
38
|
type: 'started';
|
|
36
39
|
workerName: string;
|
|
40
|
+
positivePrompt?: string;
|
|
41
|
+
negativePrompt?: string;
|
|
42
|
+
jobIndex?: number;
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
export interface JobProgress extends JobEventBase {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SupernetType } from '../../ApiClient/WebSocketClient/types';
|
|
2
2
|
import { ControlNetParams } from './ControlNetParams';
|
|
3
|
+
import { TokenType } from '../../types/token';
|
|
3
4
|
|
|
4
5
|
export interface SupportedModel {
|
|
5
6
|
id: string;
|
|
@@ -141,6 +142,11 @@ export interface ProjectParams {
|
|
|
141
142
|
* ControlNet model parameters
|
|
142
143
|
*/
|
|
143
144
|
controlNet?: ControlNetParams;
|
|
145
|
+
/**
|
|
146
|
+
* Select which tokens to use for the project.
|
|
147
|
+
* If not specified, the Sogni token will be used.
|
|
148
|
+
*/
|
|
149
|
+
tokenType?: TokenType;
|
|
144
150
|
}
|
|
145
151
|
|
|
146
152
|
export type ImageUrlParams = {
|
|
@@ -195,3 +201,5 @@ export interface EstimateRequest {
|
|
|
195
201
|
*/
|
|
196
202
|
height?: number;
|
|
197
203
|
}
|
|
204
|
+
|
|
205
|
+
export type EnhancementStrength = 'light' | 'medium' | 'heavy';
|
package/src/Stats/types.ts
CHANGED
|
@@ -4,7 +4,9 @@ export type LeaderboardType =
|
|
|
4
4
|
| 'renderSecCompleteWorker'
|
|
5
5
|
| 'renderSecCompleteArtist'
|
|
6
6
|
| 'renderTokenCompleteWorker'
|
|
7
|
+
| 'renderTokenCompleteWorker2'
|
|
7
8
|
| 'renderTokenCompleteArtist'
|
|
9
|
+
| 'renderTokenCompleteArtist2'
|
|
8
10
|
| 'jobCompleteWorker'
|
|
9
11
|
| 'jobCompleteArtist'
|
|
10
12
|
| 'projectCompleteArtist'
|