mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 09:33:10 -07:00
persist additional arguments to config, change px to rem where it makes sense
This commit is contained in:
parent
d298203338
commit
e8ccc68875
15 changed files with 93 additions and 74 deletions
|
|
@ -42,7 +42,9 @@ A koboldcpp manager. <!-- markdownlint-disable MD033 -->
|
|||
|
||||
There is ROCm Windows support maintained by YellowRoseCx in a separate fork.
|
||||
Unfortunately it does not properly support unpacking, which would greatly diminish its performance and provide a poor UX when used alongside this app.
|
||||
For Friendly Kobold to work with this fork, this issue must be fixed first: https://github.com/YellowRoseCx/koboldcpp-rocm/issues/129
|
||||
For Friendly Kobold to work with this fork, [this issue must be fixed first](https://github.com/YellowRoseCx/koboldcpp-rocm/issues/129).
|
||||
|
||||
Note that this build is not important as modern day Vulkan matches or even surpasses ROCm in terms of LLM performance for most cases.
|
||||
|
||||
### Future features
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ const config = [
|
|||
|
||||
'@typescript-eslint/no-inferrable-types': 'warn',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
|
||||
'sonarjs/cognitive-complexity': ['warn', 25],
|
||||
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "friendly-kobold",
|
||||
"productName": "Friendly Kobold",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "A modern Electron shell for KoboldCpp",
|
||||
"main": "out/main/index.js",
|
||||
"homepage": "./",
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
"@cspell/eslint-plugin": "^9.2.0",
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@types/node": "^24.3.0",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react": "^19.1.11",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
||||
"@typescript-eslint/parser": "^8.40.0",
|
||||
|
|
@ -79,12 +79,12 @@
|
|||
"vite": "^7.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mantine/core": "^8.2.5",
|
||||
"@mantine/hooks": "^8.2.5",
|
||||
"@mantine/core": "^8.2.7",
|
||||
"@mantine/hooks": "^8.2.7",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"execa": "^9.6.0",
|
||||
"got": "^14.4.7",
|
||||
"lucide-react": "^0.540.0",
|
||||
"lucide-react": "^0.541.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"systeminformation": "^5.27.7",
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ export const App = () => {
|
|||
}}
|
||||
>
|
||||
{currentScreen === null ? (
|
||||
<Center h="100%" style={{ minHeight: '400px' }}>
|
||||
<Center h="100%" style={{ minHeight: '25rem' }}>
|
||||
<Stack align="center" gap="lg">
|
||||
<Loader size="xl" type="dots" />
|
||||
<Text c="dimmed" size="lg">
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export const AppHeader = ({
|
|||
return (
|
||||
<AppShell.Header>
|
||||
<Group h="100%" px="md" justify="space-between" align="center">
|
||||
<div style={{ minWidth: '100px' }}>
|
||||
<div style={{ minWidth: '6.25rem' }}>
|
||||
{currentScreen === 'interface' ? (
|
||||
<Button
|
||||
variant="light"
|
||||
|
|
@ -121,14 +121,14 @@ export const AppHeader = ({
|
|||
placeholder="Select view"
|
||||
styles={{
|
||||
input: {
|
||||
minWidth: '150px',
|
||||
minWidth: '9.375rem',
|
||||
textAlign: 'center',
|
||||
border: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
fontWeight: 500,
|
||||
},
|
||||
dropdown: {
|
||||
minWidth: '150px',
|
||||
minWidth: '9.375rem',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
|
@ -136,7 +136,7 @@ export const AppHeader = ({
|
|||
|
||||
<div
|
||||
style={{
|
||||
minWidth: '100px',
|
||||
minWidth: '6.25rem',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export const UpdateAvailableModal = ({
|
|||
</Stack>
|
||||
</Card>
|
||||
|
||||
<Stack gap="xs" style={{ minHeight: '44px' }}>
|
||||
<Stack gap="xs" style={{ minHeight: '2.75rem' }}>
|
||||
<Progress
|
||||
value={isDownloading ? Math.min(downloadProgress, 100) : 0}
|
||||
color="orange"
|
||||
|
|
|
|||
|
|
@ -97,18 +97,6 @@ export const AdvancedTab = () => {
|
|||
label="MMAP"
|
||||
tooltip="Use MMAP to load models when enabled."
|
||||
/>
|
||||
|
||||
<CheckboxWithTooltip
|
||||
checked={lowvram}
|
||||
onChange={handleLowvramChange}
|
||||
label="Low VRAM"
|
||||
tooltip={
|
||||
backend !== 'cuda' && backend !== 'rocm'
|
||||
? 'Low VRAM mode is only available for CUDA and ROCm backends.'
|
||||
: 'Avoid offloading KV Cache or scratch buffers to VRAM. Allows more layers to fit, but may result in a speed loss.'
|
||||
}
|
||||
disabled={backend !== 'cuda' && backend !== 'rocm'}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
<Group gap="lg" align="flex-start" wrap="nowrap">
|
||||
|
|
@ -123,6 +111,18 @@ export const AdvancedTab = () => {
|
|||
}
|
||||
disabled={backend !== 'cuda' && backend !== 'rocm'}
|
||||
/>
|
||||
|
||||
<CheckboxWithTooltip
|
||||
checked={lowvram}
|
||||
onChange={handleLowvramChange}
|
||||
label="Low VRAM"
|
||||
tooltip={
|
||||
backend !== 'cuda' && backend !== 'rocm'
|
||||
? 'Low VRAM mode is only available for CUDA and ROCm backends.'
|
||||
: 'Avoid offloading KV Cache or scratch buffers to VRAM. Allows more layers to fit, but may result in a speed loss.'
|
||||
}
|
||||
disabled={backend !== 'cuda' && backend !== 'rocm'}
|
||||
/>
|
||||
</Group>
|
||||
</Stack>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
forwardRef,
|
||||
type ComponentPropsWithoutRef,
|
||||
} from 'react';
|
||||
import { Save, File, Plus } from 'lucide-react';
|
||||
import { Save, File, Plus, Check } from 'lucide-react';
|
||||
import type { ConfigFile } from '@/types';
|
||||
import styles from '@/styles/layout.module.css';
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ interface ConfigFileManagerProps {
|
|||
selectedFile: string | null;
|
||||
onFileSelection: (fileName: string) => Promise<void>;
|
||||
onCreateNewConfig: (configName: string) => Promise<void>;
|
||||
onSaveConfig: () => void;
|
||||
onSaveConfig: () => Promise<boolean>;
|
||||
onLoadConfigFiles: () => Promise<void>;
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +69,7 @@ export const ConfigFileManager = ({
|
|||
}: ConfigFileManagerProps) => {
|
||||
const [configModalOpened, setConfigModalOpened] = useState(false);
|
||||
const [newConfigName, setNewConfigName] = useState('');
|
||||
const [saveSuccess, setSaveSuccess] = useState(false);
|
||||
|
||||
const existingConfigNames = configFiles.map((file) => {
|
||||
const extension = file.name.split('.').pop() || '';
|
||||
|
|
@ -89,11 +90,22 @@ export const ConfigFileManager = ({
|
|||
setNewConfigName('');
|
||||
}, []);
|
||||
|
||||
const handleConfigSubmit = useCallback(() => {
|
||||
onCreateNewConfig(newConfigName.trim());
|
||||
setConfigModalOpened(false);
|
||||
setNewConfigName('');
|
||||
}, [newConfigName, onCreateNewConfig]);
|
||||
const handleConfigSubmit = async () => {
|
||||
await onCreateNewConfig(trimmedConfigName);
|
||||
handleCloseConfigModal();
|
||||
};
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
if (selectedFile) {
|
||||
const success = await onSaveConfig();
|
||||
if (success) {
|
||||
setSaveSuccess(true);
|
||||
setTimeout(() => setSaveSuccess(false), 1500);
|
||||
}
|
||||
} else {
|
||||
handleOpenConfigModal();
|
||||
}
|
||||
};
|
||||
|
||||
const selectData = configFiles.map((file) => {
|
||||
const extension = file.name.split('.').pop() || '';
|
||||
|
|
@ -151,17 +163,13 @@ export const ConfigFileManager = ({
|
|||
|
||||
<Button
|
||||
variant="outline"
|
||||
leftSection={<Save size={14} />}
|
||||
leftSection={saveSuccess ? <Check size={14} /> : <Save size={14} />}
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (selectedFile) {
|
||||
onSaveConfig();
|
||||
} else {
|
||||
handleOpenConfigModal();
|
||||
}
|
||||
}}
|
||||
onClick={handleSaveClick}
|
||||
color={saveSuccess ? 'green' : undefined}
|
||||
style={{ width: '6rem' }}
|
||||
>
|
||||
Save
|
||||
{saveSuccess ? 'Saved!' : 'Save'}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ export const LaunchScreen = ({
|
|||
gpulayers: gpuLayers,
|
||||
contextsize: contextSize,
|
||||
model: modelPath,
|
||||
additionalArguments,
|
||||
port,
|
||||
host,
|
||||
multiuser: multiuser ? 1 : 0,
|
||||
|
|
@ -197,7 +198,7 @@ export const LaunchScreen = ({
|
|||
'No configuration file selected for saving',
|
||||
new Error('Selected file is null')
|
||||
);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -213,12 +214,16 @@ export const LaunchScreen = ({
|
|||
'Failed to save configuration',
|
||||
new Error('Save operation failed')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to save configuration:',
|
||||
error as Error
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ export const VersionsTab = () => {
|
|||
return (
|
||||
<div
|
||||
key={`${version.name}-${version.version}-${index}`}
|
||||
style={{ paddingBottom: '8px' }}
|
||||
style={{ paddingBottom: '0.5rem' }}
|
||||
ref={isDownloading ? downloadingItemRef : null}
|
||||
>
|
||||
<DownloadCard
|
||||
|
|
|
|||
|
|
@ -166,6 +166,12 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
|||
updates.modelPath = configData.model;
|
||||
}
|
||||
|
||||
if (typeof configData.additionalArguments === 'string') {
|
||||
updates.additionalArguments = configData.additionalArguments;
|
||||
} else {
|
||||
updates.additionalArguments = '';
|
||||
}
|
||||
|
||||
if (typeof configData.port === 'number') {
|
||||
updates.port = configData.port;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -11,18 +11,18 @@ html {
|
|||
|
||||
/* Custom scrollbars */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 4px;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(134, 142, 150, 0.5);
|
||||
border-radius: 4px;
|
||||
border-radius: 0.25rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ html {
|
|||
@keyframes elephantShake {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1.3) rotate(5deg) translateX(0px);
|
||||
transform: scale(1.3) rotate(5deg) translateX(0);
|
||||
}
|
||||
10% {
|
||||
transform: scale(1.4) rotate(-3deg) translateX(-2px);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.minWidth200 {
|
||||
min-width: 200px;
|
||||
min-width: 12.5rem;
|
||||
}
|
||||
|
||||
.flex1 {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const soundAssets = {
|
|||
const audioCache = new Map<string, HTMLAudioElement>();
|
||||
let audioInitialized = false;
|
||||
|
||||
export const initializeAudio = async (): Promise<void> => {
|
||||
export const initializeAudio = async () => {
|
||||
if (audioInitialized) return;
|
||||
|
||||
try {
|
||||
|
|
@ -50,10 +50,7 @@ export const initializeAudio = async (): Promise<void> => {
|
|||
}
|
||||
};
|
||||
|
||||
export const playSound = async (
|
||||
soundUrl: string,
|
||||
volume = 0.5
|
||||
): Promise<void> => {
|
||||
export const playSound = async (soundUrl: string, volume = 0.5) => {
|
||||
try {
|
||||
if (!audioInitialized) {
|
||||
await initializeAudio();
|
||||
|
|
|
|||
42
yarn.lock
42
yarn.lock
|
|
@ -1436,9 +1436,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mantine/core@npm:^8.2.5":
|
||||
version: 8.2.5
|
||||
resolution: "@mantine/core@npm:8.2.5"
|
||||
"@mantine/core@npm:^8.2.7":
|
||||
version: 8.2.7
|
||||
resolution: "@mantine/core@npm:8.2.7"
|
||||
dependencies:
|
||||
"@floating-ui/react": "npm:^0.26.28"
|
||||
clsx: "npm:^2.1.1"
|
||||
|
|
@ -1447,19 +1447,19 @@ __metadata:
|
|||
react-textarea-autosize: "npm:8.5.9"
|
||||
type-fest: "npm:^4.27.0"
|
||||
peerDependencies:
|
||||
"@mantine/hooks": 8.2.5
|
||||
"@mantine/hooks": 8.2.7
|
||||
react: ^18.x || ^19.x
|
||||
react-dom: ^18.x || ^19.x
|
||||
checksum: 10c0/2268218faa02ecfb07819f6fb73426bf32049a3769ee6b1d1be46bdd3fb913ff14518692213a762a1ceccf6245572a5600052572f50b02c201e388475427657a
|
||||
checksum: 10c0/d10ba6ef7ac552b6bd5638b9a16c4d2405391102330d94c8df7a7d87756cdf4ec341a350eab252575eb5990f43dc4122ea13244753a9169338a43d2b996f7594
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mantine/hooks@npm:^8.2.5":
|
||||
version: 8.2.5
|
||||
resolution: "@mantine/hooks@npm:8.2.5"
|
||||
"@mantine/hooks@npm:^8.2.7":
|
||||
version: 8.2.7
|
||||
resolution: "@mantine/hooks@npm:8.2.7"
|
||||
peerDependencies:
|
||||
react: ^18.x || ^19.x
|
||||
checksum: 10c0/acd6d56703b19032ecced897c26dfb5ee7ff630c51cccfcaa2a9fa3251607432be0e984c8f8715456b4fa0c6647d48b4c240aa72d5eed78dbc358ec445b1f791
|
||||
checksum: 10c0/54dfbc36acad9dbb5e3a29d0944041f7ff31e61416cbd26ecf97c37c3a779a1b0028e05a0e6daa44cf3c3c2406c50b8f2107eb6fee3cfb6647b7524965556686
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -1905,12 +1905,12 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:^19.1.10":
|
||||
version: 19.1.10
|
||||
resolution: "@types/react@npm:19.1.10"
|
||||
"@types/react@npm:^19.1.11":
|
||||
version: 19.1.11
|
||||
resolution: "@types/react@npm:19.1.11"
|
||||
dependencies:
|
||||
csstype: "npm:^3.0.2"
|
||||
checksum: 10c0/fb583deacd0a815e2775dc1b9f764532d8cacb748ddd2c2914805a46c257ce6c237b4078f44009692074db212ab61a390301c6470f07f5aa5bfdeb78a2acfda1
|
||||
checksum: 10c0/639b225c2bbcd4b8a30e1ea7a73aec81ae5b952a4c432460b48c9881c9d12e76645c9032d24f15eefae9985a12d5cb26557fe10e9850b2da0fabfb0a1e2d16bd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -4401,10 +4401,10 @@ __metadata:
|
|||
dependencies:
|
||||
"@cspell/eslint-plugin": "npm:^9.2.0"
|
||||
"@eslint/js": "npm:^9.33.0"
|
||||
"@mantine/core": "npm:^8.2.5"
|
||||
"@mantine/hooks": "npm:^8.2.5"
|
||||
"@mantine/core": "npm:^8.2.7"
|
||||
"@mantine/hooks": "npm:^8.2.7"
|
||||
"@types/node": "npm:^24.3.0"
|
||||
"@types/react": "npm:^19.1.10"
|
||||
"@types/react": "npm:^19.1.11"
|
||||
"@types/react-dom": "npm:^19.1.7"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^8.40.0"
|
||||
"@typescript-eslint/parser": "npm:^8.40.0"
|
||||
|
|
@ -4428,7 +4428,7 @@ __metadata:
|
|||
husky: "npm:^9.1.7"
|
||||
jiti: "npm:^2.5.1"
|
||||
lint-staged: "npm:^16.1.5"
|
||||
lucide-react: "npm:^0.540.0"
|
||||
lucide-react: "npm:^0.541.0"
|
||||
prettier: "npm:^3.6.2"
|
||||
react: "npm:^19.1.1"
|
||||
react-dom: "npm:^19.1.1"
|
||||
|
|
@ -5828,12 +5828,12 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.540.0":
|
||||
version: 0.540.0
|
||||
resolution: "lucide-react@npm:0.540.0"
|
||||
"lucide-react@npm:^0.541.0":
|
||||
version: 0.541.0
|
||||
resolution: "lucide-react@npm:0.541.0"
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
checksum: 10c0/f4dc8a540b1b079958fdf7a1804dfb3f9093a9393f0c0a4b32a7e839869df5e29946c4fe226f06edd3056f6eccfa77b53e44be89f42379e7fe31c4e59caee3fa
|
||||
checksum: 10c0/ffa23a9c9ead0832c7e0bb1eb7ed44e9f38bbf083d94b4d36a66eb23fa2099d4a52e1677c91eb7e8ea922621fa98e730f5d513bc56b3111b14b835bd8ab823ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue