210 lines
9.1 KiB
TypeScript
210 lines
9.1 KiB
TypeScript
import React from "react";
|
|
import {
|
|
Binary,
|
|
ArrowRight,
|
|
Check,
|
|
Sliders,
|
|
} from "lucide-react";
|
|
import { BaseModelInfo, GGUFConfig, GGUFQuantType } from "../types";
|
|
import { getGGUFSizeEstimate } from "../utils/hardwareCalculator";
|
|
|
|
interface GGUFStudioProps {
|
|
selectedModel: BaseModelInfo;
|
|
ggufConfig: GGUFConfig;
|
|
setGgufConfig: React.Dispatch<React.SetStateAction<GGUFConfig>>;
|
|
onProceed: () => void;
|
|
}
|
|
|
|
export const GGUFStudio: React.FC<GGUFStudioProps> = ({
|
|
selectedModel,
|
|
ggufConfig,
|
|
setGgufConfig,
|
|
onProceed,
|
|
}) => {
|
|
const quantOptions: { type: GGUFQuantType; label: string; desc: string; lossRating: string }[] = [
|
|
{
|
|
type: "Q4_K_M",
|
|
label: "Q4_K_M (Gold Standard)",
|
|
desc: "Medium 4-bit k-quant. Optimal sweet spot between quality, speed, and 16GB VRAM fit.",
|
|
lossRating: "<0.5% Perplexity Loss",
|
|
},
|
|
{
|
|
type: "IQ4_XS",
|
|
label: "IQ4_XS (Importance Matrix 4-bit)",
|
|
desc: "Uses importance matrix quantization for higher fidelity at smaller file size.",
|
|
lossRating: "<0.3% Perplexity Loss",
|
|
},
|
|
{
|
|
type: "Q5_K_M",
|
|
label: "Q5_K_M (High Precision 5-bit)",
|
|
desc: "5-bit medium quant for maximum precision when ample VRAM is available.",
|
|
lossRating: "<0.1% Perplexity Loss",
|
|
},
|
|
{
|
|
type: "Q4_K_S",
|
|
label: "Q4_K_S (Compact 4-bit)",
|
|
desc: "Small 4-bit quant for maximum memory compression.",
|
|
lossRating: "<0.8% Perplexity Loss",
|
|
},
|
|
{
|
|
type: "IQ3_XXS",
|
|
label: "IQ3_XXS (Extreme 3-bit)",
|
|
desc: "Compact 3-bit format to fit 14B models comfortably in 8GB-12GB VRAM.",
|
|
lossRating: "~1.5% Perplexity Loss",
|
|
},
|
|
{
|
|
type: "Q8_0",
|
|
label: "Q8_0 (Near Lossless 8-bit)",
|
|
desc: "8-bit uncompressed precision. Virtually indistinguishable from FP16.",
|
|
lossRating: "0.0% Perplexity Loss",
|
|
},
|
|
];
|
|
|
|
const currentEst = getGGUFSizeEstimate(selectedModel.parametersBillion, ggufConfig.quantization);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header Banner */}
|
|
<div className="bg-[#18181b]/50 border border-[#27272a] rounded-xl p-5 flex flex-wrap items-center justify-between gap-4">
|
|
<div className="max-w-2xl">
|
|
<div className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded text-[10px] font-mono text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 mb-2">
|
|
<Binary className="w-3.5 h-3.5 text-emerald-400" /> GGUF MULTI-TOOL & QUANTIZATION SUITE
|
|
</div>
|
|
<h2 className="text-lg font-semibold text-[#f4f4f5]">
|
|
GGUF Quantization Matrix & RTX 4080 Super Optimization
|
|
</h2>
|
|
<p className="text-xs text-zinc-400 mt-1 leading-relaxed">
|
|
Directly export quantized GGUFs with custom context windows (up to 128k), prompt templates, stop tokens, and full GPU layer offloading (<code className="text-blue-400 font-mono">num_gpu 999</code>) for instant loading in Ollama on Windows.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="bg-black/30 px-3.5 py-2 rounded border border-zinc-800 text-xs">
|
|
<div className="text-[10px] font-mono text-zinc-500 uppercase">GGUF File Size</div>
|
|
<div className="text-base font-mono font-bold text-emerald-400">{currentEst.sizeGb} GB</div>
|
|
<div className="text-[10px] text-zinc-500">Fits 16GB GDDR6X ({Math.round((currentEst.ramRequiredGb / 16) * 100)}% VRAM)</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quantization Matrix Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{quantOptions.map((q) => {
|
|
const isSelected = ggufConfig.quantization === q.type;
|
|
const est = getGGUFSizeEstimate(selectedModel.parametersBillion, q.type);
|
|
return (
|
|
<div
|
|
key={q.type}
|
|
onClick={() => setGgufConfig((prev) => ({ ...prev, quantization: q.type }))}
|
|
className={`p-4 rounded-lg border transition-all cursor-pointer relative flex flex-col justify-between ${
|
|
isSelected
|
|
? "bg-[#18181b] border-blue-500/40 text-blue-400 ring-1 ring-blue-500/20"
|
|
: "bg-[#121214] border-[#27272a] hover:border-zinc-700 hover:bg-[#18181b]/40 text-zinc-300"
|
|
}`}
|
|
>
|
|
{isSelected && (
|
|
<div className="absolute top-3 right-3 w-4 h-4 rounded-full bg-blue-600 text-white flex items-center justify-center font-bold">
|
|
<Check className="w-3 h-3 stroke-[3]" />
|
|
</div>
|
|
)}
|
|
|
|
<div>
|
|
<div className="font-semibold text-[#f4f4f5] text-xs mb-1 font-mono">{q.label}</div>
|
|
<div className="text-[11px] text-zinc-400 mb-3 leading-relaxed">{q.desc}</div>
|
|
</div>
|
|
|
|
<div className="pt-2 border-t border-zinc-800/80 flex items-center justify-between text-xs">
|
|
<span className="font-mono text-emerald-400 font-bold">{est.sizeGb} GB</span>
|
|
<span className="text-[10px] font-mono text-zinc-500">{q.lossRating}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* GGUF Metadata & Modelfile Parameters Form */}
|
|
<div className="bg-[#18181b]/50 border border-[#27272a] rounded-xl p-5 space-y-4">
|
|
<h3 className="text-sm font-semibold text-[#f4f4f5] flex items-center gap-2">
|
|
<Sliders className="w-4 h-4 text-blue-400" /> GGUF Inference Parameters & Modelfile Configuration
|
|
</h3>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-xs">
|
|
<div className="space-y-1.5 bg-black/30 p-3.5 rounded border border-zinc-800">
|
|
<label className="text-[10px] font-mono text-zinc-400 uppercase block">Context Window (num_ctx)</label>
|
|
<select
|
|
value={ggufConfig.contextLength}
|
|
onChange={(e) =>
|
|
setGgufConfig((prev) => ({ ...prev, contextLength: parseInt(e.target.value) }))
|
|
}
|
|
className="w-full bg-zinc-950 border border-zinc-800 rounded px-2.5 py-1.5 text-zinc-200 text-xs font-mono focus:ring-1 focus:ring-blue-600 outline-none"
|
|
>
|
|
<option value={8192}>8,192 tokens</option>
|
|
<option value={16384}>16,384 tokens (Recommended for Coding & MCP)</option>
|
|
<option value={32768}>32,768 tokens (Long context)</option>
|
|
<option value={65536}>65,536 tokens</option>
|
|
<option value={131072}>131,072 tokens (Full Llama 3.1 128k)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div className="space-y-1.5 bg-black/30 p-3.5 rounded border border-zinc-800">
|
|
<label className="text-[10px] font-mono text-zinc-400 uppercase block">Temperature (Sampling)</label>
|
|
<input
|
|
type="number"
|
|
step="0.05"
|
|
value={ggufConfig.temperature}
|
|
onChange={(e) =>
|
|
setGgufConfig((prev) => ({
|
|
...prev,
|
|
temperature: parseFloat(e.target.value) || 0.6,
|
|
}))
|
|
}
|
|
className="w-full bg-zinc-950 border border-zinc-800 rounded px-2.5 py-1.5 text-zinc-200 font-mono text-xs focus:ring-1 focus:ring-blue-600 outline-none"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-1.5 bg-black/30 p-3.5 rounded border border-zinc-800">
|
|
<label className="text-[10px] font-mono text-zinc-400 uppercase block">GPU Layers Offload (num_gpu)</label>
|
|
<input
|
|
type="number"
|
|
value={ggufConfig.num_gpu_layers}
|
|
onChange={(e) =>
|
|
setGgufConfig((prev) => ({
|
|
...prev,
|
|
num_gpu_layers: parseInt(e.target.value) || 999,
|
|
}))
|
|
}
|
|
className="w-full bg-zinc-950 border border-zinc-800 rounded px-2.5 py-1.5 text-zinc-200 font-mono text-xs focus:ring-1 focus:ring-blue-600 outline-none"
|
|
/>
|
|
<span className="text-[10px] text-emerald-400 font-medium block mt-1">
|
|
999 = Full offload to RTX 4080 Super VRAM
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* System Prompt */}
|
|
<div className="space-y-1.5">
|
|
<label className="text-[10px] font-mono text-zinc-400 uppercase block">
|
|
Embedded System Instruction for Modelfile
|
|
</label>
|
|
<textarea
|
|
rows={3}
|
|
value={ggufConfig.systemPrompt}
|
|
onChange={(e) =>
|
|
setGgufConfig((prev) => ({ ...prev, systemPrompt: e.target.value }))
|
|
}
|
|
className="w-full bg-zinc-950 border border-zinc-800 rounded p-3 text-xs text-zinc-200 font-mono placeholder-zinc-600 focus:ring-1 focus:ring-blue-600 outline-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end">
|
|
<button
|
|
onClick={onProceed}
|
|
className="flex items-center gap-2 px-4 py-2 rounded text-xs font-medium bg-blue-600 hover:bg-blue-500 text-white shadow-sm transition-all cursor-pointer"
|
|
>
|
|
<span>Launch Live Training Simulator</span>
|
|
<ArrowRight className="w-3.5 h-3.5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|