-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathupload.ts
131 lines (113 loc) · 5.28 KB
/
upload.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { flags, SfdxCommand } from '@salesforce/command';
import { createReadStream, ReadStream } from 'fs-extra';
import { AITokenRetrieve } from '../../../../shared/ai/aiConstants';
import { datasetGet, datasetEndpoint, trainingEndpoint } from '../../../../shared/ai/datasetGet';
import requestPromise = require('request-promise-native');
const imageTypes = ['image', 'image-detection', 'image-multi-label'];
const textTypes = ['text-intent', 'text-sentiment'];
export default class EinsteinAIUpload extends SfdxCommand {
public static description = 'upload a dataset';
public static examples = [`sfdx shane:ai:dataset:upload -e shane.mclaughlin@salesforce.com -f ~/myPics.zip -n AwesomeDataset `];
protected static flagsConfig = {
name: flags.string({
char: 'n',
description: 'Name of the dataset. Optional. If this parameter is omitted, the dataset name is derived from the .zip file name. '
}),
file: flags.filepath({
char: 'f',
description:
'Path to the .zip (image) or .csv/.tsv/.json (language) file on the local drive (FilePart). The maximum file size you can upload from a local drive is 50 MB for images, 25 MB for text'
}),
path: flags.string({
char: 'p',
description:
'URL of the .zip (image) or .csv/.tsv/.json (language) file. The maximum file size you can upload from a web location is 2 GB (images), 25MB (text) '
}),
type: flags.string({
char: 't',
description: 'Type of dataset data. Valid values are:',
options: [...imageTypes, ...textTypes],
default: 'image'
}),
train: flags.boolean({ description: 'train a model on the dataset' }),
// sync: flags.boolean({ char: 's', description: 'keep polling until the dataset creation is done' }),
email: flags.email({ char: 'e', description: 'email address you used when you signed up for your einstein.ai account' }),
wait: flags.integer({ char: 'w', description: 'how long to wait for this to process (minutes)', default: 10 }),
verbose: flags.builtin()
};
public async run(): Promise<any> {
const token = await AITokenRetrieve(this.flags.email || process.env.EINSTEIN_EMAIL);
const endpoint = `${datasetEndpoint(textTypes.includes(this.flags.type))}/upload`;
const formData: DatasetCreateAsyncRequest = {
type: this.flags.type
};
if (this.flags.file) {
formData.data = createReadStream(this.flags.file);
}
if (this.flags.path) {
formData.path = this.flags.path;
}
if (this.flags.name) {
formData.name = this.flags.name;
}
this.ux.startSpinner('creating dataset');
const createResponse = await requestPromise(endpoint, {
method: 'POST',
formData,
headers: {
'Content-type': 'multipart/form-data',
'Cache-Control': 'no-cache',
Authorization: `Bearer ${token}`
},
json: true
});
this.ux.stopSpinner(`created dataset with id ${createResponse.id}`);
if (this.flags.wait > 0 || this.flags.train) {
this.ux.startSpinner('waiting for dataset to complete');
const completedResponse = await datasetGet({
email: this.flags.email || process.env.EINSTEIN_EMAIL,
isLanguage: textTypes.includes(this.flags.type),
dataset: createResponse.id,
poll: true,
pollLimitMins: this.flags.wait
});
this.ux.stopSpinner(`completed with status ${completedResponse.statusMsg}`);
if (!this.flags.json && this.flags.verbose) {
this.ux.logJson(completedResponse);
}
if (this.flags.train) {
this.ux.startSpinner('training model from dataset');
const trainResponse = await requestPromise(trainingEndpoint(textTypes.includes(this.flags.type)), {
method: 'POST',
formData: {
datasetId: createResponse.id,
name: this.flags.name ?? 'autocreated from shane:sfdx plugin'
},
headers: {
'Content-type': 'multipart/form-data',
'Cache-Control': 'no-cache',
Authorization: `Bearer ${token}`
},
json: true
});
this.ux.stopSpinner(`training in progress with modelId ${trainResponse.modelId}`);
if (!this.flags.json && this.flags.verbose) {
this.ux.logJson(trainResponse);
}
}
this.ux.log(`check the status using sfdx shane:ai:dataset:get -n ${completedResponse.id}`);
return completedResponse;
}
if (!this.flags.json) {
this.ux.logJson(createResponse);
}
this.ux.log(`check the status using sfdx shane:ai:dataset:get -n ${createResponse.id}`);
return createResponse;
}
}
interface DatasetCreateAsyncRequest {
type: string;
data?: ReadStream;
path?: string;
name?: string;
}