import AIServerZoo from './aiserverzoo.js';
import AIServerCloudZoo from './aiservercloudzoo.js';
import CloudServerCloudZoo from './cloudservercloudzoo.js';
import DGError from './dgerror.js';
const defaultLocalhostIP = 'localhost:8779';
/**
* @class
* @classdesc This class is the entrypoint for DeGirumJS, responsible for creating AIServerZoo / AIServerCloudZoo / CloudServerCloudZoo instances.
*
* @example <caption>Usage:</caption>
* let dg = new dg_sdk();
* let zoo = dg.connect('ws://localhost:8779', 'https://cs.degirum.com/degirum/public', secretToken);
*/
class dg_sdk {
constructor() {
// console.log('Entered dg_sdk constructor');
}
/**
* Connects to an AI Server or Cloud model zoo based on the provided parameters.
*
* This method supports three modes of inference:<br>
* 1. AIServer inference with AIServer model zoo.<br>
* 2. AIServer inference with Cloud model zoo.<br>
* 3. Cloud inference with Cloud model zoo.<br>
* Dummy flag is used for creating AIServerCloudZoo instances that only need to have model listing functionality.
* This is useful for page elements or testing that need to display the model / zoo lists without connecting to any AIServer.
*
* @example <caption>AIServer inference with AIServer model zoo:</caption>
* let zoo = dg.connect('ws://localhost:8779');
* @example <caption>AIServer inference with Cloud model zoo:</caption>
* let zoo = dg.connect('ws://localhost:8779', 'https://cs.degirum.com/degirum/public', secretToken);
* @example <caption>Cloud inference with Cloud model zoo:</caption>
* let zoo = dg.connect('cloud', 'https://cs.degirum.com/degirum/public', secretToken);
* @param {string} dest - The destination address or alias ('cloud' for cloud inference).
* @param {string} [zooUrl=null] - The URL of the cloud model zoo (required for cloud model access in AIServerCloudZoo / CloudServerCloudZoo inference).
* @param {string} [token=null] - The authentication token for the model zoo (required for cloud model access).
* @param {boolean} [isDummy=false] - Flag to indicate if a dummy zoo instance should be created.
* @returns {AIServerZoo|AIServerCloudZoo|CloudServerCloudZoo} - An instance of the appropriate zoo class based on the parameters.
*/
connect(dest, zooUrl = null, token = null, isDummy = false) {
// Input validation for destination
if (typeof dest !== 'string') {
throw new DGError('Invalid destination format. Expected string.', 'INVALID_DESTINATION_FORMAT', { dest: dest }, 'Invalid destination format.', 'Please provide a destination in string format.');
}
let cloudInferenceRequested = ['cloud', 'CLOUD', 'Cloud'].includes(dest);
let zooTokenExist = zooUrl !== null && zooUrl !== '' && token !== null && token !== '';
// If both zooUrl and token exist, and dest is not 'cloud'
if (zooTokenExist && !cloudInferenceRequested) {
// AIServer inference, Cloud model zoo
console.log('dg_sdk: Preparing AI Server inference on Cloud model zoo');
// Validate zooUrl
if (!this.isValidZooUrl(zooUrl)) {
throw new DGError('Invalid zooUrl format. Example formats: "https://foo.bar.com/path" or "https://foobar.com".', 'INVALID_ZOOURL_FORMAT', { zooUrl: zooUrl }, 'Invalid zooUrl format.', 'Please provide a zooUrl in the correct format.');
}
// 1. Prepare the websocket string
let wsAddress = this.prepareWebSocketAddress(dest);
// 2. Prepare the website string
let websiteAddress = this.prepareWebsiteAddress(zooUrl);
// 3. Return the AIServerCloudZoo instance
return new AIServerCloudZoo(wsAddress, websiteAddress, token, isDummy);
} else if (zooTokenExist && cloudInferenceRequested) {
// Cloud inference, Cloud model zoo
console.log('dg_sdk: Preparing Cloud inference on Cloud model zoo');
// Validate zooUrl
if (!this.isValidZooUrl(zooUrl)) {
throw new DGError('Invalid zooUrl format. Example formats: "https://foo.bar.com/path" or "https://foobar.com".', 'INVALID_ZOOURL_FORMAT', { zooUrl: zooUrl }, 'Invalid zooUrl format.', 'Please provide a zooUrl in the correct format.');
}
// 1. Prepare the website string
let websiteAddress = this.prepareWebsiteAddress(zooUrl);
// 2. Return the CloudServerCloudZoo instance
return new CloudServerCloudZoo(websiteAddress, token, isDummy);
}
if (cloudInferenceRequested) {
throw new DGError('Cloud inference requested but zooUrl and token are missing.', 'MISSING_ZOOURL_OR_TOKEN', { dest: dest, zooUrl: zooUrl, token: token }, 'Missing zooUrl or token.', 'Please provide a zooUrl and token for cloud inference.');
}
// Otherwise, we use AIServerZoo
console.log('dg_sdk: Preparing AI Server inference on AI Server model zoo');
const wsAddress = this.prepareWebSocketAddress(dest);
return new AIServerZoo(wsAddress);
}
/**
* Gets the list of supported devices for inference as a list of "RUNTIME/DEVICE" strings.
* @param {string} inferenceHostAddress - The address of the inference host, either an AIServer IP address or 'cloud'
* @returns {Promise<string[]>} - A promise that resolves with the list of supported runtime/device strings.
*/
async getSupportedDevices(inferenceHostAddress) {
// Input validation for inferenceHostAddress
if (typeof inferenceHostAddress !== 'string' || inferenceHostAddress === '') {
throw new DGError('Invalid inferenceHostAddress format. Expected string.', 'INVALID_INFERENCEHOSTADDRESS_FORMAT', { inferenceHostAddress: inferenceHostAddress }, 'Invalid inferenceHostAddress format.', 'Please provide an inferenceHostAddress in string format.');
}
let cloudInferenceRequested = ['cloud', 'CLOUD', 'Cloud'].includes(inferenceHostAddress);
if (cloudInferenceRequested) {
// Create dummy instance of CloudServerCloudZoo and return supported devices.
let cloudZoo = new CloudServerCloudZoo('https://cs.degirum.com/public', '', true);
return cloudZoo.systemSupportedDeviceTypes();
}
// Otherwise, we use AIServerZoo
const wsAddress = this.prepareWebSocketAddress(inferenceHostAddress);
let aiZoo = new AIServerZoo(wsAddress);
return aiZoo.systemSupportedDeviceTypes();
}
/**
* Prepares the WebSocket address based on the destination.
* @private
* @param {string} dest - The destination address.
* @returns {string} - The prepared WebSocket address.
*/
prepareWebSocketAddress(dest) {
dest = dest.replace(/^(http:\/\/|https:\/\/|ws:\/\/|wss:\/\/)/, '');
if (['localhost', 'local', 'LOCALHOST', 'LOCAL'].includes(dest)) {
dest = defaultLocalhostIP; // Default for the AI Server
}
const ipPortPattern = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):\d+$/;
const domainPortPattern = /^([a-zA-Z0-9\-\.]+):\d+$/;
if (!ipPortPattern.test(dest) && !domainPortPattern.test(dest) && dest !== defaultLocalhostIP) {
throw new DGError('Invalid address or missing port. Use the format "address:port", "ip:port", or use "localhost" or "local".', 'INVALID_ADDRESS_OR_PORT', { dest: dest }, 'Invalid address or missing port.', 'Please provide an address in the correct format.');
}
return `ws://${dest}`;
}
/**
* Prepares the website address based on the zoo URL.
* @private
*
* @param {string} zooUrl - The URL of the model zoo.
* @returns {string} - The prepared website address.
*/
prepareWebsiteAddress(zooUrl) {
zooUrl = zooUrl.endsWith('/') ? zooUrl.slice(0, -1) : zooUrl; // Remove trailing slash if present
if (!zooUrl.startsWith('http://') && !zooUrl.startsWith('https://')) {
zooUrl = 'https://' + zooUrl;
}
return zooUrl;
}
/**
* Prepares the website address based on the zoo URL.
* @private
*
* @param {string} zooUrl - The URL of the model zoo.
* @returns {string} - The prepared website address.
*/
isValidZooUrl(zooUrl) {
try {
// The URL constructor will throw an error if zooUrl is not a valid URL
new URL(zooUrl);
return true;
} catch (error) {
return false;
}
}
}
export default dg_sdk;