dont need "server only" mode, image mode launch fixes

This commit is contained in:
lone-cloud 2025-08-16 02:06:22 -07:00
parent c4b900724b
commit 6f6ef47954
14 changed files with 72 additions and 211 deletions

View file

@ -106,13 +106,6 @@
"kobold", "kobold",
"KOBOLDAI", "KOBOLDAI",
"koboldcpp", "koboldcpp",
"sdmodel",
"sdt5xxl",
"sdclipl",
"sdclipg",
"sdphotomaker",
"sdvae",
"sdapi",
"less", "less",
"letterspacing", "letterspacing",
"libvk", "libvk",
@ -175,9 +168,19 @@
"rocm", "rocm",
"rocminfo", "rocminfo",
"rollup", "rollup",
"safetensors",
"sass", "sass",
"scrollbar", "scrollbar",
"scss", "scss",
"sdapi",
"sdclipg",
"sdclipl",
"sdmodel",
"sdphotomaker",
"sdt5xxl",
"sdui",
"sdvae",
"SDXL",
"setAttribute", "setAttribute",
"shouldComponentUpdate", "shouldComponentUpdate",
"shouldn", "shouldn",
@ -190,8 +193,6 @@
"subdomain", "subdomain",
"svg", "svg",
"swiftshader", "swiftshader",
"safetensors",
"SDXL",
"tabler", "tabler",
"Tauri", "Tauri",
"temp", "temp",

View file

@ -249,7 +249,12 @@ export const App = () => {
value={activeInterfaceTab} value={activeInterfaceTab}
onChange={setActiveInterfaceTab} onChange={setActiveInterfaceTab}
data={[ data={[
{ value: 'chat', label: 'KoboldAI Lite' }, {
value: 'chat',
label: isImageGenerationMode
? 'Stable UI'
: 'KoboldAI Lite',
},
{ value: 'terminal', label: 'Terminal' }, { value: 'terminal', label: 'Terminal' },
]} ]}
placeholder="Select view" placeholder="Select view"

View file

@ -6,7 +6,6 @@ import {
} from '@/utils/imageModelPresets'; } from '@/utils/imageModelPresets';
export const useLaunchConfig = () => { export const useLaunchConfig = () => {
const [serverOnly, setServerOnly] = useState<boolean>(false);
const [gpuLayers, setGpuLayers] = useState<number>(0); const [gpuLayers, setGpuLayers] = useState<number>(0);
const [autoGpuLayers, setAutoGpuLayers] = useState<boolean>(false); const [autoGpuLayers, setAutoGpuLayers] = useState<boolean>(false);
const [contextSize, setContextSize] = useState<number>(2048); const [contextSize, setContextSize] = useState<number>(2048);
@ -199,12 +198,8 @@ export const useLaunchConfig = () => {
}, []); }, []);
const loadSavedSettings = useCallback(async () => { const loadSavedSettings = useCallback(async () => {
const [savedServerOnly, cpuCapabilities] = await Promise.all([ const cpuCapabilities = await window.electronAPI.kobold.detectCPU();
window.electronAPI.config.getServerOnly(),
window.electronAPI.kobold.detectCPU(),
]);
setServerOnly(savedServerOnly);
setModelPath(''); setModelPath('');
setGpuLayers(0); setGpuLayers(0);
setContextSize(2048); setContextSize(2048);
@ -259,11 +254,6 @@ export const useLaunchConfig = () => {
[parseAndApplyConfigFile] [parseAndApplyConfigFile]
); );
const handleServerOnlyChange = useCallback(async (checked: boolean) => {
setServerOnly(checked);
await window.electronAPI.config.setServerOnly(checked);
}, []);
const handleGpuLayersChange = useCallback(async (value: number) => { const handleGpuLayersChange = useCallback(async (value: number) => {
setGpuLayers(value); setGpuLayers(value);
}, []); }, []);
@ -436,7 +426,6 @@ export const useLaunchConfig = () => {
); );
return { return {
serverOnly,
gpuLayers, gpuLayers,
autoGpuLayers, autoGpuLayers,
contextSize, contextSize,
@ -464,7 +453,6 @@ export const useLaunchConfig = () => {
parseAndApplyConfigFile, parseAndApplyConfigFile,
loadSavedSettings, loadSavedSettings,
loadConfigFromFile, loadConfigFromFile,
handleServerOnlyChange,
handleGpuLayersChange, handleGpuLayersChange,
handleAutoGpuLayersChange, handleAutoGpuLayersChange,
handleContextSizeChangeWithStep, handleContextSizeChangeWithStep,

View file

@ -6,7 +6,6 @@ interface AppConfig {
installDir?: string; installDir?: string;
currentKoboldBinary?: string; currentKoboldBinary?: string;
selectedConfig?: string; selectedConfig?: string;
serverOnly?: boolean;
[key: string]: ConfigValue; [key: string]: ConfigValue;
} }
@ -73,13 +72,4 @@ export class ConfigManager {
this.config.selectedConfig = configName; this.config.selectedConfig = configName;
this.saveConfig(); this.saveConfig();
} }
getServerOnly(): boolean {
return this.config.serverOnly || false;
}
setServerOnly(serverOnly: boolean) {
this.config.serverOnly = serverOnly;
this.saveConfig();
}
} }

View file

@ -337,6 +337,7 @@ OS: ${osInfo}`;
const response = await dialog.showMessageBox(this.mainWindow!, { const response = await dialog.showMessageBox(this.mainWindow!, {
type: 'info', type: 'info',
title: 'Friendly Kobold',
message: 'Friendly Kobold', message: 'Friendly Kobold',
detail: aboutText, detail: aboutText,
buttons: ['Copy', 'OK'], buttons: ['Copy', 'OK'],

View file

@ -184,7 +184,7 @@ export class IPCHandlers {
const result = await dialog.showMessageBox(mainWindow, { const result = await dialog.showMessageBox(mainWindow, {
type: 'warning', type: 'warning',
title: 'Confirm Eject', title: 'Confirm Eject',
message: 'Are you sure you want to eject KoboldCpp?', message: 'Are you sure you want to eject?',
detail: detail:
'This will terminate the running process and return to the launch screen.', 'This will terminate the running process and return to the launch screen.',
buttons: ['Cancel', 'Eject'], buttons: ['Cancel', 'Eject'],
@ -203,14 +203,6 @@ export class IPCHandlers {
this.koboldManager.selectModelFile() this.koboldManager.selectModelFile()
); );
ipcMain.handle('config:getServerOnly', () =>
this.configManager.getServerOnly()
);
ipcMain.handle('config:setServerOnly', (_event, serverOnly) =>
this.configManager.setServerOnly(serverOnly)
);
ipcMain.handle('config:get', (_event, key) => this.configManager.get(key)); ipcMain.handle('config:get', (_event, key) => this.configManager.get(key));
ipcMain.handle('config:set', (_event, key, value) => ipcMain.handle('config:set', (_event, key, value) =>

View file

@ -124,9 +124,6 @@ const appAPI: AppAPI = {
}; };
const configAPI: ConfigAPI = { const configAPI: ConfigAPI = {
getServerOnly: () => ipcRenderer.invoke('config:getServerOnly'),
setServerOnly: (serverOnly: boolean) =>
ipcRenderer.invoke('config:setServerOnly', serverOnly),
get: (key: string) => ipcRenderer.invoke('config:get', key), get: (key: string) => ipcRenderer.invoke('config:get', key),
set: (key: string, value: unknown) => set: (key: string, value: unknown) =>
ipcRenderer.invoke('config:set', key, value), ipcRenderer.invoke('config:set', key, value),

View file

@ -1,56 +0,0 @@
import { useRef } from 'react';
import { Box, Text, Stack } from '@mantine/core';
interface ImageGenerationTabProps {
serverUrl?: string;
isServerReady?: boolean;
}
export const ImageGenerationTab = ({
serverUrl,
isServerReady,
}: ImageGenerationTabProps) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
if (!isServerReady || !serverUrl) {
return (
<Box
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Stack align="center" gap="md">
<Text c="dimmed" size="lg">
Waiting for KoboldCpp server to start...
</Text>
<Text c="dimmed" size="sm">
The image generation interface will load automatically when ready
</Text>
</Stack>
</Box>
);
}
const imageGenerationUrl = `${serverUrl}/sdapi/v1`;
return (
<Box style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
<iframe
ref={iframeRef}
src={imageGenerationUrl}
title="KoboldCpp Image Generation Interface"
style={{
width: '100%',
height: '100%',
border: 'none',
borderRadius: 'inherit',
}}
allow="clipboard-read; clipboard-write"
/>
</Box>
);
};

View file

@ -39,10 +39,10 @@ export const ServerTab = ({
} }
const iframeUrl = const iframeUrl =
mode === 'image-generation' ? `${serverUrl}/sdapi/v1` : serverUrl; mode === 'image-generation' ? `${serverUrl}/sdui` : serverUrl;
const title = const title =
mode === 'image-generation' mode === 'image-generation'
? 'KoboldCpp Image Generation Interface' ? 'Stable UI Interface'
: 'KoboldAI Lite Interface'; : 'KoboldAI Lite Interface';
return ( return (

View file

@ -10,13 +10,9 @@ import { ChevronDown } from 'lucide-react';
interface TerminalTabProps { interface TerminalTabProps {
onServerReady?: (serverUrl: string) => void; onServerReady?: (serverUrl: string) => void;
serverOnly?: boolean;
} }
export const TerminalTab = ({ export const TerminalTab = ({ onServerReady }: TerminalTabProps) => {
onServerReady,
serverOnly,
}: TerminalTabProps) => {
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const [terminalContent, setTerminalContent] = useState<string>(''); const [terminalContent, setTerminalContent] = useState<string>('');
const [isUserScrolling, setIsUserScrolling] = useState<boolean>(false); const [isUserScrolling, setIsUserScrolling] = useState<boolean>(false);
@ -56,7 +52,6 @@ export const TerminalTab = ({
const newData = data.toString(); const newData = data.toString();
if ( if (
!serverOnly &&
onServerReady && onServerReady &&
newData.includes('Please connect to custom endpoint at ') newData.includes('Please connect to custom endpoint at ')
) { ) {
@ -95,7 +90,7 @@ export const TerminalTab = ({
}); });
return cleanup; return cleanup;
}, [onServerReady, serverOnly]); }, [onServerReady]);
const scrollToBottom = () => { const scrollToBottom = () => {
if (viewportRef.current) { if (viewportRef.current) {

View file

@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useCallback } from 'react';
import { Card, Container } from '@mantine/core'; import { Card, Container } from '@mantine/core';
import { ServerTab } from '@/screens/Interface/ServerTab'; import { ServerTab } from '@/screens/Interface/ServerTab';
import { TerminalTab } from '@/screens/Interface/TerminalTab'; import { TerminalTab } from '@/screens/Interface/TerminalTab';
@ -14,7 +14,6 @@ export const InterfaceScreen = ({
onTabChange, onTabChange,
isImageGenerationMode = false, isImageGenerationMode = false,
}: InterfaceScreenProps) => { }: InterfaceScreenProps) => {
const [serverOnly, setServerOnly] = useState<boolean>(false);
const [serverUrl, setServerUrl] = useState<string>(''); const [serverUrl, setServerUrl] = useState<string>('');
const [isServerReady, setIsServerReady] = useState<boolean>(false); const [isServerReady, setIsServerReady] = useState<boolean>(false);
@ -23,30 +22,13 @@ export const InterfaceScreen = ({
setServerUrl(url); setServerUrl(url);
setIsServerReady(true); setIsServerReady(true);
if (!serverOnly && onTabChange) { if (onTabChange) {
onTabChange(isImageGenerationMode ? 'image' : 'chat'); onTabChange(isImageGenerationMode ? 'image' : 'chat');
} }
}, },
[serverOnly, onTabChange, isImageGenerationMode] [onTabChange, isImageGenerationMode]
); );
useEffect(() => {
const loadServerOnlySetting = async () => {
try {
const serverOnlyValue = await window.electronAPI.config.getServerOnly();
setServerOnly(serverOnlyValue);
if (serverOnlyValue && onTabChange) {
onTabChange('terminal');
}
} catch (error) {
console.error('Failed to load server-only setting:', error);
}
};
loadServerOnlySetting();
}, [onTabChange]);
return ( return (
<Container size="l" style={{ height: '85vh' }}> <Container size="l" style={{ height: '85vh' }}>
<Card <Card
@ -55,49 +37,39 @@ export const InterfaceScreen = ({
p="0" p="0"
style={{ height: 'calc(90vh - 32px)' }} style={{ height: 'calc(90vh - 32px)' }}
> >
{serverOnly ? ( <div style={{ height: '100%' }}>
<TerminalTab <div
onServerReady={handleServerReady} style={{
serverOnly={serverOnly} height: '100%',
/> display: activeTab === 'chat' ? 'block' : 'none',
) : ( }}
<div style={{ height: '100%' }}> >
<div <ServerTab
style={{ serverUrl={serverUrl}
height: '100%', isServerReady={isServerReady}
display: activeTab === 'chat' ? 'block' : 'none', mode={isImageGenerationMode ? 'image-generation' : 'chat'}
}} />
>
<ServerTab
serverUrl={serverUrl}
isServerReady={isServerReady}
mode={isImageGenerationMode ? 'image-generation' : 'chat'}
/>
</div>
<div
style={{
height: '100%',
display: activeTab === 'image' ? 'block' : 'none',
}}
>
<ServerTab
serverUrl={serverUrl}
isServerReady={isServerReady}
mode="image-generation"
/>
</div>
<div
style={{
display: activeTab === 'terminal' ? 'block' : 'none',
}}
>
<TerminalTab
onServerReady={handleServerReady}
serverOnly={false}
/>
</div>
</div> </div>
)} <div
style={{
height: '100%',
display: activeTab === 'image' ? 'block' : 'none',
}}
>
<ServerTab
serverUrl={serverUrl}
isServerReady={isServerReady}
mode="image-generation"
/>
</div>
<div
style={{
display: activeTab === 'terminal' ? 'block' : 'none',
}}
>
<TerminalTab onServerReady={handleServerReady} />
</div>
</div>
</Card> </Card>
</Container> </Container>
); );

View file

@ -3,13 +3,11 @@ import { InfoTooltip } from '@/components/InfoTooltip';
interface AdvancedTabProps { interface AdvancedTabProps {
additionalArguments: string; additionalArguments: string;
serverOnly: boolean;
noshift: boolean; noshift: boolean;
flashattention: boolean; flashattention: boolean;
noavx2: boolean; noavx2: boolean;
failsafe: boolean; failsafe: boolean;
onAdditionalArgumentsChange: (args: string) => void; onAdditionalArgumentsChange: (args: string) => void;
onServerOnlyChange: (serverOnly: boolean) => void;
onNoshiftChange: (noshift: boolean) => void; onNoshiftChange: (noshift: boolean) => void;
onFlashattentionChange: (flashattention: boolean) => void; onFlashattentionChange: (flashattention: boolean) => void;
onNoavx2Change: (noavx2: boolean) => void; onNoavx2Change: (noavx2: boolean) => void;
@ -18,13 +16,11 @@ interface AdvancedTabProps {
export const AdvancedTab = ({ export const AdvancedTab = ({
additionalArguments, additionalArguments,
serverOnly,
noshift, noshift,
flashattention, flashattention,
noavx2, noavx2,
failsafe, failsafe,
onAdditionalArgumentsChange, onAdditionalArgumentsChange,
onServerOnlyChange,
onNoshiftChange, onNoshiftChange,
onFlashattentionChange, onFlashattentionChange,
onNoavx2Change, onNoavx2Change,
@ -34,19 +30,6 @@ export const AdvancedTab = ({
<div> <div>
<Stack gap="md"> <Stack gap="md">
<Group gap="lg" align="flex-start" wrap="nowrap"> <Group gap="lg" align="flex-start" wrap="nowrap">
<div style={{ minWidth: '200px' }}>
<Group gap="xs" align="center">
<Checkbox
checked={serverOnly}
onChange={(event) =>
onServerOnlyChange(event.currentTarget.checked)
}
label="Server-only mode"
/>
<InfoTooltip label="In server-only mode, the KoboldAI Lite web UI won't be displayed. Use this if you'll be using your own frontend." />
</Group>
</div>
<div style={{ minWidth: '200px' }}> <div style={{ minWidth: '200px' }}>
<Group gap="xs" align="center"> <Group gap="xs" align="center">
<Checkbox <Checkbox
@ -59,9 +42,7 @@ export const AdvancedTab = ({
<InfoTooltip label="Use Context Shifting to reduce reprocessing. Recommended" /> <InfoTooltip label="Use Context Shifting to reduce reprocessing. Recommended" />
</Group> </Group>
</div> </div>
</Group>
<Group gap="lg" align="flex-start" wrap="nowrap">
<div style={{ minWidth: '200px' }}> <div style={{ minWidth: '200px' }}>
<Group gap="xs" align="center"> <Group gap="xs" align="center">
<Checkbox <Checkbox
@ -74,7 +55,9 @@ export const AdvancedTab = ({
<InfoTooltip label="Enable flash attention for GGUF models." /> <InfoTooltip label="Enable flash attention for GGUF models." />
</Group> </Group>
</div> </div>
</Group>
<Group gap="lg" align="flex-start" wrap="nowrap">
<div style={{ minWidth: '200px' }}> <div style={{ minWidth: '200px' }}>
<Group gap="xs" align="center"> <Group gap="xs" align="center">
<Checkbox <Checkbox
@ -87,15 +70,19 @@ export const AdvancedTab = ({
<InfoTooltip label="Do not use AVX2 instructions, a slower compatibility mode for older devices." /> <InfoTooltip label="Do not use AVX2 instructions, a slower compatibility mode for older devices." />
</Group> </Group>
</div> </div>
</Group>
<Group gap="xs" align="center"> <div style={{ minWidth: '200px' }}>
<Checkbox <Group gap="xs" align="center">
checked={failsafe} <Checkbox
onChange={(event) => onFailsafeChange(event.currentTarget.checked)} checked={failsafe}
label="Failsafe" onChange={(event) =>
/> onFailsafeChange(event.currentTarget.checked)
<InfoTooltip label="Use failsafe mode, extremely slow CPU only compatibility mode that should work on all devices. Can be combined with useclblast if your device supports OpenCL." /> }
label="Failsafe"
/>
<InfoTooltip label="Use failsafe mode, extremely slow CPU only compatibility mode that should work on all devices. Can be combined with useclblast if your device supports OpenCL." />
</Group>
</div>
</Group> </Group>
</Stack> </Stack>
</div> </div>

View file

@ -36,7 +36,6 @@ export const LaunchScreen = ({
const [newConfigName, setNewConfigName] = useState(''); const [newConfigName, setNewConfigName] = useState('');
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const { const {
serverOnly,
gpuLayers, gpuLayers,
autoGpuLayers, autoGpuLayers,
contextSize, contextSize,
@ -63,7 +62,6 @@ export const LaunchScreen = ({
parseAndApplyConfigFile, parseAndApplyConfigFile,
loadSavedSettings, loadSavedSettings,
loadConfigFromFile, loadConfigFromFile,
handleServerOnlyChange,
handleGpuLayersChange, handleGpuLayersChange,
handleAutoGpuLayersChange, handleAutoGpuLayersChange,
handleContextSizeChangeWithStep, handleContextSizeChangeWithStep,
@ -158,11 +156,6 @@ export const LaunchScreen = ({
setHasUnsavedChanges(true); setHasUnsavedChanges(true);
}; };
const handleServerOnlyChangeWithTracking = (serverOnly: boolean) => {
handleServerOnlyChange(serverOnly);
setHasUnsavedChanges(true);
};
const handlePortChangeWithTracking = (port: number) => { const handlePortChangeWithTracking = (port: number) => {
handlePortChange(port); handlePortChange(port);
setHasUnsavedChanges(true); setHasUnsavedChanges(true);
@ -472,7 +465,6 @@ export const LaunchScreen = ({
<Tabs.Panel value="advanced" pt="md"> <Tabs.Panel value="advanced" pt="md">
<AdvancedTab <AdvancedTab
additionalArguments={additionalArguments} additionalArguments={additionalArguments}
serverOnly={serverOnly}
noshift={noshift} noshift={noshift}
flashattention={flashattention} flashattention={flashattention}
noavx2={noavx2} noavx2={noavx2}
@ -480,7 +472,6 @@ export const LaunchScreen = ({
onAdditionalArgumentsChange={ onAdditionalArgumentsChange={
handleAdditionalArgumentsChangeWithTracking handleAdditionalArgumentsChangeWithTracking
} }
onServerOnlyChange={handleServerOnlyChangeWithTracking}
onNoshiftChange={handleNoshiftChangeWithTracking} onNoshiftChange={handleNoshiftChangeWithTracking}
onFlashattentionChange={ onFlashattentionChange={
handleFlashattentionChangeWithTracking handleFlashattentionChangeWithTracking

View file

@ -147,8 +147,6 @@ export interface AppAPI {
} }
export interface ConfigAPI { export interface ConfigAPI {
getServerOnly: () => Promise<boolean>;
setServerOnly: (serverOnly: boolean) => Promise<void>;
get: (key: string) => Promise<unknown>; get: (key: string) => Promise<unknown>;
set: (key: string, value: unknown) => Promise<void>; set: (key: string, value: unknown) => Promise<void>;
} }