upgrade to latest major electron v39 release, new setting to allow running the built-in image gen UI while having a different frontend preference

This commit is contained in:
Egor 2025-10-28 19:12:31 -07:00
parent c2400b9a58
commit 43de016261
14 changed files with 217 additions and 64 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "gerbil", "name": "gerbil",
"productName": "Gerbil", "productName": "Gerbil",
"version": "1.7.6", "version": "1.7.7",
"description": "Run Large Language Models locally", "description": "Run Large Language Models locally",
"main": "out/main/index.js", "main": "out/main/index.js",
"homepage": "./", "homepage": "./",
@ -39,7 +39,7 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.38.0", "@eslint/js": "^9.38.0",
"@types/node": "^24.9.1", "@types/node": "^24.9.2",
"@types/react": "^19.2.2", "@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2", "@types/react-dom": "^19.2.2",
"@types/yauzl": "^2.10.3", "@types/yauzl": "^2.10.3",
@ -47,7 +47,7 @@
"@typescript-eslint/parser": "^8.46.2", "@typescript-eslint/parser": "^8.46.2",
"@vitejs/plugin-react": "^5.1.0", "@vitejs/plugin-react": "^5.1.0",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"electron": "^38.4.0", "electron": "^39.0.0",
"electron-builder": "^26.0.12", "electron-builder": "^26.0.12",
"electron-vite": "^4.0.1", "electron-vite": "^4.0.1",
"eslint": "^9.38.0", "eslint": "^9.38.0",

View file

@ -32,19 +32,17 @@ export const TitleBar = ({
onEject, onEject,
onTabChange, onTabChange,
}: TitleBarProps) => { }: TitleBarProps) => {
const { resolvedColorScheme: colorScheme, frontendPreference } = const {
usePreferencesStore(); resolvedColorScheme: colorScheme,
frontendPreference,
imageGenerationFrontendPreference,
} = usePreferencesStore();
const { handleLogoClick, getLogoStyles } = useLogoClickSounds(); const { handleLogoClick, getLogoStyles } = useLogoClickSounds();
const [isMaximized, setIsMaximized] = useState(false); const [isMaximized, setIsMaximized] = useState(false);
const [isSelectOpen, setIsSelectOpen] = useState(false); const [isSelectOpen, setIsSelectOpen] = useState(false);
const [settingsModalOpen, setSettingsModalOpen] = useState(false); const [settingsModalOpen, setSettingsModalOpen] = useState(false);
const { isTextMode, isImageGenerationMode } = useLaunchConfigStore(); const { isTextMode, isImageGenerationMode } = useLaunchConfigStore();
const interfaceOptions = getAvailableInterfaceOptions({
frontendPreference,
isTextMode,
isImageGenerationMode,
});
const handleTabChange = (value: string | null) => { const handleTabChange = (value: string | null) => {
if (value === 'eject') { if (value === 'eject') {
@ -133,7 +131,12 @@ export const TitleBar = ({
onChange={handleTabChange} onChange={handleTabChange}
onDropdownOpen={() => setIsSelectOpen(true)} onDropdownOpen={() => setIsSelectOpen(true)}
onDropdownClose={() => setIsSelectOpen(false)} onDropdownClose={() => setIsSelectOpen(false)}
data={interfaceOptions} data={getAvailableInterfaceOptions({
frontendPreference,
imageGenerationFrontendPreference,
isTextMode,
isImageGenerationMode,
})}
renderOption={renderOption} renderOption={renderOption}
variant="unstyled" variant="unstyled"
style={{ textAlign: 'center', minWidth: '7.5rem' }} style={{ textAlign: 'center', minWidth: '7.5rem' }}

View file

@ -17,7 +17,8 @@ export const ServerTab = ({
activeTab, activeTab,
}: ServerTabProps) => { }: ServerTabProps) => {
const { isImageGenerationMode } = useLaunchConfigStore(); const { isImageGenerationMode } = useLaunchConfigStore();
const { frontendPreference } = usePreferencesStore(); const { frontendPreference, imageGenerationFrontendPreference } =
usePreferencesStore();
const effectiveImageMode = const effectiveImageMode =
activeTab === 'chat-image' activeTab === 'chat-image'
@ -30,10 +31,16 @@ export const ServerTab = ({
() => () =>
getServerInterfaceInfo({ getServerInterfaceInfo({
frontendPreference, frontendPreference,
imageGenerationFrontendPreference,
isImageGenerationMode: effectiveImageMode, isImageGenerationMode: effectiveImageMode,
serverUrl: serverUrl || '', serverUrl: serverUrl || '',
}), }),
[frontendPreference, effectiveImageMode, serverUrl] [
frontendPreference,
imageGenerationFrontendPreference,
effectiveImageMode,
serverUrl,
]
); );
if (!isServerReady || !serverUrl) { if (!isServerReady || !serverUrl) {

View file

@ -26,9 +26,13 @@ export interface TerminalTabRef {
export const TerminalTab = forwardRef<TerminalTabRef, TerminalTabProps>( export const TerminalTab = forwardRef<TerminalTabRef, TerminalTabProps>(
({ onServerReady }, ref) => { ({ onServerReady }, ref) => {
const { host, port, isImageGenerationMode } = useLaunchConfigStore(); const { host, port, isImageGenerationMode, isTextMode } =
const { frontendPreference, resolvedColorScheme: colorScheme } = useLaunchConfigStore();
usePreferencesStore(); const {
frontendPreference,
imageGenerationFrontendPreference,
resolvedColorScheme: colorScheme,
} = usePreferencesStore();
const [terminalContent, setTerminalContent] = useState(''); const [terminalContent, setTerminalContent] = useState('');
const [isUserScrolling, setIsUserScrolling] = useState(false); const [isUserScrolling, setIsUserScrolling] = useState(false);
const [shouldAutoScroll, setShouldAutoScroll] = useState(true); const [shouldAutoScroll, setShouldAutoScroll] = useState(true);
@ -79,16 +83,19 @@ export const TerminalTab = forwardRef<TerminalTabRef, TerminalTabProps>(
const serverHost = host || 'localhost'; const serverHost = host || 'localhost';
const serverPort = port || 5001; const serverPort = port || 5001;
const effectiveFrontend = isTextMode
? frontendPreference
: imageGenerationFrontendPreference === 'builtin'
? 'koboldcpp'
: frontendPreference;
let signalToCheck: string = SERVER_READY_SIGNALS.KOBOLDCPP; let signalToCheck: string = SERVER_READY_SIGNALS.KOBOLDCPP;
if (frontendPreference === 'sillytavern') { if (effectiveFrontend === 'sillytavern') {
signalToCheck = SERVER_READY_SIGNALS.SILLYTAVERN; signalToCheck = SERVER_READY_SIGNALS.SILLYTAVERN;
} else if (frontendPreference === 'openwebui') { } else if (effectiveFrontend === 'openwebui') {
signalToCheck = SERVER_READY_SIGNALS.OPENWEBUI; signalToCheck = SERVER_READY_SIGNALS.OPENWEBUI;
} else if ( } else if (effectiveFrontend === 'comfyui') {
frontendPreference === 'comfyui' &&
isImageGenerationMode
) {
signalToCheck = SERVER_READY_SIGNALS.COMFYUI; signalToCheck = SERVER_READY_SIGNALS.COMFYUI;
} }
@ -106,7 +113,15 @@ export const TerminalTab = forwardRef<TerminalTabRef, TerminalTabProps>(
); );
return cleanup; return cleanup;
}, [onServerReady, host, port, frontendPreference, isImageGenerationMode]); }, [
onServerReady,
host,
port,
frontendPreference,
imageGenerationFrontendPreference,
isImageGenerationMode,
isTextMode,
]);
const scrollToBottom = () => { const scrollToBottom = () => {
if (viewportRef.current) { if (viewportRef.current) {

View file

@ -23,16 +23,23 @@ export const InterfaceScreen = ({
const terminalTabRef = useRef<TerminalTabRef>(null); const terminalTabRef = useRef<TerminalTabRef>(null);
const { isTextMode, isImageGenerationMode } = useLaunchConfigStore(); const { isTextMode, isImageGenerationMode } = useLaunchConfigStore();
const { frontendPreference } = usePreferencesStore(); const { frontendPreference, imageGenerationFrontendPreference } =
usePreferencesStore();
const defaultInterfaceTab = useMemo( const defaultInterfaceTab = useMemo(
() => () =>
getDefaultInterfaceTab({ getDefaultInterfaceTab({
frontendPreference, frontendPreference,
imageGenerationFrontendPreference,
isTextMode, isTextMode,
isImageGenerationMode, isImageGenerationMode,
}), }),
[frontendPreference, isTextMode, isImageGenerationMode] [
frontendPreference,
imageGenerationFrontendPreference,
isTextMode,
isImageGenerationMode,
]
); );
const handleServerReady = useCallback( const handleServerReady = useCallback(

View file

@ -1,8 +1,11 @@
import { useState, useEffect, useCallback, useMemo } from 'react'; import { useState, useEffect, useCallback, useMemo } from 'react';
import { Text, Box, Anchor, rem } from '@mantine/core'; import { Text, Box, Anchor, rem } from '@mantine/core';
import { Monitor } from 'lucide-react'; import { Monitor, Image } from 'lucide-react';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import type { FrontendPreference } from '@/types'; import type {
FrontendPreference,
ImageGenerationFrontendPreference,
} from '@/types';
import { FRONTENDS } from '@/constants'; import { FRONTENDS } from '@/constants';
import { Select } from '@/components/Select'; import { Select } from '@/components/Select';
@ -27,7 +30,12 @@ interface FrontendInterfaceSelectorProps {
export const FrontendInterfaceSelector = ({ export const FrontendInterfaceSelector = ({
isOnInterfaceScreen = false, isOnInterfaceScreen = false,
}: FrontendInterfaceSelectorProps) => { }: FrontendInterfaceSelectorProps) => {
const { frontendPreference, setFrontendPreference } = usePreferencesStore(); const {
frontendPreference,
setFrontendPreference,
imageGenerationFrontendPreference,
setImageGenerationFrontendPreference,
} = usePreferencesStore();
const [frontendRequirements, setFrontendRequirements] = useState< const [frontendRequirements, setFrontendRequirements] = useState<
Map<string, boolean> Map<string, boolean>
@ -132,6 +140,12 @@ export const FrontendInterfaceSelector = ({
setFrontendPreference(value as FrontendPreference); setFrontendPreference(value as FrontendPreference);
}; };
const handleImageGenerationFrontendChange = (value: string | null) => {
setImageGenerationFrontendPreference(
value as ImageGenerationFrontendPreference
);
};
const renderDisabledFrontendWarnings = () => { const renderDisabledFrontendWarnings = () => {
const disabledFrontends = frontendConfigs.filter( const disabledFrontends = frontendConfigs.filter(
(config) => !isFrontendAvailable(config.value) (config) => !isFrontendAvailable(config.value)
@ -266,6 +280,25 @@ export const FrontendInterfaceSelector = ({
/> />
{renderDisabledFrontendWarnings()} {renderDisabledFrontendWarnings()}
<Text fw={500} mb="sm" mt="xl">
Image Generation Frontend
</Text>
<Text size="sm" c="dimmed" mb="md">
Choose which frontend to use for image generation specifically
</Text>
<Select
value={imageGenerationFrontendPreference}
onChange={handleImageGenerationFrontendChange}
disabled={isOnInterfaceScreen}
data={[
{ value: 'match', label: 'Match Frontend' },
{ value: 'builtin', label: 'Built-in' },
]}
leftSection={<Image style={{ width: rem(16), height: rem(16) }} />}
/>
</> </>
); );
}; };

View file

@ -28,7 +28,7 @@ const checkModelWarnings = (
if (showModelPriorityWarning) { if (showModelPriorityWarning) {
warnings.push({ warnings.push({
type: 'warning', type: 'info',
message: message:
'Both text and image generation models are selected. This may load both models into VRAM simultaneously, which requires significant memory (typically 16GB+ VRAM recommended). Ensure your system has sufficient VRAM to avoid crashes or poor performance.', 'Both text and image generation models are selected. This may load both models into VRAM simultaneously, which requires significant memory (typically 16GB+ VRAM recommended). Ensure your system has sufficient VRAM to avoid crashes or poor performance.',
}); });

View file

@ -6,7 +6,11 @@ import { join } from 'path';
import { platform } from 'process'; import { platform } from 'process';
import { nativeTheme } from 'electron'; import { nativeTheme } from 'electron';
import { PRODUCT_NAME } from '@/constants'; import { PRODUCT_NAME } from '@/constants';
import type { FrontendPreference, DismissedUpdate } from '@/types'; import type {
FrontendPreference,
DismissedUpdate,
ImageGenerationFrontendPreference,
} from '@/types';
import type { MantineColorScheme } from '@mantine/core'; import type { MantineColorScheme } from '@mantine/core';
import type { SavedNotepadState } from '@/types/electron'; import type { SavedNotepadState } from '@/types/electron';
@ -23,6 +27,7 @@ interface AppConfig {
currentKoboldBinary?: string; currentKoboldBinary?: string;
selectedConfig?: string; selectedConfig?: string;
frontendPreference?: FrontendPreference; frontendPreference?: FrontendPreference;
imageGenerationFrontendPreference?: ImageGenerationFrontendPreference;
colorScheme?: MantineColorScheme; colorScheme?: MantineColorScheme;
windowBounds?: WindowBounds; windowBounds?: WindowBounds;
hasSeenWelcome?: boolean; hasSeenWelcome?: boolean;

View file

@ -18,7 +18,10 @@ import { getCurrentKoboldBinary, get as getConfig } from '../config';
import { startFrontend as startSillyTavernFrontend } from '@/main/modules/sillytavern'; import { startFrontend as startSillyTavernFrontend } from '@/main/modules/sillytavern';
import { startFrontend as startOpenWebUIFrontend } from '@/main/modules/openwebui'; import { startFrontend as startOpenWebUIFrontend } from '@/main/modules/openwebui';
import { startFrontend as startComfyUIFrontend } from '@/main/modules/comfyui'; import { startFrontend as startComfyUIFrontend } from '@/main/modules/comfyui';
import type { FrontendPreference } from '@/types'; import type {
FrontendPreference,
ImageGenerationFrontendPreference,
} from '@/types';
let koboldProcess: ChildProcess | null = null; let koboldProcess: ChildProcess | null = null;
@ -219,9 +222,20 @@ export const launchKoboldCppWithCustomFrontends = async (args: string[] = []) =>
'frontendPreference' 'frontendPreference'
)) as FrontendPreference; )) as FrontendPreference;
const imageGenerationFrontendPreference = (await getConfig(
'imageGenerationFrontendPreference'
)) as ImageGenerationFrontendPreference | undefined;
const result = await launchKoboldCpp(args, frontendPreference); const result = await launchKoboldCpp(args, frontendPreference);
const { isImageMode } = parseKoboldConfig(args); const { isImageMode, isTextMode } = parseKoboldConfig(args);
if (
frontendPreference === 'koboldcpp' ||
(!isTextMode && imageGenerationFrontendPreference === 'builtin')
) {
return result;
}
if (frontendPreference === 'sillytavern') { if (frontendPreference === 'sillytavern') {
startSillyTavernFrontend(args); startSillyTavernFrontend(args);

View file

@ -1,16 +1,23 @@
import { create } from 'zustand'; import { create } from 'zustand';
import type { MantineColorScheme } from '@mantine/core'; import type { MantineColorScheme } from '@mantine/core';
import type { FrontendPreference } from '@/types'; import type {
FrontendPreference,
ImageGenerationFrontendPreference,
} from '@/types';
type ResolvedColorScheme = 'light' | 'dark'; type ResolvedColorScheme = 'light' | 'dark';
interface PreferencesStore { interface PreferencesStore {
frontendPreference: FrontendPreference; frontendPreference: FrontendPreference;
imageGenerationFrontendPreference: ImageGenerationFrontendPreference;
rawColorScheme: MantineColorScheme; rawColorScheme: MantineColorScheme;
resolvedColorScheme: ResolvedColorScheme; resolvedColorScheme: ResolvedColorScheme;
systemMonitoringEnabled: boolean; systemMonitoringEnabled: boolean;
setFrontendPreference: (preference: FrontendPreference) => void; setFrontendPreference: (preference: FrontendPreference) => void;
setImageGenerationFrontendPreference: (
preference: ImageGenerationFrontendPreference
) => void;
setColorScheme: (scheme: MantineColorScheme) => Promise<void>; setColorScheme: (scheme: MantineColorScheme) => Promise<void>;
setSystemMonitoringEnabled: (enabled: boolean) => void; setSystemMonitoringEnabled: (enabled: boolean) => void;
loadPreferences: () => Promise<void>; loadPreferences: () => Promise<void>;
@ -37,6 +44,7 @@ mediaQuery.addEventListener('change', () => {
export const usePreferencesStore = create<PreferencesStore>((set) => ({ export const usePreferencesStore = create<PreferencesStore>((set) => ({
frontendPreference: 'koboldcpp', frontendPreference: 'koboldcpp',
imageGenerationFrontendPreference: 'match',
rawColorScheme: 'auto', rawColorScheme: 'auto',
resolvedColorScheme: 'light', resolvedColorScheme: 'light',
systemMonitoringEnabled: true, systemMonitoringEnabled: true,
@ -46,6 +54,16 @@ export const usePreferencesStore = create<PreferencesStore>((set) => ({
window.electronAPI.config.set('frontendPreference', preference); window.electronAPI.config.set('frontendPreference', preference);
}, },
setImageGenerationFrontendPreference: (
preference: ImageGenerationFrontendPreference
) => {
set({ imageGenerationFrontendPreference: preference });
window.electronAPI.config.set(
'imageGenerationFrontendPreference',
preference
);
},
setSystemMonitoringEnabled: (enabled: boolean) => { setSystemMonitoringEnabled: (enabled: boolean) => {
set({ systemMonitoringEnabled: enabled }); set({ systemMonitoringEnabled: enabled });
window.electronAPI.config.set('systemMonitoringEnabled', enabled); window.electronAPI.config.set('systemMonitoringEnabled', enabled);
@ -60,18 +78,23 @@ export const usePreferencesStore = create<PreferencesStore>((set) => ({
}, },
loadPreferences: async () => { loadPreferences: async () => {
const [frontendPref, colorScheme, systemMonitoring] = await Promise.all([ const [frontendPref, imageGenFrontendPref, colorScheme, systemMonitoring] =
window.electronAPI.config.get( await Promise.all([
'frontendPreference' window.electronAPI.config.get(
) as Promise<FrontendPreference>, 'frontendPreference'
window.electronAPI.app.getColorScheme(), ) as Promise<FrontendPreference>,
window.electronAPI.config.get( window.electronAPI.config.get(
'systemMonitoringEnabled' 'imageGenerationFrontendPreference'
) as Promise<boolean>, ) as Promise<ImageGenerationFrontendPreference>,
]); window.electronAPI.app.getColorScheme(),
window.electronAPI.config.get(
'systemMonitoringEnabled'
) as Promise<boolean>,
]);
set({ set({
frontendPreference: frontendPref || 'koboldcpp', frontendPreference: frontendPref || 'koboldcpp',
imageGenerationFrontendPreference: imageGenFrontendPref || 'match',
rawColorScheme: colorScheme || 'auto', rawColorScheme: colorScheme || 'auto',
resolvedColorScheme: resolveColorScheme(colorScheme || 'auto'), resolvedColorScheme: resolveColorScheme(colorScheme || 'auto'),
systemMonitoringEnabled: systemMonitoring ?? true, systemMonitoringEnabled: systemMonitoring ?? true,

View file

@ -18,6 +18,8 @@ export type FrontendPreference =
| 'openwebui' | 'openwebui'
| 'comfyui'; | 'comfyui';
export type ImageGenerationFrontendPreference = 'match' | 'builtin';
export type Screen = 'welcome' | 'download' | 'launch' | 'interface'; export type Screen = 'welcome' | 'download' | 'launch' | 'interface';
export interface GitHubAsset { export interface GitHubAsset {

View file

@ -1,4 +1,8 @@
import type { FrontendPreference, InterfaceTab } from '@/types'; import type {
FrontendPreference,
InterfaceTab,
ImageGenerationFrontendPreference,
} from '@/types';
import { FRONTENDS, SILLYTAVERN, OPENWEBUI, COMFYUI } from '@/constants'; import { FRONTENDS, SILLYTAVERN, OPENWEBUI, COMFYUI } from '@/constants';
export interface InterfaceOption { export interface InterfaceOption {
@ -8,22 +12,32 @@ export interface InterfaceOption {
export interface InterfaceSelectionParams { export interface InterfaceSelectionParams {
frontendPreference: FrontendPreference; frontendPreference: FrontendPreference;
imageGenerationFrontendPreference?: ImageGenerationFrontendPreference;
isTextMode: boolean; isTextMode: boolean;
isImageGenerationMode: boolean; isImageGenerationMode: boolean;
} }
export function getAvailableInterfaceOptions({ export function getAvailableInterfaceOptions({
frontendPreference, frontendPreference,
imageGenerationFrontendPreference = 'match',
isTextMode, isTextMode,
isImageGenerationMode, isImageGenerationMode,
}: InterfaceSelectionParams) { }: InterfaceSelectionParams) {
const chatItems: InterfaceOption[] = []; const chatItems: InterfaceOption[] = [];
const effectiveImageFrontend =
imageGenerationFrontendPreference === 'builtin'
? 'koboldcpp'
: frontendPreference;
if ( if (
frontendPreference === 'sillytavern' || frontendPreference === 'sillytavern' ||
frontendPreference === 'openwebui' frontendPreference === 'openwebui'
) { ) {
if (isTextMode || isImageGenerationMode) { if (
isTextMode ||
(isImageGenerationMode && effectiveImageFrontend === frontendPreference)
) {
const label = const label =
frontendPreference === 'sillytavern' frontendPreference === 'sillytavern'
? FRONTENDS.SILLYTAVERN ? FRONTENDS.SILLYTAVERN
@ -34,23 +48,25 @@ export function getAvailableInterfaceOptions({
label, label,
}); });
} }
} else { } else if (frontendPreference === 'koboldcpp') {
if (isTextMode) { if (isTextMode) {
chatItems.push({ chatItems.push({
value: 'chat-text', value: 'chat-text',
label: FRONTENDS.KOBOLDAI_LITE, label: FRONTENDS.KOBOLDAI_LITE,
}); });
} }
}
if (isImageGenerationMode) { if (isImageGenerationMode) {
const imageLabel = if (effectiveImageFrontend === 'comfyui') {
frontendPreference === 'comfyui'
? FRONTENDS.COMFYUI
: FRONTENDS.STABLE_UI;
chatItems.push({ chatItems.push({
value: 'chat-image', value: 'chat-image',
label: imageLabel, label: FRONTENDS.COMFYUI,
});
} else if (effectiveImageFrontend === 'koboldcpp') {
chatItems.push({
value: 'chat-image',
label: FRONTENDS.STABLE_UI,
}); });
} }
} }
@ -64,17 +80,29 @@ export function getAvailableInterfaceOptions({
export function getDefaultInterfaceTab({ export function getDefaultInterfaceTab({
frontendPreference, frontendPreference,
imageGenerationFrontendPreference = 'match',
isTextMode, isTextMode,
isImageGenerationMode, isImageGenerationMode,
}: InterfaceSelectionParams) { }: InterfaceSelectionParams) {
const effectiveImageFrontend =
imageGenerationFrontendPreference === 'builtin'
? 'koboldcpp'
: frontendPreference;
if ( if (
frontendPreference === 'sillytavern' || frontendPreference === 'sillytavern' ||
frontendPreference === 'openwebui' frontendPreference === 'openwebui'
) { ) {
if (
isImageGenerationMode &&
effectiveImageFrontend !== frontendPreference
) {
return 'chat-image';
}
return 'chat-text'; return 'chat-text';
} }
if (frontendPreference === 'comfyui' && isImageGenerationMode) { if (effectiveImageFrontend === 'comfyui' && isImageGenerationMode) {
return 'chat-image'; return 'chat-image';
} }
@ -96,13 +124,25 @@ export interface ServerInterfaceInfo {
export function getServerInterfaceInfo({ export function getServerInterfaceInfo({
frontendPreference, frontendPreference,
imageGenerationFrontendPreference = 'match',
isImageGenerationMode, isImageGenerationMode,
serverUrl, serverUrl,
}: { }: {
frontendPreference: FrontendPreference; frontendPreference: FrontendPreference;
imageGenerationFrontendPreference?: ImageGenerationFrontendPreference;
isImageGenerationMode: boolean; isImageGenerationMode: boolean;
serverUrl: string; serverUrl: string;
}) { }) {
if (
isImageGenerationMode &&
imageGenerationFrontendPreference === 'builtin'
) {
return {
url: `${serverUrl}/sdui`,
title: FRONTENDS.STABLE_UI,
};
}
if (frontendPreference === 'sillytavern') { if (frontendPreference === 'sillytavern') {
return { return {
url: SILLYTAVERN.PROXY_URL, url: SILLYTAVERN.PROXY_URL,

View file

@ -2,6 +2,7 @@ export function parseKoboldConfig(args: string[]) {
let host = 'localhost'; let host = 'localhost';
let port = 5001; let port = 5001;
let hasSdModel = false; let hasSdModel = false;
let hasTextModel = false;
for (let i = 0; i < args.length - 1; i++) { for (let i = 0; i < args.length - 1; i++) {
if (args[i] === '--hostname' || args[i] === '--host') { if (args[i] === '--hostname' || args[i] === '--host') {
@ -13,10 +14,13 @@ export function parseKoboldConfig(args: string[]) {
} }
} else if (args[i] === '--sdmodel') { } else if (args[i] === '--sdmodel') {
hasSdModel = true; hasSdModel = true;
} else if (args[i] === '--model') {
hasTextModel = true;
} }
} }
const isImageMode = hasSdModel; const isImageMode = hasSdModel;
const isTextMode = hasTextModel;
return { host, port, isImageMode }; return { host, port, isImageMode, isTextMode };
} }

View file

@ -1394,12 +1394,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:*, @types/node@npm:^24.9.1": "@types/node@npm:*, @types/node@npm:^24.9.2":
version: 24.9.1 version: 24.9.2
resolution: "@types/node@npm:24.9.1" resolution: "@types/node@npm:24.9.2"
dependencies: dependencies:
undici-types: "npm:~7.16.0" undici-types: "npm:~7.16.0"
checksum: 10c0/c52f8168080ef9a7c3dc23d8ac6061fab5371aad89231a0f6f4c075869bc3de7e89b075b1f3e3171d9e5143d0dda1807c3dab8e32eac6d68f02e7480e7e78576 checksum: 10c0/7905d43f65cee72ef475fe76316e10bbf6ac5d08a7f0f6c38f2b6285d7ca3009e8fcafc8f8a1d2bf3f55889c9c278dbb203a9081fd0cf2d6d62161703924c6fa
languageName: node languageName: node
linkType: hard linkType: hard
@ -2822,16 +2822,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"electron@npm:^38.4.0": "electron@npm:^39.0.0":
version: 38.4.0 version: 39.0.0
resolution: "electron@npm:38.4.0" resolution: "electron@npm:39.0.0"
dependencies: dependencies:
"@electron/get": "npm:^2.0.0" "@electron/get": "npm:^2.0.0"
"@types/node": "npm:^22.7.7" "@types/node": "npm:^22.7.7"
extract-zip: "npm:^2.0.1" extract-zip: "npm:^2.0.1"
bin: bin:
electron: cli.js electron: cli.js
checksum: 10c0/3458409151d12f1fcd5e95374aa36e0d2f4aa0d3421c9f57dc521c606070294f33b24a681b3f93b49b02f4a3a07eb0070100ebda51b1198efd4b49dbf1260713 checksum: 10c0/7d2272fe6d479edd6544a010008382f3acb21b6206a2585f67df25c43274a3c905affb98dac2e7ea367b51653e8697738c83409f051293545f69d69305d2892e
languageName: node languageName: node
linkType: hard linkType: hard
@ -3771,7 +3771,7 @@ __metadata:
"@huggingface/gguf": "npm:^0.3.2" "@huggingface/gguf": "npm:^0.3.2"
"@mantine/core": "npm:^8.3.5" "@mantine/core": "npm:^8.3.5"
"@mantine/hooks": "npm:^8.3.5" "@mantine/hooks": "npm:^8.3.5"
"@types/node": "npm:^24.9.1" "@types/node": "npm:^24.9.2"
"@types/react": "npm:^19.2.2" "@types/react": "npm:^19.2.2"
"@types/react-dom": "npm:^19.2.2" "@types/react-dom": "npm:^19.2.2"
"@types/yauzl": "npm:^2.10.3" "@types/yauzl": "npm:^2.10.3"
@ -3780,7 +3780,7 @@ __metadata:
"@uiw/react-codemirror": "npm:^4.25.2" "@uiw/react-codemirror": "npm:^4.25.2"
"@vitejs/plugin-react": "npm:^5.1.0" "@vitejs/plugin-react": "npm:^5.1.0"
cross-env: "npm:^10.1.0" cross-env: "npm:^10.1.0"
electron: "npm:^38.4.0" electron: "npm:^39.0.0"
electron-builder: "npm:^26.0.12" electron-builder: "npm:^26.0.12"
electron-updater: "npm:^6.6.2" electron-updater: "npm:^6.6.2"
electron-vite: "npm:^4.0.1" electron-vite: "npm:^4.0.1"