1 |
|
2 | "use strict";
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | exports.MachineLearningApiClient = exports.isGcsTfliteModelOptions = void 0;
|
20 | var api_request_1 = require("../utils/api-request");
|
21 | var error_1 = require("../utils/error");
|
22 | var utils = require("../utils/index");
|
23 | var validator = require("../utils/validator");
|
24 | var machine_learning_utils_1 = require("./machine-learning-utils");
|
25 | var ML_V1BETA2_API = 'https://firebaseml.googleapis.com/v1beta2';
|
26 | var FIREBASE_VERSION_HEADER = {
|
27 | 'X-Firebase-Client': "fire-admin-node/" + utils.getSdkVersion(),
|
28 | };
|
29 |
|
30 | var POLL_DEFAULT_MAX_TIME_MILLISECONDS = 120000;
|
31 | var POLL_BASE_WAIT_TIME_MILLISECONDS = 3000;
|
32 | var POLL_MAX_WAIT_TIME_MILLISECONDS = 30000;
|
33 | function isGcsTfliteModelOptions(options) {
|
34 | var _a, _b;
|
35 | var gcsUri = (_b = (_a = options) === null || _a === void 0 ? void 0 : _a.tfliteModel) === null || _b === void 0 ? void 0 : _b.gcsTfliteUri;
|
36 | return typeof gcsUri !== 'undefined';
|
37 | }
|
38 | exports.isGcsTfliteModelOptions = isGcsTfliteModelOptions;
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | var MachineLearningApiClient = (function () {
|
45 | function MachineLearningApiClient(app) {
|
46 | this.app = app;
|
47 | if (!validator.isNonNullObject(app) || !('options' in app)) {
|
48 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'First argument passed to admin.machineLearning() must be a valid '
|
49 | + 'Firebase app instance.');
|
50 | }
|
51 | this.httpClient = new api_request_1.AuthorizedHttpClient(app);
|
52 | }
|
53 | MachineLearningApiClient.prototype.createModel = function (model) {
|
54 | var _this = this;
|
55 | if (!validator.isNonNullObject(model) ||
|
56 | !validator.isNonEmptyString(model.displayName)) {
|
57 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Invalid model content.');
|
58 | return Promise.reject(err);
|
59 | }
|
60 | return this.getProjectUrl()
|
61 | .then(function (url) {
|
62 | var request = {
|
63 | method: 'POST',
|
64 | url: url + "/models",
|
65 | data: model,
|
66 | };
|
67 | return _this.sendRequest(request);
|
68 | });
|
69 | };
|
70 | MachineLearningApiClient.prototype.updateModel = function (modelId, model, updateMask) {
|
71 | var _this = this;
|
72 | if (!validator.isNonEmptyString(modelId) ||
|
73 | !validator.isNonNullObject(model) ||
|
74 | !validator.isNonEmptyArray(updateMask)) {
|
75 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Invalid model or mask content.');
|
76 | return Promise.reject(err);
|
77 | }
|
78 | return this.getProjectUrl()
|
79 | .then(function (url) {
|
80 | var request = {
|
81 | method: 'PATCH',
|
82 | url: url + "/models/" + modelId + "?updateMask=" + updateMask.join(),
|
83 | data: model,
|
84 | };
|
85 | return _this.sendRequest(request);
|
86 | });
|
87 | };
|
88 | MachineLearningApiClient.prototype.getModel = function (modelId) {
|
89 | var _this = this;
|
90 | return Promise.resolve()
|
91 | .then(function () {
|
92 | return _this.getModelName(modelId);
|
93 | })
|
94 | .then(function (modelName) {
|
95 | return _this.getResourceWithShortName(modelName);
|
96 | });
|
97 | };
|
98 | MachineLearningApiClient.prototype.getOperation = function (operationName) {
|
99 | var _this = this;
|
100 | return Promise.resolve()
|
101 | .then(function () {
|
102 | return _this.getResourceWithFullName(operationName);
|
103 | });
|
104 | };
|
105 | MachineLearningApiClient.prototype.listModels = function (options) {
|
106 | var _this = this;
|
107 | if (options === void 0) { options = {}; }
|
108 | if (!validator.isNonNullObject(options)) {
|
109 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Invalid ListModelsOptions');
|
110 | return Promise.reject(err);
|
111 | }
|
112 | if (typeof options.filter !== 'undefined' && !validator.isNonEmptyString(options.filter)) {
|
113 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Invalid list filter.');
|
114 | return Promise.reject(err);
|
115 | }
|
116 | if (typeof options.pageSize !== 'undefined') {
|
117 | if (!validator.isNumber(options.pageSize)) {
|
118 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Invalid page size.');
|
119 | return Promise.reject(err);
|
120 | }
|
121 | if (options.pageSize < 1 || options.pageSize > 100) {
|
122 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Page size must be between 1 and 100.');
|
123 | return Promise.reject(err);
|
124 | }
|
125 | }
|
126 | if (typeof options.pageToken !== 'undefined' && !validator.isNonEmptyString(options.pageToken)) {
|
127 | var err = new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Next page token must be a non-empty string.');
|
128 | return Promise.reject(err);
|
129 | }
|
130 | return this.getProjectUrl()
|
131 | .then(function (url) {
|
132 | var request = {
|
133 | method: 'GET',
|
134 | url: url + "/models",
|
135 | data: options,
|
136 | };
|
137 | return _this.sendRequest(request);
|
138 | });
|
139 | };
|
140 | MachineLearningApiClient.prototype.deleteModel = function (modelId) {
|
141 | var _this = this;
|
142 | return this.getProjectUrl()
|
143 | .then(function (url) {
|
144 | var modelName = _this.getModelName(modelId);
|
145 | var request = {
|
146 | method: 'DELETE',
|
147 | url: url + "/" + modelName,
|
148 | };
|
149 | return _this.sendRequest(request);
|
150 | });
|
151 | };
|
152 | |
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | MachineLearningApiClient.prototype.handleOperation = function (op, options) {
|
159 | if (op.done) {
|
160 | if (op.response) {
|
161 | return Promise.resolve(op.response);
|
162 | }
|
163 | else if (op.error) {
|
164 | var err = machine_learning_utils_1.FirebaseMachineLearningError.fromOperationError(op.error.code, op.error.message);
|
165 | return Promise.reject(err);
|
166 | }
|
167 |
|
168 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-server-response', 'Invalid operation response.');
|
169 | }
|
170 |
|
171 | if (options === null || options === void 0 ? void 0 : options.wait) {
|
172 | return this.pollOperationWithExponentialBackoff(op.name, options);
|
173 | }
|
174 | var metadata = op.metadata || {};
|
175 | var metadataType = metadata['@type'] || '';
|
176 | if (!metadataType.includes('ModelOperationMetadata')) {
|
177 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-server-response', "Unknown Metadata type: " + JSON.stringify(metadata));
|
178 | }
|
179 | return this.getModel(extractModelId(metadata.name));
|
180 | };
|
181 |
|
182 | MachineLearningApiClient.prototype.pollOperationWithExponentialBackoff = function (opName, options) {
|
183 | var _this = this;
|
184 | var _a, _b, _c;
|
185 | var maxTimeMilliseconds = (_a = options === null || options === void 0 ? void 0 : options.maxTimeMillis) !== null && _a !== void 0 ? _a : POLL_DEFAULT_MAX_TIME_MILLISECONDS;
|
186 | var baseWaitMillis = (_b = options === null || options === void 0 ? void 0 : options.baseWaitMillis) !== null && _b !== void 0 ? _b : POLL_BASE_WAIT_TIME_MILLISECONDS;
|
187 | var maxWaitMillis = (_c = options === null || options === void 0 ? void 0 : options.maxWaitMillis) !== null && _c !== void 0 ? _c : POLL_MAX_WAIT_TIME_MILLISECONDS;
|
188 | var poller = new api_request_1.ExponentialBackoffPoller(baseWaitMillis, maxWaitMillis, maxTimeMilliseconds);
|
189 | return poller.poll(function () {
|
190 | return _this.getOperation(opName)
|
191 | .then(function (responseData) {
|
192 | if (!responseData.done) {
|
193 | return null;
|
194 | }
|
195 | if (responseData.error) {
|
196 | var err = machine_learning_utils_1.FirebaseMachineLearningError.fromOperationError(responseData.error.code, responseData.error.message);
|
197 | throw err;
|
198 | }
|
199 | return responseData.response;
|
200 | });
|
201 | });
|
202 | };
|
203 | |
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | MachineLearningApiClient.prototype.getResourceWithShortName = function (name) {
|
211 | var _this = this;
|
212 | return this.getProjectUrl()
|
213 | .then(function (url) {
|
214 | var request = {
|
215 | method: 'GET',
|
216 | url: url + "/" + name,
|
217 | };
|
218 | return _this.sendRequest(request);
|
219 | });
|
220 | };
|
221 | |
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | MachineLearningApiClient.prototype.getResourceWithFullName = function (fullName) {
|
228 | var request = {
|
229 | method: 'GET',
|
230 | url: ML_V1BETA2_API + "/" + fullName
|
231 | };
|
232 | return this.sendRequest(request);
|
233 | };
|
234 | MachineLearningApiClient.prototype.sendRequest = function (request) {
|
235 | var _this = this;
|
236 | request.headers = FIREBASE_VERSION_HEADER;
|
237 | return this.httpClient.send(request)
|
238 | .then(function (resp) {
|
239 | return resp.data;
|
240 | })
|
241 | .catch(function (err) {
|
242 | throw _this.toFirebaseError(err);
|
243 | });
|
244 | };
|
245 | MachineLearningApiClient.prototype.toFirebaseError = function (err) {
|
246 | if (err instanceof error_1.PrefixedFirebaseError) {
|
247 | return err;
|
248 | }
|
249 | var response = err.response;
|
250 | if (!response.isJson()) {
|
251 | return new machine_learning_utils_1.FirebaseMachineLearningError('unknown-error', "Unexpected response with status: " + response.status + " and body: " + response.text);
|
252 | }
|
253 | var error = response.data.error || {};
|
254 | var code = 'unknown-error';
|
255 | if (error.status && error.status in ERROR_CODE_MAPPING) {
|
256 | code = ERROR_CODE_MAPPING[error.status];
|
257 | }
|
258 | var message = error.message || "Unknown server error: " + response.text;
|
259 | return new machine_learning_utils_1.FirebaseMachineLearningError(code, message);
|
260 | };
|
261 | MachineLearningApiClient.prototype.getProjectUrl = function () {
|
262 | return this.getProjectIdPrefix()
|
263 | .then(function (projectIdPrefix) {
|
264 | return ML_V1BETA2_API + "/" + projectIdPrefix;
|
265 | });
|
266 | };
|
267 | MachineLearningApiClient.prototype.getProjectIdPrefix = function () {
|
268 | var _this = this;
|
269 | if (this.projectIdPrefix) {
|
270 | return Promise.resolve(this.projectIdPrefix);
|
271 | }
|
272 | return utils.findProjectId(this.app)
|
273 | .then(function (projectId) {
|
274 | if (!validator.isNonEmptyString(projectId)) {
|
275 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Failed to determine project ID. Initialize the SDK with service account credentials, or '
|
276 | + 'set project ID as an app option. Alternatively, set the GOOGLE_CLOUD_PROJECT '
|
277 | + 'environment variable.');
|
278 | }
|
279 | _this.projectIdPrefix = "projects/" + projectId;
|
280 | return _this.projectIdPrefix;
|
281 | });
|
282 | };
|
283 | MachineLearningApiClient.prototype.getModelName = function (modelId) {
|
284 | if (!validator.isNonEmptyString(modelId)) {
|
285 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Model ID must be a non-empty string.');
|
286 | }
|
287 | if (modelId.indexOf('/') !== -1) {
|
288 | throw new machine_learning_utils_1.FirebaseMachineLearningError('invalid-argument', 'Model ID must not contain any "/" characters.');
|
289 | }
|
290 | return "models/" + modelId;
|
291 | };
|
292 | return MachineLearningApiClient;
|
293 | }());
|
294 | exports.MachineLearningApiClient = MachineLearningApiClient;
|
295 | var ERROR_CODE_MAPPING = {
|
296 | INVALID_ARGUMENT: 'invalid-argument',
|
297 | NOT_FOUND: 'not-found',
|
298 | RESOURCE_EXHAUSTED: 'resource-exhausted',
|
299 | UNAUTHENTICATED: 'authentication-error',
|
300 | UNKNOWN: 'unknown-error',
|
301 | };
|
302 | function extractModelId(resourceName) {
|
303 | return resourceName.split('/').pop();
|
304 | }
|