Comparing version 0.0.27 to 0.0.28
@@ -26,3 +26,3 @@ "use strict"; | ||
constructor(config) { | ||
const { accessKey, url = "https://api.fxn.ai" } = config; | ||
const { accessKey, url = GraphClient.URL } = config; | ||
this.url = url; | ||
@@ -33,9 +33,8 @@ this.auth = accessKey ? `Bearer ${accessKey}` : null; | ||
* Query the Function graph API. | ||
* @param query Graph query. | ||
* @param variables Query variables. | ||
*/ | ||
query(query, variables) { | ||
query({ query, variables, url: urlOverride }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Request | ||
const response = yield fetch(`${this.url}/graph`, { | ||
const url = urlOverride !== null && urlOverride !== void 0 ? urlOverride : `${this.url}/graph`; | ||
const response = yield fetch(url, { | ||
method: "POST", | ||
@@ -56,1 +55,2 @@ headers: { Accept: "application/json", "Content-Type": "application/json", Authorization: this.auth }, | ||
exports.GraphClient = GraphClient; | ||
GraphClient.URL = "https://api.fxn.ai"; |
@@ -30,3 +30,4 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { user } } = yield this.client.query(`query ($input: UserInput) { | ||
const { data: { user } } = yield this.client.query({ | ||
query: `query ($input: UserInput) { | ||
user (input: $input) { | ||
@@ -44,3 +45,5 @@ ... on User { | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return (_a = user === null || user === void 0 ? void 0 : user.environmentVariables) !== null && _a !== void 0 ? _a : null; | ||
@@ -56,7 +59,10 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { environment } } = yield this.client.query(`mutation ($input: CreateEnvironmentVariableInput!) { | ||
const { data: { environment } } = yield this.client.query({ | ||
query: `mutation ($input: CreateEnvironmentVariableInput!) { | ||
environment: createEnvironmentVariable (input: $input) { | ||
name | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return environment; | ||
@@ -72,5 +78,8 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { result } } = yield this.client.query(`mutation ($input: DeleteEnvironmentVariableInput!) { | ||
const { data: { result } } = yield this.client.query({ | ||
query: `mutation ($input: DeleteEnvironmentVariableInput!) { | ||
result: deleteEnvironmentVariable (input: $input) | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return result; | ||
@@ -77,0 +86,0 @@ }); |
@@ -38,5 +38,9 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.PredictionService = exports.PREDICTION_FIELDS = void 0; | ||
const browser_or_node_1 = require("browser-or-node"); | ||
const data_urls_1 = __importDefault(require("data-urls")); | ||
const types_1 = require("../types"); | ||
@@ -67,3 +71,3 @@ const value_1 = require("./value"); | ||
this.FXNC_CACHE_ROOT = `${this.FXNC_DATA_ROOT}/cache`; | ||
this.FXNC_VERSION = "0.0.13"; | ||
this.FXNC_VERSION = "0.0.14"; | ||
this.FXNC_LIB_URL_BASE = `https://cdn.fxn.ai/edgefxn/${this.FXNC_VERSION}`; | ||
@@ -89,9 +93,5 @@ this.client = client; | ||
// Serialize inputs | ||
const values = yield serializeCloudInputs(inputs, this.storage); | ||
// Build URL | ||
const url = new URL(`/predict/${tag}`, this.client.url); | ||
url.searchParams.append("rawOutputs", "true"); | ||
if (dataUrlLimit) | ||
url.searchParams.append("dataUrlLimit", dataUrlLimit.toString()); | ||
const values = yield this.serializeCloudInputs(inputs, dataUrlLimit); | ||
// Query | ||
const url = this.getPredictUrl(tag, { rawOutputs: true, dataUrlLimit }); | ||
const response = yield fetch(url, { | ||
@@ -112,3 +112,3 @@ method: "POST", | ||
// Parse | ||
prediction.results = yield parseResults(prediction.results, rawOutputs); | ||
prediction.results = yield this.parseResults(prediction.results, rawOutputs); | ||
// Check edge prediction | ||
@@ -142,9 +142,5 @@ if (prediction.type !== types_1.PredictorType.Edge || rawOutputs) | ||
// Serialize inputs | ||
const values = yield __await(serializeCloudInputs(inputs, this.storage)); | ||
const values = yield __await(this.serializeCloudInputs(inputs, dataUrlLimit)); | ||
// Request | ||
const url = new URL(`/predict/${tag}`, this.client.url); | ||
url.searchParams.append("rawOutputs", "true"); | ||
url.searchParams.append("stream", "true"); | ||
if (dataUrlLimit) | ||
url.searchParams.append("dataUrlLimit", dataUrlLimit.toString()); | ||
const url = this.getPredictUrl(tag, { stream: true, rawOutputs: true, dataUrlLimit }); | ||
const response = yield __await(fetch(url, { | ||
@@ -170,9 +166,15 @@ method: "POST", | ||
// Check error | ||
const payload = JSON.parse(value); | ||
const prediction = JSON.parse(value); | ||
if (response.status >= 400) | ||
throw new Error((_c = (_b = payload.errors) === null || _b === void 0 ? void 0 : _b[0].message) !== null && _c !== void 0 ? _c : "An unknown error occurred"); | ||
// Deserialize | ||
payload.results = yield __await(parseResults(payload.results, rawOutputs)); | ||
throw new Error((_c = (_b = prediction.errors) === null || _b === void 0 ? void 0 : _b[0].message) !== null && _c !== void 0 ? _c : "An unknown error occurred"); | ||
// Parse | ||
prediction.results = yield __await(this.parseResults(prediction.results, rawOutputs)); | ||
// Check edge prediction | ||
if (prediction.type !== types_1.PredictorType.Edge || rawOutputs) | ||
return yield __await(prediction); | ||
// Load edge predictor | ||
const predictor = yield __await(this.load(prediction)); | ||
this.cache.set(tag, predictor); | ||
// Yield | ||
yield yield __await(payload); | ||
yield yield __await(!!inputs ? this.predict(tag, predictor, inputs) : prediction); | ||
} | ||
@@ -200,2 +202,118 @@ }); | ||
} | ||
/** | ||
* Convert an object into a Function value. | ||
* @param input Input arguments. | ||
* @returns Function value. | ||
*/ | ||
toValue(input) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { value, name, minUploadSize: dataUrlLimit = 4096, key } = input; | ||
// Null | ||
if (value === null) | ||
return { data: null, type: "null" }; | ||
// Value | ||
if ((0, value_1.isFunctionValue)(value)) | ||
return value; | ||
// Tensor | ||
if ((0, value_1.isTensor)(value)) { | ||
const data = yield this.storage.upload({ name, buffer: value.data.buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
const dtype = getTypedArrayDtype(value.data); | ||
const type = dtypeToString(dtype); | ||
return { data, type, shape: value.shape }; | ||
} | ||
// Typed array | ||
if ((0, value_1.isTypedArray)(value)) | ||
return yield this.toValue(Object.assign(Object.assign({}, input), { value: { data: value, shape: [value.length] } })); | ||
// Binary | ||
if (value instanceof ArrayBuffer) { | ||
const data = yield this.storage.upload({ name, buffer: value, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "binary" }; | ||
} | ||
// String | ||
if (typeof (value) === "string") { | ||
const buffer = new TextEncoder().encode(value).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "string" }; | ||
} | ||
// Number | ||
if (typeof (value) === "number") { | ||
const isInt = Number.isInteger(value); | ||
const buffer = isInt ? new Int32Array([value]).buffer : new Float32Array([value]).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
const type = isInt ? "int32" : "float32"; | ||
return { data, type, shape: [] }; | ||
} | ||
// Boolean | ||
if (typeof (value) === "boolean") { | ||
const buffer = new Uint8Array([+value]).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "bool", shape: [] }; | ||
} | ||
// Boolean array // We want benefits of `TypedArray` given that there's no `BoolArray` | ||
if (Array.isArray(value) && | ||
value.length > 0 && | ||
typeof (value[0]) === "boolean" && | ||
!value.some(e => typeof (e) !== "boolean") // fail faster for non-boolean arrays | ||
) { | ||
const buffer = new Uint8Array(value).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "bool", shape: [value.length] }; | ||
} | ||
// List | ||
if (Array.isArray(value)) { | ||
const serializedValue = JSON.stringify(value); | ||
const buffer = new TextEncoder().encode(serializedValue).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "list" }; | ||
} | ||
// Dict | ||
if (typeof (value) === "object") { | ||
const serializedValue = JSON.stringify(value); | ||
const buffer = new TextEncoder().encode(serializedValue).buffer; | ||
const data = yield this.storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "dict" }; | ||
} | ||
// Throw | ||
throw new Error(`Value ${value} of type ${typeof (value)} cannot be converted to a Function value`); | ||
}); | ||
} | ||
/** | ||
* Convert a Function value to a plain object. | ||
* If the Function value cannot be converted to a plain object, the Function value is returned as-is. | ||
* @param input Input arguments. | ||
* @returns Plain object. | ||
*/ | ||
toObject(input) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { value: { data, type, shape } } = input; | ||
// Null | ||
if (type === "null") | ||
return null; | ||
// Download | ||
const buffer = yield getValueData(data); | ||
// Tensor | ||
const ARRAY_TYPES = [ | ||
"float16", "float32", "float64", | ||
"int8", "int16", "int32", "int64", | ||
"uint8", "uint16", "uint32", "uint64" | ||
]; | ||
if (ARRAY_TYPES.includes(type)) | ||
return toTypedArrayOrNumber(buffer, type, shape); | ||
// Boolean | ||
if (type === "bool") | ||
return toBooleanArrayOrBoolean(buffer, shape); | ||
// String | ||
if (type === "string") | ||
return new TextDecoder().decode(buffer); | ||
// JSON | ||
const JSON_TYPES = ["list", "dict"]; | ||
if (JSON_TYPES.includes(type)) | ||
return JSON.parse(new TextDecoder().decode(buffer)); | ||
// Binary | ||
if (type === "binary") | ||
return buffer; | ||
// Return Function value | ||
return input.value; | ||
}); | ||
} | ||
loadFxnc() { | ||
@@ -439,3 +557,3 @@ return __awaiter(this, void 0, void 0, function* () { | ||
const { data, shape } = value; | ||
const dtype = dtypeFromTypedArray(data); | ||
const dtype = getTypedArrayDtype(data); | ||
const elementCount = shape.reduce((a, b) => a * b, 1); | ||
@@ -554,20 +672,20 @@ const pBuffer = fxnc._malloc(data.byteLength); | ||
switch (type) { | ||
case 0 /* Dtype.Null */: return null; | ||
case 1 /* Dtype.Float16 */: throw new Error(`Cannot convert prediction output of type 'float16' to value because it is not supported`); | ||
case 2 /* Dtype.Float32 */: return toTensorOrNumber(new Float32Array(fxnc.HEAPF32.buffer, pData, elementCount), shape); | ||
case 3 /* Dtype.Float64 */: return toTensorOrNumber(new Float64Array(fxnc.HEAPF64.buffer, pData, elementCount), shape); | ||
case 4 /* Dtype.Int8 */: return toTensorOrNumber(new Int8Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 5 /* Dtype.Int16 */: return toTensorOrNumber(new Int16Array(fxnc.HEAP16.buffer, pData, elementCount), shape); | ||
case 6 /* Dtype.Int32 */: return toTensorOrNumber(new Int32Array(fxnc.HEAP32.buffer, pData, elementCount), shape); | ||
case 7 /* Dtype.Int64 */: return toTensorOrNumber(new BigInt64Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 8 /* Dtype.Uint8 */: return toTensorOrNumber(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 9 /* Dtype.Uint16 */: return toTensorOrNumber(new Uint16Array(fxnc.HEAPU16.buffer, pData, elementCount), shape); | ||
case 10 /* Dtype.Uint32 */: return toTensorOrNumber(new Uint32Array(fxnc.HEAPU32.buffer, pData, elementCount), shape); | ||
case 11 /* Dtype.Uint64 */: return toTensorOrNumber(new BigUint64Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 12 /* Dtype.Bool */: return toTensorOrBoolean(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 13 /* Dtype.String */: return fxnc.UTF8ToString(pData); | ||
case 14 /* Dtype.List */: return JSON.parse(fxnc.UTF8ToString(pData)); | ||
case 15 /* Dtype.Dict */: return JSON.parse(fxnc.UTF8ToString(pData)); | ||
case 16 /* Dtype.Image */: return toImage(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 17 /* Dtype.Binary */: return toArrayBuffer(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount)); | ||
case 0 /* FXNDtype.Null */: return null; | ||
case 1 /* FXNDtype.Float16 */: throw new Error(`Cannot convert prediction output of type 'float16' to value because it is not supported`); | ||
case 2 /* FXNDtype.Float32 */: return toTensorOrNumber(new Float32Array(fxnc.HEAPF32.buffer, pData, elementCount), shape); | ||
case 3 /* FXNDtype.Float64 */: return toTensorOrNumber(new Float64Array(fxnc.HEAPF64.buffer, pData, elementCount), shape); | ||
case 4 /* FXNDtype.Int8 */: return toTensorOrNumber(new Int8Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 5 /* FXNDtype.Int16 */: return toTensorOrNumber(new Int16Array(fxnc.HEAP16.buffer, pData, elementCount), shape); | ||
case 6 /* FXNDtype.Int32 */: return toTensorOrNumber(new Int32Array(fxnc.HEAP32.buffer, pData, elementCount), shape); | ||
case 7 /* FXNDtype.Int64 */: return toTensorOrNumber(new BigInt64Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 8 /* FXNDtype.Uint8 */: return toTensorOrNumber(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 9 /* FXNDtype.Uint16 */: return toTensorOrNumber(new Uint16Array(fxnc.HEAPU16.buffer, pData, elementCount), shape); | ||
case 10 /* FXNDtype.Uint32 */: return toTensorOrNumber(new Uint32Array(fxnc.HEAPU32.buffer, pData, elementCount), shape); | ||
case 11 /* FXNDtype.Uint64 */: return toTensorOrNumber(new BigUint64Array(fxnc.HEAP8.buffer, pData, elementCount), shape); | ||
case 12 /* FXNDtype.Bool */: return toTensorOrBoolean(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 13 /* FXNDtype.String */: return fxnc.UTF8ToString(pData); | ||
case 14 /* FXNDtype.List */: return JSON.parse(fxnc.UTF8ToString(pData)); | ||
case 15 /* FXNDtype.Dict */: return JSON.parse(fxnc.UTF8ToString(pData)); | ||
case 16 /* FXNDtype.Image */: return toImage(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount), shape); | ||
case 17 /* FXNDtype.Binary */: return toArrayBuffer(new Uint8Array(fxnc.HEAPU8.buffer, pData, elementCount)); | ||
default: throw new Error(`Cannot convert prediction output to value because of unknown type: ${type}`); | ||
@@ -583,29 +701,47 @@ } | ||
} | ||
getPredictUrl(tag, query) { | ||
const qs = Object.entries(query) | ||
.filter(([key, value]) => value != null) | ||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) | ||
.join("&"); | ||
return `${this.client.url}/predict/${tag}?${qs}`; | ||
} | ||
serializeCloudInputs(inputs, minUploadSize = 4096) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Check | ||
if (!inputs) | ||
return null; | ||
// Serialize | ||
const key = Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2); // this doesn't have to be robust | ||
const entries = yield Promise.all(Object.entries(inputs) | ||
.map(([name, value]) => this.toValue({ value, name, minUploadSize, key }) | ||
.then(f => (Object.assign(Object.assign({}, f), { name }))))); | ||
const result = Object.fromEntries(entries.map((_a) => { | ||
var { name } = _a, value = __rest(_a, ["name"]); | ||
return [name, value]; | ||
})); | ||
// Return | ||
return result; | ||
}); | ||
} | ||
parseResults(rawResults, rawOutputs) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return rawResults && !rawOutputs ? | ||
yield Promise.all(rawResults.map(value => this.toObject({ value }))) : | ||
rawResults; | ||
}); | ||
} | ||
} | ||
exports.PredictionService = PredictionService; | ||
function serializeCloudInputs(inputs, storage, minUploadSize = 4096) { | ||
function getValueData(url) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Check | ||
if (!inputs) | ||
return null; | ||
// Serialize | ||
const key = Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2); // this doesn't have to be robust | ||
const entries = yield Promise.all(Object.entries(inputs) | ||
.map(([name, value]) => (0, value_1.toFunctionValue)({ storage, value, name, minUploadSize, key }) | ||
.then(f => (Object.assign(Object.assign({}, f), { name }))))); | ||
const result = Object.fromEntries(entries.map((_a) => { | ||
var { name } = _a, value = __rest(_a, ["name"]); | ||
return [name, value]; | ||
})); | ||
// Return | ||
return result; | ||
// Data URL | ||
if (url.startsWith("data:")) | ||
return (0, data_urls_1.default)(url).body.buffer; | ||
// Download | ||
const response = yield fetch(url); | ||
const buffer = yield response.arrayBuffer(); | ||
return buffer; | ||
}); | ||
} | ||
function parseResults(rawResults, rawOutputs) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return rawResults && !rawOutputs ? | ||
yield Promise.all(rawResults.map(value => (0, value_1.toPlainValue)({ value: value }))) : | ||
rawResults; | ||
}); | ||
} | ||
function getResourceName(url) { | ||
@@ -627,2 +763,23 @@ return new URL(url).pathname.split("/").pop(); | ||
} | ||
function toTypedArrayOrNumber(buffer, type, shape) { | ||
const CTOR_MAP = { | ||
"float32": Float32Array, | ||
"float64": Float64Array, | ||
"int8": Int8Array, | ||
"int16": Int16Array, | ||
"int32": Int32Array, | ||
"int64": BigInt64Array, | ||
"uint8": Uint8Array, | ||
"uint16": Uint16Array, | ||
"uint32": Uint32Array, | ||
"uint64": BigUint64Array, | ||
}; | ||
const data = new CTOR_MAP[type](buffer); | ||
return shape.length > 0 ? shape.length > 1 ? { data, shape } : data : data[0]; | ||
} | ||
function toBooleanArrayOrBoolean(buffer, shape) { | ||
const tensor = new Uint8Array(buffer); | ||
const array = Array.from(tensor).map(num => num !== 0); | ||
return shape.length > 0 ? array : array[0]; | ||
} | ||
function toImage(data, shape) { | ||
@@ -634,29 +791,46 @@ return { data: cloneTypedArray(data), width: shape[2], height: shape[1] }; | ||
} | ||
function dtypeFromTypedArray(data) { | ||
function getTypedArrayDtype(data) { | ||
if (data instanceof BoolArray) | ||
return 12 /* Dtype.Bool */; | ||
return 12 /* FXNDtype.Bool */; | ||
if (data instanceof Float32Array) | ||
return 2 /* Dtype.Float32 */; | ||
return 2 /* FXNDtype.Float32 */; | ||
if (data instanceof Float64Array) | ||
return 3 /* Dtype.Float64 */; | ||
return 3 /* FXNDtype.Float64 */; | ||
if (data instanceof Int8Array) | ||
return 4 /* Dtype.Int8 */; | ||
return 4 /* FXNDtype.Int8 */; | ||
if (data instanceof Int16Array) | ||
return 5 /* Dtype.Int16 */; | ||
return 5 /* FXNDtype.Int16 */; | ||
if (data instanceof Int32Array) | ||
return 6 /* Dtype.Int32 */; | ||
return 6 /* FXNDtype.Int32 */; | ||
if (data instanceof BigInt64Array) | ||
return 7 /* Dtype.Int64 */; | ||
return 7 /* FXNDtype.Int64 */; | ||
if (data instanceof Uint8Array) | ||
return 8 /* Dtype.Uint8 */; | ||
return 8 /* FXNDtype.Uint8 */; | ||
if (data instanceof Uint8ClampedArray) | ||
return 8 /* Dtype.Uint8 */; | ||
return 8 /* FXNDtype.Uint8 */; | ||
if (data instanceof Uint16Array) | ||
return 9 /* Dtype.Uint16 */; | ||
return 9 /* FXNDtype.Uint16 */; | ||
if (data instanceof Uint32Array) | ||
return 10 /* Dtype.Uint32 */; | ||
return 10 /* FXNDtype.Uint32 */; | ||
if (data instanceof BigUint64Array) | ||
return 11 /* Dtype.Uint64 */; | ||
throw new Error("Unsupported TypedArray or ArrayBuffer type"); | ||
return 11 /* FXNDtype.Uint64 */; | ||
return 17 /* FXNDtype.Binary */; | ||
} | ||
function dtypeToString(type) { | ||
switch (type) { | ||
case 12 /* FXNDtype.Bool */: return "bool"; | ||
case 2 /* FXNDtype.Float32 */: return "float32"; | ||
case 3 /* FXNDtype.Float64 */: return "float64"; | ||
case 4 /* FXNDtype.Int8 */: return "int8"; | ||
case 5 /* FXNDtype.Int16 */: return "int16"; | ||
case 6 /* FXNDtype.Int32 */: return "int32"; | ||
case 7 /* FXNDtype.Int64 */: return "int64"; | ||
case 8 /* FXNDtype.Uint8 */: return "uint8"; | ||
case 9 /* FXNDtype.Uint16 */: return "uint16"; | ||
case 10 /* FXNDtype.Uint32 */: return "uint32"; | ||
case 11 /* FXNDtype.Uint64 */: return "uint64"; | ||
case 17 /* FXNDtype.Binary */: return "binary"; | ||
default: throw new Error(`Cannot convert data type ${type} to string`); | ||
} | ||
} | ||
function assert(condition, message) { | ||
@@ -663,0 +837,0 @@ if (!condition) |
@@ -40,7 +40,10 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { predictor } } = yield this.client.query(`query ($input: PredictorInput!) { | ||
const { data: { predictor } } = yield this.client.query({ | ||
query: `query ($input: PredictorInput!) { | ||
predictor (input: $input) { | ||
${exports.PREDICTOR_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return predictor; | ||
@@ -58,3 +61,4 @@ }); | ||
const _b = input !== null && input !== void 0 ? input : {}, { owner: username } = _b, predictors = __rest(_b, ["owner"]); | ||
const { data: { user } } = yield this.client.query(`query ($user: UserInput, $predictors: UserPredictorsInput) { | ||
const { data: { user } } = yield this.client.query({ | ||
query: `query ($user: UserInput, $predictors: UserPredictorsInput) { | ||
user (input: $user) { | ||
@@ -65,3 +69,5 @@ predictors (input: $predictors) { | ||
} | ||
}`, { user: username && { username }, predictors }); | ||
}`, | ||
variables: { user: username && { username }, predictors } | ||
}); | ||
return (_a = user === null || user === void 0 ? void 0 : user.predictors) !== null && _a !== void 0 ? _a : null; | ||
@@ -77,7 +83,10 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { predictors } } = yield this.client.query(`query ($input: PredictorsInput) { | ||
const { data: { predictors } } = yield this.client.query({ | ||
query: `query ($input: PredictorsInput) { | ||
predictors (input: $input) { | ||
${exports.PREDICTOR_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return predictors; | ||
@@ -93,7 +102,10 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { predictor } } = yield this.client.query(`mutation ($input: CreatePredictorInput!) { | ||
const { data: { predictor } } = yield this.client.query({ | ||
query: `mutation ($input: CreatePredictorInput!) { | ||
predictor: createPredictor (input: $input) { | ||
${exports.PREDICTOR_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return predictor; | ||
@@ -109,5 +121,8 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { result } } = yield this.client.query(`mutation ($input: DeletePredictorInput!) { | ||
const { data: { result } } = yield this.client.query({ | ||
query: `mutation ($input: DeletePredictorInput!) { | ||
result: deletePredictor (input: $input) | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return result; | ||
@@ -123,7 +138,10 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { predictor } } = yield this.client.query(`mutation ($input: ArchivePredictorInput!) { | ||
const { data: { predictor } } = yield this.client.query({ | ||
query: `mutation ($input: ArchivePredictorInput!) { | ||
archivePredictor (input: $input) { | ||
${exports.PREDICTOR_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return predictor; | ||
@@ -130,0 +148,0 @@ }); |
@@ -18,2 +18,3 @@ "use strict"; | ||
const base64_arraybuffer_1 = require("base64-arraybuffer"); | ||
const graph_1 = require("../graph"); | ||
class StorageService { | ||
@@ -30,5 +31,9 @@ constructor(client) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { url } } = yield this.client.query(`mutation ($input: CreateUploadUrlInput!) { | ||
const { data: { url } } = yield this.client.query({ | ||
query: `mutation ($input: CreateUploadUrlInput!) { | ||
url: createUploadUrl (input: $input) | ||
}`, { input }); | ||
}`, | ||
variables: { input }, | ||
url: `${graph_1.GraphClient.URL}/graph` | ||
}); | ||
return url; | ||
@@ -35,0 +40,0 @@ }); |
@@ -29,3 +29,4 @@ "use strict"; | ||
const username = input === null || input === void 0 ? void 0 : input.username; | ||
const { data: { user } } = yield this.client.query(`query ($input: UserInput) { | ||
const { data: { user } } = yield this.client.query({ | ||
query: `query ($input: UserInput) { | ||
user (input: $input) { | ||
@@ -35,3 +36,5 @@ ${exports.PROFILE_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return user; | ||
@@ -47,3 +50,4 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { data: { user } } = yield this.client.query(`mutation ($input: UpdateUserInput!) { | ||
const { data: { user } } = yield this.client.query({ | ||
query: `mutation ($input: UpdateUserInput!) { | ||
user: updateUser (input: $input) { | ||
@@ -53,3 +57,5 @@ ${exports.PROFILE_FIELDS} | ||
} | ||
}`, { input }); | ||
}`, | ||
variables: { input } | ||
}); | ||
return user; | ||
@@ -56,0 +62,0 @@ }); |
@@ -6,136 +6,5 @@ "use strict"; | ||
*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isTypedArray = exports.isImage = exports.isTensor = exports.isFunctionValue = exports.toPlainValue = exports.toFunctionValue = void 0; | ||
const data_urls_1 = __importDefault(require("data-urls")); | ||
const types_1 = require("../types"); | ||
exports.isTypedArray = exports.isImage = exports.isTensor = exports.isFunctionValue = void 0; | ||
/** | ||
* Convert a plain value into a Function value. | ||
* @param input Input arguments. | ||
* @returns Function value. | ||
*/ | ||
function toFunctionValue(input) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { value, name, storage, minUploadSize: dataUrlLimit = 4096, key } = input; | ||
// Null | ||
if (value === null) | ||
return { data: null, type: "null" }; | ||
// Value | ||
if (isFunctionValue(value)) | ||
return value; | ||
// Tensor | ||
if (isTensor(value)) { | ||
const data = yield storage.upload({ name, buffer: value.data.buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
const type = getTypedArrayDtype(value.data); | ||
return { data, type, shape: value.shape }; | ||
} | ||
// Typed array | ||
if (isTypedArray(value)) | ||
return yield toFunctionValue(Object.assign(Object.assign({}, input), { value: { data: value, shape: [value.length] } })); | ||
// Binary | ||
if (value instanceof ArrayBuffer) { | ||
const data = yield storage.upload({ name, buffer: value, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "binary" }; | ||
} | ||
// String | ||
if (typeof (value) === "string") { | ||
const buffer = new TextEncoder().encode(value).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "string" }; | ||
} | ||
// Number | ||
if (typeof (value) === "number") { | ||
const isInt = Number.isInteger(value); | ||
const buffer = isInt ? new Int32Array([value]).buffer : new Float32Array([value]).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
const type = isInt ? "int32" : "float32"; | ||
return { data, type, shape: [] }; | ||
} | ||
// Boolean | ||
if (typeof (value) === "boolean") { | ||
const buffer = new Uint8Array([+value]).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "bool", shape: [] }; | ||
} | ||
// Boolean array // We want benefits of `TypedArray` given that there's no `BoolArray` | ||
if (Array.isArray(value) && | ||
value.length > 0 && | ||
typeof (value[0]) === "boolean" && | ||
!value.some(e => typeof (e) !== "boolean") // fail faster for non-boolean arrays | ||
) { | ||
const buffer = new Uint8Array(value).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "bool", shape: [value.length] }; | ||
} | ||
// List | ||
if (Array.isArray(value)) { | ||
const serializedValue = JSON.stringify(value); | ||
const buffer = new TextEncoder().encode(serializedValue).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "list" }; | ||
} | ||
// Dict | ||
if (typeof (value) === "object") { | ||
const serializedValue = JSON.stringify(value); | ||
const buffer = new TextEncoder().encode(serializedValue).buffer; | ||
const data = yield storage.upload({ name, buffer, type: types_1.UploadType.Value, dataUrlLimit, key }); | ||
return { data, type: "dict" }; | ||
} | ||
// Throw | ||
throw new Error(`Value ${value} of type ${typeof (value)} cannot be converted to a Function value`); | ||
}); | ||
} | ||
exports.toFunctionValue = toFunctionValue; | ||
/** | ||
* Convert a Function value to a plain value. | ||
* If the Function value cannot be converted to a plain value, the Function value is returned as-is. | ||
* @param input Input arguments. | ||
* @returns Plain value. | ||
*/ | ||
function toPlainValue(input) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { value: { data, type, shape } } = input; | ||
// Null | ||
if (type === "null") | ||
return null; | ||
// Download | ||
const buffer = yield getValueData(data); | ||
// Tensor | ||
const ARRAY_TYPES = [ | ||
"float16", "float32", "float64", | ||
"int8", "int16", "int32", "int64", | ||
"uint8", "uint16", "uint32", "uint64" | ||
]; | ||
if (ARRAY_TYPES.includes(type)) | ||
return toTypedArrayOrNumber(buffer, type, shape); | ||
// Boolean | ||
if (type === "bool") | ||
return toBooleanArrayOrBoolean(buffer, shape); | ||
// String | ||
if (type === "string") | ||
return new TextDecoder().decode(buffer); | ||
// JSON | ||
const JSON_TYPES = ["list", "dict"]; | ||
if (JSON_TYPES.includes(type)) | ||
return JSON.parse(new TextDecoder().decode(buffer)); | ||
// Binary | ||
if (type === "binary") | ||
return buffer; | ||
// Return Function value | ||
return input.value; | ||
}); | ||
} | ||
exports.toPlainValue = toPlainValue; | ||
/** | ||
* Check whether an input value is a Function value. | ||
@@ -205,58 +74,1 @@ * @param value Input value. | ||
exports.isTypedArray = isTypedArray; | ||
function getValueData(url) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Data URL | ||
if (url.startsWith("data:")) | ||
return (0, data_urls_1.default)(url).body.buffer; | ||
// Download | ||
const response = yield fetch(url); | ||
const buffer = yield response.arrayBuffer(); | ||
return buffer; | ||
}); | ||
} | ||
function toTypedArrayOrNumber(buffer, type, shape) { | ||
const CTOR_MAP = { | ||
"float32": Float32Array, | ||
"float64": Float64Array, | ||
"int8": Int8Array, | ||
"int16": Int16Array, | ||
"int32": Int32Array, | ||
"int64": BigInt64Array, | ||
"uint8": Uint8Array, | ||
"uint16": Uint16Array, | ||
"uint32": Uint32Array, | ||
"uint64": BigUint64Array, | ||
}; | ||
const data = new CTOR_MAP[type](buffer); | ||
return shape.length > 0 ? shape.length > 1 ? { data, shape } : data : data[0]; | ||
} | ||
function toBooleanArrayOrBoolean(buffer, shape) { | ||
const tensor = new Uint8Array(buffer); | ||
const array = Array.from(tensor).map(num => num !== 0); | ||
return shape.length > 0 ? array : array[0]; | ||
} | ||
function getTypedArrayDtype(value) { | ||
if (value instanceof Float32Array) | ||
return "float32"; | ||
if (value instanceof Float64Array) | ||
return "float64"; | ||
if (value instanceof Int8Array) | ||
return "int8"; | ||
if (value instanceof Int16Array) | ||
return "int16"; | ||
if (value instanceof Int32Array) | ||
return "int32"; | ||
if (value instanceof BigInt64Array) | ||
return "int64"; | ||
if (value instanceof Uint8Array) | ||
return "uint8"; | ||
if (value instanceof Uint8ClampedArray) | ||
return "uint8"; | ||
if (value instanceof Uint16Array) | ||
return "uint16"; | ||
if (value instanceof Uint32Array) | ||
return "uint32"; | ||
if (value instanceof BigUint64Array) | ||
return "uint64"; | ||
return "binary"; | ||
} |
@@ -12,2 +12,18 @@ import { FunctionConfig } from "../client"; | ||
} | ||
export interface QueryInput { | ||
/** | ||
* GraphQL query. | ||
*/ | ||
query: string; | ||
/** | ||
* Query variables. | ||
*/ | ||
variables?: { | ||
[key: string]: any; | ||
}; | ||
/** | ||
* Graph API URL override. | ||
*/ | ||
url?: string; | ||
} | ||
/** | ||
@@ -19,2 +35,3 @@ * Function graph API client. | ||
readonly auth: string; | ||
static readonly URL: string; | ||
/** | ||
@@ -27,8 +44,4 @@ * Create a Function graph API client. | ||
* Query the Function graph API. | ||
* @param query Graph query. | ||
* @param variables Query variables. | ||
*/ | ||
query<T = any>(query: string, variables?: { | ||
[key: string]: any; | ||
}): Promise<GraphPayload<T>>; | ||
query<T = any>({ query, variables, url: urlOverride }: QueryInput): Promise<GraphPayload<T>>; | ||
} |
@@ -40,2 +40,23 @@ import { GraphClient } from "../graph"; | ||
} | ||
export interface ToValueInput { | ||
/** | ||
* Input value. | ||
*/ | ||
value: Value | PlainValue; | ||
/** | ||
* Value name. | ||
*/ | ||
name: string; | ||
/** | ||
* Value larger than this size in bytes will be uploaded. | ||
*/ | ||
minUploadSize?: number; | ||
key?: string; | ||
} | ||
export interface ToObjectInput { | ||
/** | ||
* Function value. | ||
*/ | ||
value: Value; | ||
} | ||
export declare class PredictionService { | ||
@@ -70,2 +91,15 @@ private readonly client; | ||
delete(input: DeletePredictionInput): Promise<boolean>; | ||
/** | ||
* Convert an object into a Function value. | ||
* @param input Input arguments. | ||
* @returns Function value. | ||
*/ | ||
toValue(input: ToValueInput): Promise<Value>; | ||
/** | ||
* Convert a Function value to a plain object. | ||
* If the Function value cannot be converted to a plain object, the Function value is returned as-is. | ||
* @param input Input arguments. | ||
* @returns Plain object. | ||
*/ | ||
toObject(input: ToObjectInput): Promise<PlainValue | Value>; | ||
private loadFxnc; | ||
@@ -75,4 +109,7 @@ private getConfigurationId; | ||
private predict; | ||
plainToEdgeValue(value: PlainValue | Value): number; | ||
private plainToEdgeValue; | ||
private edgeToPlainValue; | ||
private getPredictUrl; | ||
private serializeCloudInputs; | ||
private parseResults; | ||
} |
@@ -1,45 +0,3 @@ | ||
import { Image, PlainValue, Tensor, TypedArray, Value } from "../types"; | ||
import { StorageService } from "./storage"; | ||
export interface ToFunctionValueInput { | ||
/** | ||
* Input value. | ||
*/ | ||
value: Value | PlainValue; | ||
/** | ||
* Value name. | ||
*/ | ||
name: string; | ||
/** | ||
* Storage service for uploading the value. | ||
*/ | ||
storage: StorageService; | ||
/** | ||
* Value larger than this size in bytes will be uploaded. | ||
*/ | ||
minUploadSize?: number; | ||
/** | ||
* Unused. | ||
*/ | ||
key?: string; | ||
} | ||
export interface ToPlainValueInput { | ||
/** | ||
* Input Function value. | ||
*/ | ||
value: Value; | ||
} | ||
import { Image, Tensor, TypedArray, Value } from "../types"; | ||
/** | ||
* Convert a plain value into a Function value. | ||
* @param input Input arguments. | ||
* @returns Function value. | ||
*/ | ||
export declare function toFunctionValue(input: ToFunctionValueInput): Promise<Value>; | ||
/** | ||
* Convert a Function value to a plain value. | ||
* If the Function value cannot be converted to a plain value, the Function value is returned as-is. | ||
* @param input Input arguments. | ||
* @returns Plain value. | ||
*/ | ||
export declare function toPlainValue(input: ToPlainValueInput): Promise<PlainValue | Value>; | ||
/** | ||
* Check whether an input value is a Function value. | ||
@@ -46,0 +4,0 @@ * @param value Input value. |
{ | ||
"name": "fxnjs", | ||
"version": "0.0.27", | ||
"version": "0.0.28", | ||
"description": "Run AI prediction functions in your JavaScript and Node.js apps.", | ||
@@ -5,0 +5,0 @@ "scripts": { |
Sorry, the diff of this file is too big to display
689135
55594