/** * Label Config Builder * * Flexible, declarative Label Studio configuration generator. * Supports any data type and control combination without hardcoding templates. */ export interface LabelConfigSpec { dataType: 'image' | 'text' | 'audio' | 'video' | 'timeseries' | 'html' | 'hypertext' dataName?: string // default: 'data' controls: ControlSpec[] } export interface ControlSpec { type: 'choices' | 'labels' | 'textarea' | 'rating' | 'rectangles' | 'polygon' | 'keypoint' | 'brush' name: string toName: string config: any } export interface ChoicesConfig { choices: string[] choice?: 'single' | 'multiple' required?: boolean } export interface LabelsConfig { labels: Array<{ value: string background?: string hotkey?: string }> } export interface RatingConfig { maxRating?: number icon?: string size?: 'small' | 'medium' | 'large' } export class LabelConfigBuilder { /** * Build Label Studio XML configuration from specification */ static build(spec: LabelConfigSpec): string { const dataName = spec.dataName || 'data' const dataTag = this.buildDataTag(spec.dataType, dataName) const controlTags = spec.controls.map(c => this.buildControlTag(c)) return ` ${dataTag} ${controlTags.join('\n ')} `.trim() } /** * Build data source tag (Image, Text, Audio, etc.) */ private static buildDataTag(type: string, name: string): string { const capitalizedType = type.charAt(0).toUpperCase() + type.slice(1) return `<${capitalizedType} name="${name}" value="$${name}"/>` } /** * Build control tag based on type */ private static buildControlTag(control: ControlSpec): string { switch (control.type) { case 'choices': return this.buildChoices(control) case 'labels': return this.buildLabels(control) case 'textarea': return this.buildTextArea(control) case 'rating': return this.buildRating(control) case 'rectangles': return this.buildRectangles(control) case 'polygon': return this.buildPolygon(control) case 'keypoint': return this.buildKeypoint(control) case 'brush': return this.buildBrush(control) default: throw new Error(`Unknown control type: ${control.type}`) } } /** * Build Choices control (single or multiple selection) */ private static buildChoices(control: ControlSpec): string { const config = control.config as ChoicesConfig const choice = config.choice || 'single' const required = config.required ? 'required="true"' : '' const choiceElements = config.choices .map(c => ` `) .join('\n') return ` ${choiceElements} ` } /** * Build Labels control (for NER, classification, etc.) */ private static buildLabels(control: ControlSpec): string { const config = control.config as LabelsConfig const labelElements = config.labels .map(l => { const background = l.background ? `background="${l.background}"` : '' const hotkey = l.hotkey ? `hotkey="${l.hotkey}"` : '' return `