mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
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:
parent
c2400b9a58
commit
43de016261
14 changed files with 217 additions and 64 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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' }}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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) }} />}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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.',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
yarn.lock
20
yarn.lock
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue