@aws/ml-container-creator 0.2.0
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/LICENSE +202 -0
- package/LICENSE-THIRD-PARTY +68620 -0
- package/NOTICE +2 -0
- package/README.md +106 -0
- package/bin/cli.js +365 -0
- package/config/defaults.json +32 -0
- package/config/presets/transformers-djl.json +26 -0
- package/config/presets/transformers-gpu.json +24 -0
- package/config/presets/transformers-lmi.json +27 -0
- package/package.json +129 -0
- package/servers/README.md +419 -0
- package/servers/base-image-picker/catalogs/model-servers.json +1191 -0
- package/servers/base-image-picker/catalogs/python-slim.json +38 -0
- package/servers/base-image-picker/catalogs/triton-backends.json +51 -0
- package/servers/base-image-picker/catalogs/triton.json +38 -0
- package/servers/base-image-picker/index.js +495 -0
- package/servers/base-image-picker/manifest.json +17 -0
- package/servers/base-image-picker/package.json +15 -0
- package/servers/hyperpod-cluster-picker/LICENSE +202 -0
- package/servers/hyperpod-cluster-picker/index.js +424 -0
- package/servers/hyperpod-cluster-picker/manifest.json +14 -0
- package/servers/hyperpod-cluster-picker/package.json +17 -0
- package/servers/instance-recommender/LICENSE +202 -0
- package/servers/instance-recommender/catalogs/instances.json +852 -0
- package/servers/instance-recommender/index.js +284 -0
- package/servers/instance-recommender/manifest.json +16 -0
- package/servers/instance-recommender/package.json +15 -0
- package/servers/lib/LICENSE +202 -0
- package/servers/lib/bedrock-client.js +160 -0
- package/servers/lib/custom-validators.js +46 -0
- package/servers/lib/dynamic-resolver.js +36 -0
- package/servers/lib/package.json +11 -0
- package/servers/lib/schemas/image-catalog.schema.json +185 -0
- package/servers/lib/schemas/instances.schema.json +124 -0
- package/servers/lib/schemas/manifest.schema.json +64 -0
- package/servers/lib/schemas/model-catalog.schema.json +91 -0
- package/servers/lib/schemas/regions.schema.json +26 -0
- package/servers/lib/schemas/triton-backends.schema.json +51 -0
- package/servers/model-picker/catalogs/jumpstart-public.json +66 -0
- package/servers/model-picker/catalogs/popular-diffusors.json +88 -0
- package/servers/model-picker/catalogs/popular-transformers.json +226 -0
- package/servers/model-picker/index.js +1693 -0
- package/servers/model-picker/manifest.json +18 -0
- package/servers/model-picker/package.json +20 -0
- package/servers/region-picker/LICENSE +202 -0
- package/servers/region-picker/catalogs/regions.json +263 -0
- package/servers/region-picker/index.js +230 -0
- package/servers/region-picker/manifest.json +16 -0
- package/servers/region-picker/package.json +15 -0
- package/src/app.js +1007 -0
- package/src/copy-tpl.js +77 -0
- package/src/lib/accelerator-validator.js +39 -0
- package/src/lib/asset-manager.js +385 -0
- package/src/lib/aws-profile-parser.js +181 -0
- package/src/lib/bootstrap-command-handler.js +1647 -0
- package/src/lib/bootstrap-config.js +238 -0
- package/src/lib/ci-register-helpers.js +124 -0
- package/src/lib/ci-report-helpers.js +158 -0
- package/src/lib/ci-stage-helpers.js +268 -0
- package/src/lib/cli-handler.js +529 -0
- package/src/lib/comment-generator.js +544 -0
- package/src/lib/community-reports-validator.js +91 -0
- package/src/lib/config-manager.js +2106 -0
- package/src/lib/configuration-exporter.js +204 -0
- package/src/lib/configuration-manager.js +695 -0
- package/src/lib/configuration-matcher.js +221 -0
- package/src/lib/cpu-validator.js +36 -0
- package/src/lib/cuda-validator.js +57 -0
- package/src/lib/deployment-config-resolver.js +103 -0
- package/src/lib/deployment-entry-schema.js +125 -0
- package/src/lib/deployment-registry.js +598 -0
- package/src/lib/docker-introspection-validator.js +51 -0
- package/src/lib/engine-prefix-resolver.js +60 -0
- package/src/lib/huggingface-client.js +172 -0
- package/src/lib/key-value-parser.js +37 -0
- package/src/lib/known-flags-validator.js +200 -0
- package/src/lib/manifest-cli.js +280 -0
- package/src/lib/mcp-client.js +303 -0
- package/src/lib/mcp-command-handler.js +532 -0
- package/src/lib/neuron-validator.js +80 -0
- package/src/lib/parameter-schema-validator.js +284 -0
- package/src/lib/prompt-runner.js +1349 -0
- package/src/lib/prompts.js +1138 -0
- package/src/lib/registry-command-handler.js +519 -0
- package/src/lib/registry-loader.js +198 -0
- package/src/lib/rocm-validator.js +80 -0
- package/src/lib/schema-validator.js +157 -0
- package/src/lib/sensitive-redactor.js +59 -0
- package/src/lib/template-engine.js +156 -0
- package/src/lib/template-manager.js +341 -0
- package/src/lib/validation-engine.js +314 -0
- package/src/prompt-adapter.js +63 -0
- package/templates/Dockerfile +300 -0
- package/templates/IAM_PERMISSIONS.md +84 -0
- package/templates/MIGRATION.md +488 -0
- package/templates/PROJECT_README.md +439 -0
- package/templates/TEMPLATE_SYSTEM.md +243 -0
- package/templates/buildspec.yml +64 -0
- package/templates/code/chat_template.jinja +1 -0
- package/templates/code/flask/gunicorn_config.py +35 -0
- package/templates/code/flask/wsgi.py +10 -0
- package/templates/code/model_handler.py +387 -0
- package/templates/code/serve +300 -0
- package/templates/code/serve.py +175 -0
- package/templates/code/serving.properties +105 -0
- package/templates/code/start_server.py +39 -0
- package/templates/code/start_server.sh +39 -0
- package/templates/diffusors/Dockerfile +72 -0
- package/templates/diffusors/patch_image_api.py +35 -0
- package/templates/diffusors/serve +115 -0
- package/templates/diffusors/start_server.sh +114 -0
- package/templates/do/.gitkeep +1 -0
- package/templates/do/README.md +541 -0
- package/templates/do/build +83 -0
- package/templates/do/ci +681 -0
- package/templates/do/clean +811 -0
- package/templates/do/config +260 -0
- package/templates/do/deploy +1560 -0
- package/templates/do/export +306 -0
- package/templates/do/logs +319 -0
- package/templates/do/manifest +12 -0
- package/templates/do/push +119 -0
- package/templates/do/register +580 -0
- package/templates/do/run +113 -0
- package/templates/do/submit +417 -0
- package/templates/do/test +1147 -0
- package/templates/hyperpod/configmap.yaml +24 -0
- package/templates/hyperpod/deployment.yaml +71 -0
- package/templates/hyperpod/pvc.yaml +42 -0
- package/templates/hyperpod/service.yaml +17 -0
- package/templates/nginx-diffusors.conf +74 -0
- package/templates/nginx-predictors.conf +47 -0
- package/templates/nginx-tensorrt.conf +74 -0
- package/templates/requirements.txt +61 -0
- package/templates/sample_model/test_inference.py +123 -0
- package/templates/sample_model/train_abalone.py +252 -0
- package/templates/test/test_endpoint.sh +79 -0
- package/templates/test/test_local_image.sh +80 -0
- package/templates/test/test_model_handler.py +180 -0
- package/templates/triton/Dockerfile +128 -0
- package/templates/triton/config.pbtxt +163 -0
- package/templates/triton/model.py +130 -0
- package/templates/triton/requirements.txt +11 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Manager
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates configuration loading, matching, and merging for the multi-registry system.
|
|
5
|
+
* Handles framework configurations, model-specific overrides, and HuggingFace API integration.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: 1.7, 2.1, 2.2, 2.3, 2.4, 4.1, 4.2, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import RegistryLoader from './registry-loader.js';
|
|
11
|
+
import ConfigurationMatcher from './configuration-matcher.js';
|
|
12
|
+
import ValidationEngine from './validation-engine.js';
|
|
13
|
+
import HuggingFaceClient from './huggingface-client.js';
|
|
14
|
+
|
|
15
|
+
export default class ConfigurationManager {
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.registryLoader = new RegistryLoader();
|
|
18
|
+
this.validationEngine = new ValidationEngine();
|
|
19
|
+
this.hfClient = new HuggingFaceClient({
|
|
20
|
+
timeout: options.hfTimeout || 5000,
|
|
21
|
+
offline: options.offline || false
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Registries (loaded on demand)
|
|
25
|
+
this.frameworkRegistry = null;
|
|
26
|
+
this.modelRegistry = null;
|
|
27
|
+
this.instanceMapping = null;
|
|
28
|
+
|
|
29
|
+
// Configuration matcher (initialized after registries load)
|
|
30
|
+
this.configMatcher = null;
|
|
31
|
+
|
|
32
|
+
// Validation options
|
|
33
|
+
this.validateEnvVars = options.validateEnvVars ?? true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Load all registries from disk
|
|
38
|
+
* Gracefully handles missing or invalid registries by using empty objects
|
|
39
|
+
*
|
|
40
|
+
* Requirements: 1.7, 2.8
|
|
41
|
+
*/
|
|
42
|
+
async loadRegistries() {
|
|
43
|
+
this.frameworkRegistry = await this.registryLoader.loadFrameworkRegistry();
|
|
44
|
+
this.modelRegistry = await this.registryLoader.loadModelRegistry();
|
|
45
|
+
this.instanceMapping = await this.registryLoader.loadInstanceAcceleratorMapping();
|
|
46
|
+
|
|
47
|
+
// Initialize configuration matcher with loaded registries
|
|
48
|
+
this.configMatcher = new ConfigurationMatcher(
|
|
49
|
+
this.frameworkRegistry,
|
|
50
|
+
this.modelRegistry
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find best matching configuration for user selections
|
|
56
|
+
* Orchestrates matching across framework, model, and HuggingFace sources
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} userSelections - User's configuration choices
|
|
59
|
+
* @param {string} userSelections.framework - Framework name (e.g., "vllm")
|
|
60
|
+
* @param {string} userSelections.version - Framework version (e.g., "0.3.0")
|
|
61
|
+
* @param {string} [userSelections.modelId] - Optional model ID
|
|
62
|
+
* @param {string} [userSelections.frameworkProfile] - Optional framework profile name
|
|
63
|
+
* @param {string} [userSelections.modelProfile] - Optional model profile name
|
|
64
|
+
* @returns {Promise<Object>} Matched configuration profile
|
|
65
|
+
*
|
|
66
|
+
* Requirements: 2.1, 2.2, 2.3, 5.1, 5.2, 5.3, 12.1, 12.2
|
|
67
|
+
*/
|
|
68
|
+
async matchConfiguration(userSelections) {
|
|
69
|
+
// Ensure registries are loaded
|
|
70
|
+
if (!this.configMatcher) {
|
|
71
|
+
await this.loadRegistries();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Match framework configuration
|
|
75
|
+
const frameworkConfig = this.configMatcher.matchFramework(
|
|
76
|
+
userSelections.framework,
|
|
77
|
+
userSelections.version
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Get framework profile if specified
|
|
81
|
+
let frameworkProfile = null;
|
|
82
|
+
if (userSelections.frameworkProfile && frameworkConfig?.profiles) {
|
|
83
|
+
frameworkProfile = frameworkConfig.profiles[userSelections.frameworkProfile];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Match model configuration (if model ID provided)
|
|
87
|
+
let modelConfig = null;
|
|
88
|
+
let hfData = null;
|
|
89
|
+
|
|
90
|
+
if (userSelections.modelId) {
|
|
91
|
+
// Try HuggingFace API first
|
|
92
|
+
hfData = await this._fetchHuggingFaceData(userSelections.modelId);
|
|
93
|
+
|
|
94
|
+
// Check model registry for overrides
|
|
95
|
+
modelConfig = this.configMatcher.matchModel(userSelections.modelId);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Get model profile if specified
|
|
99
|
+
let modelProfile = null;
|
|
100
|
+
if (userSelections.modelProfile && modelConfig?.profiles) {
|
|
101
|
+
modelProfile = modelConfig.profiles[userSelections.modelProfile];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Merge all configurations
|
|
105
|
+
return this.mergeConfigurations({
|
|
106
|
+
frameworkConfig,
|
|
107
|
+
frameworkProfile,
|
|
108
|
+
hfData,
|
|
109
|
+
modelConfig,
|
|
110
|
+
modelProfile,
|
|
111
|
+
userSelections
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Merge configurations with correct priority order
|
|
117
|
+
* Priority (highest to lowest): model profile → model config → HF data → framework profile → framework base
|
|
118
|
+
*
|
|
119
|
+
* @param {Object} configs - Configuration sources
|
|
120
|
+
* @param {Object} configs.frameworkConfig - Base framework configuration
|
|
121
|
+
* @param {Object} [configs.frameworkProfile] - Framework profile configuration
|
|
122
|
+
* @param {Object} [configs.hfData] - HuggingFace API data
|
|
123
|
+
* @param {Object} [configs.modelConfig] - Model registry configuration
|
|
124
|
+
* @param {Object} [configs.modelProfile] - Model profile configuration
|
|
125
|
+
* @param {Object} configs.userSelections - User selections
|
|
126
|
+
* @returns {Object} Merged configuration profile
|
|
127
|
+
*
|
|
128
|
+
* Requirements: 1.7, 5.3, 12.6, 12.13
|
|
129
|
+
*/
|
|
130
|
+
mergeConfigurations(configs) {
|
|
131
|
+
const {
|
|
132
|
+
frameworkConfig,
|
|
133
|
+
frameworkProfile,
|
|
134
|
+
hfData,
|
|
135
|
+
modelConfig,
|
|
136
|
+
modelProfile,
|
|
137
|
+
userSelections
|
|
138
|
+
} = configs;
|
|
139
|
+
|
|
140
|
+
// Start with empty configuration (graceful degradation)
|
|
141
|
+
const merged = {
|
|
142
|
+
// User selections (always preserved)
|
|
143
|
+
framework: userSelections?.framework || null,
|
|
144
|
+
version: userSelections?.version || null,
|
|
145
|
+
modelId: userSelections?.modelId || null,
|
|
146
|
+
|
|
147
|
+
// Configuration fields (will be populated if sources available)
|
|
148
|
+
baseImage: null,
|
|
149
|
+
accelerator: null,
|
|
150
|
+
envVars: {},
|
|
151
|
+
inferenceAmiVersion: null,
|
|
152
|
+
chatTemplate: null,
|
|
153
|
+
recommendedInstanceTypes: [],
|
|
154
|
+
|
|
155
|
+
// Metadata
|
|
156
|
+
configSources: [],
|
|
157
|
+
validationLevel: 'unknown',
|
|
158
|
+
matchType: null,
|
|
159
|
+
generatedAt: new Date().toISOString()
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Apply configurations in priority order (lowest to highest)
|
|
163
|
+
|
|
164
|
+
// 1. Framework base configuration
|
|
165
|
+
if (frameworkConfig) {
|
|
166
|
+
this._applyFrameworkConfig(merged, frameworkConfig);
|
|
167
|
+
merged.configSources.push('Framework_Registry');
|
|
168
|
+
merged.validationLevel = frameworkConfig.validationLevel || 'unknown';
|
|
169
|
+
merged.matchType = frameworkConfig.matchType;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 2. Framework profile
|
|
173
|
+
if (frameworkProfile) {
|
|
174
|
+
this._applyProfileConfig(merged, frameworkProfile);
|
|
175
|
+
merged.configSources.push('Framework_Profile');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 3. HuggingFace API data
|
|
179
|
+
if (hfData) {
|
|
180
|
+
this._applyHuggingFaceData(merged, hfData);
|
|
181
|
+
merged.configSources.push('HuggingFace_Hub_API');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 4. Model registry configuration
|
|
185
|
+
if (modelConfig) {
|
|
186
|
+
this._applyModelConfig(merged, modelConfig);
|
|
187
|
+
merged.configSources.push('Model_Registry');
|
|
188
|
+
// Model registry can override validation level
|
|
189
|
+
if (modelConfig.validationLevel) {
|
|
190
|
+
merged.validationLevel = modelConfig.validationLevel;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 5. Model profile (highest priority)
|
|
195
|
+
if (modelProfile) {
|
|
196
|
+
this._applyProfileConfig(merged, modelProfile);
|
|
197
|
+
merged.configSources.push('Model_Profile');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// If no sources provided configuration, mark as default
|
|
201
|
+
if (merged.configSources.length === 0) {
|
|
202
|
+
merged.configSources.push('Default');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return merged;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Validate instance type against framework requirements
|
|
210
|
+
*
|
|
211
|
+
* @param {string} instanceType - Instance type to validate
|
|
212
|
+
* @param {Object} frameworkConfig - Framework configuration with accelerator requirements
|
|
213
|
+
* @returns {Object} Validation result
|
|
214
|
+
* @returns {boolean} result.compatible - Whether instance is compatible
|
|
215
|
+
* @returns {string} [result.error] - Error message if incompatible
|
|
216
|
+
* @returns {string} [result.warning] - Warning message if issues detected
|
|
217
|
+
* @returns {string} [result.info] - Informational message
|
|
218
|
+
* @returns {Array<string>} [result.recommendations] - Recommended instance types
|
|
219
|
+
*
|
|
220
|
+
* Requirements: 4.1, 4.2, 4.7, 4.8, 4.10, 4.11, 4.12, 4.13, 4.14, 4.15
|
|
221
|
+
*/
|
|
222
|
+
validateInstanceType(instanceType, frameworkConfig) {
|
|
223
|
+
// Ensure registries are loaded
|
|
224
|
+
if (!this.instanceMapping) {
|
|
225
|
+
return {
|
|
226
|
+
compatible: true,
|
|
227
|
+
warning: 'Instance accelerator mapping not loaded. Proceeding without validation.'
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Get instance configuration
|
|
232
|
+
const instanceConfig = this.instanceMapping[instanceType];
|
|
233
|
+
|
|
234
|
+
if (!instanceConfig) {
|
|
235
|
+
return {
|
|
236
|
+
compatible: true,
|
|
237
|
+
warning: `No accelerator data for ${instanceType}. Proceeding with best-effort validation.`
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Validate accelerator compatibility
|
|
242
|
+
if (!frameworkConfig?.accelerator) {
|
|
243
|
+
return {
|
|
244
|
+
compatible: true,
|
|
245
|
+
info: 'No accelerator requirements specified for framework.'
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const validation = this.validationEngine.validateAcceleratorCompatibility(
|
|
250
|
+
frameworkConfig,
|
|
251
|
+
instanceConfig
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
// Add recommendations if incompatible
|
|
255
|
+
if (!validation.compatible && frameworkConfig.accelerator) {
|
|
256
|
+
const recommendations = this.validationEngine.getRecommendedInstanceTypes(
|
|
257
|
+
frameworkConfig,
|
|
258
|
+
this.instanceMapping
|
|
259
|
+
);
|
|
260
|
+
validation.recommendations = recommendations.map(r => r.instanceType);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return validation;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Validate environment variables using validation engine
|
|
268
|
+
*
|
|
269
|
+
* @param {Object} envVars - Environment variables to validate
|
|
270
|
+
* @param {Object} frameworkConfig - Framework configuration
|
|
271
|
+
* @returns {Object} Validation result
|
|
272
|
+
* @returns {Array<Object>} result.errors - Validation errors
|
|
273
|
+
* @returns {Array<Object>} result.warnings - Validation warnings
|
|
274
|
+
* @returns {Array<string>} result.strategiesUsed - Validation strategies used
|
|
275
|
+
*
|
|
276
|
+
* Requirements: 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8
|
|
277
|
+
*/
|
|
278
|
+
validateEnvironmentVariables(envVars, frameworkConfig) {
|
|
279
|
+
return this.validationEngine.validateEnvironmentVariables(
|
|
280
|
+
envVars,
|
|
281
|
+
frameworkConfig,
|
|
282
|
+
{
|
|
283
|
+
enabled: this.validateEnvVars,
|
|
284
|
+
useKnownFlags: true,
|
|
285
|
+
useCommunityReports: true,
|
|
286
|
+
useDockerIntrospection: false
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Fetch model data from HuggingFace Hub API
|
|
293
|
+
* Gracefully handles failures by returning null
|
|
294
|
+
*
|
|
295
|
+
* @param {string} modelId - Model ID
|
|
296
|
+
* @returns {Promise<Object|null>} Model data or null
|
|
297
|
+
* @private
|
|
298
|
+
*/
|
|
299
|
+
async _fetchHuggingFaceData(modelId) {
|
|
300
|
+
try {
|
|
301
|
+
// Fetch metadata
|
|
302
|
+
const metadata = await this.hfClient.fetchModelMetadata(modelId);
|
|
303
|
+
|
|
304
|
+
// Fetch tokenizer config for chat template
|
|
305
|
+
const tokenizerConfig = await this.hfClient.fetchTokenizerConfig(modelId);
|
|
306
|
+
|
|
307
|
+
// Fetch model config for architecture
|
|
308
|
+
const modelConfig = await this.hfClient.fetchModelConfig(modelId);
|
|
309
|
+
|
|
310
|
+
// Combine data
|
|
311
|
+
if (!metadata && !tokenizerConfig && !modelConfig) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
metadata,
|
|
317
|
+
tokenizerConfig,
|
|
318
|
+
modelConfig,
|
|
319
|
+
chatTemplate: tokenizerConfig?.chat_template || null
|
|
320
|
+
};
|
|
321
|
+
} catch (error) {
|
|
322
|
+
// Graceful fallback
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Apply framework configuration to merged config
|
|
329
|
+
* @private
|
|
330
|
+
*/
|
|
331
|
+
_applyFrameworkConfig(merged, frameworkConfig) {
|
|
332
|
+
if (frameworkConfig.baseImage) {
|
|
333
|
+
merged.baseImage = frameworkConfig.baseImage;
|
|
334
|
+
}
|
|
335
|
+
if (frameworkConfig.accelerator) {
|
|
336
|
+
merged.accelerator = { ...frameworkConfig.accelerator };
|
|
337
|
+
}
|
|
338
|
+
if (frameworkConfig.envVars) {
|
|
339
|
+
merged.envVars = { ...merged.envVars, ...frameworkConfig.envVars };
|
|
340
|
+
}
|
|
341
|
+
if (frameworkConfig.inferenceAmiVersion) {
|
|
342
|
+
merged.inferenceAmiVersion = frameworkConfig.inferenceAmiVersion;
|
|
343
|
+
}
|
|
344
|
+
if (frameworkConfig.recommendedInstanceTypes) {
|
|
345
|
+
merged.recommendedInstanceTypes = [...frameworkConfig.recommendedInstanceTypes];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Apply profile configuration to merged config
|
|
351
|
+
* @private
|
|
352
|
+
*/
|
|
353
|
+
_applyProfileConfig(merged, profileConfig) {
|
|
354
|
+
if (profileConfig.envVars) {
|
|
355
|
+
merged.envVars = { ...merged.envVars, ...profileConfig.envVars };
|
|
356
|
+
}
|
|
357
|
+
if (profileConfig.recommendedInstanceTypes) {
|
|
358
|
+
merged.recommendedInstanceTypes = [...profileConfig.recommendedInstanceTypes];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Apply HuggingFace data to merged config
|
|
364
|
+
* @private
|
|
365
|
+
*/
|
|
366
|
+
_applyHuggingFaceData(merged, hfData) {
|
|
367
|
+
if (hfData.chatTemplate) {
|
|
368
|
+
merged.chatTemplate = hfData.chatTemplate;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Apply model configuration to merged config
|
|
374
|
+
* @private
|
|
375
|
+
*/
|
|
376
|
+
_applyModelConfig(merged, modelConfig) {
|
|
377
|
+
if (modelConfig.chatTemplate) {
|
|
378
|
+
merged.chatTemplate = modelConfig.chatTemplate;
|
|
379
|
+
}
|
|
380
|
+
if (modelConfig.envVars) {
|
|
381
|
+
merged.envVars = { ...merged.envVars, ...modelConfig.envVars };
|
|
382
|
+
}
|
|
383
|
+
if (modelConfig.recommendedInstanceTypes) {
|
|
384
|
+
merged.recommendedInstanceTypes = [...modelConfig.recommendedInstanceTypes];
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Export configuration for community contribution
|
|
390
|
+
* Creates a shareable configuration entry in the correct format for the appropriate registry
|
|
391
|
+
*
|
|
392
|
+
* @param {Object} config - Configuration profile to export
|
|
393
|
+
* @param {Object} options - Export options
|
|
394
|
+
* @param {string} [options.testingNotes] - User's testing notes
|
|
395
|
+
* @param {string} [options.instanceType] - Instance type used for testing
|
|
396
|
+
* @param {boolean} [options.deploymentSuccess] - Whether deployment was successful
|
|
397
|
+
* @param {boolean} [options.inferenceSuccess] - Whether inference worked correctly
|
|
398
|
+
* @param {string} [options.testerName] - Name/handle of tester (optional)
|
|
399
|
+
* @returns {Object} Export result with configuration entry and submission instructions
|
|
400
|
+
* @returns {string} result.registryType - "framework" or "model"
|
|
401
|
+
* @returns {Object} result.configEntry - Configuration entry in registry format
|
|
402
|
+
* @returns {string} result.submissionInstructions - Instructions for submitting
|
|
403
|
+
* @returns {Object} result.metadata - Export metadata
|
|
404
|
+
*
|
|
405
|
+
* Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6
|
|
406
|
+
*/
|
|
407
|
+
exportConfiguration(config, options = {}) {
|
|
408
|
+
const {
|
|
409
|
+
testingNotes = '',
|
|
410
|
+
instanceType = null,
|
|
411
|
+
deploymentSuccess = false,
|
|
412
|
+
inferenceSuccess = false,
|
|
413
|
+
testerName = 'Anonymous'
|
|
414
|
+
} = options;
|
|
415
|
+
|
|
416
|
+
// Determine registry type based on configuration
|
|
417
|
+
const registryType = this._determineRegistryType(config);
|
|
418
|
+
|
|
419
|
+
// Create configuration entry
|
|
420
|
+
const configEntry = this._createConfigEntry(config, {
|
|
421
|
+
testingNotes,
|
|
422
|
+
instanceType,
|
|
423
|
+
deploymentSuccess,
|
|
424
|
+
inferenceSuccess,
|
|
425
|
+
testerName
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Generate submission instructions
|
|
429
|
+
const submissionInstructions = this._generateSubmissionInstructions(
|
|
430
|
+
registryType,
|
|
431
|
+
config,
|
|
432
|
+
configEntry
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
// Create metadata
|
|
436
|
+
const metadata = {
|
|
437
|
+
generatorVersion: this._getGeneratorVersion(),
|
|
438
|
+
exportedAt: new Date().toISOString(),
|
|
439
|
+
configSource: config.configSources?.join(', ') || 'Unknown',
|
|
440
|
+
validationLevel: config.validationLevel || 'experimental',
|
|
441
|
+
testerName,
|
|
442
|
+
instanceType,
|
|
443
|
+
deploymentSuccess,
|
|
444
|
+
inferenceSuccess
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
registryType,
|
|
449
|
+
configEntry,
|
|
450
|
+
submissionInstructions,
|
|
451
|
+
metadata
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Determine which registry type this configuration should be exported to
|
|
457
|
+
* @private
|
|
458
|
+
*/
|
|
459
|
+
_determineRegistryType(config) {
|
|
460
|
+
// If model ID is present and model-specific overrides exist, export to Model_Registry
|
|
461
|
+
if (config.modelId && (config.chatTemplate || config.configSources?.includes('Model_Registry'))) {
|
|
462
|
+
return 'model';
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Otherwise, export to Framework_Registry
|
|
466
|
+
return 'framework';
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Create configuration entry in registry format
|
|
471
|
+
* @private
|
|
472
|
+
*/
|
|
473
|
+
_createConfigEntry(config, testingInfo) {
|
|
474
|
+
if (this._determineRegistryType(config) === 'framework') {
|
|
475
|
+
return this._createFrameworkEntry(config, testingInfo);
|
|
476
|
+
} else {
|
|
477
|
+
return this._createModelEntry(config, testingInfo);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Create Framework_Registry entry
|
|
483
|
+
* @private
|
|
484
|
+
*/
|
|
485
|
+
_createFrameworkEntry(config, testingInfo) {
|
|
486
|
+
const entry = {
|
|
487
|
+
[config.version]: {
|
|
488
|
+
baseImage: config.baseImage || 'REPLACE_WITH_BASE_IMAGE',
|
|
489
|
+
accelerator: config.accelerator || {
|
|
490
|
+
type: 'cuda',
|
|
491
|
+
version: '12.1',
|
|
492
|
+
versionRange: {
|
|
493
|
+
min: '12.0',
|
|
494
|
+
max: '12.2'
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
envVars: config.envVars || {},
|
|
498
|
+
inferenceAmiVersion: config.inferenceAmiVersion || 'REPLACE_WITH_AMI_VERSION',
|
|
499
|
+
recommendedInstanceTypes: config.recommendedInstanceTypes?.length > 0
|
|
500
|
+
? config.recommendedInstanceTypes
|
|
501
|
+
: (testingInfo.instanceType ? [testingInfo.instanceType] : ['ml.g5.xlarge']),
|
|
502
|
+
validationLevel: this._determineValidationLevel(testingInfo),
|
|
503
|
+
notes: this._createTestingNotes(testingInfo)
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
return entry;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Create Model_Registry entry
|
|
512
|
+
* @private
|
|
513
|
+
*/
|
|
514
|
+
_createModelEntry(config, testingInfo) {
|
|
515
|
+
const entry = {
|
|
516
|
+
[config.modelId]: {
|
|
517
|
+
family: this._extractModelFamily(config.modelId),
|
|
518
|
+
chatTemplate: config.chatTemplate || null,
|
|
519
|
+
requiresTemplate: !!config.chatTemplate,
|
|
520
|
+
validationLevel: this._determineValidationLevel(testingInfo),
|
|
521
|
+
frameworkCompatibility: {
|
|
522
|
+
[config.framework]: `>=${config.version}`
|
|
523
|
+
},
|
|
524
|
+
notes: this._createTestingNotes(testingInfo)
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// Add environment variables if present
|
|
529
|
+
if (config.envVars && Object.keys(config.envVars).length > 0) {
|
|
530
|
+
entry[config.modelId].envVars = config.envVars;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Add recommended instance types if present
|
|
534
|
+
if (config.recommendedInstanceTypes?.length > 0) {
|
|
535
|
+
entry[config.modelId].recommendedInstanceTypes = config.recommendedInstanceTypes;
|
|
536
|
+
} else if (testingInfo.instanceType) {
|
|
537
|
+
entry[config.modelId].recommendedInstanceTypes = [testingInfo.instanceType];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return entry;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Determine validation level based on testing results
|
|
545
|
+
* @private
|
|
546
|
+
*/
|
|
547
|
+
_determineValidationLevel(testingInfo) {
|
|
548
|
+
const { deploymentSuccess, inferenceSuccess } = testingInfo;
|
|
549
|
+
|
|
550
|
+
if (deploymentSuccess && inferenceSuccess) {
|
|
551
|
+
return 'community-validated';
|
|
552
|
+
} else if (deploymentSuccess) {
|
|
553
|
+
return 'experimental';
|
|
554
|
+
} else {
|
|
555
|
+
return 'unknown';
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Create testing notes from testing info
|
|
561
|
+
* @private
|
|
562
|
+
*/
|
|
563
|
+
_createTestingNotes(testingInfo) {
|
|
564
|
+
const { testingNotes, instanceType, deploymentSuccess, inferenceSuccess, testerName } = testingInfo;
|
|
565
|
+
|
|
566
|
+
const notes = [];
|
|
567
|
+
|
|
568
|
+
if (testingNotes) {
|
|
569
|
+
notes.push(testingNotes);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (instanceType) {
|
|
573
|
+
notes.push(`Tested on ${instanceType}`);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (deploymentSuccess && inferenceSuccess) {
|
|
577
|
+
notes.push('✓ Deployment and inference successful');
|
|
578
|
+
} else if (deploymentSuccess) {
|
|
579
|
+
notes.push('✓ Deployment successful, inference not tested');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (testerName && testerName !== 'Anonymous') {
|
|
583
|
+
notes.push(`Tested by: ${testerName}`);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
notes.push(`Exported: ${new Date().toISOString().split('T')[0]}`);
|
|
587
|
+
|
|
588
|
+
return notes.join('. ');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Extract model family from model ID
|
|
593
|
+
* @private
|
|
594
|
+
*/
|
|
595
|
+
_extractModelFamily(modelId) {
|
|
596
|
+
if (!modelId) return 'unknown';
|
|
597
|
+
|
|
598
|
+
// Extract family from model ID (e.g., "meta-llama/Llama-2-7b-chat-hf" -> "llama-2")
|
|
599
|
+
const parts = modelId.toLowerCase().split('/');
|
|
600
|
+
const modelName = parts[parts.length - 1];
|
|
601
|
+
|
|
602
|
+
// Common patterns
|
|
603
|
+
if (modelName.includes('llama-2')) return 'llama-2';
|
|
604
|
+
if (modelName.includes('llama-3')) return 'llama-3';
|
|
605
|
+
if (modelName.includes('llama')) return 'llama';
|
|
606
|
+
if (modelName.includes('mistral')) return 'mistral';
|
|
607
|
+
if (modelName.includes('mixtral')) return 'mixtral';
|
|
608
|
+
if (modelName.includes('gemma')) return 'gemma';
|
|
609
|
+
if (modelName.includes('phi')) return 'phi';
|
|
610
|
+
if (modelName.includes('qwen')) return 'qwen';
|
|
611
|
+
|
|
612
|
+
// Default: use first part of model name
|
|
613
|
+
return modelName.split('-')[0];
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Generate submission instructions
|
|
618
|
+
* @private
|
|
619
|
+
*/
|
|
620
|
+
_generateSubmissionInstructions(registryType, config, configEntry) {
|
|
621
|
+
const registryFile = registryType === 'framework'
|
|
622
|
+
? 'servers/base-image-picker/catalogs/model-servers.json'
|
|
623
|
+
: 'servers/model-picker/catalogs/popular-transformers.json';
|
|
624
|
+
|
|
625
|
+
const registryName = registryType === 'framework'
|
|
626
|
+
? 'Framework_Catalog'
|
|
627
|
+
: 'Model_Catalog';
|
|
628
|
+
|
|
629
|
+
const key = registryType === 'framework'
|
|
630
|
+
? config.framework
|
|
631
|
+
: config.modelId;
|
|
632
|
+
|
|
633
|
+
return `
|
|
634
|
+
# Configuration Export for Community Contribution
|
|
635
|
+
|
|
636
|
+
Thank you for testing this configuration! Your contribution helps the community.
|
|
637
|
+
|
|
638
|
+
## Configuration Details
|
|
639
|
+
|
|
640
|
+
- **Registry Type**: ${registryName}
|
|
641
|
+
- **${registryType === 'framework' ? 'Framework' : 'Model'}**: ${key}
|
|
642
|
+
- **Validation Level**: ${config.validationLevel || 'experimental'}
|
|
643
|
+
- **Tested On**: ${new Date().toISOString().split('T')[0]}
|
|
644
|
+
|
|
645
|
+
## Submission Instructions
|
|
646
|
+
|
|
647
|
+
### Option 1: GitHub Issue (Recommended)
|
|
648
|
+
|
|
649
|
+
1. Go to: https://github.com/YOUR_REPO/issues/new
|
|
650
|
+
2. Title: "[Config] Add ${registryType === 'framework' ? `${config.framework } ${ config.version}` : config.modelId}"
|
|
651
|
+
3. Paste the configuration entry below
|
|
652
|
+
4. Add any additional context about your testing
|
|
653
|
+
|
|
654
|
+
### Option 2: Pull Request
|
|
655
|
+
|
|
656
|
+
1. Fork the repository
|
|
657
|
+
2. Edit: \`${registryFile}\`
|
|
658
|
+
3. Add the configuration entry to the appropriate section
|
|
659
|
+
4. Submit a pull request with title: "Add ${registryType === 'framework' ? `${config.framework } ${ config.version}` : config.modelId} configuration"
|
|
660
|
+
|
|
661
|
+
## Configuration Entry
|
|
662
|
+
|
|
663
|
+
Add this to \`${registryFile}\`:
|
|
664
|
+
|
|
665
|
+
\`\`\`javascript
|
|
666
|
+
${JSON.stringify(configEntry, null, 2)}
|
|
667
|
+
\`\`\`
|
|
668
|
+
|
|
669
|
+
## Testing Information
|
|
670
|
+
|
|
671
|
+
- **Instance Type**: ${config.recommendedInstanceTypes?.[0] || 'Not specified'}
|
|
672
|
+
- **Accelerator**: ${config.accelerator?.type || 'Not specified'} ${config.accelerator?.version || ''}
|
|
673
|
+
- **Base Image**: ${config.baseImage || 'Not specified'}
|
|
674
|
+
- **AMI Version**: ${config.inferenceAmiVersion || 'Not specified'}
|
|
675
|
+
|
|
676
|
+
## Notes
|
|
677
|
+
|
|
678
|
+
${config.notes || 'No additional notes'}
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
Generated by ML Container Creator v${this._getGeneratorVersion()}
|
|
683
|
+
`.trim();
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Get generator version
|
|
688
|
+
* @private
|
|
689
|
+
*/
|
|
690
|
+
_getGeneratorVersion() {
|
|
691
|
+
// In a real implementation, this would read from package.json
|
|
692
|
+
// For now, return a placeholder
|
|
693
|
+
return '1.0.0';
|
|
694
|
+
}
|
|
695
|
+
}
|