Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 72 additions & 42 deletions frontend/src/components/LoRAManager.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { useState, useEffect } from "react";
import { Button } from "./ui/button";
import { SliderWithInput } from "./ui/slider-with-input";
import { Plus, X, RefreshCw } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "./ui/tooltip";
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "./ui/select";
import { Plus, X, RefreshCw } from "lucide-react";
import { LabelWithTooltip } from "./ui/label-with-tooltip";
import { PARAMETER_METADATA } from "../data/parameterMetadata";
import type { LoRAConfig, LoraMergeStrategy } from "../types";
import { listLoRAFiles, type LoRAFileInfo } from "../lib/api";
import { FilePicker } from "./ui/file-picker";
Expand Down Expand Up @@ -61,6 +64,7 @@ export function LoRAManager({
id: crypto.randomUUID(),
path: "",
scale: 1.0,
mergeMode: loraMergeStrategy,
};
onLorasChange([...loras, newLora]);
};
Expand All @@ -83,6 +87,18 @@ export function LoRAManager({
handleLoraChange(id, { scale });
};

const getScaleAdjustmentInfo = (lora: LoRAConfig) => {
const effectiveMergeMode = lora.mergeMode || loraMergeStrategy;
const isPermanentMerge = effectiveMergeMode === "permanent_merge";
const isDisabled = disabled || (isStreaming && isPermanentMerge);
const tooltipText =
isStreaming && isPermanentMerge
? PARAMETER_METADATA.loraScaleDisabledDuringStream.tooltip
: PARAMETER_METADATA.loraScale.tooltip;

return { isDisabled, tooltipText };
};

return (
<div className="space-y-2">
<div className="flex items-center justify-between">
Expand Down Expand Up @@ -155,42 +171,56 @@ export function LoRAManager({
</div>

<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground w-12">Scale:</span>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className="flex-1 min-w-0">
<SliderWithInput
value={localScales[lora.id] ?? lora.scale}
onValueChange={value => {
handleLocalScaleChange(lora.id, value);
}}
onValueCommit={value => {
handleScaleCommit(lora.id, value);
}}
min={-10}
max={10}
step={0.1}
incrementAmount={0.1}
disabled={
disabled ||
(isStreaming &&
loraMergeStrategy === "permanent_merge")
}
className="flex-1"
valueFormatter={v => Math.round(v * 10) / 10}
/>
</div>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs">
{isStreaming && loraMergeStrategy === "permanent_merge"
? "Runtime adjustment is disabled with Permanent Merge strategy. LoRA scales are fixed at load time."
: "Adjust LoRA strength. Updates automatically when you release the slider or use +/- buttons. 0.0 = no effect, 1.0 = full strength"}
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<LabelWithTooltip
label="Strategy:"
tooltip={PARAMETER_METADATA.loraMergeStrategy.tooltip}
className="text-xs text-muted-foreground w-16"
/>
<Select
value={lora.mergeMode || loraMergeStrategy}
onValueChange={value => {
handleLoraChange(lora.id, {
mergeMode: value as LoraMergeStrategy,
});
}}
disabled={disabled || isStreaming}
>
<SelectTrigger className="h-7 flex-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="permanent_merge">
Permanent Merge
</SelectItem>
<SelectItem value="runtime_peft">Runtime PEFT</SelectItem>
</SelectContent>
</Select>
</div>

<div className="flex items-center gap-2">
<LabelWithTooltip
label="Scale:"
tooltip={getScaleAdjustmentInfo(lora).tooltipText}
className="text-xs text-muted-foreground w-16"
/>
<div className="flex-1 min-w-0">
<SliderWithInput
value={localScales[lora.id] ?? lora.scale}
onValueChange={value => {
handleLocalScaleChange(lora.id, value);
}}
onValueCommit={value => {
handleScaleCommit(lora.id, value);
}}
min={-10}
max={10}
step={0.1}
incrementAmount={0.1}
disabled={getScaleAdjustmentInfo(lora).isDisabled}
className="flex-1"
valueFormatter={v => Math.round(v * 10) / 10}
/>
</div>
</div>
</div>
))}
Expand Down
60 changes: 0 additions & 60 deletions frontend/src/components/SettingsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ interface SettingsPanelProps {
loras?: LoRAConfig[];
onLorasChange: (loras: LoRAConfig[]) => void;
loraMergeStrategy?: LoraMergeStrategy;
onLoraMergeStrategyChange?: (strategy: LoraMergeStrategy) => void;
}

export function SettingsPanel({
Expand Down Expand Up @@ -88,7 +87,6 @@ export function SettingsPanel({
loras = [],
onLorasChange,
loraMergeStrategy = "permanent_merge",
onLoraMergeStrategyChange,
}: SettingsPanelProps) {
// Use pipeline-specific default if resolution is not provided
const effectiveResolution = resolution || getDefaultResolution(pipelineId);
Expand Down Expand Up @@ -308,64 +306,6 @@ export function SettingsPanel({
isStreaming={isStreaming}
loraMergeStrategy={loraMergeStrategy}
/>

{loras.length > 0 && (
<div className="space-y-2">
<div className="flex items-center justify-between gap-2">
<LabelWithTooltip
label={PARAMETER_METADATA.loraMergeStrategy.label}
tooltip={PARAMETER_METADATA.loraMergeStrategy.tooltip}
className="text-sm text-foreground"
/>
<Select
value={loraMergeStrategy}
onValueChange={value => {
onLoraMergeStrategyChange?.(value as LoraMergeStrategy);
}}
disabled={isStreaming}
>
<SelectTrigger className="w-[180px] h-7">
<SelectValue />
</SelectTrigger>
<SelectContent>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<SelectItem value="permanent_merge">
Permanent Merge
</SelectItem>
</TooltipTrigger>
<TooltipContent side="right" className="max-w-xs">
<p className="text-xs">
Maximum performance, no runtime updates. LoRA
scales are permanently merged into model weights
at load time. Ideal for when you already know what
scale to use.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<SelectItem value="runtime_peft">
Runtime PEFT
</SelectItem>
</TooltipTrigger>
<TooltipContent side="right" className="max-w-xs">
<p className="text-xs">
Lower performance, instant runtime updates. LoRA
scales can be adjusted during streaming without
reloading the model. Faster initialization.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</SelectContent>
</Select>
</div>
</div>
)}
</div>
)}

Expand Down
10 changes: 10 additions & 0 deletions frontend/src/data/parameterMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,14 @@ export const PARAMETER_METADATA: Record<string, ParameterMetadata> = {
tooltip:
"LoRA merge strategy affects performance and update capabilities. Permanent Merge: Maximum performance, no runtime updates. Runtime PEFT: Lower performance, instant runtime updates.",
},
loraScale: {
label: "Scale:",
tooltip:
"Adjust LoRA strength. Updates automatically when you release the slider or use +/- buttons. Typical values: 0.0 = no effect, 1.0 = full strength. Full range -10.0 to 10.0 available depending on LoRA specifications.",
},
loraScaleDisabledDuringStream: {
label: "Scale:",
tooltip:
"Runtime adjustment is disabled with Permanent Merge strategy. LoRA scales are fixed at load time. Typical values: 0.0 = no effect, 1.0 = full strength. Full range -10.0 to 10.0 available depending on LoRA specifications.",
},
};
19 changes: 9 additions & 10 deletions frontend/src/pages/StreamPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@ import { sendLoRAScaleUpdates } from "../utils/loraHelpers";
function buildLoRAParams(
loras?: LoRAConfig[],
strategy?: LoraMergeStrategy
): { loras?: { path: string; scale: number }[]; lora_merge_mode: string } {
): {
loras?: { path: string; scale: number; merge_mode?: string }[];
lora_merge_mode: string;
} {
return {
loras: loras?.map(({ path, scale }) => ({ path, scale })),
loras: loras?.map(({ path, scale, mergeMode }) => ({
path,
scale,
...(mergeMode && { merge_mode: mergeMode }),
})),
lora_merge_mode: strategy ?? "permanent_merge",
};
}
Expand Down Expand Up @@ -341,13 +348,6 @@ export function StreamPage() {
// Note: Adding/removing LoRAs requires pipeline reload
};

const handleLoraMergeStrategyChange = (
loraMergeStrategy: "permanent_merge" | "runtime_peft"
) => {
updateSettings({ loraMergeStrategy });
// Note: This setting requires pipeline reload, so we don't send parameter update here
};

const handleResetCache = () => {
// Send reset cache command to backend
sendParameterUpdate({
Expand Down Expand Up @@ -841,7 +841,6 @@ export function StreamPage() {
loras={settings.loras || []}
onLorasChange={handleLorasChange}
loraMergeStrategy={settings.loraMergeStrategy ?? "permanent_merge"}
onLoraMergeStrategyChange={handleLoraMergeStrategyChange}
/>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface LoRAConfig {
id: string;
path: string;
scale: number;
mergeMode?: LoraMergeStrategy;
}

export interface SettingsState {
Expand Down
Loading