add jinja UI controls, smooth download ETA, filter new kcpp spam, fix right-click in popups

This commit is contained in:
lone-cloud 2026-04-05 22:18:28 -07:00
parent ca7fd211ff
commit 826d63c68a
Signed by: lone-cloud
GPG key ID: B0848536D672CD8D
11 changed files with 122 additions and 32 deletions

View file

@ -1,6 +1,6 @@
{
"name": "gerbil",
"version": "1.21.2",
"version": "1.22.0",
"description": "Run Large Language Models locally",
"keywords": [
"ai",

8
pnpm-lock.yaml generated
View file

@ -1163,8 +1163,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.10.14:
resolution: {integrity: sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==}
baseline-browser-mapping@2.10.15:
resolution: {integrity: sha512-1nfKCq9wuAZFTkA2ey/3OXXx7GzFjLdkTiFVNwlJ9WqdI706CZRIhEqjuwanjMIja+84jDLa9rcyZDPDiVkASQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@ -4082,7 +4082,7 @@ snapshots:
base64-js@1.5.1: {}
baseline-browser-mapping@2.10.14: {}
baseline-browser-mapping@2.10.15: {}
bl@4.1.0:
dependencies:
@ -4108,7 +4108,7 @@ snapshots:
browserslist@4.28.2:
dependencies:
baseline-browser-mapping: 2.10.14
baseline-browser-mapping: 2.10.15
caniuse-lite: 1.0.30001785
electron-to-chromium: 1.5.331
node-releases: 2.0.37

View file

@ -14,11 +14,17 @@ export const AdvancedTab = () => {
noavx2,
failsafe,
debugmode,
jinja,
jinjatools,
jinjakwargs,
setAdditionalArguments,
setPreLaunchCommands,
setNoavx2,
setFailsafe,
setDebugmode,
setJinja,
setJinjatools,
setJinjakwargs,
} = useLaunchConfigStore();
const [commandLineModalOpen, setCommandLineModalOpen] = useState(false);
const [backendSupport, setBackendSupport] = useState<{
@ -86,11 +92,47 @@ export const AdvancedTab = () => {
label="Debug Mode"
tooltip="Shows additional debug info in the terminal."
/>
<CheckboxWithTooltip
checked={jinja}
onChange={(val) => {
setJinja(val);
if (!val) setJinjatools(false);
}}
label="Use Jinja"
tooltip="Enables using jinja chat template formatting for chat completions endpoint."
/>
<CheckboxWithTooltip
checked={jinjatools}
onChange={(val) => {
setJinjatools(val);
if (val) setJinja(true);
}}
label="Jinja for Tools"
tooltip="Allows jinja even with tool calls. If unchecked, jinja will be disabled when tools are used."
/>
</SimpleGrid>
</div>
{(jinja || jinjatools) && (
<div>
<Group>
<Text size="sm" fw={500}>
Jinja Kwargs
</Text>
<InfoTooltip label="Set additional fields for the Jinja JSON template parser, must be a valid JSON object." />
</Group>
<TextInput
placeholder='e.g. {"enable_thinking":true}'
value={jinjakwargs}
onChange={(event) => setJinjakwargs(event.currentTarget.value)}
/>
</div>
)}
<div>
<Group mb="xs" justify="space-between">
<Group justify="space-between">
<Group>
<Text size="sm" fw={500}>
Additional Arguments
@ -109,7 +151,7 @@ export const AdvancedTab = () => {
</div>
<div>
<Group mb="xs">
<Group>
<Text size="sm" fw={500}>
Pre-Launch Commands
</Text>

View file

@ -59,6 +59,9 @@ const UI_COVERED_ARGS = new Set([
'--tensor_split',
'--debugmode',
'--lowvram',
'--jinja',
'--jinja_tools',
'--jinja_kwargs',
'--smartcache',
'--pipelineparallel',
'--nopipelineparallel',
@ -396,30 +399,6 @@ const COMMAND_LINE_ARGUMENTS = [
flag: '--chatcompletionsadapter',
metavar: '[filename]',
},
{
category: 'Advanced',
description:
'Enables using jinja chat template formatting for chat completions endpoint. Other endpoints are unaffected. Tool calls are done without jinja.',
flag: '--jinja',
type: 'boolean',
},
{
aliases: ['--jinja-tools', '--jinjatools'],
category: 'Advanced',
description:
'Enables using jinja chat template formatting for chat completions endpoint. Other endpoints are unaffected. Tool calls are done with jinja.',
flag: '--jinja_tools',
type: 'boolean',
},
{
aliases: ['--jinja-kwargs', '--jinjakwargs', '--chat-template-kwargs'],
category: 'Advanced',
default: '',
description:
'Set additional fields for Jinja JSON template parser, must be a valid JSON object.',
flag: '--jinja_kwargs',
metavar: '{"parameter":"value",...}',
},
{
category: 'Advanced',
description:

View file

@ -68,6 +68,9 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
smartcache,
pipelineparallel,
quantkv,
jinja,
jinjatools,
jinjakwargs,
parseAndApplyConfigFile,
loadConfigFromFile,
setModel,
@ -187,6 +190,9 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
usevulkan: acceleration === 'vulkan',
websearch,
quantkv,
jinja,
jinjatools,
jinjakwargs,
});
const handleCreateNewConfig = async (configName: string) => {
@ -301,6 +307,9 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
usemmap,
websearch,
quantkv,
jinja,
jinjatools,
jinjakwargs,
});
}, [
handleLaunch,
@ -342,6 +351,9 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
smartcache,
pipelineparallel,
quantkv,
jinja,
jinjatools,
jinjakwargs,
]);
return (

View file

@ -47,6 +47,9 @@ interface LaunchArgs {
smartcache: boolean;
pipelineparallel: boolean;
quantkv: number;
jinja: boolean;
jinjatools: boolean;
jinjakwargs: string;
}
const buildModelArgs = (model: string, sdmodel: string, launchArgs: LaunchArgs) => {
@ -162,6 +165,16 @@ const buildConfigArgs = (isImageMode: boolean, launchArgs: LaunchArgs) => {
args.push('--quantkv', launchArgs.quantkv.toString());
}
if (launchArgs.jinjatools) {
args.push('--jinja_tools');
} else if (launchArgs.jinja) {
args.push('--jinja');
}
if ((launchArgs.jinja || launchArgs.jinjatools) && launchArgs.jinjakwargs.trim()) {
args.push('--jinja_kwargs', launchArgs.jinjakwargs.trim());
}
return args;
};

View file

@ -149,6 +149,8 @@ export function filterSpam(output: string) {
/^done_getting_tensors:/,
/^sched_reserve:/,
/^llama_memory_recurrent:/,
/^str: cannot properly format tensor name/,
/^tensor .+ buffer type overridden to /,
];
return output

View file

@ -142,6 +142,8 @@ async function downloadFile(
let downloadedBytes = 0;
let lastReportTime = Date.now();
let lastReportedBytes = 0;
const speedSamples: number[] = [];
const SPEED_WINDOW = 10;
fileStream = createWriteStream(tempPath);
@ -154,7 +156,10 @@ async function downloadFile(
if (timeDiff >= 0.5) {
const bytesDiff = downloadedBytes - lastReportedBytes;
const speedBytesPerSec = bytesDiff / timeDiff;
const instantSpeed = bytesDiff / timeDiff;
speedSamples.push(instantSpeed);
if (speedSamples.length > SPEED_WINDOW) speedSamples.shift();
const speedBytesPerSec = speedSamples.reduce((a, b) => a + b, 0) / speedSamples.length;
const percent = totalBytes ? Math.round((downloadedBytes / totalBytes) * 100) : 0;
const downloadedMB = (downloadedBytes / 1024 / 1024).toFixed(2);
const totalMB = (totalBytes / 1024 / 1024).toFixed(2);

View file

@ -148,6 +148,10 @@ export async function createMainWindow(options?: { startHidden?: boolean }) {
},
}));
mainWindow.webContents.on('did-create-window', (popupWindow) => {
setupContextMenu(popupWindow);
});
mainWindow.on('close', (event) => {
saveBounds();
if (getEnableSystemTray() && isTrayActive()) {

View file

@ -45,6 +45,9 @@ interface LaunchConfigState {
smartcache: boolean;
pipelineparallel: boolean;
quantkv: number;
jinja: boolean;
jinjatools: boolean;
jinjakwargs: string;
isImageGenerationMode: boolean;
isTextMode: boolean;
@ -88,6 +91,9 @@ interface LaunchConfigState {
setSmartcache: (smartcache: boolean) => void;
setPipelineparallel: (pipelineparallel: boolean) => void;
setQuantkv: (quantkv: number) => void;
setJinja: (jinja: boolean) => void;
setJinjatools: (jinjatools: boolean) => void;
setJinjakwargs: (jinjakwargs: string) => void;
parseAndApplyConfigFile: (configPath: string) => Promise<void>;
loadConfigFromFile: (
@ -400,11 +406,32 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
updates.quantkv = 0;
}
if (typeof configData.jinja === 'boolean') {
updates.jinja = configData.jinja;
} else {
updates.jinja = false;
}
if (typeof configData.jinjatools === 'boolean') {
updates.jinjatools = configData.jinjatools;
} else {
updates.jinjatools = false;
}
if (typeof configData.jinjakwargs === 'string') {
updates.jinjakwargs = configData.jinjakwargs;
} else {
updates.jinjakwargs = '';
}
set(updates);
}
},
pipelineparallel: false,
quantkv: 0,
jinja: false,
jinjatools: false,
jinjakwargs: '',
port: undefined,
preLaunchCommands: [''],
quantmatmul: true,
@ -482,6 +509,9 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
setSdvae: (vae) => set({ sdvae: vae }),
setSdvaecpu: (enabled) => set({ sdvaecpu: enabled }),
setSmartcache: (smartcache) => set({ smartcache }),
setJinja: (jinja) => set({ jinja }),
setJinjatools: (jinjatools) => set({ jinjatools }),
setJinjakwargs: (jinjakwargs) => set({ jinjakwargs }),
setTensorSplit: (split) => set({ tensorSplit: split }),
setUsemmap: (usemmap) => set({ usemmap }),

View file

@ -120,6 +120,9 @@ export interface KoboldConfig {
smartcache?: boolean;
pipelineparallel?: boolean;
quantkv?: number;
jinja?: boolean;
jinjatools?: boolean;
jinjakwargs?: string;
autoGpuLayers?: boolean;
model?: string;
backend?: string;