* Initial implementation * Succeed on creating a whatif request to aiToolkit * New schema support for AIToolkit, general cleanup and code improvements * Fix types * Fix types * Add logic to require prompts for AIToolkit * Support new training schema via the resource-training-v2 * Adjust messaging and prompt requirements * Fix typeissues * Add support for QWEN training from the FE. * Configure QWEN image model and auto-populate sample prompts from caption * Apply suggestions from code review * Apply suggestion from @manuelurenah * Apply suggestion from @manuelurenah * Apply suggestion from @manuelurenah * Apply suggestion from @manuelurenah * Apply suggestion from @manuelurenah --------- Co-authored-by: Manuel Emilio Urena <manuel.ureh@hotmail.com>
32 KiB
AI Toolkit Training Implementation Plan
Overview
This document outlines the plan to implement AI Toolkit training as a new training engine option in Civitai. Similar to how Rapid Training works for Flux models, AI Toolkit training will be a toggleable option that supports all training model types (SD1.5, SDXL, Flux.1, SD3, Wan, Hunyuan, Chroma).
🎯 Key Implementation Details
Ecosystem and Model Variant Requirements
Both ecosystem and modelVariant ARE required (with specific rules per ecosystem):
| Ecosystem | Model Variant | Required? |
|---|---|---|
sd1 |
N/A | No variant |
sdxl |
N/A | No variant |
sd3 |
"large" (or "medium") |
Required |
flux1 |
"dev" or "schnell" |
Required |
wan |
"2.1" or "2.2" |
Required |
Excluded Parameters
The following parameters from Kohya training are NOT used in AI Toolkit and will be excluded:
- ❌
numRepeats- Not used by AI Toolkit - ❌
trainBatchSize- Not used by AI Toolkit
These parameters are still present in the frontend state (for consistency with Kohya), but are not sent to the AI Toolkit API.
Key Findings
✅ Client Types Available
The @civitai/client beta 12 package already includes all required types:
TrainingStep/TrainingStepTemplate(with$type: 'training')TrainingInputtype with all required fields- These types match the HTTP API examples exactly!
🔑 Critical Decision: Use New API Format
The civitai client exposes two different training API formats:
-
Legacy Format (
$type: 'imageResourceTraining'):- Currently used for Kohya, Rapid, and Musubi engines
- Uses
ImageResourceTrainingInputtype - Parameters:
maxTrainEpochs,unetLR,shuffleCaption
-
NEW Format (
$type: 'training') ← We're using this for AI Toolkit- Uses
TrainingStep+TrainingInputtypes - Parameters:
epochs,lr,shuffleTokens(different from Kohya) - Includes:
ecosystemandmodelVariantfields - Excludes:
numRepeatsandtrainBatchSize(not used by AI Toolkit)
- Uses
This means AI Toolkit will use a different step type and input format than the existing engines.
Background
Current Training System
- Engines:
kohya(standard),flux-dev-fast(rapid),musubi(video) - Rapid Training: Flux-only toggle that switches engine from
kohyatoflux-dev-fast - Location: Toggle in
TrainingSubmitAdvancedSettings.tsx
New AI Toolkit Engine
The civitai client beta 12 exposes a new TrainingInput type that uses the ai-toolkit engine with support for:
- SD1.5 (ecosystem: "sd1")
- SDXL (ecosystem: "sdxl")
- Flux.1 (ecosystem: "flux1", modelVariant: "dev")
- SD3 (ecosystem: "sd3", modelVariant: "large")
- Wan (ecosystem: "wan", modelVariant: "2.1")
Implementation Plan
Phase 1: Backend - Type Definitions & Schema Updates
1.1 Update Enums
File: src/server/common/enums.ts
Changes:
export enum OrchEngineTypes {
Kohya = 'kohya',
Rapid = 'flux-dev-fast',
Musubi = 'musubi',
AiToolkit = 'ai-toolkit', // NEW
}
File: src/utils/training.ts
Changes:
export const engineTypes = ['kohya', 'rapid', 'musubi', 'ai-toolkit'] as const;
export type EngineTypes = (typeof engineTypes)[number];
1.2 Define AI Toolkit Parameter Schema
File: src/server/schema/orchestrator/training.schema.ts
New Schema:
// AI Toolkit specific parameters - uses discriminated union for proper modelVariant validation
const aiToolkitBaseParams = z.object({
engine: z.literal('ai-toolkit'),
epochs: z.number(),
resolution: z.number().nullable(),
lr: z.number(),
textEncoderLr: z.number().nullable(),
trainTextEncoder: z.boolean(),
lrScheduler: z.enum(['constant', 'constant_with_warmup', 'cosine', 'linear', 'step']),
optimizerType: z.enum([
'adam',
'adamw',
'adamw8bit',
'adam8bit',
'lion',
'lion8bit',
'adafactor',
'adagrad',
'prodigy',
'prodigy8bit',
]),
networkDim: z.number().nullable(),
networkAlpha: z.number().nullable(),
noiseOffset: z.number().nullable(),
minSnrGamma: z.number().nullable(),
flipAugmentation: z.boolean(),
shuffleTokens: z.boolean(),
keepTokens: z.number(),
});
// Use discriminated union to enforce modelVariant requirements per ecosystem
const aiToolkitTrainingParams = z.discriminatedUnion('ecosystem', [
// SD1 and SDXL don't need modelVariant
aiToolkitBaseParams.extend({
ecosystem: z.literal('sd1'),
modelVariant: z.undefined().optional(),
}),
aiToolkitBaseParams.extend({
ecosystem: z.literal('sdxl'),
modelVariant: z.undefined().optional(),
}),
// SD3, Flux1, and Wan require modelVariant
aiToolkitBaseParams.extend({
ecosystem: z.literal('sd3'),
modelVariant: z.enum(['large', 'medium']),
}),
aiToolkitBaseParams.extend({
ecosystem: z.literal('flux1'),
modelVariant: z.enum(['dev', 'schnell']),
}),
aiToolkitBaseParams.extend({
ecosystem: z.literal('wan'),
modelVariant: z.enum(['2.1', '2.2']),
}),
]);
export type AiToolkitTrainingParams = z.infer<typeof aiToolkitTrainingParams>;
Update Union Type:
const imageTrainingStepSchema = imageTrainingBaseSchema.extend({
// ... existing fields ...
params: z.union([
kohyaParams,
fluxDevFastParams,
musubiParams,
aiToolkitTrainingParams, // NEW
]),
});
Important Notes:
- AI Toolkit excludes
numRepeatsandtrainBatchSize(not used) ecosystemis required for all AI Toolkit trainingmodelVariantis conditionally required:- Not needed for
sd1,sdxl - Required for
sd3,flux1,wan
- Not needed for
- Different parameter names than Kohya:
epochsinstead ofmaxTrainEpochslrinstead ofunetLRtextEncoderLrinstead oftextEncoderLRshuffleTokensinstead ofshuffleCaption
1.3 Update Civitai Client Import
File: src/server/services/orchestrator/training/training.orch.ts
Add Import:
import {
FluxDevFastImageResourceTrainingInput,
ImageResourceTrainingStep,
ImageResourceTrainingStepTemplate,
KohyaImageResourceTrainingInput,
MusubiImageResourceTrainingInput,
TrainingStep, // NEW - for ai-toolkit
TrainingStepTemplate, // NEW - for ai-toolkit
TrainingInput, // NEW - for ai-toolkit
} from '@civitai/client';
IMPORTANT DISCOVERY: The civitai client beta 12 has TWO training API formats:
-
Legacy Format (currently used):
- Step type:
ImageResourceTrainingStepwith$type: 'imageResourceTraining' - Input type:
ImageResourceTrainingInput(+ variants like KohyaImageResourceTrainingInput) - Uses:
maxTrainEpochs, noecosystem/modelVariant
- Step type:
-
NEW Format (for AI Toolkit):
- Step type:
TrainingStepwith$type: 'training' - Input type:
TrainingInput - Uses:
epochs,ecosystem,modelVariant - This matches your HTTP examples exactly!
- Step type:
Decision: We will use the NEW format (TrainingStep + TrainingInput) for AI Toolkit training.
1.4 Add AI Toolkit Training Step Creator
File: src/server/services/orchestrator/training/training.orch.ts
Add New Function (similar to existing createTrainingStep_Run but for the new format):
// NEW: Create training step using the new TrainingStep format (for ai-toolkit)
const createTrainingStep_AiToolkit = (
input: ImageTrainingStepSchema
): TrainingStepTemplate => {
const {
model,
priority,
loraName,
trainingData,
trainingDataImagesCount,
samplePrompts,
negativePrompt,
modelFileId,
params,
} = input;
const aiToolkitParams = params as AiToolkitTrainingParams;
const trainingInput: TrainingInput = {
engine: 'ai-toolkit',
ecosystem: aiToolkitParams.ecosystem,
model,
...(aiToolkitParams.modelVariant && { modelVariant: aiToolkitParams.modelVariant }),
trainingData: {
type: 'zip',
sourceUrl: trainingData,
count: trainingDataImagesCount,
},
samples: {
prompts: samplePrompts,
},
epochs: aiToolkitParams.epochs,
// NOTE: numRepeats and trainBatchSize are NOT included (not used by AI Toolkit)
resolution: aiToolkitParams.resolution,
lr: aiToolkitParams.lr,
textEncoderLr: aiToolkitParams.textEncoderLr,
trainTextEncoder: aiToolkitParams.trainTextEncoder,
lrScheduler: aiToolkitParams.lrScheduler,
optimizerType: aiToolkitParams.optimizerType,
networkDim: aiToolkitParams.networkDim,
networkAlpha: aiToolkitParams.networkAlpha,
noiseOffset: aiToolkitParams.noiseOffset,
minSnrGamma: aiToolkitParams.minSnrGamma,
flipAugmentation: aiToolkitParams.flipAugmentation,
shuffleTokens: aiToolkitParams.shuffleTokens,
keepTokens: aiToolkitParams.keepTokens,
};
return {
$type: 'training',
metadata: { modelFileId },
priority,
retries: constants.maxTrainingRetries,
input: trainingInput,
};
};
Update createTrainingStep dispatcher to route to the correct function:
const createTrainingStep = (
input: ImageTrainingStepSchema
): ImageResourceTrainingStepTemplate | TrainingStepTemplate => {
const { engine } = input;
if (engine === 'ai-toolkit') {
return createTrainingStep_AiToolkit(input);
} else {
return createTrainingStep_Run(input); // Existing function for kohya, rapid, musubi
}
};
1.5 Ecosystem Mapping for AI Toolkit
File: src/utils/training.ts (or backend helper)
Add Ecosystem Mapping Function:
import { getBaseModelEcosystem } from '~/shared/constants/base-model.constants';
/**
* Map civitai ecosystem (from getBaseModelEcosystem) to AI Toolkit ecosystem format
*/
export function getAiToolkitEcosystem(baseModel: string): string | null {
const civitaiEcosystem = getBaseModelEcosystem(baseModel);
// Ecosystem mapping for AI Toolkit API
const ecosystemMap: Record<string, string> = {
// SD 1.x variants
'sd1': 'sd1',
// SDXL variants (including Pony, Illustrious, NoobAI which have ecosystem: 'sdxl')
'sdxl': 'sdxl',
'pony': 'sdxl',
'illustrious': 'sdxl',
'noobai': 'sdxl',
// Flux variants
'flux1': 'flux1',
// SD3 variants
'sd3': 'sd3',
'sd3_5m': 'sd3', // SD 3.5 Medium has ecosystem: 'sd3'
// Video models - all Wan/Hunyuan variants map to 'wan'
'wanvideo': 'wan',
'wanvideo14b_t2v': 'wan',
'wanvideo14b_i2v_480p': 'wan',
'wanvideo14b_i2v_720p': 'wan',
'wanvideo-22-t2v-a14b': 'wan',
'wanvideo-22-i2v-a14b': 'wan',
'wanvideo-22-ti2v-5b': 'wan',
'wanvideo-25-t2v': 'wan',
'wanvideo-25-i2v': 'wan',
'hyv1': 'wan', // Hunyuan maps to wan ecosystem
};
const mapped = ecosystemMap[civitaiEcosystem.toLowerCase()];
if (!mapped) {
console.warn(`Unknown ecosystem for AI Toolkit: ${civitaiEcosystem}`);
return null;
}
return mapped;
}
/**
* Get model variant for AI Toolkit based on base model
*/
export function getAiToolkitModelVariant(
baseModel: TrainingDetailsBaseModel
): string | undefined {
// Model variant mapping based on specific models
const variantMap: Partial<Record<TrainingDetailsBaseModelList, string>> = {
// Flux variants
'flux_dev': 'dev',
// 'flux_schnell': 'schnell', // if/when added
// SD3 variants
// 'sd3_medium': 'medium', // if/when enabled
// 'sd3_large': 'large', // if/when enabled
// Wan variants - determine from model name
'wan_2_1_t2v_14b': '2.1',
'wan_2_1_i2v_14b_720p': '2.1',
// Wan 2.2 models would be '2.2'
};
// If it's a custom model (civitai:xxx@yyy or AIR format), try to infer from URN
if (typeof baseModel === 'string' && baseModel.includes('civitai:')) {
return undefined;
}
return variantMap[baseModel as TrainingDetailsBaseModelList];
}
Model URN Handling:
The model URN (AIR format) is still passed in the model field. Example URNs:
- SD1.5:
urn:air:sd1:checkpoint:civitai:4384@128713 - SDXL:
urn:air:sdxl:checkpoint:civitai:101055@128078 - Flux:
urn:air:flux1:checkpoint:civitai:1330309@2164239 - SD3:
urn:air:sd3:checkpoint:civitai:139562@782002 - Wan:
urn:air:wanvideo:checkpoint:civitai:1329096@1501344
Phase 2: Backend - Feature Flag Implementation
2.1 Add Feature Flag
File: src/server/services/feature-flags.service.ts
Add Flag (around line 85):
const featureFlags = {
// ... existing flags ...
aiToolkitTraining: {
displayName: 'AI Toolkit Training',
description: 'Enable AI Toolkit as a training engine option',
availability: ['mod'], // Start with mods only for testing
toggleable: true,
default: false,
},
// ... rest of flags ...
};
Rollout Strategy:
- Phase 1:
['mod']- Moderators only for testing - Phase 2:
['bronze', 'silver', 'gold']- Paid tiers - Phase 3:
['user']- All authenticated users
2.2 Environment Variable Override
Add support for FEATURE_FLAG_AI_TOOLKIT_TRAINING=true in environment variables for testing.
Phase 3: Frontend - UI Components
3.1 Add AI Toolkit Toggle
File: src/components/Training/Form/TrainingSubmitAdvancedSettings.tsx
Add After Rapid Training Toggle (around line 222):
{/* AI Toolkit Training Toggle */}
{hasFeature('aiToolkitTraining') && isAiToolkitSupported(selectedRun.baseType) && (
<Group mt="md">
<Switch
label={
<Group gap={4} wrap="nowrap">
<InfoPopover type="hover" size="xs" iconProps={{ size: 16 }}>
<Text>
Train using the AI Toolkit engine, offering improved quality and flexibility.
{selectedRun.baseType === 'flux' && selectedRun.params.engine === 'rapid' && (
<> Note: Enabling AI Toolkit will disable Rapid Training.</>
)}
</Text>
</InfoPopover>
<Text>AI Toolkit Training</Text>
<Badge color="blue" size="xs">Beta</Badge>
</Group>
}
labelPosition="left"
checked={selectedRun.params.engine === 'ai-toolkit'}
// Disable if Rapid Training is enabled (mutually exclusive)
disabled={selectedRun.params.engine === 'rapid'}
onChange={(event) => {
const newEngine = event.currentTarget.checked ? 'ai-toolkit' : getDefaultEngine(selectedRun.baseType);
updateRun(modelId, mediaType, selectedRun.id, {
params: { ...selectedRun.params, engine: newEngine },
});
}}
/>
</Group>
)}
Important: Also update the Rapid Training toggle to be disabled when AI Toolkit is enabled:
{selectedRun.baseType === 'flux' && (
<Group mt="md">
<Switch
label={...}
labelPosition="left"
checked={selectedRun.params.engine === 'rapid'}
// Disable if AI Toolkit is enabled (mutually exclusive)
disabled={selectedRun.params.engine === 'ai-toolkit'}
onChange={(event) =>
updateRun(modelId, mediaType, selectedRun.id, {
params: { engine: event.currentTarget.checked ? 'rapid' : 'kohya' },
})
}
/>
</Group>
)}
3.2 Add Helper Functions
File: src/utils/training.ts
New Functions:
import { getBaseModelEcosystem } from '~/shared/constants/base-model.constants';
// Check if base model supports AI Toolkit
export const isAiToolkitSupported = (baseType: TrainingBaseModelType): boolean => {
// AI Toolkit supports all base model types
const supportedTypes: TrainingBaseModelType[] = ['sd15', 'sdxl', 'flux', 'sd35', 'video', 'hunyuan', 'wan', 'chroma'];
return supportedTypes.includes(baseType);
};
// Get ecosystem string for AI Toolkit (mirrors backend function)
export const getAiToolkitEcosystem = (baseModel: string): string | null => {
const civitaiEcosystem = getBaseModelEcosystem(baseModel);
const ecosystemMap: Record<string, string> = {
'sd1': 'sd1',
'sdxl': 'sdxl',
'pony': 'sdxl',
'illustrious': 'sdxl',
'noobai': 'sdxl',
'flux1': 'flux1',
'sd3': 'sd3',
'sd3_5m': 'sd3',
'wanvideo': 'wan',
'wanvideo14b_t2v': 'wan',
'wanvideo14b_i2v_480p': 'wan',
'wanvideo14b_i2v_720p': 'wan',
'wanvideo-22-t2v-a14b': 'wan',
'wanvideo-22-i2v-a14b': 'wan',
'wanvideo-22-ti2v-5b': 'wan',
'wanvideo-25-t2v': 'wan',
'wanvideo-25-i2v': 'wan',
'hyv1': 'wan',
};
return ecosystemMap[civitaiEcosystem.toLowerCase()] || null;
};
// Get model variant for AI Toolkit
export const getAiToolkitModelVariant = (
baseModel: TrainingDetailsBaseModel
): string | undefined => {
const variantMap: Partial<Record<TrainingDetailsBaseModelList, string>> = {
'flux_dev': 'dev',
'wan_2_1_t2v_14b': '2.1',
'wan_2_1_i2v_14b_720p': '2.1',
};
if (typeof baseModel === 'string' && baseModel.includes('civitai:')) {
return undefined;
}
return variantMap[baseModel as TrainingDetailsBaseModelList];
};
// Get default engine for base type
export const getDefaultEngine = (baseType: TrainingBaseModelType): EngineTypes => {
if (baseType === 'video') return 'musubi';
return 'kohya';
};
// Check if AI Toolkit is valid for the model
export const isValidAiToolkit = (
baseModel: TrainingBaseModelType,
engine: EngineTypes
): boolean => {
return isAiToolkitSupported(baseModel) && engine === 'ai-toolkit';
};
// Check if AI Toolkit is invalid for the model
export const isInvalidAiToolkit = (
baseModel: TrainingBaseModelType,
engine: EngineTypes
): boolean => {
return !isAiToolkitSupported(baseModel) && engine === 'ai-toolkit';
};
3.3 Update Parameter Defaults
File: src/components/Training/Form/TrainingParams.tsx
Add AI Toolkit Parameter Overrides:
export const trainingSettings = {
// ... existing settings ...
// AI Toolkit specific settings
aiToolkit: {
sd15: {
resolution: [512],
epochs: { min: 5, max: 20, default: 5 },
trainBatchSize: { min: 1, max: 4, default: 2 },
lr: 0.0001,
textEncoderLr: 0.00005,
trainTextEncoder: true,
networkDim: { min: 16, max: 64, default: 32 },
networkAlpha: { min: 16, max: 64, default: 32 },
},
sdxl: {
resolution: [1024],
epochs: { min: 5, max: 20, default: 5 },
trainBatchSize: { min: 1, max: 2, default: 2 },
lr: 0.0001,
textEncoderLr: 0.00005,
trainTextEncoder: true,
networkDim: { min: 16, max: 64, default: 32 },
networkAlpha: { min: 16, max: 64, default: 32 },
},
flux1: {
resolution: [1024],
epochs: { min: 5, max: 20, default: 5 },
trainBatchSize: { min: 1, max: 1, default: 1 },
lr: 0.0001,
textEncoderLr: null,
trainTextEncoder: false,
networkDim: { min: 8, max: 32, default: 16 },
networkAlpha: { min: 8, max: 32, default: 16 },
},
sd3: {
resolution: [1024],
epochs: { min: 5, max: 20, default: 5 },
trainBatchSize: { min: 1, max: 1, default: 1 },
lr: 0.0001,
textEncoderLr: null,
trainTextEncoder: false,
networkDim: { min: 8, max: 32, default: 16 },
networkAlpha: { min: 8, max: 32, default: 16 },
},
wan: {
resolution: [512],
epochs: { min: 2, max: 10, default: 2 },
trainBatchSize: { min: 1, max: 1, default: 1 },
lr: 0.0002,
textEncoderLr: null,
trainTextEncoder: false,
networkDim: { min: 16, max: 64, default: 32 },
networkAlpha: { min: 16, max: 64, default: 32 },
},
},
};
3.4 Update Parameter Visibility
File: src/components/Training/Form/TrainingParams.tsx (or wherever params are rendered)
Hide AI Toolkit-incompatible parameters:
{/* Only show numRepeats for non-AI-Toolkit engines */}
{selectedRun.params.engine !== 'ai-toolkit' && (
<NumberInput
label="Num Repeats"
value={selectedRun.params.numRepeats}
onChange={(value) => updateRun(...)}
/>
)}
{/* Only show trainBatchSize for non-AI-Toolkit engines */}
{selectedRun.params.engine !== 'ai-toolkit' && (
<NumberInput
label="Train Batch Size"
value={selectedRun.params.trainBatchSize}
onChange={(value) => updateRun(...)}
/>
)}
{/* All other parameters are shown for both engines */}
<NumberInput
label="Epochs"
value={selectedRun.params.maxTrainEpochs}
onChange={(value) => updateRun(...)}
/>
{/* ... other shared parameters ... */}
3.5 Update Form Validation
File: src/components/Training/Form/TrainingSubmit.tsx
Add Validation in handleSubmit() (around line 280):
// Check if ai-toolkit is invalid for base model
if (isInvalidAiToolkit(run.baseType, run.params.engine)) {
showErrorNotification({
title: 'Invalid Training Configuration',
error: new Error(
`AI Toolkit training is not supported for ${run.baseType} models. Please disable AI Toolkit or select a different model.`
),
});
return;
}
3.6 Add AI Toolkit Info Badge
File: src/components/Training/Form/TrainingSubmit.tsx
Add Visual Indicator near the cost/ETA section:
{selectedRun.params.engine === 'ai-toolkit' && (
<Alert color="blue" variant="light" icon={<IconSparkles size={16} />}>
<Text size="sm">
Training with AI Toolkit engine for improved quality and flexibility.
</Text>
</Alert>
)}
Phase 4: Frontend - Parameter Mapping
4.1 Update Training Store
File: src/store/training.store.ts
Add Getter for AI Toolkit Params:
// Helper to transform params for AI Toolkit API submission
getAiToolkitParams: (runId: number) => {
const run = get().runs.find(r => r.id === runId);
if (!run || run.params.engine !== 'ai-toolkit') return null;
// Get ecosystem and model variant
const ecosystem = getAiToolkitEcosystem(run.base);
const modelVariant = getAiToolkitModelVariant(run.base);
if (!ecosystem) {
console.error('Failed to determine ecosystem for AI Toolkit training');
return null;
}
// Transform parameter names from internal Kohya-style to AI Toolkit API format
return {
engine: 'ai-toolkit',
ecosystem,
modelVariant,
epochs: run.params.maxTrainEpochs,
// NOTE: numRepeats and trainBatchSize are NOT included (not used by AI Toolkit)
resolution: run.params.resolution,
lr: run.params.unetLR,
textEncoderLr: run.params.textEncoderLR || null,
trainTextEncoder: !!run.params.textEncoderLR,
lrScheduler: run.params.lrScheduler,
optimizerType: run.params.optimizerType,
networkDim: run.params.networkDim,
networkAlpha: run.params.networkAlpha,
noiseOffset: run.params.noiseOffset || null,
minSnrGamma: run.params.minSnrGamma || null,
flipAugmentation: run.params.flipAugmentation || false,
shuffleTokens: run.params.shuffleCaption,
keepTokens: run.params.keepTokens,
};
},
Note: The internal state still uses Kohya-style names (maxTrainEpochs, unetLR, shuffleCaption) for consistency. Only at submission time do we:
- Transform to AI Toolkit names (
epochs,lr,shuffleTokens) - Add
ecosystemandmodelVariantfields - Exclude
numRepeatsandtrainBatchSize
4.2 Update Submission Handler
File: src/components/Training/Form/TrainingSubmit.tsx
Update handleConfirm() (around line 400):
runs.forEach(async (run, idx) => {
// ... existing code ...
let params: any = { ...run.params };
// Transform params for AI Toolkit
if (run.params.engine === 'ai-toolkit') {
const aiToolkitParams = getAiToolkitParams(run.id);
if (!aiToolkitParams) {
console.error('Failed to get AI Toolkit params');
return;
}
params = aiToolkitParams;
}
// Check if engine is invalid for base model
if (isInvalidAiToolkit(run.baseType, run.params.engine)) {
showErrorNotification({
title: 'Invalid Training Configuration',
error: new Error('AI Toolkit training is not supported for this model'),
});
return;
}
// ... rest of submission logic ...
});
Phase 5: Rollout & Documentation
5.1 Feature Flag Rollout Plan
Week 1-2: Internal Testing
- Enable for moderators only:
['mod'] - Test all supported ecosystems
- Gather feedback and fix issues
Week 3-4: Paid Tier Beta
- Expand to paid tiers:
['bronze', 'silver', 'gold'] - Monitor training success rates
- Optimize parameter defaults if needed
Week 5+: Public Release
- Enable for all users:
['user'] - Monitor system load and costs
- Gather user feedback
5.2 Documentation Updates
User Documentation
- Create guide: "Training with AI Toolkit"
- Document parameter differences vs. Kohya
- Add FAQ section
- Create comparison table
Developer Documentation
- Update API documentation
- Document new training input schema
- Add troubleshooting guide
- Update architecture diagrams
Phase 6: Monitoring & Optimization
6.1 Metrics to Track
- Training success rate by engine type
- Average training duration (AI Toolkit vs. Kohya)
- Cost per training (AI Toolkit vs. Kohya)
- User adoption rate
- Error rates and common failure modes
6.2 Performance Optimization
- Monitor queue times for AI Toolkit jobs
- Optimize default parameters based on success rates
- A/B test parameter configurations
Open Questions & Decisions Needed
Critical Questions
-
✅ Client Type Availability: CONFIRMED -
@civitai/clientbeta 12 exposesTrainingInput,TrainingStep, andTrainingStepTemplatetypes that match the HTTP API examples exactly. -
✅ Parameter Mapping: CONFIRMED - The
TrainingInputtype uses the correct parameter names (epochs,lr,textEncoderLr,shuffleTokens, etc.) that match the HTTP examples. -
✅ Parameter Mapping: CONFIRMED - The parameter name mappings are:
unetLR→lr✓textEncoderLR→textEncoderLr✓maxTrainEpochs→epochs✓shuffleCaption→shuffleTokens✓
-
✅ Ecosystem Mapping: CONFIRMED using
getBaseModelEcosystem()with mapping to AI Toolkit format:- SD1.5 →
"sd1"(no variant) - SDXL (including Pony, Illustrious, NoobAI) →
"sdxl"(no variant) - Flux →
"flux1"(variant:"dev"or"schnell") - SD3 (including SD 3.5 Medium) →
"sd3"(variant:"large"or"medium") - Wan Video/Hunyuan →
"wan"(variant:"2.1"or"2.2")
- SD1.5 →
-
✅ Excluded Parameters:
numRepeatsandtrainBatchSizeare NOT used by AI Toolkit
Design Decisions (Confirmed)
-
✅ Cost Structure: Cost will be provided by the orchestrator just like Kohya. A whatif request will be made to get pricing.
-
✅ UI/UX - Mutually Exclusive: AI Toolkit and Rapid Training should be mutually exclusive toggles (only one can be enabled at a time).
- When AI Toolkit is enabled, Rapid Training must be disabled
- When Rapid Training is enabled, AI Toolkit must be disabled
-
✅ Default Engine: AI Toolkit will be opt-in initially (not the default engine)
-
✅ Parameter Visibility: Yes, only show parameters relevant to AI Toolkit when it's enabled:
- Hide:
numRepeats,trainBatchSize(not used by AI Toolkit) - Show: All other standard training parameters
- Hide:
-
✅ Error Handling: Initially, just error out if AI Toolkit is selected but backend doesn't support it
File Change Summary
Backend Files to Modify
src/server/common/enums.ts- AddAiToolkittoOrchEngineTypessrc/utils/training.ts- Add 'ai-toolkit' toengineTypessrc/server/schema/orchestrator/training.schema.ts- Add AI Toolkit params schemasrc/server/services/orchestrator/training/training.orch.ts- Add transformation logicsrc/server/services/feature-flags.service.ts- Add feature flag
Frontend Files to Modify
src/components/Training/Form/TrainingSubmitAdvancedSettings.tsx- Add togglesrc/utils/training.ts- Add helper functionssrc/components/Training/Form/TrainingParams.tsx- Add parameter defaultssrc/components/Training/Form/TrainingSubmit.tsx- Add validation & submission logicsrc/store/training.store.ts- Add AI Toolkit param getter
New Files to Create
None required - all changes are modifications to existing files.
Timeline Estimate
- Phase 1 (Backend Types): 1-1.5 days
- Phase 2 (Feature Flag): 0.5 day
- Phase 3 (Frontend UI): 2-3 days
- Including mutually exclusive toggles
- Parameter visibility logic
- Phase 4 (Parameter Mapping): 1-1.5 days
- Phase 5 (Rollout & Documentation): 1-2 days
- Phase 6 (Monitoring): Ongoing
Total Estimated Time: 6-9 days (1-2 weeks)**
Risk Assessment
High Risk
- Backend Support: AI Toolkit backend must be ready and tested before frontend can be fully enabled
Medium Risk
- Ecosystem Mapping Errors: Incorrect ecosystem or variant mapping could cause training failures
- Parameter Mapping Errors: Incorrect parameter name transformations could cause training failures (mitigated by testing)
- Cost Estimation: If pricing differs, whatif queries need to handle AI Toolkit engine
Low Risk
- ✅ Civitai Client Compatibility: CONFIRMED - Beta 12 has all required types
- UI/UX Changes: Toggle implementation is straightforward based on Rapid Training pattern
- Feature Flag: Well-established pattern in the codebase
Success Criteria
Launch Criteria
- AI Toolkit toggle works for all supported models
- AI Toolkit and Rapid Training are mutually exclusive
- Parameters
numRepeatsandtrainBatchSizeare hidden when AI Toolkit is enabled - Parameter transformation is correct (ecosystem, modelVariant, parameter names)
- Cost estimation works with AI Toolkit engine (whatif query)
- Training submission succeeds for all supported ecosystems
- Feature flag controls access correctly
Post-Launch Metrics
- 90%+ training success rate with AI Toolkit
- Positive user feedback
- No significant increase in support tickets
- Adoption rate of 20%+ within first month
Notes
- Implementation should follow the existing Rapid Training pattern for consistency
- Keep AI Toolkit as an opt-in feature initially
- Monitor backend capacity before expanding access
- Consider adding telemetry to track parameter usage patterns
Summary of Key Technical Decisions
1. Two API Formats in Civitai Client
The implementation needs to handle two different training API formats:
- Legacy:
ImageResourceTrainingStep($type: 'imageResourceTraining') - New:
TrainingStep($type: 'training') ← Using this for AI Toolkit
2. Ecosystem and Model Variant Mapping
Required Fields: Both ecosystem and modelVariant are included in the AI Toolkit input.
Ecosystem Mapping (using getBaseModelEcosystem()):
- Civitai uses detailed ecosystem names:
sd1,sdxl,flux1,sd3,hyv1,wanvideo14b_t2v, etc. - AI Toolkit expects simplified names:
sd1,sdxl,flux1,sd3,wan - All Wan/Hunyuan variants map to
wan
Model Variant Rules:
sd1,sdxl: No variant neededsd3: Requires variant ("large"or"medium")flux1: Requires variant ("dev"or"schnell")wan: Requires variant ("2.1"or"2.2")
3. Supported Models (Based on Current Training System)
All current training models will support AI Toolkit:
- SD 1.5: 4 variants (sd_1_5, anime, semi, realistic)
- SDXL: 3 variants (sdxl, pony, illustrious)
- Flux: 1 variant (flux_dev)
- Wan Video: 2 variants (wan_2_1_t2v_14b, wan_2_1_i2v_14b_720p)
- Hunyuan: 1 variant (hy_720_fp8)
- Chroma: 1 variant (chroma)
- SD3: 0 variants (currently commented out, but ready for future)
4. Parameter Handling
Name Transformations - Frontend state uses Kohya-style naming, AI Toolkit API needs:
maxTrainEpochs→epochsunetLR→lrtextEncoderLR→textEncoderLrshuffleCaption→shuffleTokens
Excluded Parameters - These are NOT sent to AI Toolkit:
- ❌
numRepeats- Not used by AI Toolkit - ❌
trainBatchSize- Not used by AI Toolkit
Added Parameters - These are computed and added:
- ✅
ecosystem- Derived from base model usinggetAiToolkitEcosystem() - ✅
modelVariant- Derived from base model usinggetAiToolkitModelVariant()(conditional)
Transformation happens in the submission handler.