11import React , { useState , useEffect , useRef , useCallback } from 'react' ;
2- import { Sparkles , ChevronDown , Settings2 , Trash2 , Music2 , Sliders , Dices , Hash , RefreshCw , Plus , Upload , Play , Pause , Info } from 'lucide-react' ;
2+ import { Sparkles , ChevronDown , Settings2 , Trash2 , Music2 , Sliders , Dices , Hash , RefreshCw , Plus , Upload , Play , Pause , Info , Loader2 } from 'lucide-react' ;
33import { GenerationParams , Song } from '../types' ;
44import { useAuth } from '../context/AuthContext' ;
5- import { generateApi } from '../services/api' ;
5+ import { generateApi , type LoraAdapter } from '../services/api' ;
66
77interface ReferenceTrack {
88 id : string ;
@@ -142,12 +142,12 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
142142 const [ duration , setDuration ] = useState ( - 1 ) ;
143143 const [ batchSize , setBatchSize ] = useState ( 1 ) ;
144144 const [ bulkCount , setBulkCount ] = useState ( 1 ) ; // Number of independent generation jobs to queue
145- const [ guidanceScale , setGuidanceScale ] = useState ( 7 .0) ;
145+ const [ guidanceScale , setGuidanceScale ] = useState ( 4 .0) ;
146146 const [ randomSeed , setRandomSeed ] = useState ( true ) ;
147147 const [ seed , setSeed ] = useState ( - 1 ) ;
148148 const [ thinking , setThinking ] = useState ( false ) ; // Default false for GPU compatibility
149149 const [ audioFormat , setAudioFormat ] = useState < 'mp3' | 'flac' > ( 'mp3' ) ;
150- const [ inferenceSteps , setInferenceSteps ] = useState ( 8 ) ;
150+ const [ inferenceSteps , setInferenceSteps ] = useState ( 65 ) ;
151151 const [ inferMethod , setInferMethod ] = useState < 'ode' | 'sde' > ( 'ode' ) ;
152152 const [ shift , setShift ] = useState ( 3.0 ) ;
153153
@@ -171,6 +171,10 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
171171 const [ cfgIntervalStart , setCfgIntervalStart ] = useState ( 0.0 ) ;
172172 const [ cfgIntervalEnd , setCfgIntervalEnd ] = useState ( 1.0 ) ;
173173 const [ customTimesteps , setCustomTimesteps ] = useState ( '' ) ;
174+ const [ loraAdapters , setLoraAdapters ] = useState < LoraAdapter [ ] > ( [ ] ) ;
175+ const [ loraLoading , setLoraLoading ] = useState ( false ) ;
176+ const [ loraNameOrPath , setLoraNameOrPath ] = useState ( '' ) ;
177+ const [ loraWeight , setLoraWeight ] = useState ( 0.75 ) ;
174178 const [ useCotMetas , setUseCotMetas ] = useState ( true ) ;
175179 const [ useCotCaption , setUseCotCaption ] = useState ( true ) ;
176180 const [ useCotLanguage , setUseCotLanguage ] = useState ( true ) ;
@@ -249,6 +253,17 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
249253 }
250254 } , [ referenceAudioUrl , sourceAudioUrl ] ) ;
251255
256+ const fetchLoraAdapters = useCallback ( ( ) => {
257+ setLoraLoading ( true ) ;
258+ generateApi . getLoraAdapters ( )
259+ . then ( ( res ) => setLoraAdapters ( res . adapters || [ ] ) )
260+ . catch ( ( ) => setLoraAdapters ( [ ] ) )
261+ . finally ( ( ) => setLoraLoading ( false ) ) ;
262+ } , [ ] ) ;
263+
264+ // Fetch LoRA adapters on mount (Training output + custom_lora)
265+ useEffect ( ( ) => { fetchLoraAdapters ( ) ; } , [ fetchLoraAdapters ] ) ;
266+
252267 useEffect ( ( ) => {
253268 const handleMouseMove = ( e : MouseEvent ) => {
254269 if ( ! isResizing ) return ;
@@ -629,6 +644,8 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
629644 cfgIntervalStart,
630645 cfgIntervalEnd,
631646 customTimesteps : customTimesteps . trim ( ) || undefined ,
647+ loraNameOrPath : loraNameOrPath . trim ( ) || undefined ,
648+ loraWeight,
632649 useCotMetas,
633650 useCotCaption,
634651 useCotLanguage,
@@ -1373,7 +1390,7 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
13731390 < div className = "flex items-center justify-between" >
13741391 < span className = "inline-flex items-center gap-1.5" >
13751392 < label className = "text-xs font-medium text-zinc-600 dark:text-zinc-400" > Inference Steps</ label >
1376- < InfoTooltip text = "Number of denoising steps. Turbo: 1–20 (8 recommended). More steps = better quality, slower ." />
1393+ < InfoTooltip text = "Number of denoising steps. 65 recommended for quality (low CFG + high steps). Turbo: 8–20 ." />
13771394 </ span >
13781395 < span className = "text-xs font-mono text-zinc-900 dark:text-white bg-zinc-100 dark:bg-black/20 px-2 py-0.5 rounded" > { inferenceSteps } </ span >
13791396 </ div >
@@ -1386,7 +1403,7 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
13861403 onChange = { ( e ) => setInferenceSteps ( Number ( e . target . value ) ) }
13871404 className = "w-full h-2 bg-zinc-200 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-pink-500"
13881405 />
1389- < p className = "text-[10px] text-zinc-500" > More steps = better quality, slower (8 recommended for turbo) </ p >
1406+ < p className = "text-[10px] text-zinc-500" > 65 recommended for quality; more steps = slower </ p >
13901407 </ div >
13911408
13921409 { /* Guidance Scale */ }
@@ -1442,6 +1459,50 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
14421459 </ div >
14431460 </ div >
14441461
1462+ { /* LoRA adapter (Training / custom_lora) */ }
1463+ < div className = "grid grid-cols-2 gap-3" >
1464+ < div className = "space-y-1.5" >
1465+ < span className = "inline-flex items-center gap-1.5" >
1466+ < label className = "text-xs font-medium text-zinc-600 dark:text-zinc-400" > LoRA adapter</ label >
1467+ < InfoTooltip text = "Use a custom LoRA (e.g. from Training). After training, click Refresh to see new adapters." />
1468+ < button
1469+ type = "button"
1470+ onClick = { fetchLoraAdapters }
1471+ disabled = { loraLoading }
1472+ className = "p-0.5 rounded hover:bg-zinc-200 dark:hover:bg-zinc-600 disabled:opacity-50"
1473+ title = "Refresh LoRA list"
1474+ >
1475+ { loraLoading ? < Loader2 size = { 12 } className = "animate-spin" /> : < RefreshCw size = { 12 } /> }
1476+ </ button >
1477+ </ span >
1478+ < select
1479+ value = { loraNameOrPath }
1480+ onChange = { ( e ) => setLoraNameOrPath ( e . target . value ) }
1481+ className = "w-full bg-zinc-50 dark:bg-black/20 border border-zinc-200 dark:border-white/10 rounded-lg px-2 py-1.5 text-xs text-zinc-900 dark:text-white focus:outline-none"
1482+ >
1483+ < option value = "" > None</ option >
1484+ { loraAdapters . map ( ( a ) => (
1485+ < option key = { a . path } value = { a . path } > { a . name } </ option >
1486+ ) ) }
1487+ </ select >
1488+ </ div >
1489+ < div className = "space-y-1.5" >
1490+ < span className = "inline-flex items-center gap-1.5" >
1491+ < label className = "text-xs font-medium text-zinc-600 dark:text-zinc-400" > LoRA weight</ label >
1492+ < InfoTooltip text = "Strength of the LoRA (0–2). 0.75 is a good default; lower = subtler, higher = stronger style." />
1493+ </ span >
1494+ < input
1495+ type = "number"
1496+ min = { 0 }
1497+ max = { 2 }
1498+ step = { 0.05 }
1499+ value = { loraWeight }
1500+ onChange = { ( e ) => setLoraWeight ( Number ( e . target . value ) ) }
1501+ className = "w-full bg-zinc-50 dark:bg-black/20 border border-zinc-200 dark:border-white/10 rounded-lg px-2 py-1.5 text-xs text-zinc-900 dark:text-white focus:outline-none"
1502+ />
1503+ </ div >
1504+ </ div >
1505+
14451506 { /* Seed */ }
14461507 < div className = "space-y-2" >
14471508 < div className = "flex items-center justify-between" >
0 commit comments